Základné operácie na wifi module ESP8266 od Arduina
Kedy Espressif uviedla na trh prvé moduly wifi s integrovanou ESP8266 a firmware pomocou AT príkazov, nás používateľov zaujímala integrácia do zostáv s mikrokontroléry a problémy sa zredukovali na poznanie (predtým) tmy Tabuľka príkazov ESP8266 AT, potreby kŕmenia resp Aktualizácia firmvéru ESP8266.
Potom rýchlo prišli alternatívy na programovanie ESP8266 a implementácie modulov wifi veľmi odlišných formátov, ktoré vyvolali ďalšie obavy: ktorý wifi modul ESP8266 si vybrať v závislosti od dosahu rôznych antén (vrátane externých) alebo fyzickej integrácie týchto nových modulov do našich zostáv.
V dôsledku všetkých týchto zmien sa určite nekládol dôraz na najzákladnejšie aspekty, najzákladnejšie riadenie Wifi modul ESP8266. Hoci polarita.es Môžete nájsť informácie o použití ESP8266 a existujú niektoré aplikácie určené na všeobecné vysvetlenie fungovania Wifi modul ESP8266 pomocou AT príkazov, najmä v článku o knižnica na vytváranie HTTP dotazov z Arduina pomocou wifi modulu ESP8266, dojmy čitateľov naznačujú, že by bolo užitočné pridať niekoľko základných informácií, ktoré by pomohli používateľom stránky ESP8266 vykonávať vlastné implementácie.
Diskutujte o základných operáciách pri práci s ESP8266 a navrhovanie všeobecných riešení je cieľom niekoľkých veľmi odlišných častí; Ako pomôcka vám môže poslúžiť nasledujúci index, ktorý vám pomôže sledovať obsah článku:
- Ovládajte wifi modul ESP8266 z počítača cez sériový port
- Aktualizujte firmvér pomocou esptool
- Odosielajte objednávky do modulu
- Prijímajte dáta z ESP8266
- Analyzujte odpoveď vyhľadávaním textov v obsahu
- Obmedzte čakaciu dobu na prijatie odpovede
- Vykonajte komplexnú operáciu definovanú viacerými AT príkazmi
Ovládajte wifi modul ESP8266 z počítača cez sériový port
Z taniera Arduino a pomocou vášho IDE je možné sledovať chod a Wifi modul ESP8266, pošlite ESP8266 AT príkazy a pozrite si odpoveď, ale oveľa pohodlnejšie je to urobiť z počítača s aplikáciou typu terminálu.
Podľa toho na akej doske Arduino Ak sa používa, môže byť dostupný iba jeden hardvérový sériový port, čo spôsobuje trochu nepohodlia pri odosielaní a prijímaní. Zmena rýchlosti komunikácie je oveľa pohodlnejšia v sériovej komunikačnej aplikácii z počítača a niektorých základných dosiek. Arduino (a za určitých okolností) nepodporujú najvyššie rýchlosti sériovej komunikácie dobre, najmä 115200 baud, čo je predvolená rýchlosť najnovších verzií firmware.
O Aký program použiť na sledovanie ESP8266 pomocou sériového portu, existuje veľa na výber podľa potrieb a preferencií; v poslednej dobe viac pouzivam klasiku CuteCom (ten na obrázku vyššie), pretože je pre mňa veľmi pohodlné opakovať isté ESP8266 wifi modul AT objednávky pri testovaní projektu.
Niektoré odporúčania tu už boli uvedené pre programy, ktoré fungujú ako sériová konzola; Napríklad, keď sa hovorí o PuTTY na ovládanie sériových zariadení UART z počítača. PuTTYOkrem toho, že je to vynikajúca aplikácia, je dostupná pre väčšinu desktopových operačných systémov. Ďalej, ako PuTTY môže byť použitý ako konzola so sériovým portom aj s rodina internetových protokolov (TCP/IP)vrátane tých, ktoré fungujú na TLS, sa stáva bežným nástrojom, ktorý viac ako spláca (málo) času stráveného jeho konfiguráciou a zvykaním si na jeho používanie.
Okrem softvéru na sériovú komunikáciu, na pripojenie Wifi modul ESP8266 do prístavu USB Počítač tiež vyžaduje prevodník USB do série TTL. Podobne ako v prípade softvéru existuje viacero verzií, z ktorých slúžia len na konverziu portu USB na sériovom porte TTL (ktoré sa dajú získať od jedného eura) až po tie, ktoré dokážu emulovať rôzne protokoly (ako napr SPI o I2C).
Rovnako ako program, ktorý funguje ako sériová konzola, hardvér na komunikáciu s počítačom USB s logickým obvodom (nielen s ESP8266) bude bežným nástrojom v práci vývojára mikroriadených aplikácií, oplatí sa mať ho čo najskôr v paneli nástrojov a pracovať s ním Wifi modul ESP8266 Je to skvelá príležitosť získať ho.
Prevodník USB a UART TTL Môže sa tiež použiť na monitorovanie správania obvodu, ktorý používa ESP8266, za týmto účelom sú výstupy, ktoré chcete monitorovať, zapojené do série s dátovým vstupom (RX) prevodníka s rýchlou diódou (tzv. 1N4148, napríklad) a odpor (napríklad 2K2) paralelne navzájom. Takéto nastavenie funguje ako hardvérový sériový sniffer.
Hoci sniffer na obrázku vyššie je určite základný (okrem iného nemá nárazník) postačuje na monitorovanie činnosti zostavy s Arduino a ESP8266.
Odstránenie sniffer z predchádzajúcej schémy, schéma znázorňujúca spôsob pripojenia a Wifi modul ESP8266 na tanier Arduino. Okrem napájania na 3V3 musí byť resetovací kolík a aktivačný kolík integrovaného pripojené k vysokej úrovni (povoliť). Samozrejme, RX pin jedného sa musí spojiť s TX druhého.
Pre zjednodušenie predchádzajúceho diagramu bola znázornená doska Arduino napájané 3V3 a pre ktoré sa predpokladá, že napätie na sériovom porte je tiež 3V3. Ak používate a mikrokontrolér s inou úrovňou signálu na sériovom porte (zvyčajne 5 V), aby nedošlo k poškodeniu ESP8266, použite a prevodník úrovní ako tie na diagramoch nižšie. Tento obvod sa často nachádza v mnohých komerčných implementáciách štandardných modulov.
Aktualizujte firmvér ESP8266
L ESP8266 AT príkazy, jeho ukončenie, predvolená rýchlosť modulu... závisí od verzie Firmvér ESP8266. Najlepšie je zabezpečiť, aby ste mali rovnakú verziu vo všetkých moduloch, a ak je to možné, aby to bola najnovšia verzia.
Bohužiaľ, väčšina Modely wifi modulu ESP8266 Majú len 4 Mbit, takže najnovšia verzia sa na ne nedá nainštalovať. Najnovšia (oficiálna) verzia firmvéru, na ktorú je možné nainštalovať WiFi moduly ESP8266 so 4 Mbit (väčšina) je 0.9.4, čo zahŕňa verziu 0.2 ESP8266 AT príkazy.
Stručne povedané, na aktualizáciu firmvéru potrebujete:
-
Stiahnite si príslušnú verziu firmvéru. najnovšia (oficiálna) verzia modulu, ktorý má 4 Mbit pamäte, sa nachádza v priečinku Espressif na githube, V Webová stránka Espressif Môžete si stiahnuť najnovšiu verziu firmvéru, ale je veľmi dôležité overiť, či modul, na ktorom je nainštalovaný, má dostatok pamäte.
-
Stiahnite si najnovšiu verziu nástroja na inštaláciu firmvéru. Môj obľúbený je esptool ktorý je napísaný v Pytón, takže funguje na akejkoľvek platforme. Okrem stiahnutia sa dá aj nainštalovať s
pip install esptool
(opip2
opython -m pip
…). Samozrejme, Espressif Ponúka aj vlastný nástroj, no momentálne je dostupný len pre Windows. -
Pripravte stiahnuté súbory; rozbaľte ich do prístupného priečinka a v prípade potreby urobte nástroj spustiteľným esptool, v mojom prípade od r GNU / Linux, S
chmod +x esptool
-
Pripojte modul k počítaču pomocou prevodníka USB UART TTL ktorý funguje na 3V3 alebo použite menič úrovne, ak pracuje na 5 V. Okrem napájania budete musieť pripojiť TX na RX meniča USB UART TTL, RX na TX, GPIO0 na nízkej úrovni (GND) a možno GPIO2 na vysokej úrovni (v mojich testoch fungovalo pripojenie na nízkej úrovni aj odpojenie). Ak má modul voľné pripojenie GPIO15 (ako sa vyskytuje v ESP-12), musí byť pripojený k nízkej úrovni. RESET, ktorý by bol normálne počas prevádzky na vysokej úrovni, môže byť ponechaný nezapojený alebo pripojený k vysokej úrovni pomocou odporu (napríklad 10K), pretože pred spustením nahrávania môže byť potrebné resetovať zariadenie jeho pripojením. na nízku úroveň.
Po zapnutí modulu bude k dispozícii na aktualizáciu, ale Ak sa zobrazí chyba pripojenia, bude potrebné ju resetovať pripojenie RESET na nízkej úrovni na okamih a potom ponechanie na vzduchu (bez pripojenia) pre proces aktualizácie.
Modul má polampérová spotreba vrcholí (podľa niektorých používateľov až 600 mA), preto je dôležité používať napájací zdroj schopný túto spotrebu podporovať, najmä pri aktualizácii firmvéru. -
Spustite nástroj na aktualizáciu firmvéru. V mojom prípade som uložil nástroje a dokumenty firmvéru v kroku 3 do rovnakého priečinka, takže spustím z konzoly:
cd ~/Datos/firmwareESP8266
(prejdite do priečinka obsahujúceho nástroj a firmvér)./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
nastavuje rýchlosť ESP8266 (115200 baud v mojom prípade) a--port
sériový port, ku ktorému sa pripája (v mojom prípade emulovaný, prvý USB). Rôzne dokumenty, ktoré tvoria firmvér, idú pozaduwrite_flash
predchádza adresa, pričom dokument user1.bin obsahuje užitočné zaťaženie aktualizácie.
Odošlite príkazy do wifi modulu ESP8266
Na ovládanie ESP8266 z počítača, s ktorým budeme musieť začať nakonfigurujte aplikáciu pre ktorý bude stačiť ① zvoliť port, ku ktorému je prevodník pripojený USB UART TTL, niečo ako /dev/USB0
v GNU/Linux a podobne alebo podobne COM6
v systéme Windows ② vyberte rýchlosť, akou sa ESP8266, pravdepodobne 115200 baud, ③ nastavte 8 dátových bitov plus jeden stop bit, bez parity alebo handshake, a ④ nastavte koniec riadku v závislosti od firmware, takmer vždy CR+LF.
Keď je aplikácia nakonfigurovaná (alebo tam, kde je to vhodné, uložená a vybraná), je otvorte spojenie („otvorené zariadenie“ a „otvorené“ na snímkach obrazovky vyššie uvedených príkladov s CuteCom y PuTTY) a môžete začať odosielať objednávky na ESP8266.
Ako je možné vidieť v Tabuľka príkazov ESP8266 AT, formát na aktiváciu, deaktiváciu, nastavenie hodnoty a odkazovanie na ňu je celkom predvídateľný, ale vo všeobecnosti nie je ľahké si ich všetky zapamätať a pravdepodobne ho budete musieť mať po ruke, aby ste sa naň mohli odkazovať.
Spôsob odoslať AT objednávky al Wifi modul ESP8266 z Arduino Je to veľmi jednoduché: ① nakonfigurujte komunikáciu s Serial.begin(115200);
(alebo Serial1, Serial2… na doskách s viacerými hardvérovými sériovými portami) a ② odošlite príkazy vo formáte 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() { } |
Vyššie uvedený príklad ukazuje, ako odoslať ESP8266 wifi modul AT objednávky z Arduino. V tomto prípade je to znázornené AT+CWJAP
, ktorý sa používa na pripojenie k prístupovému bodu. Tento príkaz používa ako argumenty identifikátor prístupového bodu (SSID) a kľúč, oba v úvodzovkách, takže sa stanú objektom Srtring
a uzavrite ich do úvodzoviek pomocou únikového kódu (\"
). Na dokončenie objednávky použite \r\n
čo zodpovedá CR
y LF
.
Nezabudnite, že sériový port nie je vždy identifikovaný Serial
(na určitých tanieroch to môže byť Serial1
, Serial2
…) použitý objekt portu bol definovaný jeho priradením k makru PUERTO_SERIE
. Detekcia typu použitej dosky by mohla pridať trochu inteligencie do výberu sériového portu; Neskôr si prejdeme, ako môžete zistiť typ Arduino. Ostatné definície sú obvyklé, ktoré vám umožňujú „pomenovať“ konštantné hodnoty, aby ste sa vyhli ich opakovaniu (a chybám) a uľahčili ich zmenu.
Vyššie uvedený príklad má spájať Wifi modul ESP8266 k uvedenému prístupovému bodu, ale bol už predtým pripojený? Fungovalo spojenie? Aby sme to vedeli, musíme "počúvať" čo ESP8266
Prijímajte dáta z wifi modulu ESP8266
Po pripojení vyššie opísaného sledovača údajov k počítaču uvidíte, čo Arduino poslal do ESP8266 a jeho odpoveď. Na čítanie z Arduino a spracovávať informácie v ňom, ktoré bude potrebné zisťovať Serial.available()
či prišli nejaké dáta a ak áno, načítaj ich Serial.read()
. Nasledujúci príklad ukazuje, ako čítať odpoveď z AT+CWJAP?
, ktorý bude hlásiť, či existuje pripojenie k akémukoľvek prístupovému bodu.
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(); } } |
Ako na tanieri Arduino Uno (av iných) otvorenie sériového monitora resetuje program, možno ho použiť na zobrazenie v sériovej konzole Arduino informácie, na ktoré posielate ESP8266 ako ukazuje snímka obrazovky nižšie.
Analyzujte odpoveď odoslanú modulom wifi ESP8266
Už sme videli, ako čítať informácie, ktoré sa dostanú Arduino z ESP8266. Problém, s ktorým sa musíte vysporiadať, je, že neviete, kedy to začne prichádzať, ako dlho to bude trvať, aká bude dĺžka... a nie je veľmi efektívne čakať na odpoveď od ESP8266 sa prijíma bez toho, aby sa nechal mikrokontrolér medzitým vykonávať iné úlohy.
Jednoduchý spôsob, ako zvládnuť túto okolnosť, je iterujte získané údaje a hľadajte konkrétne odpovede pomocou ktorých sa napríklad aktivujú indikátory (príznaky alebo booleovské premenné), ktoré určia, či pokračovať v hľadaní v prijatom texte a aké akcie by sa mali vykonať na základe informácií, ktoré prichádzajú z ESP8266. Kým príde odpoveď mikrokontrolér môže venovať iným úlohámnapríklad prijímanie údajov zo senzorov a ich spracovanie.
Vyhľadajte text v informáciách prijatých z ESP8266
Ak chcete vyhľadať text, ktorý pochádza z ESP8266 môžete porovnajte každý prijatý list s tým, ktorý zodpovedá správe, ktorú hľadáte. Bude potrebné použiť počítadlo (alebo ukazovateľ), ktoré ukazuje na porovnávané písmeno; Ak postava, ktorá prichádza z ESP8266 je rovnaký ako ten, ktorý sa skúma v správe, počítadlo sa posunie dopredu, ak je iné, inicializuje sa.
Aby sme vedeli, že koniec bol dosiahnutý, konzultuje sa ďalší znak hľadanej správy, ktorým bude nula (\0
) alebo sa dĺžka správy uloží, aby sa jej porovnaním s počítadlom zistilo, či sa porovnanie skončilo, a teda Wifi modul ESP8266 odoslal požadovanú správu.
Nasledujúci príklad používa príkaz AT+CWLAP
ktorý vráti zoznam prístupových bodov a v rámci nich sa hľadá jeden s názvom „wifi polaridad.es“. Hoci sme sa rozhodli overiť, že posledný znak je nula, pretože nárazník Ukladá len hľadaný text a je známa jeho dĺžka, dalo by sa skontrolovať aj to, či bol prijatý taký počet správnych písmen. S LED pripojený na kolík 2 je hlásené, že očakávaný text bol nájdený.
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 } } } } |
V kóde predchádzajúceho príkladu môžete vidieť aj spôsob vyberte sériový port v závislosti od typu dosky Arduino použité. Tento príklad predpokladá, že máte pre projekt tri typy dosiek: jednu Arduino Uno, One Arduino Mega 2560 a arduino leonardo. Ak pracujete s a Arduino Uno bude sa používať Serial
a inak Serial1
.
Ak pracujete s tanierom arduino leonardo Rovnakú metódu môžete použiť na zastavenie programu a počkať na konzolu (sériový port spojený s Serial
) je k dispozícii.
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 |
Vyhľadajte rôzne texty v odpovedi ESP8266
Kód v predchádzajúcom príklade sa používa na vyhľadávanie textu v informáciách odoslaných serverom ESP8266 ale odpoveď môže obsahovať rôzne informácie v závislosti od operácie. Predpokladajme, že v nasledujúcom príklade začneme jednoduchým prípadom, že text odoslaný MCU ESP8266 es OK
keď je operácia vykonaná správne a ERROR
Inak ako pri objednávke AT+CWJAP?
, ktorá slúži na overenie, či je Wifi modul ESP8266 je už pripojený k prístupovému bodu.
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 } } } } } |
Táto nová implementácia rovnakej metódy, ktorá hľadá zhodu s niekoľkými možnými správami, vám umožňuje vybrať si medzi rôznymi akciami v závislosti od odpovede prijatej od ESP8266, jednoducho zapnite LED zodpovedajúce.
Obmedzte čas potrebný na prijatie odpovede
Doposiaľ nebola uvedená žiadna zmienka o relevantnej otázke: maximálny čas čakania (časový limit) pred zvážením zlyhania operácie. Ak z akéhokoľvek dôvodu spojenie s Wifi modul ESP8266, modul s prístupovým bodom, prístupový bod s internetom alebo napríklad hypotetický server nie je k dispozícii, program môže byť v jednom bode zablokovaný a čaká na neurčito, takže na takéto okolnosti bude potrebné reagovať. Maximálnu dobu čakania je možné nakonfigurovať pre celú aplikáciu, zvyčajne bude v takom prípade „štedrejšia“, alebo je možné pre každú operáciu naprogramovať individuálne doby čakania.
Skontrolovať, či uplynul (aspoň) určitý časový interval „Čas“ okamihu, v ktorom je účet spustený, sa zvyčajne odpočíta od aktuálneho „času“ a overí sa, že rozdiel je väčší ako požadovaný limit. Tento „čas“ nemusí byť skutočný čas, zvyčajne zodpovedá intervalu, ktorý uplynul od MCU začať počítať čas; Toto neovplyvní program, pretože zaujímavý je uplynutý čas a nie absolútny čas.
Zvyčajne sa na kontrolu, či uplynul určitý interval, používa výraz typu:
1 | (unsigned long)(millis()–milisegundos_al_empezar)>intervalo_de_tiempo |
premenlivý milisegundos_al_empezar
obsahuje hodnotu millis()
určitého momentu v prevedení, od ktorého sa meria, takže nie je nezvyčajné, že jeho názov odkazuje na slovo „chronometer“. Premenná intervalo_de_tiempo
obsahuje maximálny počet milisekúnd, v ktorom je predchádzajúci výraz pravdivý, to znamená, že predstavuje časový limit; Väčšinou ide o konštantu (alebo makro) a ako v predchádzajúcom prípade sa v jej názve často vyskytuje slovo „TIMEOUT“. Ak pracujete s veľmi krátkymi intervalmi, môžete použiť micros()
namiesto millis()
(mikrosekundy namiesto milisekúnd), hoci je to oveľa menej bežné a oveľa menej presné.
1 | (unsigned long)(millis()–cronometro)>TIMEOUT |
Dlhé celé číslo v Arduino (unsigned long
) zaberá 4 bajty (32 bitov), takže najväčšia hodnota, ktorú môže predstavovať, je 4294967295 (2 na mocninu 32 mínus jedna, pretože začína na nule). na tanieri Arduino Počas nepretržitého chodu sa počítadlo milisekúnd vynuluje (vráti sa na nulu) približne každých 50 dní. Pri odčítaní s nepodpísanými typmi údajov sa reprodukuje rovnaké správanie (preklápanie počítadla), takže je možné ovládať časový limit na neurčito.
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; } } } |
Vyššie uvedený kód ukazuje a veľmi základná implementácia obmedzenia časového limitu začlenenie riadkov označených vzhľadom na príklad, ktorý mu predchádza. Keďže overenie časového limitu sa vykonáva po spracovaní údajov prichádzajúcich z Wifi modul ESP8266, operáciu možno považovať za úspešnú aj vtedy, ak príjem trvá dlhšie, ako je stanovená čakacia doba.
Vykonajte komplexnú operáciu definovanú viacerými AT príkazmi
Ak chcete mať príklad odkazu na účel aplikácie, ktorá využíva Wifi modul ESP8266, predpokladajme, že áno uchovávať informácie v databáze prístupnej prostredníctvom webovej služby na sledovanie teploty. Nasledujúci kód načíta v určitom časovom intervale snímač pripojený k analógovému vstupu, vypočíta priemernú hodnotu a po dlhšom časovom intervale ju odošle na web server (v štýle IoT) prostredníctvom a petície HTTP (POSLAŤ, ZÍSKAŤ...).
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”); } } |
V tomto príklade zaznamenávania teploty sa na webový server pristupuje každých päť minút. Hoci dostupnosť nie je príliš vysoká, dá sa očakávať, že návrh bude fungovať, ale ak by bola potrebná vyššia frekvencia záznamu, museli by sa implementovať iné zdroje, napr. dátová vyrovnávacia pamäť čaká na odoslanie, poslať niekoľko, keď sa server môže zúčastniť, a uložiť ich na dobu, keď nebude k dispozícii. Ak by frekvencia, s akou je potrebné zaznamenávať údaje, bola ešte väčšia, museli by sa navrhnúť iné typy protokolov ako alternatíva k HTTP alebo dokonca nahradiť TCP podľa UDP aby bolo možné odosielať väčšinu dát požadovanou rýchlosťou aj za cenu straty niektorých.
Operácie, ktoré tvoria úlohu, ktorá sa má vykonať na odoslanie teploty, by boli:
- Resetujte modul wifi
- Odpojiť sa od aktuálneho prístupového bodu (v prípade, že existuje predvolené pripojenie)
- Nastavte nastavenia. Napríklad sa predpokladá, že musí byť nakonfigurovaný režim pripojenia (jednoduchý) a úloha v komunikácii Wi-Fi (stanica).
- Pripojte sa k prístupovému bodu
- Overte, či je pripojenie správne (v skutočnosti je to vstupný bod) Ak nie je pripojenie, začnite proces od začiatku
- Pripojiť k serveru
- Pošlite žiadosť HTTP s údajmi, ktoré sa majú uložiť
Poradie operácií nemusí byť presne toto (hoci operácia áno) a každý krok môže vyžadovať niekoľko ESP8266 AT príkazyNapríklad konfigurácia uvedená vyššie by potrebovala dve: AT+CIPMUX=0
y AT+CWMODE=1
.
Dátová štruktúra reprezentujúca operácie na ESP8266
V predchádzajúcich príkladoch, aj keď veľmi jednoduchým spôsobom, je už navrhnuté všeobecné riešenie problému: použiť dátovú štruktúru, ktorá ukladá možné odpovede a akcie, ktoré sa musia v každom prípade vykonať; odošlite akciu, počkajte na odpoveď a pokračujte podľa toho, čo odpoveď znamená. Pretože každá zložitá operácia bude vyžadovať niekoľko ESP8266 AT príkazy, dátová štruktúra musí spájať operáciu s ďalšími, nasledujúcimi alebo predchádzajúcimi, ktoré sa musia v každom prípade vykonať v závislosti od odozvy ESP8266.
V predchádzajúcich príkladoch sa správa hľadala v rámci odpovede ESP8266 a bolo to interpretované ako úspech alebo chyba. Okrem príjmu (a analýzy) všetkých prijatých textov, Ak chcete mať všeobecné minimum, je vhodné venovať sa aj vyplneniu správy alebo, inými slovami, na dostupnosť Wifi modul ESP8266 prijímať nové objednávky. Týmto spôsobom by zmena do stavu, ktorý by sme mohli nazvať napríklad „wifi k dispozícii“, mohla byť prijímaním názvu prístupového bodu a prijímaním textu ERROR
alebo text OK
by znamenalo, že ESP8266 dokončili ste odpoveď a teraz môžete odoslať ďalšiu AT príkaz na 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; |
Vyššie uvedený kód používa vektor (operacion
) na uloženie textu po sebe nasledujúcich operácií, ktoré tvoria kompletnú úlohu. Používa sa dvojrozmerné pole (mensaje
) s tromi analyzovanými odpoveďami. Ako je vysvetlené vyššie, okrem správy, ktorá predstavuje správnu alebo nesprávnu odpoveď, je potrebné hľadať správy, ktoré predstavujú koniec odpovede. Nie všetky operácie budú mať rovnaký počet možných odpovedí; Pri menšom počte odpovedí je možné použiť prázdnu správu, ktorá pri analýze spotrebuje čo najmenší počet cyklov (aj tak to nie je najoptimálnejší spôsob). Logicky bude potrebné, aby minimálny počet hľadaných odpovedí (v príklade tri) zahŕňal všetky prevádzkové možnosti, aj keď nie všetky možné.
Keď hovoríme o možných odpovediach, už je vidieť, že tento príklad nie je veľmi užitočný na prijímanie údajov v ľubovoľnom formáte z Wifi modul ESP8266, ale ide o to, že v kontexte použitia s mikrokontroléry nie je to obvyklé; Najbežnejšou vecou je odosielanie údajov zozbieraných senzormi, ktoré majú pripojené, a/alebo prijímanie informácií o tom, čo robiť s ovládačmi, ktoré ovláda. Veľmi cenné informácie, ktoré sa dajú veľmi dobre predvídať.
V predchádzajúcej dátovej štruktúre, rovnako ako sa to robí na vyjadrenie možných odpovedí, ktoré sa analyzujú, sa tiež používa dvojrozmerná matica na určenie operácie, ktorá sa musí v každom prípade vykonať (siguiente_operacion
). Konkrétne sme sa rozhodli odpovedať na tri typy správ: ① ľubovoľný text (LITERAL
) na overenie, či existuje pripojenie k prístupovému bodu Wi-Fi a serveru, ② text na zistenie chýb v procese (FALLO
) a ③ text označujúci, že operácia bola úspešne dokončená (ACIERTO
).
Nakoniec existujú dva ďalšie vektory na nastavenie maximálnej doby čakania, kým sa vzdáte (timeout
) a špecifikujte (configuracion
) ak operácia skončí bez čakania na odpoveď (ESPERAR_RESPUESTA
) a správy označujúce koniec komunikácie. Tento posledný vektor na ilustráciu príkladu toho, ako by sa dala šetriť pamäť, pracuje s bitmi konfiguračného bajtu na označenie rôznych stavov.
Prvý ESP8266 AT príkazy dátovej štruktúry vždy očakávať odpoveď, ktorou môže byť úspešná alebo chybová správa. Keď sa vyskytne chyba, modul sa reštartuje a spustí sa odznova a ak správa indikuje, že operácia je správna, prejde na ďalšiu.
Po pripojení k serveru sa vzor zmení. V tomto prípade je potrebné ① odoslať dĺžku dátového paketu, ktorý sa má preniesť a ② zostaviť požiadavku HTTP s pevným textom plus hodnotou (teploty), ktorá sa odošle na uloženie na server. Príprava týchto údajov sa vykonáva v každej zásielke a je potrebné ich rozdeliť na dve (oznámiť dĺžku) alebo tri (zaslať požiadavku HTTP) Ak chcete ESP8266 AT objednávka. Na odozvu bude čakať len posledná z častí, na ktoré je operácia rozdelená.
V tomto prípade to bude fungovať bez problémov (možno upozornenie, že modul je zaneprázdnený), ale pri väčšej dĺžke dát bude potrebné rozdeliť dátové bloky na menšie časti a možno bude potrebné implementovať aj čakanie, napr. sa vykonáva s odčítaním teploty, aby mal modul čas na odoslanie údajov bez ich vypĺňania nárazník.
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(); |
Spoločne s ďalšími makrami, ktoré už boli vysvetlené vyššie, vyššie uvedený príklad kódu ukazuje, ako sú definované rôzne stavy, pomocou ktorých je možné určiť, či sa má čakať na odpoveď, a ak je to vhodné, aká správa označuje, že sa skončila.
Rovnako ako v rôznych bodoch kódu bude odoslaná operácia (keď je čas odoslať priemernú teplotu, ak je prekročená čakacia doba operácie, keď je aktuálna operácia úspešne dokončená...), ale ako to urobiť globálne, bolo definované ako makro ENVIAR_OPERACION
ktorý zoskupuje kroky súvisiace s prepravou.
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(); |
Nasleduje kód hlavného programu príkladu. Najexternejšia úloha je tá, ktorá má na starosti odber vzoriek teploty na výpočet priemernej hodnoty, ktorá sa vždy po určitom čase odošle na server pomocou Wifi modul ESP8266. Po odoslaní každej operácie sa analyzuje odpoveď, aby sa určilo, ktorá je ďalšia, alebo či bola úloha odoslania informácií dokončená.
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 } } } |
Logicky je možné vykonať niekoľko optimalizačných akcií na predchádzajúcom kóde, ale keďže toto je príklad, aby ste pochopili, ako ESP8266 Vo všeobecnosti sa oplatí zamerať sa len na niektoré aspekty, pričom prvým je štruktúra údajov. Zdá sa, že je to logické použiť dátovú štruktúru programovacieho jazyka (struct
), ktoré predstavujú spracovávané informácie: ESP8266 AT príkazy a správy, ktoré sa analyzujú.
Použite štruktúru (struct
) ukladať údaje namiesto vzorových polí (na nich založených) je triviálne a hoci to môže viesť k elegantnejšiemu kódu, neznamená to žiadne zlepšenie výsledku. Skutočnou alternatívou je použitie struct
je implementovať, ako je vysvetlené nižšie, variabilné dĺžky v štruktúrach, ktoré obsahujú „vnútorné“ dáta na ktoré sa odvolávajú. Týmto spôsobom by napríklad nebolo potrebné, aby operácia mala pevný počet odpovedí na analýzu.
Tento prístup naznačuje, že je to najlepší spôsob implementácie riešenia, ale nevýhodou je, že by to bolo potrebné používať dynamickú alokáciu pamäte, riskantnú prax pri práci s a mikrokontrolér čo si vyžaduje starostlivé meranie toho, koľko pamäte sa bude používať za behu, keďže nás na to kompilátor sotva bude vedieť upozorniť a je tu istá možnosť vyčerpania pamäte (alebo zásobníka) s fatálnymi následkami pre vykonávanie programu.
V riadku optimalizácie kódu je zaujímavé pripomenúť, že v programe tohto typu, ktorý používa veľké množstvo textu, môže ušetriť miesto v pamäti SRAM ukladanie textových reťazcov do pamäte programu (blesk) s makrom F()
. Na nasledujúcich snímkach obrazovky môžete vidieť rozdielne rozdelenie programu a dynamickej pamäte pri bežnom používaní textu a makra F()
.
S ohľadom na akcie, ktoré sa vykonávajú podľa informácií, ktoré prichádzajú z Wifi modul ESP8266, ako alternatíva ku kontrole správy z kódu a vykonaniu jednej alebo druhej podľa toho, čo bolo prijaté, môže byť uložená v tejto dátovej štruktúre ukazovatele na funkcie, ktoré vykonávajú jednotlivé úlohy, namiesto indikátorov stavu (príznaky), ktoré upozorňujú na určitý stav, za ktorý je aplikácia zodpovedná, napríklad v rámci hlavnej slučky.
Nasleduje príklad štruktúr na ukladanie údajov požiadaviek na server ESP8266 (typ údajov operacion_esp8266
) a ich odpovede (údajový typ 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; |
Ako štruktúra, ktorá predstavuje operáciu (údaje odoslané do Wifi modul ESP8266) odkazuje na štruktúru, s ktorou sú odpovede definované, a štruktúru odpovedí na štruktúru operácií, je potrebné najprv deklarovať obojedefinovaním nového dátového typu a následným definovaním jeho obsahu.
Predchádzajúci príklad predpokladá, že program, ktorý ho obsahuje, sa rozhodol použiť a indikátor stavu, ktorá musí zodpovedať premennej prístupnej z kódu, ktorý je zodpovedný za vykonanie jednej alebo iných operácií, ako je označené uvedenou hodnotou. Ak v odpovedi na ESP8266 Keď sa analyzuje určitý text, stav nadobudne hodnotu, ktorá označuje štruktúru zodpovedajúcej odpovede.
Ako už bolo povedané, ďalšou alternatívou by bola náhrada alebo doplnenie indikátora stavu uložiť funkciu do referenčnej štruktúry (ukazovateľ), ktorý by sa vyvolal pri stretnutí s určitým textom v odpovedi z Wifi modul 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; |
V predchádzajúcom príklade bol pridaný do dátovej štruktúry, ktorá sa používa na spracovanie odpovede z Wifi modul ESP8266 ukazovateľ na (údajnú) funkciu, ktorá vracia údaje typu float
(môže to byť vážená hodnota analógového odčítania) a ku ktorému sú poskytnuté dva bajty ako argumenty (dva unsigned char
čo by mohol byť pin, z ktorého sa číta analógový vstup, a ten, ktorý aktivuje ENABLE hypotetickej integrácie).
Vo vývoji pre MCUNa rozdiel od toho, čo sa vyskytuje vo vývojovom štýle pre väčšie systémy, nie je také nezvyčajné používať globálne premenné pri definovaní (globálneho) správania aplikácie, ktorá riadi zostavu, takže nebude obzvlášť zriedkavé nájsť tento typ definícií ako funkcie bez parametrov a ktoré nevracajú hodnoty, niečo ako void (*accion)();
Ak pracujete s týmto spôsobom reprezentácie údajov, použite struct
dát s premenlivou dĺžkou, bude potrebné dynamicky alokovať pamäť s malloc()
(o new()
, ak sa používajú objekty), ktorý použije množstvo pridelenej pamäte ako parameter a vráti ukazovateľ na začiatok oblasti pamäte, ktorá je rezervovaná. s sizeof()
Na type, ktorý je uložený, vynásobený počtom použitých prvkov, môžete získať množstvo pamäte, ktoré je potrebné. Príklad s a bez použitia je možné vidieť na snímkach obrazovky nižšie. malloc()
; Buďte opatrní s pamäťou, ktorú program používa v prvom prípade, musíte načítať knižnicu, ktorá obsahuje túto funkciu.
Ak operácie na Wifi modul ESP8266 sa bude počas vykonávania programu líšiť, bude potrebné uvoľniť pamäť, ktorá sa nepoužíva free()
(o delete()
, v prípade, že ide o predmety). Hoci je rozumné očakávať, že kompilátor (GCC) zoptimalizuje program, aby sa predišlo deleniu pamäte, výkon určite nebude taký optimálny ako pri práci so staticky pridelenou pamäťou.
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 } } } |
Aj keď v tomto príklade (v oboch implementáciách) to nedáva veľký zmysel, aby sa operácia zovšeobecnila, aby ju bolo možné aplikovať na iné prípady, je potrebné poznamenať, že Pri odosielaní údajov sa vždy opakuje rovnaký protokol: oznámte počet bajtov, ktoré budú odoslané, počkajte na indikátor (>) a odošlite údaje.
Keďže v tomto príklade sa používa iba raz (celá požiadavka je vykonaná v jednom pakete), nezdá sa to byť veľmi užitočné, ale vo všeobecnosti môže byť potrebné vykonať niekoľko odoslaní v tej istej operácii, vrátane prípadov, keď musia prenášať značné množstvo údajov, ktoré musia byť fragmentované, aby nedošlo k preplneniu pamäte ESP8266.
Na implementáciu tohto správania je možné použiť posledné dva prvky spojenia, takže pri každom odoslaní údajov sa údaje naplnia zodpovedajúcimi hodnotami: v prvom prípade počet odoslaných bajtov a v druhom prípade ( časť žiadosti, ktorá sa má odoslať.
Na zopakovanie priradenia a odoslania rôznych prvkov, ktoré sa musia preniesť, je možné uložiť do vektora. Tento nový vektor bude ten, ktorý určí koniec zložitej operácie a nie poslednú operáciu ako doteraz.
1 komentár