Operații de bază pe un modul wifi ESP8266 de la Arduino
Când Espresiv a lansat primele module pe piață Wifi cu cel integrat ESP8266 și firmware cu care să-l manevrem folosind comenzi AT, ceea ce ne-a interesat pe noi, utilizatorii, era să îl integrăm în ansambluri microcontrolere iar problemele s-au redus la cunoașterea (fosta) întunericului Tabelul de comandă ESP8266 AT, nevoile de hrănire sau Actualizare firmware ESP8266.
Apoi au sosit rapid alternative pentru a programa ESP8266 și implementări de module Wifi de formate foarte diferite care au ridicat alte preocupări: ce modul WiFi ESP8266 să alegeți în funcție de raza de acțiune a diferitelor antene (inclusiv cele externe) sau de integrarea fizică a acestor noi module în ansamblurile noastre.
Cu siguranță, din cauza tuturor acestor schimbări, s-ar putea să nu se fi pus accent pe aspectele cele mai elementare, pe cel mai elementar management al Modul WiFi ESP8266. Cu toate că polaritate.es Puteți găsi informații despre utilizarea ESP8266 și există unele aplicații menite să explice într-un mod generic funcționarea Modul WiFi ESP8266 folosind comenzi AT, în special în articolul despre bibliotecă pentru a face interogări HTTP din Arduino cu modulul WiFi ESP8266, impresiile cititorilor sugerează că ar fi util să adăugați mai multe informații de bază pentru a ajuta utilizatorii ESP8266 pentru a realiza propriile implementări.
Discutați operațiunile de bază pentru a lucra cu ESP8266 și propunerea de soluții generice este un obiectiv din mai multe părți foarte diferite; Pentru a ajuta la urmărirea conținutului articolului, următorul index poate servi drept ghid:
- Controlați modulul wifi ESP8266 de la computer prin portul serial
- Actualizați firmware-ul cu esptool
- Trimiteți comenzi către modul
- Primiți date de la ESP8266
- Analizați răspunsul căutând texte în conținut
- Limitați timpul de așteptare pentru primirea răspunsului
- Executați o operație complexă definită de mai multe comenzi AT
Controlați modulul wifi ESP8266 de la computer prin portul serial
Din farfurie Arduino și folosind dvs IDE este posibil să se monitorizeze funcționarea unui Modul WiFi ESP8266, trimite comenzi ESP8266 AT si vezi raspunsul dar este mult mai comod sa o faci de pe un calculator cu o aplicatie de tip terminal.
Depinde de ce placa Arduino utilizat, este posibil să fie disponibil un singur port serial hardware, ceea ce adaugă un mic inconvenient la trimitere și primire. Schimbarea vitezei de comunicație este mult mai confortabilă într-o aplicație de comunicații seriale de la un computer și unele plăci de bază. Arduino (și în unele circumstanțe) nu acceptă bine vitezele mai mari ale comunicațiilor seriale, în special 115200 baud, care este viteza implicită a celor mai recente versiuni ale firmware.
Despre Ce program să utilizați pentru a monitoriza ESP8266 folosind portul serial, sunt multe din care sa alegi in functie de nevoi si preferinte; in ultimul timp folosesc mai mult clasicul CuteCom (cel din captura de ecran de mai sus) pentru că îmi este foarte confortabil să repet anumite Modul wifi ESP8266 AT comenzi în testarea proiectelor.
Unele recomandări au fost deja date aici cu privire la programele care funcționează ca o consolă serială; De exemplu, când vorbim despre PuTTY pentru controlul dispozitivelor seriale UART de pe computer. PuTTYPe lângă faptul că este o aplicație excelentă, este disponibilă pentru majoritatea sistemelor de operare desktop. Mai mult, ca PuTTY poate fi folosit pentru a acționa ca o consolă atât cu portul serial, cât și cu portul Familia de protocoale de internet (TCP/IP), inclusiv cele care operează pe TLS, devine un instrument obișnuit care mai mult decât să răsplătească timpul (puțin) petrecut configurându-l și obișnuindu-se cu utilizarea lui.
Pe lângă software-ul de comunicații seriale, pentru conectarea Modul WiFi ESP8266 spre port USB Un computer necesită și un convertor USB o serie TTL. Ca și în cazul software-ului, există mai multe versiuni, din care sunt folosite doar pentru a converti portul USB pe un port serial TTL (care pot fi obținute de la un euro) până la cele care pot emula diferite protocoale (cum ar fi SPI o I2C).
La fel ca un program care funcționează ca o consolă serială, hardware-ul prin care să comunice computerul USB cu un circuit logic (nu doar ESP8266) va fi un instrument comun în munca unui dezvoltator de aplicații microcontrolate, merită să îl aveți în cutia de instrumente cât mai curând posibil și să lucrați cu el Modul WiFi ESP8266 Este o oportunitate excelentă de a obține unul.
Convertorul USB a UART TTL Poate fi folosit și pentru a monitoriza comportamentul unui circuit care utilizează ESP8266, pentru a face acest lucru, ieșirile pe care doriți să le monitorizați sunt conectate în serie la intrarea de date (RX) a convertorului cu o diodă rapidă ( 1N4148, de exemplu) și un rezistor (2K2, de exemplu) în paralel unul cu celălalt. O astfel de configurare funcționează ca un sniffer serial hardware.
Deși snifferul din imaginea de mai sus este cu siguranță rudimentar (printre altele nu are tampon) este suficient pentru a monitoriza funcționarea unui ansamblu cu Arduino și ESP8266.
Eliminarea sniffer-ului din schema anterioară, the schematică care arată cum se conectează a Modul WiFi ESP8266 la o farfurie Arduino. Pe lângă alimentarea acestuia la 3V3, pinul de resetare și pinul de activare al integratului trebuie să fie conectate la un nivel înalt (activare). Desigur, pinul RX al unuia trebuie să se conecteze la TX-ul celuilalt.
Pentru a simplifica diagrama anterioară, a fost reprezentată o placă Arduino alimentat la 3V3 și pentru care se presupune că o tensiune pe portul serial este de asemenea 3V3. Dacă utilizați un microcontroler cu un nivel diferit de semnal pe portul serial (de obicei 5 V) va fi necesar, pentru a nu deteriora ESP8266, folosește o convertor de nivel ca cele din diagramele de mai jos. Acest circuit se găsește frecvent în multe implementări comerciale de module disponibile.
Actualizați firmware-ul ESP8266
Las comenzi ESP8266 AT, terminarea acestuia, viteza implicită a modulului... depind de versiunea firmware ESP8266. Cel mai bine este să vă asigurați că aveți aceeași versiune în toate modulele și, dacă este posibil, că este cea mai recentă versiune.
Din păcate, majoritatea Modele de module wifi ESP8266 Au doar 4Mbit, deci cea mai recentă versiune nu poate fi instalată pe ele. Cea mai recentă versiune (oficială) de firmware pe care poate fi instalată Module wifi ESP8266 cu 4 Mbit (majoritatea) este 0.9.4 care include versiunea 0.2 a comenzi ESP8266 AT.
Pe scurt, pentru a actualiza firmware-ul aveți nevoie de:
-
Descărcați versiunea de firmware corespunzătoare. cea mai recentă versiune (oficială) pentru un modul cu 4Mbit de memorie, găsită în folderul Espressif de pe github. În Site-ul Espressif Puteți descărca cea mai recentă versiune a firmware-ului, dar este foarte important să verificați dacă modulul pe care este instalat are suficientă memorie.
-
Descărcați cea mai recentă versiune a instrumentului de instalare a firmware-ului. Preferatul meu este esptool care este scris în Piton, deci funcționează pe orice platformă. Pe lângă faptul că este descărcat, poate fi instalat și cu
pip install esptool
(opip2
opython -m pip
…). Desigur, Espresiv De asemenea, oferă propriul instrument, dar în prezent este disponibil numai pentru Windows. -
Pregătiți fișierele descărcate; dezarhivați-le într-un folder accesibil și, dacă este necesar, faceți instrumentul executabil esptool, în cazul meu, din moment ce GNU / Linux, Cu
chmod +x esptool
-
Conectați modulul la computer folosind un convertor USB UART TTL care funcționează la 3V3 sau folosiți un convertor de nivel dacă funcționează la 5 V. Pe lângă putere, va trebui să conectați TX la RX al convertorului USB UART TTL, RX la TX, GPIO0 la nivel scăzut (GND) și poate GPIO2 la nivel înalt (în testele mele a funcționat atât conectându-l la nivel scăzut, cât și deconectandu-l). Dacă modulul are conexiunea GPIO15 liberă (cum se întâmplă în ESP-12), acesta trebuie conectat la un nivel scăzut. RESET, care ar fi în mod normal la un nivel ridicat în timpul funcționării, poate fi lăsat neconectat sau conectat la un nivel înalt prin intermediul unui rezistor (10K, de exemplu), deoarece înainte de a începe înregistrarea poate fi necesară resetarea dispozitivului conectându-l. la un nivel scăzut.
Prin pornirea modulului, acesta va fi disponibil pentru actualizare, dar, Dacă se afișează o eroare de conexiune, va fi necesar să o resetați conectarea RESET la un nivel scăzut pentru o clipă și apoi lăsarea ei (fără conectare) pentru procesul de actualizare.
Modulul are vârfuri de consum de jumătate de amperi (până la 600 mA, după unii utilizatori) deci este important să folosiți o sursă de alimentare capabilă să suporte acest consum, mai ales pentru actualizarea firmware-ului. -
Rulați instrumentul pentru a actualiza firmware-ul. În cazul meu, am salvat instrumentul și documentele firmware la pasul 3 în același folder, așa că rulez din consolă:
cd ~/Datos/firmwareESP8266
(schimbați în folderul care conține instrumentul și firmware-ul)./esptool.py --baud 115200 --port /dev/ttyUSB0 write_flash \
0x00000 ./boot_v1.1.bin \
0x01000 ./user1.bin \
0x7C000 ./esp_init_data_default.bin \
0x7E000 ./blank.bin
--baud
setează viteza ESP8266 (115200 baud în cazul meu) și--port
portul serial la care se conectează (în cazul meu, emulat, primul USB). Diferitele documente care alcătuiesc firmware-ul merg în urmăwrite_flash
precedat de adresă, cu documentul user1.bin care conține încărcătura utilă de actualizare.
Trimiteți comenzi către modulul WiFi ESP8266
Pentru a controla ESP8266 de la un computer cu care va trebui să începem configurați aplicația pentru care va fi suficient să ① alegeți portul la care este conectat convertorul USB UART TTL, ceva asemănător cu /dev/USB0
în GNU/Linux și similar sau ceva de genul COM6
în Windows, ② alegeți viteza la care ESP8266, probabil 115200 baud, ③ setați 8 biți de date plus un bit de oprire, fără paritate sau strângere de mână și ④ setați sfârșitul liniei, în funcție de firmware, aproape întotdeauna CR+LF.
Odată ce aplicația este configurată (sau, după caz, stocată și selectată), aceasta este deschide conexiunea („dispozitiv deschis” și, respectiv, „deschidere”, în capturile de ecran din exemplele de mai sus cu CuteCom y PuTTY) și puteți începe să trimiteți comenzi către ESP8266.
După cum se poate vedea în Tabelul de comandă ESP8266 AT, formatul de activare, dezactivare, setare a unei valori și referire la ea este destul de previzibil, dar în general nu este ușor să le reții pe toate și probabil că va trebui să o ai la îndemână pentru a te referi la el.
Modul de enviar comenzi AT al Modul WiFi ESP8266 de la Arduino este foarte simplu: ① configurează comunicațiile cu Serial.begin(115200);
(sau Serial1, Serial2... pe plăci cu mai multe porturi seriale hardware) și ② trimite comenzile folosind formatul Serial.print(orden+"\r\n");
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
#define PUERTO_SERIE Serial // Objeto serie que corresponde a puerto serie hardware al que está conectado el módulo wifi ESP8266
#define VELOCIDAD_ESP8266 115200 // Velocidad, en baudios, a la que está configurado el ESP8266
#define IDENTIFICADOR_WIFI “polaridad.es” // SSID (Service Set Identifier)
#define CLAVE_WIFI “54lLij1RiTn3MEd3v41C” // Clave del punto de acceso wifi al que se conecta el ESP8266
void setup()
{
PUERTO_SERIE.begin(VELOCIDAD_ESP8266);
PUERTO_SERIE.print
(
“AT+CWJAP=\””+
String(IDENTIFICADOR_WIFI)+
“\”,\””+
String(CLAVE_WIFI)+
“\”\r\n”
);
}
void loop()
{
}
|
Exemplul de mai sus arată cum se trimite Modul wifi ESP8266 AT comenzi de la Arduino. În acest caz este ilustrat AT+CWJAP
, care este utilizat pentru a vă conecta la un punct de acces. Această comandă folosește ca argumente identificatorul punctului de acces (SSID) și cheia, ambele între ghilimele, deci devin obiect Srtring
și includeți-le între ghilimele folosind codul de escape (\"
). Pentru a finaliza comanda, utilizați \r\n
care corespunde CR
y LF
.
De reținut că portul serial nu este întotdeauna identificat cu Serial
(pe anumite farfurii poate fi Serial1
, Serial2
…) obiectul port utilizat a fost definit prin alocarea acestuia macro-ului PUERTO_SERIE
. Detectarea tipului de placă utilizată ar putea adăuga un pic de inteligență selecției portului serial; Mai târziu vom analiza cum puteți afla tipul de Arduino. Restul definițiilor sunt cele obișnuite care vă permit să „denumiți” valorile constante pentru a evita repetarea lor (și greșelile) și pentru a le schimba mai ușor.
Exemplul de mai sus ar trebui să conecteze Modul WiFi ESP8266 la punctul de acces indicat, dar era deja conectat înainte? A funcționat conexiunea? Pentru a ști asta, trebuie să „ascultăm” ceea ce ESP8266
Primiți date de la modulul wifi ESP8266
Conectând sniffer-ul de date explicat mai sus la computer, puteți vedea ce Arduino a trimis către ESP8266 și răspunsul lui. De citit din Arduino și procesează informațiile din el va fi necesar să se detecteze cu Serial.available()
dacă au sosit date și dacă da încărcați-le cu Serial.read()
. Următorul exemplu arată cum să citiți răspunsul de la AT+CWJAP?
, care va raporta dacă există o conexiune la orice punct de acces.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
#define PUERTO_ESP8266 Serial // Objeto serie que corresponde a puerto serie hardware al que está conectado el módulo wifi ESP8266
#define VELOCIDAD_ESP8266 115200 // Velocidad, en baudios, a la que está configurado el ESP8266
char letra_recibida;
void setup()
{
PUERTO_ESP8266.begin(VELOCIDAD_ESP8266);
PUERTO_ESP8266.print(“AT+CWJAP?\r\n”);
}
void loop()
{
while(PUERTO_ESP8266.available())
{
letra_recibida=PUERTO_ESP8266.read();
}
}
|
Ca pe o farfurie Arduino Uno (și în altele) deschiderea monitorului serial resetează programul, acesta poate fi folosit pentru a vedea în consola serial Arduino informațiile către care trimiteți ESP8266 așa cum arată captura de ecran din imaginea de mai jos.
Analizați răspunsul trimis de modulul wifi ESP8266
Am văzut deja cum să citim informațiile care ajung Arduino din ESP8266. Problema cu care trebuie să te confrunți este că nu știi când va începe să sosească, cât va dura să ajungă, ce lungime va avea... și nu este foarte eficient să aștepți răspunsul de la ESP8266 este primit fără a lăsa microcontroler îndeplini alte sarcini între timp.
O modalitate simplă de a gestiona această circumstanță este iterează asupra datelor primite căutând răspunsuri concrete cu care, de exemplu, se activează indicatori (steaguri sau variabile booleene) care vor determina dacă se continuă căutarea în textul primit și ce acțiuni ar trebui efectuate pe baza informațiilor care sosesc din ESP8266. În timp ce răspunsul vine microcontroler se poate dedica altor sarcini, de exemplu, primirea datelor de la senzori și procesarea acestora.
Căutați un text în informațiile primite de la ESP8266
Pentru a căuta textul care provine din ESP8266 poți compara fiecare scrisoare primita cu cea care corespunde mesajului pe care il cauti. Va fi necesar să folosiți un numărător (sau un indicator) care indică litera care trebuie comparată; Dacă personajul care vine din ESP8266 este la fel cu cel examinat in mesaj, contorul avanseaza, daca este diferit se initializeaza.
Pentru a ști că s-a ajuns la final, se consultă următorul caracter al mesajului căutat, care va fi zero (\0
) sau se stochează lungimea mesajului pentru a, comparându-l cu contorul, să știe dacă comparația s-a încheiat și, prin urmare, Modul WiFi ESP8266 a trimis mesajul dorit.
Următorul exemplu utilizează comanda AT+CWLAP
care va returna o lista de puncte de acces si in cadrul acestora se cauta unul numit "wifi polaridad.es". Deși am ales să verificăm că ultimul caracter este zero, deoarece tampon Stochează doar textul căutat și se cunoaște lungimea acestuia, se poate verifica și dacă s-a primit un astfel de număr de litere corecte. Cu LED-uri conectat la pinul 2 se raportează că a fost găsit textul așteptat.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
#if defined(ARDUINO_AVR_LEONARDO)||defined(ARDUINO_AVR_MEGA2560) /* ¿Es una placa Arduino Mega 2560 o Arduino Leonardo? */
#define SERIE Serial1 /* Si es una placa Arduino Mega 2560 o Arduino Leonardo usar Serial1 */
#else /* En este proyecto solamente uso Placas Leonardo, Mega 2560 y Uno, así que tiene que ser un Arduino Uno si llega hasta aquí */
#define SERIE Serial /* Si es una placa Arduino Uno usar Serial */
#endif
#define VELOCIDAD 115200 // Velocidad (en baudios) al que está configurado el módulo wifi ESP8266 (Cuidado con la placa utilizada, no todas o siempre son capaces de trabajar a una velocidad tan alta)
#define ORDEN “AT+CWLAP\r\n” // Buscar los puntos de acceso wifi disponibles. (Dependiendo de la versión del firmware) Las órdenes terminan en CR+LF
#define MENSAJE_BUSCADO “wifi polaridad.es” // Ver si está disponible el punto de acceso llamado “wifi polaridad.es”
#define LONGITUD_MENSAJE 18 // Se necesita guardar, al menos, 17 letras y el terminador \0
#define PIN_LED_ENCONTRADO 2 // Pin al que se conecta el LED que informa de que se ha encontrado el texto (el punto de acceso buscado está disponible)
#include <string.h> // strncpy
boolean esperando=true;
char buffer_mensaje;
char mensaje[LONGITUD_MENSAJE];
byte posicion_mensaje=0;
void setup()
{
pinMode(PIN_LED_ENCONTRADO,OUTPUT);
digitalWrite(PIN_LED_ENCONTRADO,LOW); // Apagar el LED (por ahora no se ha encontrado el mensaje)
strncpy(mensaje,MENSAJE_BUSCADO,LONGITUD_MENSAJE); // sizeof(mensaje)
SERIE.begin(VELOCIDAD); // Configurar el puerto serie de Arduino a la velocidad del ESP8266
SERIE.print(ORDEN); // Enviar la orden (consultar los puntos de acceso disponibles) al módulo wifi ESP8266
}
void loop()
{
if(esperando) // Buscará infinitamente hasta que llegue el texto esperado (y si no existe el punto de acceso nunca llegará ¡Es un ejemplo!)
{
while(SERIE.available()) // Si ha llegado algún dato por el puerto serie…
{
buffer_mensaje=SERIE.read(); // …almacenarlo en el buffer
if(buffer_mensaje==mensaje[posicion_mensaje]) // Si el dato que ha llegado es igual al que correspondería del mensaje buscado…
{
posicion_mensaje++; // Pasar a la siguiente letra del mensaje
if(mensaje[posicion_mensaje]==0) // ¿Ha terminado de analizarse todo el mensaje? (la última letra de la cadena de texto es \0)
{
esperando=false; // Si se ha terminado de analizar con éxito todo el mensaje ya no se está esperando
digitalWrite(PIN_LED_ENCONTRADO,HIGH); // Encender el LED para indicar que se ha encontrado el texto buscado
}
}
else // Si la letra que ha llegado por el puerto serie no corresponde con la buscada del mensaje…
{
posicion_mensaje=0; // …empezar desde la primera letra del texto buscado
}
}
}
}
|
În codul exemplului anterior puteți vedea și o modalitate de a alegeți portul serial în funcție de tipul plăcii Arduino folosit. Acest exemplu presupune că aveți trei tipuri de plăci pentru proiect: unul Arduino Uno, One Arduino Mega 2560 și o arduino leonardo. Dacă lucrați cu un Arduino Uno va fi folosit Serial
si altfel Serial1
.
Dacă lucrezi cu o farfurie arduino leonardo Puteți folosi aceeași metodă pentru a opri programul și a aștepta consola (portul serial asociat cu Serial
) este disponibil.
1
2
3
4
5
6
7
8
9
10
11
|
#ifdef ARDUINO_AVR_LEONARDO
#define SERIE Serial1
#define ESPERA_CONSOLA while(!Serial){} /* Esperar a la consola */
#else
#define ESPERA_CONSOLA /* Si no es un Arduino Leonardo no hace falta esperar a la consola */
#ifdef ARDUINO_AVR_MEGA2560
#define SERIE Serial1
#else // En este proyecto solamente uso Placas Leonardo, Mega 2560 y Uno, así que tiene que ser un Arduino Uno si llega hasta aquí
#define SERIE Serial
#endif
#endif
|
Căutați diverse texte în răspunsul ESP8266
Codul din exemplul anterior este folosit pentru a căuta text în informațiile trimise de ESP8266 dar răspunsul poate include informații diferite în funcție de operație. Să presupunem, pentru a începe cu un caz simplu din exemplul următor, că textul trimis de către MCU ESP8266 es OK
când operaţia este efectuată corect şi ERROR
In rest, ca la comanda AT+CWJAP?
, care servește la verificarea dacă Modul WiFi ESP8266 este deja conectat la un punct de acces.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
#if defined(ARDUINO_AVR_LEONARDO)||defined(ARDUINO_AVR_MEGA2560) /* ¿Es una placa Arduino Mega 2560 o Arduino Leonardo? */
#define SERIE Serial1 /* Si es una placa Arduino Mega 2560 o Arduino Leonardo usar Serial1 */
#else /* En este proyecto solamente uso Placas Leonardo, Mega 2560 y Uno, así que tiene que ser un Arduino Uno si llega hasta aquí */
#define SERIE Serial /* Si es una placa Arduino Uno usar Serial */
#endif
#define VELOCIDAD 115200 // Velocidad (en baudios) al que está configurado el módulo wifi ESP8266 (Cuidado con la placa utilizada, no todas o siempre son capaces de trabajar a una velocidad tan alta)
#define ORDEN “AT+CWJAP?\r\n” // Verificar que está conectado a un punto de acceso
#define CANTIDAD_MENSAJES 2 // Se distingue entre dos mensajes: acierto y error que se identificarán con true y false
#define MENSAJE_ACIERTO “OK”
#define MENSAJE_ERROR “ERROR”
#define LONGITUD_MENSAJE 6 // Se necesita guardar, al menos, 5 letras y el terminador \0 (Un pequeño desperdicio al hacer una matriz en la que todos los elementos ocupan como el mayor. Es admisible porque son muy pocos elementos y así no se complica este ejemplo inicial)
#define PIN_LED_ACIERTO 2 // Pin al que se conecta el LED que informa del acierto
#define PIN_LED_ERROR 3 // Pin al que se conecta el LED que informa del error
#include <string.h> // strncpy
boolean esperando=true; // Todavía no se ha encontrado el final del mensaje
char buffer_mensaje; // Para almacenar la última letra cargada desde el ESP8266
byte led_estado[CANTIDAD_MENSAJES]; // Un LED (pin) para cada estado
char mensaje[CANTIDAD_MENSAJES][LONGITUD_MENSAJE]; // Mensajes de acierto y error
byte posicion_mensaje[CANTIDAD_MENSAJES]; // Un contador de posición para cada mensaje
void setup()
{
led_estado[true]=PIN_LED_ACIERTO;
led_estado[false]=PIN_LED_ERROR;
for(byte numero_mensaje=0;numero_mensaje<CANTIDAD_MENSAJES;numero_mensaje++)
{
pinMode(led_estado[numero_mensaje],OUTPUT); // Establecer el pin del LED
digitalWrite(led_estado[numero_mensaje],LOW); // Apagar el LED
posicion_mensaje[numero_mensaje]=0; // Inicializar a cero el número de letra a analizar de cada mensaje
}
strncpy(mensaje[true],MENSAJE_ACIERTO,LONGITUD_MENSAJE); // Preparar el mensaje de acierto
strncpy(mensaje[false],MENSAJE_ERROR,LONGITUD_MENSAJE); // Preparar el mensaje de error
SERIE.begin(VELOCIDAD); // Configurar el puerto serie de Arduino a la velocidad del ESP8266
SERIE.print(ORDEN); // Enviar la orden (verificar si existe conexión a un punto de acceso) al módulo wifi ESP8266
}
void loop()
{
if(esperando) // Buscará infinitamente hasta que llegue el texto esperado (y si no existe el punto de acceso nunca llegará ¡Es un ejemplo!)
{
while(SERIE.available()) // Si ha llegado algún dato por el puerto serie…
{
buffer_mensaje=SERIE.read(); // …almacenarlo en el buffer
for(byte numero_mensaje=0;numero_mensaje<CANTIDAD_MENSAJES;numero_mensaje++)
{
if(buffer_mensaje==mensaje[numero_mensaje][posicion_mensaje[numero_mensaje]]) // Si el dato que ha llegado es igual al que correspondería del mensaje buscado…
{
posicion_mensaje[numero_mensaje]++; // Pasar a la siguiente letra del mensaje
if(mensaje[numero_mensaje][posicion_mensaje[numero_mensaje]]==0) // ¿Ha terminado de analizarse todo el mensaje actual? (la última letra de la cadena de texto es \0)
{
esperando=false; // Si se ha encontrado algún mensaje y ya no se está esperando
digitalWrite(led_estado[numero_mensaje],HIGH); // Encender el LED correspondiente al mensaje encontrado
}
}
else // Si la letra que ha llegado por el puerto serie no corresponde con la buscada del mensaje…
{
posicion_mensaje[numero_mensaje]=0; // …empezar desde la primera letra del texto buscado
}
}
}
}
}
|
Această nouă implementare a aceleiași metode, care caută o potrivire cu mai multe mesaje posibile, vă permite să alegeți între diferite acțiuni în funcție de răspunsul primit de la ESP8266, pur și simplu porniți LED-uri care corespunde.
Limitați timpul necesar pentru a primi un răspuns
Până acum nu s-a făcut referire la o problemă relevantă: the timpul maxim de așteptare (timeout) înainte de a considera o operațiune eșuată. Dacă din orice motiv legătura cu Modul WiFi ESP8266, modulul cu punctul de acces, punctul de acces cu Internet sau, de exemplu, un server ipotetic nu este disponibil, programul poate fi blocat la un moment dat așteptând pe termen nelimitat, așa că va trebui articulat un răspuns la astfel de circumstanțe. Timpul maxim de așteptare poate fi configurat pentru întreaga aplicație, de obicei va fi mai „generoasă” în acest caz, sau timpii de așteptare individuali pot fi programați pentru fiecare operațiune.
Pentru a verifica dacă (cel puțin) a trecut un anumit interval de timp „Timpul” momentului în care se începe contul se scade de obicei din „ora” curentă și se verifică că diferența este mai mare decât limita dorită. Acest „timp” nu trebuie să fie în timp real, de obicei corespunde intervalului care a trecut de la MCU începeți să numărați timpul; Acest lucru nu afectează programul, deoarece ceea ce este interesant este timpul scurs și nu timpul absolut.
De obicei, pentru a verifica dacă a trecut un anumit interval, se folosește o expresie de tipul:
1
|
(unsigned long)(millis()–milisegundos_al_empezar)>intervalo_de_tiempo
|
variabil milisegundos_al_empezar
conţine valoarea de millis()
a unui anumit moment al execuției de la care este cronometrat, așa că nu este neobișnuit ca numele său să se refere la cuvântul „cronometru”. Variabila intervalo_de_tiempo
conține numărul maxim de milisecunde care face ca expresia anterioară să fie adevărată, adică reprezintă timeout-ul; Este de obicei o constantă (sau o macro) și, ca și în cazul precedent, cuvântul „TIMEOUT” apare adesea în numele său. Dacă lucrați cu intervale foarte scurte, puteți utiliza micros()
în loc de millis()
(microsecunde în loc de milisecunde) deși este mult mai puțin comun și mult mai puțin precis.
1
|
(unsigned long)(millis()–cronometro)>TIMEOUT
|
Un întreg lung în Arduino (unsigned long
) ocupă 4 octeți (32 de biți), deci cea mai mare valoare pe care o poate reprezenta este 4294967295 (2 la puterea de 32 minus unu, deoarece începe de la zero). pe o farfurie Arduino În timp ce rulează continuu, contorul de milisecunde se va reseta (reveni la zero) aproximativ la fiecare 50 de zile. La scăderea cu tipuri de date nesemnate este reprodus același comportament (întoarcerea contorului), astfel încât este posibil să se controleze timpul de expirare pe termen nelimitat.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
|
#if defined(ARDUINO_AVR_LEONARDO)||defined(ARDUINO_AVR_MEGA2560) /* ¿Es una placa Arduino Mega 2560 o Arduino Leonardo? */
#define SERIE Serial1 /* Si es una placa Arduino Mega 2560 o Arduino Leonardo usar Serial1 */
#else /* En este proyecto solamente uso Placas Leonardo, Mega 2560 y Uno, así que tiene que ser un Arduino Uno si llega hasta aquí */
#define SERIE Serial /* Si es una placa Arduino Uno usar Serial */
#endif
#define VELOCIDAD 115200 // Velocidad (en baudios) al que está configurado el módulo wifi ESP8266 (Cuidado con la placa utilizada, no todas o siempre son capaces de trabajar a una velocidad tan alta)
#define ORDEN “AT+CWJAP?\r\n” // Verificar que está conectado a un punto de acceso
#define CANTIDAD_MENSAJES 2 // Se distingue entre dos mensajes: acierto y error que se identificarán con true y false
#define MENSAJE_ACIERTO “OK”
#define MENSAJE_ERROR “ERROR”
#define LONGITUD_MENSAJE 6 // Se necesita guardar, al menos, 5 letras y el terminador \0 (Un pequeño desperdicio al hacer una matriz en la que todos los elementos ocupan como el mayor. Es admisible porque son muy pocos elementos y así no se complica este ejemplo inicial)
#define PIN_LED_ACIERTO 2 // Pin al que se conecta el LED que informa del acierto
#define PIN_LED_ERROR 3 // Pin al que se conecta el LED que informa del error
#define TIMEOUT 5000 // Espera 5 segundos la respuesta del ESP8266 (y su análisis) antes de desistir
#include <string.h> // strncpy
boolean esperando=true; // Todavía no se ha encontrado el final del mensaje
boolean encontrado=false; // Salvo que se encuentre el punto de acceso se considera que la operación ha fracasado
char buffer_mensaje; // Para almacenar la última letra cargada desde el ESP8266
byte led_estado[CANTIDAD_MENSAJES]; // Un LED (pin) para cada estado
char mensaje[CANTIDAD_MENSAJES][LONGITUD_MENSAJE]; // Mensajes de acierto y error
byte posicion_mensaje[CANTIDAD_MENSAJES]; // Un contador de posición para cada mensaje
unsigned long cronometro;
void setup()
{
led_estado[true]=PIN_LED_ACIERTO;
led_estado[false]=PIN_LED_ERROR;
for(byte numero_mensaje=0;numero_mensaje<CANTIDAD_MENSAJES;numero_mensaje++)
{
pinMode(led_estado[numero_mensaje],OUTPUT); // Establecer el pin del LED
digitalWrite(led_estado[numero_mensaje],LOW); // Apagar el LED
posicion_mensaje[numero_mensaje]=0; // Inicializar a cero el número de letra a analizar de cada mensaje
}
strncpy(mensaje[true],MENSAJE_ACIERTO,LONGITUD_MENSAJE); // Preparar el mensaje de acierto
strncpy(mensaje[false],MENSAJE_ERROR,LONGITUD_MENSAJE); // Preparar el mensaje de error
SERIE.begin(VELOCIDAD); // Configurar el puerto serie de Arduino a la velocidad del ESP8266
SERIE.print(ORDEN); // Enviar la orden (verificar si existe conexión a un punto de acceso) al módulo wifi ESP8266
cronometro=millis();
}
void loop()
{
if(esperando) // Buscará infinitamente hasta que llegue el texto esperado (y si no existe el punto de acceso nunca llegará ¡Es un ejemplo!)
{
while(SERIE.available()) // Si ha llegado algún dato por el puerto serie…
{
buffer_mensaje=SERIE.read(); // …almacenarlo en el buffer
for(byte numero_mensaje=0;numero_mensaje<CANTIDAD_MENSAJES;numero_mensaje++)
{
if(buffer_mensaje==mensaje[numero_mensaje][posicion_mensaje[numero_mensaje]]) // Si el dato que ha llegado es igual al que correspondería del mensaje buscado…
{
posicion_mensaje[numero_mensaje]++; // Pasar a la siguiente letra del mensaje
if(mensaje[numero_mensaje][posicion_mensaje[numero_mensaje]]==0) // ¿Ha terminado de analizarse todo el mensaje actual? (la última letra de la cadena de texto es \0)
{
encontrado=numero_mensaje; // (numero_mensaje!=0) Hay conexión con el punto de acceso
esperando=false; // Si se ha encontrado algún mensaje y ya no se está esperando
digitalWrite(led_estado[numero_mensaje],HIGH); // Encender el LED correspondiente al mensaje encontrado
}
}
else // Si la letra que ha llegado por el puerto serie no corresponde con la buscada del mensaje…
{
posicion_mensaje[numero_mensaje]=0; // …empezar desde la primera letra del texto buscado
}
}
}
if((unsigned long)(millis()–cronometro)>TIMEOUT&&!encontrado) // Se ha superado el tiempo de espera y no hay conexión (se ha verificado que no hay o no ha llegado respuesta)
{
digitalWrite(PIN_LED_ERROR,HIGH); // Si ha superado el tiempo de espera encender el LED de error
esperando=false;
}
}
}
|
Codul de mai sus arată a implementare foarte simplă a limitării timeout încorporând liniile marcate în raport cu exemplul care îl precede. Deoarece verificarea timeout-ului se efectuează după procesarea datelor care sosesc de la Modul WiFi ESP8266, operațiunea poate fi considerată reușită chiar dacă recepția durează mai mult decât timpul de așteptare impus.
Executați o operație complexă definită de mai multe comenzi AT
Pentru a avea un exemplu de referință cu scopul aplicației care exploatează Modul WiFi ESP8266, să presupunem că este stocarea informațiilor într-o bază de date accesată printr-un serviciu web pentru a ține evidența temperaturii. Următorul cod citește un senzor conectat la o intrare analogică la fiecare anumit interval de timp, calculează valoarea medie și, după un interval de timp mai lung, o trimite către serverul web (stil IoT) prin a petiție HTTP (POSTAȚI, PRIȚI…).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
#define PIN_TEMPERATURA A0 // Pin analógico al que se conecta la salida del sensor de temperatura LM35
#define INTERVALO_LECTURA_TEMPERATURA 30000 // Leer la temperatura cada 30 segundos (30*1000)
#define INTERVALO_GRABACION_TEMPERATURA 300000 // Grabar la media de la temperatura cada 5 minutos (5*60*1000)
unsigned long muestras=0; // Número de veces que se ha medido la temperatura (para calcular la media)
float temperatura; // de -55.0 °C a +150 °C | de -550 mV a +1500 mV | de 0 V a 2.050 V | analogRead*5.0/1023.0*100-55.0 -> analogRead/2.46-55.0
float media_temperaturas=0.0;
unsigned long cronometro_lectura_temperatura;
unsigned long cronometro_grabacion_temperatura;
void setup()
{
Serial.begin(9600);
cronometro_lectura_temperatura=millis();
cronometro_grabacion_temperatura=millis();
}
void loop()
{
if((unsigned long)(millis()–cronometro_lectura_temperatura)>INTERVALO_LECTURA_TEMPERATURA)
{
cronometro_lectura_temperatura=millis();
temperatura=analogRead(PIN_TEMPERATURA)/2.46–55.0;
muestras++;
media_temperaturas=(float)temperatura/(float)muestras+media_temperaturas*(float)(muestras–1)/(float)(muestras);
}
if((unsigned long)(millis()–cronometro_grabacion_temperatura)>INTERVALO_GRABACION_TEMPERATURA)
{
cronometro_grabacion_temperatura=millis();
// Aquí iría la parte del código que graba la temperatura. Para verificar el funcionamiento, en este ejemplo simplemente se muestra en la consola
Serial.println(“\nTemperatura media “+String(temperatura,DEC)+” °C (“+String((float)millis()/1000.0,DEC)+” s)\n”);
}
}
|
În acest exemplu de înregistrare a temperaturii, un server web este accesat la fiecare cinci minute. Deși disponibilitatea nu este deosebit de mare, este de așteptat ca propunerea să funcționeze, dar dacă ar fi necesară o frecvență mai mare de înregistrare, ar trebui implementate alte resurse, de exemplu, un tampon de date așteaptă să fie trimis, pentru a trimite mai multe când serverul poate participa și pentru a le stoca atunci când nu este disponibil. Dacă frecvența cu care datele trebuie înregistrate ar fi și mai mare, ar trebui propuse alte tipuri de protocoale ca alternativă la HTTP sau chiar înlocuiți TCP de UDP pentru a putea trimite majoritatea datelor la viteza necesară chiar și cu prețul pierderii unora.
Operatiile care alcatuiesc sarcina de efectuat pentru transmiterea temperaturii ar fi:
- Resetați modulul wifi
- Deconectați-vă de la punctul de acces curent (în cazul în care există o conexiune implicită)
- Setați setările. Pentru exemplu, se presupune că modul de conectare (simplu) și rolul în comunicațiile Wi-Fi (stație) trebuie configurate.
- Conectați-vă la punctul de acces
- Verificați dacă conexiunea este corectă (de fapt, acesta este punctul de intrare) Dacă nu există conexiune, începeți procesul de la început
- Conectați-vă la server
- Trimite cererea HTTP cu datele de stocat
Ordinea operațiilor nu trebuie să fie exact așa (deși operația este) și fiecare pas poate necesita mai multe comenzi ESP8266 ATDe exemplu, configurația enumerată mai sus ar avea nevoie de două: AT+CIPMUX=0
y AT+CWMODE=1
.
O structură de date pentru a reprezenta operațiunile pe ESP8266
În exemplele anterioare, deși într-un mod foarte simplu, o soluție generică a problemei este deja sugerată: utilizați o structură de date care stochează răspunsurile posibile și acțiunile care trebuie întreprinse în fiecare caz; trimiteți o acțiune, așteptați un răspuns și continuați în funcție de ceea ce înseamnă răspunsul. Deoarece fiecare operațiune complexă va necesita mai multe comenzi ESP8266 AT, structura de date trebuie să lege o operațiune cu altele, următoare sau anterioare, care trebuie efectuată în fiecare caz în funcție de răspunsul ESP8266.
În exemplele anterioare, un mesaj a fost căutat în răspunsul lui ESP8266 și a fost interpretat ca succes sau eroare. Pe lângă o recepție (și o analiză) a întregului text primit, Pentru a avea un minim generic, este indicat să vă ocupați și de completarea mesajului sau, cu alte cuvinte, la disponibilitatea Modul WiFi ESP8266 pentru a primi comenzi noi. În acest fel, schimbarea într-o stare pe care am putea-o numi, de exemplu, „wifi disponibil”, ar putea fi primirea numelui punctului de acces și primirea textului ERROR
sau textul OK
ar însemna că ESP8266 ați terminat răspunsul și acum îl puteți trimite pe următorul Comanda AT către ESP8266.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
|
// inicializar_operaciones.h
// 0 Reiniciar el módulo wifi ESP8266
operacion[REINICIAR_ESP8266]=“AT+RST”;
mensaje[REINICIAR_ESP8266][FALLO]=mensaje_fallo;
mensaje[REINICIAR_ESP8266][ACIERTO]=“ready\r\n”;
mensaje[REINICIAR_ESP8266][LITERAL]=mensaje_vacio;
siguiente_operacion[REINICIAR_ESP8266][FALLO]=REINICIAR_ESP8266;
siguiente_operacion[REINICIAR_ESP8266][ACIERTO]=DESCONECTAR_WIFI;
siguiente_operacion[REINICIAR_ESP8266][LITERAL]=DESCONECTAR_WIFI;
configuracion[REINICIAR_ESP8266]=ESPERAR_RESPUESTA|ACIERTO_TERMINA|FALLO_TERMINA;
timeout[REINICIAR_ESP8266]=10000;
// 1 Desconectar del punto de acceso por defecto (si fuera el caso)
operacion[DESCONECTAR_WIFI]=“AT+CWQAP”;
mensaje[DESCONECTAR_WIFI][FALLO]=mensaje_fallo;
mensaje[DESCONECTAR_WIFI][ACIERTO]=mensaje_acierto;
mensaje[DESCONECTAR_WIFI][LITERAL]=mensaje_vacio;
siguiente_operacion[DESCONECTAR_WIFI][FALLO]=REINICIAR_ESP8266;
siguiente_operacion[DESCONECTAR_WIFI][ACIERTO]=MODO_ESTACION;
siguiente_operacion[DESCONECTAR_WIFI][LITERAL]=MODO_ESTACION;
configuracion[DESCONECTAR_WIFI]=ESPERAR_RESPUESTA|ACIERTO_TERMINA|FALLO_TERMINA;
timeout[DESCONECTAR_WIFI]=2500;
// 2 Establecer el modo de estación (no punto de acceso)
operacion[MODO_ESTACION]=“AT+CWMODE=1”;
mensaje[MODO_ESTACION][FALLO]=mensaje_fallo;
mensaje[MODO_ESTACION][ACIERTO]=mensaje_acierto;
mensaje[MODO_ESTACION][LITERAL]=mensaje_vacio;
siguiente_operacion[MODO_ESTACION][FALLO]=REINICIAR_ESP8266;
siguiente_operacion[MODO_ESTACION][ACIERTO]=MODO_SIMPLE;
siguiente_operacion[MODO_ESTACION][LITERAL]=MODO_SIMPLE;
configuracion[MODO_ESTACION]=ESPERAR_RESPUESTA|ACIERTO_TERMINA|FALLO_TERMINA;
timeout[MODO_ESTACION]=2500;
// 3 Establecer el modo de conexión simple
operacion[MODO_SIMPLE]=“AT+CIPMUX=0”;
mensaje[MODO_SIMPLE][FALLO]=mensaje_fallo;
mensaje[MODO_SIMPLE][ACIERTO]=mensaje_acierto;
mensaje[MODO_SIMPLE][LITERAL]=mensaje_vacio;
siguiente_operacion[MODO_SIMPLE][FALLO]=REINICIAR_ESP8266;
siguiente_operacion[MODO_SIMPLE][ACIERTO]=CONECTAR_WIFI;
siguiente_operacion[MODO_SIMPLE][LITERAL]=CONECTAR_WIFI;
configuracion[MODO_SIMPLE]=ESPERAR_RESPUESTA|ACIERTO_TERMINA|FALLO_TERMINA;
timeout[MODO_SIMPLE]=2500;
// 4 Conectar al punto de acceso
operacion[CONECTAR_WIFI]=“AT+CWJAP=\”polaridad.es\”,\”54lLij1RiTn3MEd3v41C\””;
mensaje[CONECTAR_WIFI][FALLO]=mensaje_fallo;
mensaje[CONECTAR_WIFI][ACIERTO]=mensaje_acierto;
mensaje[CONECTAR_WIFI][LITERAL]=mensaje_vacio;
siguiente_operacion[CONECTAR_WIFI][FALLO]=REINICIAR_ESP8266;
siguiente_operacion[CONECTAR_WIFI][ACIERTO]=VERIFICAR_CONEXION;
siguiente_operacion[CONECTAR_WIFI][LITERAL]=VERIFICAR_CONEXION;
configuracion[CONECTAR_WIFI]=ESPERAR_RESPUESTA|ACIERTO_TERMINA|FALLO_TERMINA;
timeout[CONECTAR_WIFI]=20000;
// 5 Verificar si hay conexión
operacion[VERIFICAR_CONEXION]=“AT+CIPSTATUS”;
mensaje[VERIFICAR_CONEXION][FALLO]=mensaje_fallo;
mensaje[VERIFICAR_CONEXION][ACIERTO]=mensaje_acierto;
mensaje[VERIFICAR_CONEXION][LITERAL]=“STATUS:5”;
siguiente_operacion[VERIFICAR_CONEXION][FALLO]=REINICIAR_ESP8266;
siguiente_operacion[VERIFICAR_CONEXION][ACIERTO]=REINICIAR_ESP8266;
siguiente_operacion[VERIFICAR_CONEXION][LITERAL]=CONECTAR_SERVIDOR;
configuracion[VERIFICAR_CONEXION]=ESPERAR_RESPUESTA|ACIERTO_TERMINA|FALLO_TERMINA;
timeout[VERIFICAR_CONEXION]=5000;
// 6 Conectar al servidor
operacion[CONECTAR_SERVIDOR]=“AT+CIPSTART=\”TCP\”,\”servidoriot.com\”,80″;
mensaje[CONECTAR_SERVIDOR][FALLO]=mensaje_fallo;
mensaje[CONECTAR_SERVIDOR][ACIERTO]=mensaje_acierto;
mensaje[CONECTAR_SERVIDOR][LITERAL]=“CONNECT”;
siguiente_operacion[CONECTAR_SERVIDOR][FALLO]=REINICIAR_ESP8266;
siguiente_operacion[CONECTAR_SERVIDOR][ACIERTO]=INFORMAR_CANTIDAD;
siguiente_operacion[CONECTAR_SERVIDOR][LITERAL]=INFORMAR_CANTIDAD;
configuracion[CONECTAR_SERVIDOR]=ESPERAR_RESPUESTA|ACIERTO_TERMINA|FALLO_TERMINA;
timeout[CONECTAR_SERVIDOR]=15000;
// 7 Avisar de la cantidad de datos que se envían
operacion[INFORMAR_CANTIDAD]=“AT+CIPSEND=”;
mensaje[INFORMAR_CANTIDAD][FALLO]=mensaje_vacio;
mensaje[INFORMAR_CANTIDAD][ACIERTO]=mensaje_acierto;
mensaje[INFORMAR_CANTIDAD][LITERAL]=mensaje_vacio;
siguiente_operacion[INFORMAR_CANTIDAD][FALLO]=REINICIAR_ESP8266;
siguiente_operacion[INFORMAR_CANTIDAD][ACIERTO]=ENVIAR_CANTIDAD;
siguiente_operacion[INFORMAR_CANTIDAD][LITERAL]=ENVIAR_CANTIDAD;
configuracion[INFORMAR_CANTIDAD]=NO_ESPERAR_RESPUESTA;
timeout[INFORMAR_CANTIDAD]=1000;
// 8 Enviar cantidad
//operacion[ENVIAR_CANTIDAD]=”123″; // Definido para cada envío
mensaje[ENVIAR_CANTIDAD][FALLO]=sin_enlace;
mensaje[ENVIAR_CANTIDAD][ACIERTO]=“>”;
mensaje[ENVIAR_CANTIDAD][LITERAL]=mensaje_vacio;
siguiente_operacion[ENVIAR_CANTIDAD][FALLO]=REINICIAR_ESP8266;
siguiente_operacion[ENVIAR_CANTIDAD][ACIERTO]=ENVIAR_PREFIJO_PETICION;
siguiente_operacion[ENVIAR_CANTIDAD][LITERAL]=ENVIAR_PREFIJO_PETICION;
configuracion[ENVIAR_CANTIDAD]=ESPERAR_RESPUESTA|ACIERTO_TERMINA|FALLO_TERMINA;
timeout[ENVIAR_CANTIDAD]=5000;
// 9 Enviar el prefijo de la petición
operacion[ENVIAR_PREFIJO_PETICION]=“GET /frigo03/almacenar_temperatura.php?temperatura=”;
mensaje[ENVIAR_PREFIJO_PETICION][FALLO]=mensaje_vacio;
mensaje[ENVIAR_PREFIJO_PETICION][ACIERTO]=mensaje_vacio;
mensaje[ENVIAR_PREFIJO_PETICION][LITERAL]=mensaje_vacio;
siguiente_operacion[ENVIAR_PREFIJO_PETICION][FALLO]=REINICIAR_ESP8266;
siguiente_operacion[ENVIAR_PREFIJO_PETICION][ACIERTO]=ENVIAR_DATOS;
siguiente_operacion[ENVIAR_PREFIJO_PETICION][LITERAL]=ENVIAR_DATOS;
configuracion[ENVIAR_PREFIJO_PETICION]=NO_ESPERAR_RESPUESTA;
timeout[ENVIAR_PREFIJO_PETICION]=10000;
// 10 Enviar la temperatura
//operacion[ENVIAR_DATOS]=”+000.00″; // Definido para cada envío
mensaje[ENVIAR_DATOS][FALLO]=mensaje_vacio;
mensaje[ENVIAR_DATOS][ACIERTO]=mensaje_vacio;
mensaje[ENVIAR_DATOS][LITERAL]=mensaje_vacio;
siguiente_operacion[ENVIAR_DATOS][FALLO]=REINICIAR_ESP8266;
siguiente_operacion[ENVIAR_DATOS][ACIERTO]=ENVIAR_SUFIJO_PETICION;
siguiente_operacion[ENVIAR_DATOS][LITERAL]=ENVIAR_SUFIJO_PETICION;
configuracion[ENVIAR_DATOS]=NO_ESPERAR_RESPUESTA;
timeout[ENVIAR_DATOS]=5000;
// 11 Enviar el sufijo de la petición
operacion[ENVIAR_SUFIJO_PETICION]=” HTTP/1.1\r\nHost: www.servidoriot.com\r\nUser-Agent: ESP8266\r\nConnection: close\r\n\r\n”;
mensaje[ENVIAR_SUFIJO_PETICION][FALLO]=sin_enlace;
mensaje[ENVIAR_SUFIJO_PETICION][ACIERTO]=“CLOSED\r\n\r\nOK\r\n”;
mensaje[ENVIAR_SUFIJO_PETICION][LITERAL]=mensaje_vacio; // “SEND OK”
siguiente_operacion[ENVIAR_SUFIJO_PETICION][FALLO]=REINICIAR_ESP8266;
siguiente_operacion[ENVIAR_SUFIJO_PETICION][ACIERTO]=VERIFICAR_CONEXION;
siguiente_operacion[ENVIAR_SUFIJO_PETICION][LITERAL]=VERIFICAR_CONEXION;
configuracion[ENVIAR_SUFIJO_PETICION]=ESPERAR_RESPUESTA|ACIERTO_TERMINA|FALLO_TERMINA;
timeout[ENVIAR_SUFIJO_PETICION]=20000;
|
Codul de mai sus folosește un vector (operacion
) pentru a stoca textul operațiunilor succesive care formează sarcina completă. Se folosește o matrice bidimensională (mensaje
) cu cele trei răspunsuri care sunt analizate. După cum s-a explicat mai sus, este necesar să căutați mesajele care reprezintă sfârșitul răspunsului pe lângă mesajul care reprezintă un răspuns corect sau incorect. Nu toate operațiunile vor avea același număr de răspunsuri posibile; Când sunt mai puține răspunsuri, se poate folosi un mesaj gol care consumă cel mai mic număr posibil de cicluri în analiza sa (chiar și așa, nu este cel mai optim mod). În mod logic, va fi necesar ca numărul minim de răspunsuri căutate (trei în exemplu) să cuprindă toate posibilitățile de operare, chiar dacă nu sunt toate posibile.
Când vorbim despre posibilele răspunsuri, se poate observa deja că acest exemplu nu este foarte util pentru primirea de date cu format arbitrar de la un Modul WiFi ESP8266, dar chestia este că, în contextul utilizării cu microcontrolere nu este obișnuit; Cel mai obișnuit este să trimiți datele culese de senzorii pe care i-au conectat și/sau să primești informații despre ce să faci cu actuatoarele pe care le controlează. Informații foarte valoroase, care pot fi prezise foarte bine.
În structura anterioară de date, la fel cum se face pentru a exprima răspunsurile posibile care sunt analizate, se folosește și o matrice bidimensională pentru a determina operația care trebuie efectuată în fiecare caz (siguiente_operacion
). Mai exact, am ales să răspundem la trei tipuri de mesaje: ① un text arbitrar (LITERAL
) pentru a verifica dacă există o conexiune la punctul de acces Wi-Fi și la server, ② un text pentru a detecta erorile în proces (FALLO
) și ③ un text care indică faptul că operațiunea a fost finalizată cu succes (ACIERTO
).
În cele din urmă, mai există doi vectori pentru a seta timpul maxim de așteptare înainte de a renunța (timeout
) și specificați (configuracion
) dacă operațiunea se încheie fără a aștepta un răspuns (ESPERAR_RESPUESTA
) și mesaje care indică încheierea comunicării. Acest ultim vector, pentru a ilustra un exemplu despre cum ar putea fi salvată memoria, funcționează cu biții unui octet de configurare pentru a indica diferitele stări.
Primul comenzi ESP8266 AT al structurii de date se așteaptă întotdeauna un răspuns, care poate fi mesajul de succes sau de eroare. Când apare o eroare, modulul este repornit și pornește din nou și dacă mesajul indică că operația este corectă, se trece la următoarea.
Când v-ați conectat la server, modelul se schimbă. În acest caz, este necesar să ① trimiteți lungimea pachetului de date care urmează să fie transmis și ② să compuneți cererea HTTP cu un text fix plus valoarea (temperaturii) care este trimisă pentru a fi stocată pe server. Pregătirea acestor date se efectuează în fiecare expediere și este necesară împărțirea acesteia în două (se anunță lungimea) sau trei (trimite cererea HTTP) la Comanda ESP8266 AT. Numai ultima dintre părțile în care este împărțită operația va aștepta un răspuns.
În acest caz, va funcționa fără probleme (poate avertizând că modulul este ocupat), dar atunci când lungimea datelor este mai mare va fi necesară împărțirea blocurilor de date în bucăți mai mici și poate fi chiar necesară implementarea unei așteptări, ca se face cu citirea temperaturii, pentru a da timp modulului să trimită datele fără a le completa tampon.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
#if defined(ARDUINO_AVR_LEONARDO)||defined(ARDUINO_AVR_MEGA2560) /* ¿Es una placa Arduino Mega 2560 o Arduino Leonardo? */
#define SERIE Serial1 /* Si es una placa Arduino Mega 2560 o Arduino Leonardo usar Serial1 */
#else /* En este proyecto solamente uso Placas Leonardo, Mega 2560 y Uno, así que tiene que ser un Arduino Uno si llega hasta aquí */
#define SERIE Serial /* Si es una placa Arduino Uno usar Serial */
#endif
#define VELOCIDAD 115200 // Velocidad (en baudios) al que está configurado el módulo wifi ESP8266 (Cuidado con la placa utilizada, no todas o siempre son capaces de trabajar a una velocidad tan alta)
#define REINICIAR_ESP8266 0 // Índice del vector de operaciones que representa la orden de reinicio del módulo wifi ESP8266
#define DESCONECTAR_WIFI 1
#define MODO_ESTACION 2
#define MODO_SIMPLE 3
#define CONECTAR_WIFI 4
#define VERIFICAR_CONEXION 5
#define CONECTAR_SERVIDOR 6
#define INFORMAR_CANTIDAD 7
#define ENVIAR_CANTIDAD 8
#define ENVIAR_PREFIJO_PETICION 9
#define ENVIAR_DATOS 10
#define ENVIAR_SUFIJO_PETICION 11
#define CANTIDAD_OPERACIONES 12 // Cantidad de operaciones que forma el cuerpo de la aplicación
#define FALLO 0 // Índice del vector de respuestas que representa el mensaje de error
#define FALLO_TERMINA 0B00000001 // 1<<FALLO
#define ACIERTO 1
#define ACIERTO_TERMINA 0B00000010 // 1<<ACIERTO
#define LITERAL 2
#define LITERAL_TERMINA 0B00000100 // 1<<LITERAL
#define CANTIDAD_RESPUESTAS 3 // Cantidad de posibles respuestas que se buscan en el texto recibido desde el ESP8266
#define ESPERAR_RESPUESTA 0B00001000 // 1<<CANTIDAD_RESPUESTAS
#define NO_ESPERAR_RESPUESTA 0B00000000
#define ENVIAR_OPERACION esperando_respuesta=true;SERIE.print(operacion[operacion_actual]);if(configuracion[operacion_actual]&ESPERAR_RESPUESTA){SERIE.print(“\r\n”);}for(unsigned char numero_respuesta=0;numero_respuesta<CANTIDAD_RESPUESTAS;numero_respuesta++){numero_caracter[numero_respuesta]=0;}cronometro_esp8266=millis();
|
Împreună cu alte macrocomenzi care au fost deja explicate anterior, exemplul de cod de mai sus arată cum sunt definite diferitele stări cu care se specifică dacă să aștepte un răspuns și, dacă este cazul, ce mesaj indică faptul că acesta s-a terminat.
Ca și în diferite puncte ale codului, se va trimite o operațiune (când este timpul să trimiteți temperatura medie, dacă timpul de așteptare al unei operații este depășit, când operațiunea curentă este finalizată cu succes...) dar cum se face este stabilit la nivel global, a fost definită o macro ENVIAR_OPERACION
care grupează etapele implicate în transport.
1
2
3
4
5
6
7
8
9
10
11
12
|
// La macro ENVIAR_OPERACION corresponde con las operaciones:
esperando_respuesta=true;
SERIE.print(operacion[operacion_actual]);
if(configuracion[operacion_actual]&ESPERAR_RESPUESTA)
{
SERIE.print(“\r\n”);
}
for(unsigned char numero_respuesta=0;numero_respuesta<CANTIDAD_RESPUESTAS;numero_respuesta++)
{
numero_caracter[numero_respuesta]=0;
}
cronometro_esp8266=millis();
|
Următorul este codul programului principal al exemplului. Cea mai externă sarcină este cea însărcinată cu eșantionarea temperaturii pentru a calcula media și, la fiecare anumită perioadă de timp, este trimisă la server folosind Modul WiFi ESP8266. Odată ce fiecare operație este trimisă, răspunsul este analizat pentru a determina care urmează sau dacă sarcina de trimitere a informațiilor a fost finalizată.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
#include “ESP8266_operacion_compleja_varias_ordenes_AT.h”
#define PIN_TEMPERATURA A0 // Pin analógico al que se conecta la salida del sensor de temperatura LM35
#define INTERVALO_LECTURA_TEMPERATURA 30000 // Leer la temperatura cada 30 segundos (30*1000)
#define INTERVALO_GRABACION_TEMPERATURA 300000 // Grabar la media de la temperatura cada 5 minutos (5*60*1000)
unsigned long muestras=0; // Número de veces que se ha medido la temperatura (para calcular la media)
float temperatura; // de -55.0 °C a +150 °C | de 0 V a 2.050 V | de -550 mV a +1500 mV | analogRead*5.0/1023.0*100-55.0 analogRead/2.46-55.0
float media_temperaturas=0.0;
unsigned long cronometro_lectura_temperatura;
unsigned long cronometro_grabacion_temperatura;
char *mensaje_fallo=“ERROR\r\n”;
char *mensaje_acierto=“OK\r\n”;
char *sin_enlace=“link is not\r\n”;
char *mensaje_vacio=“\f”;
char *operacion[CANTIDAD_OPERACIONES]; // Matriz de punteros a constantes de caracteres con las operaciones que se envían al ESP8266 (no solo órdenes AT, aunque seguro que algunas son órdenes AT)
char *mensaje[CANTIDAD_OPERACIONES][CANTIDAD_RESPUESTAS]; // Mensajes de respuesta
unsigned char siguiente_operacion[CANTIDAD_OPERACIONES][CANTIDAD_RESPUESTAS];
unsigned char configuracion[CANTIDAD_OPERACIONES];
unsigned int timeout[CANTIDAD_OPERACIONES];
unsigned char numero_caracter[CANTIDAD_RESPUESTAS];
unsigned int longitud_peticion;
char texto_longitud_peticion[4]; // 3 caracteres para almacenar la longitud de la petición en formato texto
char valor_enviado[9]; // signo + 4 enteros + punto + 2 decimales + \0 = 9
unsigned long cronometro_esp8266;
unsigned char operacion_actual; // Número de operación que se está procesando
unsigned char proxima_operacion; // Siguiente operación que se procesará cuando termine la actual
char lectura_serie;
boolean grabando_datos=false;
boolean esperando_respuesta;
void setup()
{
#include “inicializar_operaciones.h”
longitud_peticion=strlen(operacion[ENVIAR_PREFIJO_PETICION])+strlen(operacion[ENVIAR_SUFIJO_PETICION]);
SERIE.begin(VELOCIDAD); // Configurar el puerto serie de Arduino a la velocidad del ESP8266
//delay(8000); // En fase de pruebas se puede introducir un tiempo de espera para conectar una consola/sniffer
cronometro_lectura_temperatura=millis();
cronometro_grabacion_temperatura=millis();
}
void loop()
{
if((unsigned long)(millis()–cronometro_lectura_temperatura)>INTERVALO_LECTURA_TEMPERATURA)
{
cronometro_lectura_temperatura=millis();
temperatura=analogRead(PIN_TEMPERATURA)/2.46–55.0;
muestras++;
media_temperaturas=(float)temperatura/(float)muestras+media_temperaturas*(float)(muestras–1)/(float)(muestras);
}
if(grabando_datos)
{
if((unsigned long)(millis()–cronometro_esp8266)>timeout[operacion_actual]) // Si se ha superado el tiempo de espera máximo
{
operacion_actual=siguiente_operacion[operacion_actual][FALLO]; // Pasar a la operación correspondiente al error
ENVIAR_OPERACION
}
else // Si no se ha superado el tiempo de espera máximo
{
if(configuracion[operacion_actual]&ESPERAR_RESPUESTA) // Si la siguiente operación depende de la respuesta a la actual desde el ESP8266 hay que leer la información que llegue desde el puerto serie
{
while(SERIE.available())
{
lectura_serie=SERIE.read();
for(unsigned char numero_respuesta=0;numero_respuesta<CANTIDAD_RESPUESTAS;numero_respuesta++) // Comparar la letra cargada desde el puerto serie con la correspondiente de los mensajes disponibles
{
if(lectura_serie==mensaje[operacion_actual][numero_respuesta][numero_caracter[numero_respuesta]]) // Si el dato que ha llegado es igual al que correspondería del mensaje buscado…
{
numero_caracter[numero_respuesta]++; // Como el carácter coincide, se puede comparar con el siguiente lo próximo que llegue por el puerto serie
if(mensaje[operacion_actual][numero_respuesta][numero_caracter[numero_respuesta]]==0) // Si el carácter que toca es \0 es que se ha terminado de analizar el mensaje
{
if(esperando_respuesta) // Todavía no se ha encontrado un mensaje que determine la siguiente operación
{
proxima_operacion=siguiente_operacion[operacion_actual][numero_respuesta]; // La próxima operación que habrá que procesar será la que indique el mensaje encontrado para la operación actual
esperando_respuesta=false; // Ya se ha encontrado un mensaje que determina la siguiente operación
}
if(configuracion[operacion_actual]&(1<<numero_respuesta)) // Si el mensaje encontrado es uno de los que terminan la operación…
{
if(operacion_actual+1==CANTIDAD_OPERACIONES) // Se ha completado la última operación de la tarea compleja
{
grabando_datos=false; // Se ha terminado la tarea compleja (grabar datos en el servidor)
}
else // No es la última operación de la tarea compleja, hay que seguir realizando otras operaciones
{
operacion_actual=proxima_operacion; // Ejecutar la siguiente operación
ENVIAR_OPERACION
}
}
}
}
else // Si la letra recibida no es igual que la correspondiente del mensaje
{
numero_caracter[numero_respuesta]=0; // Empezar a comparar desde la primera letra del mensaje
}
}
}
}
else // Si no hay que esperar datos desde el puerto serie
{
operacion_actual=siguiente_operacion[operacion_actual][ACIERTO];
ENVIAR_OPERACION
}
}
}
else
{
if((unsigned long)(millis()–cronometro_grabacion_temperatura)>INTERVALO_GRABACION_TEMPERATURA)
{
cronometro_grabacion_temperatura=millis();
dtostrf(media_temperaturas,4,2,valor_enviado); // snprintf(valor_enviado,9,”%+3.2f”,media_temperaturas); // printf y derivadas no funcionan en AVR
snprintf(texto_longitud_peticion,4,“%d”,longitud_peticion+strlen(valor_enviado));
grabando_datos=true;
operacion_actual=VERIFICAR_CONEXION;
operacion[ENVIAR_DATOS]=valor_enviado;
operacion[ENVIAR_CANTIDAD]=texto_longitud_peticion;
ENVIAR_OPERACION
}
}
}
|
În mod logic, mai multe acțiuni de optimizare pot fi efectuate pe codul anterior, dar, deoarece acesta este un exemplu pentru a înțelege cum ESP8266 Într-un mod generic, merită să ne concentrăm doar asupra unor aspecte, primul fiind structura datelor. Se pare că lucrul logic este utilizați o structură de date în limbaj de programare (struct
) pentru a reprezenta informațiile în curs de prelucrare: comenzi ESP8266 AT și mesajele care sunt analizate.
Utilizați o structură (struct
) pentru a stoca datele în locul matricelor de exemplu (pe baza acestora) este banal și, deși poate duce la un cod mai elegant, nu implică nicio îmbunătățire a rezultatului. Adevărata alternativă prezentată de utilizarea lui struct
este de a implementa, după cum se explică mai jos, lungimi variabile în structurile care conțin date „interioare”. la care se referă ei. În acest fel, de exemplu, nu ar fi necesar ca o operațiune să aibă un număr fix de răspunsuri de analizat.
Această abordare sugerează că este cea mai bună modalitate de a implementa soluția, dar dezavantajul este că ar fi necesară utilizați alocarea dinamică a memoriei, o practică riscantă de lucru cu a microcontroler ceea ce necesită măsurarea atentă a câtă memorie va fi utilizată în timpul execuției, deoarece compilatorul cu greu ne va putea avertiza despre acest lucru și există o anumită posibilitate de a epuiza memoria (sau stiva) cu consecințe fatale pentru execuția programului.
În linia de optimizare a codului, este interesant de reținut că, într-un program de acest tip, care utilizează o cantitate mare de text, poate economisi spațiu de memorie SRAM stocarea șirurilor de text în memoria programului (bliţ) cu macro-ul F()
. În următoarele capturi de ecran puteți vedea diferitele distribuții ale programului și ale memoriei dinamice cu utilizarea normală a textului și utilizarea macrocomenzii F()
.
În ceea ce privește acțiunile care se execută conform informațiilor care sosesc de la Modul WiFi ESP8266, ca alternativă la verificarea mesajului din cod și efectuarea unuia sau altul în funcție de ceea ce este primit, poate fi stocat în această structură de date indicii către funcții care îndeplinesc fiecare sarcină în locul indicatorilor de stare (steaguri) care avertizează asupra unei anumite stări pe care aplicația este responsabilă pentru gestionarea, de exemplu, în cadrul buclei principale.
Următorul este un exemplu de structuri pentru stocarea datelor cererilor către ESP8266 (tipul de date operacion_esp8266
) și răspunsurile acestora (tipul de date respuesta_esp8266
).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
typedef struct estructura_operacion_esp8266 operacion_esp8266; // Se define el tipo de datos operacion_esp8266 que corresponde con la estructura (struct) llamada estructura_operacion_esp8266 que se define más adelante
typedef struct estructura_respuesta_esp8266 respuesta_esp8266; // Se define el tipo de datos respuesta_esp8266 que corresponde con la estructura (struct) llamada struct estructura_respuesta_esp8266 que se define más adelante
struct estructura_operacion_esp8266
{
char *peticion; // Datos que se envían al ESP8266 para iniciar una operación (como una orden AT, pero también algo como la petición a un servidor…)
unsigned char cantidad_respuestas; // Número de posibles respuestas del ESP8266 que se van a analizar, que puede ser variable en cada petición (no solo OK y ERROR)
unsigned char timeout; // Tiempo (segundos) que se espera la respuesta del ESP8266 antes de desistir
respuesta_esp8266 *respuesta; // Respuestas (estructura) que se esperan de esta operación
};
struct estructura_respuesta_esp8266
{
char *mensaje; // Mensaje que se espera recibir desde el ESP8266
unsigned char posicion_mensaje; // Posición (letra) que se está comparando con la recibida desde el ESP8266
//boolean estado; // El estado se representa por un valor booleano (por ejemplo ¿se ha encontrado ya esta respuesta? para no seguir buscándola)
//unsigned char *estado; // El estado se representa con un texto (de longitud variable)
unsigned char estado; // El estado se establece con 8 banderas, una por bit
operacion_esp8266 *operacion; // Puntero a operación que se ejecutará si se encuentra esta respuesta en el mensaje devuelto por el ESP8266
};
operacion_esp8266 comprobar_conexion;
respuesta_esp8266 respuesta_OK;
respuesta_esp8266 respuesta_ERROR;
|
Ca structură care reprezintă operația (datele care sunt trimise către Modul WiFi ESP8266) se referă la structura cu care sunt definite răspunsurile și structura răspunsurilor la structura operațiunilor, este necesar să le declarăm pe ambele mai întâi, prin definirea noului tip de date și apoi definirea conținutului acestuia.
Exemplul anterior consideră că programul care îl include a ales să folosească a indicator de stare, care trebuie să corespundă unei variabile accesibile din cod care este responsabilă pentru efectuarea uneia sau a altor operații, așa cum este indicat de respectiva valoare. Dacă în răspunsul lui ESP8266 Atunci când un anumit text este analizat, starea ia valoarea care indică structura răspunsului corespunzător.
După cum sa spus anterior, o altă alternativă, fie pentru a înlocui, fie pentru a completa un indicator de stare, ar fi stocați o funcție în structura de referință (un indicator) care ar fi apelat la întâlnirea unui anumit text în răspunsul de la Modul WiFi ESP8266.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
typedef struct estructura_operacion_esp8266 operacion_esp8266; // Se define el tipo de datos operacion_esp8266 que corresponde con la estructura (struct) llamada estructura_operacion_esp8266 que se define más adelante
typedef struct estructura_respuesta_esp8266 respuesta_esp8266; // Se define el tipo de datos respuesta_esp8266 que corresponde con la estructura (struct) llamada struct estructura_respuesta_esp8266 que se define más adelante
struct estructura_operacion_esp8266
{
char *peticion; // Datos que se envían al ESP8266 para iniciar una operación (como una orden AT, pero también algo como la petición a un servidor…)
unsigned char cantidad_respuestas; // Número de posibles respuestas del ESP8266 que se van a analizar, que puede ser variable en cada petición (no solo OK y ERROR)
unsigned char timeout; // Tiempo (segundos) que se espera la respuesta del ESP8266 antes de desistir
respuesta_esp8266 *respuesta; // Respuestas (estructura) que se esperan de esta operación
};
struct estructura_respuesta_esp8266
{
char *mensaje; // Mensaje que se espera recibir desde el ESP8266
unsigned char posicion_mensaje; // Posición (letra) que se está comparando con la recibida desde el ESP8266
//boolean estado; // El estado se representa por un valor booleano (por ejemplo ¿se ha encontrado ya esta respuesta? para no seguir buscándola)
//unsigned char *estado; // El estado se representa con un texto (de longitud variable)
unsigned char estado; // El estado se establece con 8 banderas, una por bit
float (*accion)(unsigned char,unsigned char); // Puntero a la función que se llama si se encuentra la respuesta
operacion_esp8266 *operacion; // Puntero a operación que se ejecutará si se encuentra esta respuesta en el mensaje devuelto por el ESP8266
};
operacion_esp8266 comprobar_conexion;
respuesta_esp8266 respuesta_OK;
respuesta_esp8266 respuesta_ERROR;
|
În exemplul anterior, a fost adăugat la structura de date care este utilizată pentru a procesa răspunsul de la Modul WiFi ESP8266 un pointer către o funcție (presupusă) care returnează date de tip float
(ar putea fi valoarea ponderată a unei citiri analogice) și căreia îi sunt furnizați doi octeți ca argumente (doi unsigned char
care ar putea fi pinul din care se citește intrarea analogică și cel care activează ENABLE-ul unui ipotetic integrat).
În dezvoltare pentru MCU, spre deosebire de ceea ce se întâmplă în stilul de dezvoltare pentru sisteme mai mari, nu este atât de neobișnuit să folosiți variabile globale atunci când definiți comportamentul (global) al aplicației care controlează un ansamblu, așa că nu va fi deosebit de rar să găsiți acest tip de definiții ca functii fara parametri si care nu returneaza valori, ceva de genul void (*accion)();
Dacă lucrați cu acest mod de reprezentare a datelor, folosind struct
de date de lungime variabilă, va fi necesară alocarea dinamică a memoriei cu malloc()
(o new()
, dacă sunt folosite obiecte), care va folosi cantitatea de memorie alocată ca parametru și va returna un pointer la începutul zonei de memorie care este rezervată. Cu sizeof()
Pe tipul care sunt stocate, înmulțit cu numărul de elemente utilizate, puteți obține cantitatea de memorie necesară. Un exemplu cu și fără utilizarea acestuia poate fi văzut în capturile de ecran de mai jos. malloc()
; Aveți grijă la memoria folosită de program în primul caz, trebuie să încărcați biblioteca care conține această funcție.
Dacă operațiunile pe Modul WiFi ESP8266 va varia pe parcursul execuției programului, va fi necesară eliberarea memoriei cu care nu este utilizată free()
(o delete()
, în cazul a fi obiecte). Deși este rezonabil să ne așteptăm ca compilatorul (CGC) va optimiza programul pentru a evita partiţionarea memoriei, cu siguranţă performanţa nu va fi la fel de optimă precum lucrul cu memoria alocată static.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
|
error_operacion.mensaje=“ERROR\r\n”;
error_operacion.termina_operacion=true;
error_operacion.operacion=&reiniciar_esp8266;
error_enlace.mensaje=“link is not\r\n”;
error_enlace.termina_operacion=true;
error_enlace.operacion=&reiniciar_esp8266;
reiniciar_esp8266_correcto.mensaje=“ready\r\n”;
reiniciar_esp8266_correcto.termina_operacion=true;
reiniciar_esp8266_correcto.operacion=&desconectar_wifi;
desconectar_wifi_correcto.mensaje=mensaje_acierto;
desconectar_wifi_correcto.termina_operacion=true;
desconectar_wifi_correcto.operacion=&establecer_modo_estacion;
establecer_modo_estacion_correcto.mensaje=mensaje_acierto;
establecer_modo_estacion_correcto.termina_operacion=true;
establecer_modo_estacion_correcto.operacion=&establecer_modo_simple;
establecer_modo_simple_correcto.mensaje=mensaje_acierto;
establecer_modo_simple_correcto.termina_operacion=true;
establecer_modo_simple_correcto.operacion=&conectar_wifi;
conectar_wifi_correcto.mensaje=mensaje_acierto;
conectar_wifi_correcto.termina_operacion=true;
conectar_wifi_correcto.operacion=&verificar_conexion;
verificar_conexion_correcto.mensaje=“STATUS:5”;
verificar_conexion_correcto.termina_operacion=false;
verificar_conexion_correcto.operacion=&conectar_servidor;
verificar_conexion_terminado.mensaje=mensaje_acierto;
verificar_conexion_terminado.termina_operacion=true;
verificar_conexion_terminado.operacion=&reiniciar_esp8266;
conectar_servidor_correcto.mensaje=“CONNECT”;
conectar_servidor_correcto.termina_operacion=false;
conectar_servidor_correcto.operacion=&informar_cantidad;
conectar_servidor_terminado.mensaje=mensaje_acierto;
conectar_servidor_terminado.termina_operacion=true;
conectar_servidor_terminado.operacion=&reiniciar_esp8266;
informar_cantidad_correcto.mensaje=mensaje_acierto;
informar_cantidad_correcto.termina_operacion=true;
informar_cantidad_correcto.operacion=&enviar_cantidad;
enviar_cantidad_correcto.mensaje=“>”;
enviar_cantidad_correcto.termina_operacion=true;
enviar_cantidad_correcto.operacion=&enviar_prefijo;
enviar_prefijo_correcto.operacion=&enviar_datos;
enviar_datos_correcto.operacion=&enviar_sufijo;
enviar_sufijo_correcto.mensaje=“CLOSED\r\n\r\nOK\r\n”;
enviar_sufijo_correcto.termina_operacion=true;
enviar_sufijo_correcto.operacion=&verificar_conexion;
reiniciar_esp8266.peticion=“AT+RST”;
reiniciar_esp8266.timeout=15000;
reiniciar_esp8266.cantidad_respuestas=2;
reiniciar_esp8266.respuesta=malloc(sizeof(respuesta_esp8266*)*reiniciar_esp8266.cantidad_respuestas);
reiniciar_esp8266.respuesta[FALLO]=&error_operacion;
reiniciar_esp8266.respuesta[ACIERTO]=&reiniciar_esp8266_correcto;
desconectar_wifi.peticion=“AT+CWQAP”;
desconectar_wifi.timeout=2500;
desconectar_wifi.cantidad_respuestas=2;
desconectar_wifi.respuesta=malloc(sizeof(respuesta_esp8266*)*desconectar_wifi.cantidad_respuestas);
desconectar_wifi.respuesta[FALLO]=&error_operacion;
desconectar_wifi.respuesta[ACIERTO]=&desconectar_wifi_correcto;
establecer_modo_estacion.peticion=“AT+CWMODE=1”;
establecer_modo_estacion.timeout=2500;
establecer_modo_estacion.cantidad_respuestas=2;
establecer_modo_estacion.respuesta=malloc(sizeof(respuesta_esp8266*)*establecer_modo_estacion.cantidad_respuestas);
establecer_modo_estacion.respuesta[FALLO]=&error_operacion;
establecer_modo_estacion.respuesta[ACIERTO]=&establecer_modo_estacion_correcto;
establecer_modo_simple.peticion=“AT+CIPMUX=0”;
establecer_modo_simple.timeout=2500;
establecer_modo_simple.cantidad_respuestas=2;
establecer_modo_simple.respuesta=malloc(sizeof(respuesta_esp8266*)*establecer_modo_simple.cantidad_respuestas);
establecer_modo_simple.respuesta[FALLO]=&error_operacion;
establecer_modo_simple.respuesta[ACIERTO]=&establecer_modo_simple_correcto;
conectar_wifi.peticion=“AT+CWJAP=\”polaridad.es\”,\”54lLij1RiTn3MEd3v41C\””;;
conectar_wifi.timeout=20000;
conectar_wifi.cantidad_respuestas=2;
conectar_wifi.respuesta=malloc(sizeof(respuesta_esp8266*)*conectar_wifi.cantidad_respuestas);
conectar_wifi.respuesta[FALLO]=&error_operacion;
conectar_wifi.respuesta[ACIERTO]=&conectar_wifi_correcto;
verificar_conexion.peticion=“AT+CIPSTATUS”;
verificar_conexion.timeout=5000;
verificar_conexion.cantidad_respuestas=3;
verificar_conexion.respuesta=malloc(sizeof(respuesta_esp8266*)*verificar_conexion.cantidad_respuestas);
verificar_conexion.respuesta[FALLO]=&error_operacion;
verificar_conexion.respuesta[ACIERTO]=&verificar_conexion_correcto;
verificar_conexion.respuesta[OTRO_MENSAJE]=&verificar_conexion_terminado;
conectar_servidor.peticion=“AT+CIPSTART=\”TCP\”,\”servidoriot.com\”,80″;
conectar_servidor.timeout=15000;
conectar_servidor.cantidad_respuestas=3;
conectar_servidor.respuesta=malloc(sizeof(respuesta_esp8266*)*conectar_servidor.cantidad_respuestas);
conectar_servidor.respuesta[FALLO]=&error_operacion;
conectar_servidor.respuesta[ACIERTO]=&conectar_servidor_correcto;
conectar_servidor.respuesta[OTRO_MENSAJE]=&conectar_servidor_terminado; // OK, no significa que haya conexión pero sí termina la operación
informar_cantidad.peticion=“AT+CIPSEND=”;
informar_cantidad.timeout=1000;
informar_cantidad.cantidad_respuestas=1;
informar_cantidad.respuesta=malloc(sizeof(respuesta_esp8266*)*informar_cantidad.cantidad_respuestas);
informar_cantidad.respuesta[0]=&informar_cantidad_correcto;
//enviar_cantidad.peticion=””; // Se asigna cuando se conoce el valor que se va a enviar y se puede calcular la longitud que ocupa (número de caracteres)
enviar_cantidad.timeout=5000;
enviar_cantidad.cantidad_respuestas=2;
enviar_cantidad.respuesta=malloc(sizeof(respuesta_esp8266*)*enviar_cantidad.cantidad_respuestas);
enviar_cantidad.respuesta[FALLO]=&error_enlace;
enviar_cantidad.respuesta[ACIERTO]=&enviar_cantidad_correcto;
enviar_prefijo.peticion=“GET /frigo03/almacenar_temperatura.php?temperatura=”;
enviar_prefijo.timeout=10000;
enviar_prefijo.cantidad_respuestas=1;
enviar_prefijo.respuesta=malloc(sizeof(respuesta_esp8266*)*enviar_prefijo.cantidad_respuestas);
enviar_prefijo.respuesta[0]=&enviar_prefijo_correcto;
//enviar_datos.peticion=””; // Se asigna en cuando se conoce el valor que se va a enviar
enviar_datos.timeout=5000;
enviar_datos.cantidad_respuestas=1;
enviar_datos.respuesta=malloc(sizeof(respuesta_esp8266*)*enviar_datos.cantidad_respuestas);
enviar_datos.respuesta[0]=&enviar_datos_correcto;
enviar_sufijo.peticion=” HTTP/1.1\r\nHost: www.servidoriot.com\r\nUser-Agent: ESP8266\r\nConnection: close\r\n\r\n”;
enviar_sufijo.timeout=20000;
enviar_sufijo.cantidad_respuestas=2;
enviar_sufijo.respuesta=malloc(sizeof(respuesta_esp8266*)*enviar_sufijo.cantidad_respuestas);
enviar_sufijo.respuesta[FALLO]=&error_enlace;
enviar_sufijo.respuesta[ACIERTO]=&enviar_sufijo_correcto;
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
|
#if defined(ARDUINO_AVR_LEONARDO)||defined(ARDUINO_AVR_MEGA2560) /* ¿Es una placa Arduino Mega 2560 o Arduino Leonardo? */
#define SERIE Serial1 /* Si es una placa Arduino Mega 2560 o Arduino Leonardo usar Serial1 */
#else /* En este proyecto solamente uso Placas Leonardo, Mega 2560 y Uno, así que tiene que ser un Arduino Uno si llega hasta aquí */
#define SERIE Serial /* Si es una placa Arduino Uno usar Serial */
#endif
#define VELOCIDAD 115200 // Velocidad (en baudios) al que está configurado el módulo wifi ESP8266 (Cuidado con la placa utilizada, no todas o siempre son capaces de trabajar a una velocidad tan alta)
#define FALLO 0 // Índice del vector de respuestas que representa el mensaje de error
#define FALLO_TERMINA 0B00000001 // 1<<FALLO
#define ACIERTO 1
#define ACIERTO_TERMINA 0B00000010 // 1<<ACIERTO
#define OTRO_MENSAJE 2
#define OTRO_MENSAJE_TERMINA 0B00000100 // 1<<OTRO_MENSAJE
#define CANTIDAD_RESPUESTAS 3 // Cantidad de posibles respuestas que se buscan en el texto recibido desde el ESP8266
#define ESPERAR_RESPUESTA 0B00001000 // 1<<CANTIDAD_RESPUESTAS
#define NO_ESPERAR_RESPUESTA 0B00000000
#define ENVIAR_OPERACION esperando_respuesta=true;SERIE.print((*operacion_actual).peticion);if((*operacion_actual).cantidad_respuestas>1){SERIE.print(“\r\n”);for(unsigned char numero_respuesta=0;numero_respuesta<(*operacion_actual).cantidad_respuestas;numero_respuesta++){numero_caracter[numero_respuesta]=0;}}cronometro_esp8266=millis();
#define PIN_TEMPERATURA A0 // Pin analógico al que se conecta la salida del sensor de temperatura LM35
#define INTERVALO_LECTURA_TEMPERATURA 30000 // Leer la temperatura cada 30 segundos (30*1000)
#define INTERVALO_GRABACION_TEMPERATURA 300000 // Grabar la media de la temperatura cada 5 minutos (5*60*1000)
unsigned long muestras=0; // Número de veces que se ha medido la temperatura (para calcular la media)
float temperatura; // de -55.0 °C a +150 °C | de 0 V a 2.050 V | de -550 mV a +1500 mV | analogRead*5.0/1023.0*100-55.0 analogRead/2.46-55.0
float media_temperaturas=0.0;
unsigned long cronometro_lectura_temperatura;
unsigned long cronometro_grabacion_temperatura;
char *mensaje_acierto=“OK\r\n”;
typedef struct estructura_operacion_esp8266 operacion_esp8266; // Se define el tipo de datos operacion_esp8266 que corresponde con la estructura (struct) llamada estructura_operacion_esp8266 que se define más adelante
typedef struct estructura_respuesta_esp8266 respuesta_esp8266; // Se define el tipo de datos respuesta_esp8266 que corresponde con la estructura (struct) llamada struct estructura_respuesta_esp8266 que se define más adelante
struct estructura_operacion_esp8266
{
char *peticion; // Datos que se envían al ESP8266 para iniciar una operación (como una orden AT, pero también algo como la petición a un servidor…)
unsigned int timeout; // Tiempo (segundos) que se espera la respuesta del ESP8266 antes de desistir
bool espera_respuesta; // Si no espera respuesta en cuanto se termine de enviar la orden se puede pasar a la siguiente
unsigned char cantidad_respuestas; // Número de posibles respuestas del ESP8266 que se van a analizar, que puede ser variable en cada petición (no solo OK y ERROR)
respuesta_esp8266 **respuesta; // Respuestas (estructura) que se esperan de esta operación
};
struct estructura_respuesta_esp8266
{
char *mensaje; // Mensaje que se espera recibir desde el ESP8266
bool termina_operacion; // Cuando se termina de leer el mensaje ha terminado la operación
operacion_esp8266 *operacion; // Puntero a operación que se ejecutará si se encuentra esta respuesta en el mensaje devuelto por el ESP8266
};
operacion_esp8266 *operacion_actual; // Operación sobre el ESP8266 que se está ejecutando actualmente
operacion_esp8266 *proxima_operacion; // Siguiente operación que se procesará cuando termine la actual
unsigned int longitud_peticion; // Número de caracteres que ocupa la petición HTTP
char texto_longitud_peticion[4]; // 3 caracteres para almacenar la longitud de la petición en formato texto
char valor_enviado[9]; // signo + 4 enteros + punto + 2 decimales + \0 = 9
unsigned long cronometro_esp8266; // Cronómetro para controlar el tiempo máximo de respuesta del ESP8266 antes de desistir
char lectura_serie; // buffer con el carácter leído desde el ESP8266
boolean grabando_datos=false; // Verdadero cuando han terminado todas las operaciones necesarias para grabar los datos
boolean esperando_respuesta; // Verdadero si aún no se ha encontrado una de los mensajes que indica que ha terminado la respuesta
unsigned char numero_caracter[CANTIDAD_RESPUESTAS]; // Número de orden de la letra del mensaje-respuesta que se está almacenando (una matriz de, como máximo, el mayor número de respuestas posible)
operacion_esp8266 reiniciar_esp8266; // Reiniciar el módulo wifi ESP8266
operacion_esp8266 desconectar_wifi; // Desconectar del punto de acceso por defecto (si fuera el caso)
operacion_esp8266 establecer_modo_estacion; // Establecer el modo de estación (no punto de acceso)
operacion_esp8266 establecer_modo_simple; // Establecer el modo de conexión simple
operacion_esp8266 conectar_wifi; // Conectar al punto de acceso
operacion_esp8266 verificar_conexion; // Verificar si hay conexión
operacion_esp8266 conectar_servidor; // Conectar al servidor
operacion_esp8266 informar_cantidad; // Avisar de la cantidad de datos que se envían
operacion_esp8266 enviar_cantidad; // Enviar cantidad
operacion_esp8266 enviar_prefijo; // Enviar el prefijo de la petición
operacion_esp8266 enviar_datos; // Enviar la temperatura
operacion_esp8266 enviar_sufijo; // Enviar el sufijo de la petición
respuesta_esp8266 error_operacion; // Todas las respuestas “ERROR” reinician el módulo wifi ESP8266
respuesta_esp8266 error_enlace; // Las respuestas “link is not” también reinician el módulo wifi ESP8266
respuesta_esp8266 reiniciar_esp8266_correcto;
respuesta_esp8266 desconectar_wifi_correcto;
respuesta_esp8266 establecer_modo_estacion_correcto;
respuesta_esp8266 establecer_modo_simple_correcto;
respuesta_esp8266 conectar_wifi_correcto;
respuesta_esp8266 verificar_conexion_correcto;
respuesta_esp8266 verificar_conexion_terminado;
respuesta_esp8266 conectar_servidor_correcto;
respuesta_esp8266 conectar_servidor_terminado;
respuesta_esp8266 informar_cantidad_correcto;
respuesta_esp8266 enviar_cantidad_correcto;
respuesta_esp8266 enviar_prefijo_correcto;
respuesta_esp8266 enviar_datos_correcto;
respuesta_esp8266 enviar_sufijo_correcto;
void setup()
{
#include “inicializar_operaciones.h”
longitud_peticion=strlen(enviar_prefijo.peticion)+strlen(enviar_sufijo.peticion);
SERIE.begin(VELOCIDAD); // Configurar el puerto serie de Arduino a la velocidad del ESP8266
//delay(8000); // En fase de pruebas se puede introducir un tiempo de espera para conectar una consola/sniffer
cronometro_lectura_temperatura=millis();
cronometro_grabacion_temperatura=millis();
}
void loop()
{
if((unsigned long)(millis()–cronometro_lectura_temperatura)>INTERVALO_LECTURA_TEMPERATURA)
{
cronometro_lectura_temperatura=millis();
temperatura=analogRead(PIN_TEMPERATURA)/2.46–55.0;
muestras++;
media_temperaturas=(float)temperatura/(float)muestras+media_temperaturas*(float)(muestras–1)/(float)(muestras);
}
if(grabando_datos)
{
if((unsigned long)(millis()–cronometro_esp8266)>(unsigned long)(*operacion_actual).timeout) // Si se ha superado el tiempo de espera máximo
{
operacion_actual=(*(*operacion_actual).respuesta[FALLO]).operacion; // Pasar a la operación correspondiente al error
ENVIAR_OPERACION
}
else // Si no se ha superado el tiempo de espera máximo
{
if((*operacion_actual).cantidad_respuestas>1) // Si la siguiente operación depende de la respuesta a la actual desde el ESP8266 hay que leer la información que llegue desde el puerto serie
{
while(SERIE.available())
{
lectura_serie=SERIE.read();
for(unsigned char numero_respuesta=0;numero_respuesta<(*operacion_actual).cantidad_respuestas;numero_respuesta++) // Comparar la letra cargada desde el puerto serie con la correspondiente de los mensajes disponibles
{
if(lectura_serie==(*(*operacion_actual).respuesta[numero_respuesta]).mensaje[numero_caracter[numero_respuesta]]) // Si el dato que ha llegado es igual al que correspondería del mensaje buscado…
{
numero_caracter[numero_respuesta]++; // Como el carácter coincide, se puede comparar con el siguiente lo próximo que llegue por el puerto serie
if((*(*operacion_actual).respuesta[numero_respuesta]).mensaje[numero_caracter[numero_respuesta]]==0) // Si el carácter que toca es \0 es que se ha terminado de analizar el mensaje
{
if(esperando_respuesta) // Todavía no se ha encontrado un mensaje que determine la siguiente operación
{
proxima_operacion=(*(*operacion_actual).respuesta[numero_respuesta]).operacion; // La próxima operación que habrá que procesar será la que indique el mensaje encontrado para la operación actual
esperando_respuesta=false; // Ya se ha encontrado un mensaje que determina la siguiente operación
}
if((*(*operacion_actual).respuesta[numero_respuesta]).termina_operacion) // Si el mensaje encontrado es uno de los que terminan la operación…
{
if(operacion_actual==&enviar_sufijo) // Se ha completado la última operación de la tarea compleja
{
grabando_datos=false; // Se ha terminado la tarea compleja (grabar datos en el servidor)
}
else // No es la última operación de la tarea compleja, hay que seguir realizando otras operaciones
{
operacion_actual=proxima_operacion; // Ejecutar la siguiente operación
ENVIAR_OPERACION
}
}
}
}
else // Si la letra recibida no es igual que la correspondiente del mensaje
{
numero_caracter[numero_respuesta]=0; // Empezar a comparar desde la primera letra del mensaje
}
}
}
}
else // Si no hay que esperar datos desde el puerto serie
{
operacion_actual=(*(*operacion_actual).respuesta[0]).operacion;
ENVIAR_OPERACION
}
}
}
else
{
if((unsigned long)(millis()–cronometro_grabacion_temperatura)>INTERVALO_GRABACION_TEMPERATURA)
{
cronometro_grabacion_temperatura=millis();
dtostrf(media_temperaturas,4,2,valor_enviado); // snprintf(valor_enviado,9,”%+3.2f”,media_temperaturas); // printf y derivadas no funcionan en AVR
snprintf(texto_longitud_peticion,4,“%d”,longitud_peticion+strlen(valor_enviado));
grabando_datos=true;
operacion_actual=&verificar_conexion;
enviar_datos.peticion=valor_enviado;
enviar_cantidad.peticion=texto_longitud_peticion;
ENVIAR_OPERACION
}
}
}
|
Deși în acest exemplu (în ambele implementări) nu are prea mult sens, pentru a generaliza operația pentru a o putea aplica și în alte cazuri, trebuie menționat că trimiterea datelor repetă întotdeauna același protocol: notificați numărul de octeți care vor fi trimiși, așteptați indicatorul (>) și trimiteți datele.
Întrucât în acest exemplu se folosește o singură dată (întreaga cerere se face într-un singur pachet), nu pare foarte utilă dar, în general, poate fi necesară efectuarea mai multor trimiteri în aceeași operațiune, inclusiv cazurile în care trebuie să fie transmise cantități semnificative de date care trebuie fragmentate pentru a evita debordarea memoriei ESP8266.
Pentru implementarea acestui comportament, ultimele două elemente ale conexiunii pot fi folosite astfel încât de fiecare dată când datele sunt trimise, datele să fie completate cu valorile corespunzătoare: în primul caz, numărul de octeți trimiși și în al doilea, ( parte din) cerere.să fie transmis.
Pentru a repeta atribuirea și trimiterea diferitelor elemente care trebuie transmise pot fi stocate într-un vector. Acest nou vector va fi cel care determină sfârșitul operației complexe și nu ultima operație ca până acum.
1 comentariu