En aquest cas s'ha dissenyat un mesurador que es comunica amb un script de Google, el qual guarda les dades en un full de càlcul. Si les pulsacions surten fora del rang considerat normal es canvia el color del NeoPixel.
També es va crear una aplicació de telèfon mòbil que permet veure l'última dada obtinguda i el gràfic de tots els valors de pulsacions, així com els valors màxim i mínim fins al moment.
El programa del microcontrolador és el següent:
#include <SPI.h> #include <WiFiNINA.h> #include <Adafruit_NeoPixel.h> #define LEDPIN 6 // Pota on hi ha el LED de la placa #define SENSOR A2 // Pota on hi ha el sensor #define ValComp 6 #define server_len 50 #define pag_len 400 #define P_max 200 #define P_min 40
const char idXarxa[] = "xarxa-wifi"; // Nom del punt d'accés const char contrasenya[] = "contrasenya-wifi""; //Contrassenya unsigned char Pulsacions = 0; Adafruit_NeoPixel cadena = Adafruit_NeoPixel(3, 1, NEO_GRB + NEO_KHZ800); boolean color = false; const String server0 = "script.google.com"; String pagina0 = ""; const String pagina_base = "/macros/s/^^fycby91BLlyp5Rk2UxpP1nvnRtliZrtnLbNeA02H3WIYHeoz4lnS9JimeEVosvzRbOM6DM/exec?" ; char server[server_len]; char pagina[pag_len]; unsigned long darreraConnexio = 0; bool pendent, completa, redir; bool ara = false; String data; String peticio = ""; String peticioAux = ""; int status = WL_IDLE_STATUS; WiFiSSLClient client;
void setup() { // Inicialització
Serial.begin(9600); // Monitor sèrie
pinMode(LEDPIN, OUTPUT);
digitalWrite(LEDPIN, LOW);
cadena.begin(); // Inicialitza els NeoPixels
cadena.show();
if (WiFi.status() == WL_NO_MODULE) {
Serial.println("No s'ha trobat el dispositiu Wi-Fi");
while (true); // Bloquegem el programa
}
String versio = WiFi.firmwareVersion();
if (versio < "1.0.0") {
Serial.println("Convindria actualitzar el firmware");
}
while (status != WL_CONNECTED) {
Serial.print("Connectant a la xarxa ");
Serial.println(idXarxa);
status = WiFi.begin(idXarxa, contrasenya);
delay(5000); // Ho tornarem a intentar passats 5 s
}
Serial.print("Connectat a ");
Serial.println(WiFi.SSID());
Serial.print("Estat de la connexió: ");
Serial.println(WiFi.status());
Serial.print("Adreça IP del dispositiu: ");
Serial.println(WiFi.localIP());
Serial.print("Intensitat del senyal: ");
Serial.print(WiFi.RSSI());
Serial.println(" dBm");
Serial.println();
redir = false;
}
void loop() {
while (client.available()) {
char c = client.read(); // Rebem caràcters del servidor
Serial.print(c);
if (c == '\n') { // Mirem si és un salt de línia
peticioAux = peticio; // Guardem la petició anterior
peticio = ""; // Ens preparem per a la línia següent
completa = true; // Preparat per escriure-ho
} else {
peticio += c; // Afegim el caràcter rebut
}
if (completa){ // Ha arribat una línia completa
if (peticioAux.startsWith("HTTP/1.1 200")){ // Resposta bona
pendent = true;
}
if (peticioAux.startsWith("HTTP/1.1 302")){ // Redireccionament
redir = true;
}
if (redir && (peticioAux.startsWith("Location:"))){
// Si hi ha redireccionament, hem de buscar l'adreça
// i extreure'n el servidor i la pàgina
String adre = peticioAux.substring(peticioAux.indexOf("//") +2);
String server1 = adre.substring(0, adre.indexOf(".com") +4);
String pagina1 = adre.substring(adre.indexOf(".com") +4);
server1.toCharArray(server, 50);
pagina1.toCharArray(pagina, 400);
ara = true;
}
completa = false;
}
}
// Hi ha una resposta per processar
// Però ignorarem les dades que ens envia l'script
if (pendent) {
pendent = false;
}
// Quan toca, tornem a fer una petició
Pulsacions = llegir();
if (Pulsacions>P_max || Pulsacions<P_min){
color = true;
}else{
color = false;
}
data = "t=";
data += Pulsacions;
if (redir){
redir = false;
}else {
pagina0 = pagina_base + data;
server0.toCharArray(server, server_len);
pagina0.toCharArray(pagina, pag_len);
}
ara = false;
client.stop();
if (client.connect(server, 443)) {
Serial.println("S'ha fet la connexió al servidor");
client.print("GET ");
client.print(pagina);
client.println(" HTTP/1.1");
client.print("Host: ");
client.println(server);
client.println("Connection: close");
client.println();
// Guardem quan hem fet la connexió
darreraConnexio = millis();
Serial.print("Enviat: ");
Serial.println(data);
} else {
Serial.println("connection failed");
}
}
unsigned char llegir(){
unsigned int Max = 0;
unsigned int Min = 4096;
unsigned int Centre = 0;
unsigned char Polsos = 0;
boolean Pols = 1;
unsigned long TempsLec = millis();
unsigned long Temps = millis();
while((millis() - Temps) <= 15000){
if((millis() - TempsLec) >= 2){
TempsLec = millis();
unsigned int Lectura = analogRead(SENSOR);
if(Centre == 0){
if(Lectura > Max){
Max = Lectura;
}
if(Lectura < Min){
Min = Lectura;
}
if((millis() - Temps) > 2000){
Centre = (Max + Min) / 2; // Ja tenim el valor del centre de l'ona
Temps = millis(); // Torna a iniciar el temps
if((Max-Min)>300||(Max-Min)<50){ //Si el max i min estan molt allunyats
Serial.print("Max = ");
Serial.print(Max);
Serial.print(" Centre = ");
Serial.print(Centre);
Serial.print(" Min = ");
Serial.println(Min);
Serial.println("Tornant a calcular centre");
cadena.setPixelColor(0, 0, 0, 250); // NeoPixel blau
cadena.show();
Centre = 0;
delay(3000)
Temps = millis(); //tornem a calcular el centre
Min = 4096;
Max = 0;
}else{
Serial.println("Centre trobat");
Serial.print("Max = ");
Serial.print(Max);
Serial.print(" Centre = ");
Serial.print(Centre);
Serial.print(" Min = ");
Serial.println(Min);
}
}
} else {
if(Pols){ // Si busquem la vall
if(Lectura < (Centre + Min)/2){
Pols = 0; // Hem trobat la vall
digitalWrite(LEDPIN, LOW); // Apaga el LED
cadena.setPixelColor(0, 0, 0, 0); // Apaga el NeoPixel
cadena.show();
}
} else {
if(Lectura > (Centre + Max)/2){
Pols = 1; // Hem trobat el pic
digitalWrite(LEDPIN, HIGH); // Encén el LED
if(color){ //Si les pulsacions estan fora del intèrval acceptat
cadena.setPixelColor(0, 200, 0, 0); // Encén NeoPixel vermell
cadena.show();
}else{
cadena.setPixelColor(0, 0, 200, 0); // Encén NeoPixel verd
cadena.show();
}
Polsos++; // Afegim un pols
}
}
}
}
}
Polsos = Polsos * 4;
return Polsos;
}
El programa de l'script és el següent:
var IdFull = "^^vwT764z-Xc7VV-Z7Vi6mAYbYnt15r_N6mBb4VzAyUA"; // Identificador del full de càlcul
var numFull = 0; // Número del full amb el que hem de treballar
var numCols = 2; // Nombre de columnes que hem de llegir
// Funció que s'executa quan hi ha una ordre get
// t Valor de les pulsacions
function doGet(e) {
var resultat = '';
var camps = new Array(1); // Valors per guardar a la taula
var Accio = e.parameter.acc;
// Assignem els paràmetres a variables
var Pols = e.parameter.t;
if (Accio == undefined){
if (Pols == undefined){
resultat = 'Falten paràmetres';
} else {
var sh = SpreadsheetApp.openById(IdFull);
var sheet = sh.getSheets();
if (sheet[numFull].getLastRow()>=181){
sheet[numFull].deleteRows(2,180);
}
camps[0] = Pols;
sheet[numFull].appendRow(camps);
resultat = 'Valors guardats';
}
}
if (Accio == "read"){
var sh = SpreadsheetApp.openById(IdFull);
var sheet = sh.getSheets();
// Llegim les dades del full seleccionat
var full = sheet[numFull].getDataRange().getValues();
range = sheet[numFull].getLastRow(); // Índex de la darrera filera (+1 pels títols)
if (range > 1){ // Si és 1 només hi ha els títols
var filera = full[range -1]; // Agafem la darrera filera
var resultat = '';
for(var j = 0;j < numCols;j++){
if (j > 0){
resultat = resultat + '/'; // La barra separarà els valors
}
resultat = resultat + filera[j];
}
}
}
return ContentService.createTextOutput(resultat);
}
L'aplicació feta amb App Inventor té una pantalla. La disposició d'elements és:

El programa d'aquesta pantalla és el següent:


Aquesta obra d'Oriol Boix està llicenciada sota una llicència no importada Reconeixement-NoComercial-SenseObraDerivada 3.0.