Alapvető műveletek az Arduino ESP8266 wifi modulján
Mikor Nyomasztó piacra dobta az első modulokat wifi az integrálttal ESP8266 és firmware amivel AT parancsokkal kezelhetjük, mi felhasználókat érdekelt, hogy összeállításokba integráljuk mikrovezérlők és a problémák a (korábbi) sötétség ismeretére redukálódtak ESP8266 AT parancstábla, takarmányozási igények ill ESP8266 firmware frissítés.
Aztán gyorsan megérkeztek az alternatívák a programozáshoz ESP8266 és modul implementációk wifi nagyon különböző formátumok, amelyek más aggályokat is felvetettek: melyik ESP8266 wifi modult válasszuk a különböző antennák hatótávolságától (beleértve a külsőket is) vagy ezeknek az új moduloknak az összeállításainkba való fizikai integrációjától függően.
Bizonyára mindezen változások miatt nem a legalapvetőbb szempontokra, a legalapvetőbb gazdálkodásra helyezték a hangsúlyt. ESP8266 wifi modul. Habár polaritás.es Használatáról tájékozódhat a ESP8266 és vannak olyan alkalmazások, amelyek általános magyarázattal szolgálnak a ESP8266 wifi modul AT parancsok használatával, különösen a cikkben könyvtárat, hogy HTTP-lekérdezéseket tegyen az Arduino-ból az ESP8266 wifi modullal, az olvasók benyomásai azt sugallják, hogy hasznos lenne néhány alapvető információval kiegészíteni a felhasználókat ESP8266 saját megvalósításuk elvégzésére.
Beszéljétek meg az alapvető műveleteket a ESP8266 és az általános megoldások javaslata több nagyon különböző részből álló célkitűzés; A cikk tartalmának követéséhez a következő tárgymutató szolgálhat útmutatóul:
- Az ESP8266 wifi modul vezérlése a számítógépről a soros porton keresztül
- Frissítse a firmware-t az esptool segítségével
- Megrendelések küldése a modulnak
- Adatok fogadása az ESP8266-ról
- Elemezze a választ úgy, hogy szövegeket keres a tartalomban
- Korlátozza a válasz beérkezésének várakozási idejét
- Több AT-parancs által meghatározott összetett művelet végrehajtása
Az ESP8266 wifi modul vezérlése a számítógépről a soros porton keresztül
Tányérból Arduino és az Ön IDE nyomon követhető a működése a ESP8266 wifi modul, küldje el a ESP8266 AT parancsok és lásd a választ, de sokkal kényelmesebb ezt egy terminál típusú alkalmazással rendelkező számítógépről megtenni.
Attól függően, hogy melyik tábla Arduino használva, csak egy hardveres soros port áll rendelkezésre, ami egy kis kényelmetlenséget okoz a küldésben és a fogadásban. A kommunikációs sebesség megváltoztatása sokkal kényelmesebb a számítógépről és egyes alaplapokról érkező soros kommunikációs alkalmazásokban. Arduino (és bizonyos körülmények között) nem támogatják jól a soros kommunikáció legnagyobb sebességét, különösen az 115200 XNUMX baudot, ami a legújabb verziók alapértelmezett sebessége. firmware.
-Ról Milyen programmal lehet figyelni a ESP8266 a soros port használatával, sok közül lehet választani az igényeknek és preferenciáknak megfelelően; mostanában inkább a klasszikust használom CuteCom (a fenti képernyőképen), mert nagyon kényelmes, hogy megismételjek bizonyos ESP8266 wifi modul AT rendelés projekt tesztelésben.
A soros konzolként működő programokkal kapcsolatban már szerepelt itt néhány ajánlás; Például amikor arról beszélünk PuTTY az UART soros eszközök számítógépről történő vezérléséhez. PuTTYAmellett, hogy kiváló alkalmazás, a legtöbb asztali operációs rendszerhez elérhető. Továbbá, mint PuTTY konzolként használható mind a soros porttal, mind a Internet protokoll család (TCP/IP), beleértve azokat is, amelyeken működnek TLS, általános eszközzé válik, amely bőven megtéríti a konfigurálására és használatához való rászoktatásra fordított (kevés) időt.
A soros kommunikációs szoftverek mellett csatlakoztatni a ESP8266 wifi modul a kikötőbe USB A számítógéphez konverter is szükséges USB sorozathoz TTL. A szoftverekhez hasonlóan itt is több verzió létezik, amelyekből csak a port konvertálására szolgálnak USB soros porton TTL (amely egy eurótól beszerezhető) azokra, amelyek különböző protokollokat emulálnak (pl SPI o I2C).
Csakúgy, mint egy soros konzolként működő program, amely hardveren keresztül kommunikál a számítógéppel USB logikai áramkörrel (nem csak a ESP8266) elterjedt eszköze lesz egy mikrokontrollos alkalmazásfejlesztő munkájában, érdemes minél előbb az eszköztárba kerülni és dolgozni vele ESP8266 wifi modul Kiváló lehetőség egy ilyen megszerzésére.
Az átalakító USB a UART TTL Használható egy olyan áramkör viselkedésének megfigyelésére is, amely a ESP8266, ehhez a monitorozni kívánt kimeneteket gyorsdiódával sorba kötik az átalakító adatbemenetére (RX) (a 1N4148például) és egy ellenállás (például 2K2) egymással párhuzamosan. Egy ilyen beállítás úgy működik, mint egy hardveres soros szippantó.
Bár a fenti képen látható szippantó minden bizonnyal kezdetleges (többek között nincs ütköző) elegendő a szerelvény működésének felügyeletéhez Arduino és ESP8266.
Az előző sémából a szippantót eltávolítva a vázlat, amely bemutatja, hogyan kell csatlakoztatni a ESP8266 wifi modul egy tányérhoz Arduino. Amellett, hogy 3V3-ról táplálja, az integrált reset tűjét és aktiváló tűjét magas szintre kell kötni (engedélyezni). Természetesen az egyik RX lábának csatlakoznia kell a másik TX csatlakozójához.
Az előző diagram egyszerűsítése érdekében egy lemezt ábrázoltunk Arduino 3V3-ról táplálják, és amelynél a soros port feszültségét szintén 3V3-nak kell tekinteni. Ha használ a mikrovezérlő eltérő jelszinttel a soros porton (általában 5 V) lesz szükség, hogy ne sérüljön meg a ESP8266, használj szintváltó mint az alábbi diagramokon. Ez az áramkör gyakran megtalálható számos kereskedelmi forgalomban kapható modul-megvalósításban.
Frissítse az ESP8266 firmware-t
az ESP8266 AT parancsok, a lezárása, a modul alapértelmezett sebessége... függ a verziótól ESP8266 firmware. A legjobb, ha minden modulban ugyanazt a verziót használja, és ha lehetséges, akkor a legújabb verziót.
Sajnos a legtöbb a ESP8266 wifi modul modellek Csak 4 Mbit-esek, így a legújabb verzió nem telepíthető rájuk. A firmware legújabb (hivatalos) verziója, amelyre telepíthető ESP8266 wifi modulok 4 Mbit-tel (a legtöbb) 0.9.4, amely tartalmazza a 0.2-es verziót ESP8266 AT parancsok.
Összefoglalva, a firmware frissítéséhez szüksége van:
-
Töltse le a megfelelő firmware verziót. A A 4 Mbit memóriával rendelkező modul legújabb (hivatalos) verziója a github Espressif mappájában található. Ban,-ben Espressif weboldal Letöltheti a firmware legújabb verzióját, de nagyon fontos ellenőrizni, hogy a modul, amelyre telepítve van, elegendő memóriával rendelkezik.
-
Töltse le a firmware-telepítő eszköz legújabb verzióját. A kedvencem esptool ami be van írva Piton, tehát minden platformon működik. Amellett, hogy letölthető, azzal is telepíthető
pip install esptool
(opip2
opython -m pip
…). Természetesen, Nyomasztó Saját eszközt is kínál, de jelenleg csak Windowshoz érhető el. -
Készítse elő a letöltött fájlokat; csomagolja ki őket egy hozzáférhető mappába, és ha szükséges, tegye futtathatóvá az eszközt esptool, az én esetemben, mivel GNU / Linux, A
chmod +x esptool
-
Csatlakoztassa a modult a számítógéphez konverter segítségével USB UART TTL ami 3V3-on működik vagy használjon szintátalakítót, ha az 5 V-on működik. A tápon kívül a konverter TX-et is csatlakoztatnia kell az RX-hez. USB UART TTL, RX to TX, GPIO0 alacsony szinten (GND) és talán GPIO2 magas szinten (teszteimben mind alacsony szinten bekötve, mind leválasztva működött). Ha a modul GPIO15 csatlakozása szabad (mint az ESP-12 esetén), akkor alacsony szintre kell csatlakoztatni. A RESET, amely működés közben általában magas szinten van, csatlakoztatatlanul hagyható, vagy egy ellenállás segítségével magas szintre csatlakoztatható (például 10K), mivel a rögzítés megkezdése előtt szükség lehet az eszköz visszaállítására annak csatlakoztatásával. alacsony szintre.
A modul bekapcsolásával frissíthető lesz, de Ha kapcsolódási hiba jelenik meg, akkor azt vissza kell állítani a RESET csatlakoztatása alacsony szinten egy pillanatra, majd bekapcsolva hagyja (csatlakozás nélkül) a frissítési folyamathoz.
A modul rendelkezik fél amper fogyasztási csúcsok (egyes felhasználók szerint 600 mA-ig), ezért fontos, hogy olyan tápegységet használjunk, amely képes ezt a fogyasztást támogatni, különösen a firmware frissítéséhez. -
Futtassa az eszközt a firmware frissítéséhez. Az én esetemben a 3. lépésben ugyanabba a mappába mentettem az eszközt és a firmware-dokumentumokat, így a konzolról futok:
cd ~/Datos/firmwareESP8266
(váltás az eszközt és a firmware-t tartalmazó mappára)./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
beállítja a sebességét ESP8266 (115200 baud esetemben) és--port
a soros port, amelyhez csatlakozik (esetemben emulált, az első USB). A firmware-t alkotó különböző dokumentumok hátra vannakwrite_flash
előtt a cím szerepel, a user1.bin dokumentummal, amely tartalmazza a frissítés hasznos adatát.
Parancsok küldése az ESP8266 wifi modulnak
Ellenőrizni a ESP8266 számítógépről kell majd kezdenünk konfigurálja az alkalmazást amelyhez elég lesz ① kiválasztani azt a portot, amelyhez az átalakító csatlakozik USB UART TTL, Valami hasonló /dev/USB0
GNU/Linux és hasonló vagy valami hasonló COM6
Windows rendszerben ② válassza ki azt a sebességet, amellyel a ESP8266, valószínűleg 115200 baud, ③ állítson be 8 adatbitet plusz egy stopbitet, paritás vagy kézfogás nélkül, és ④ állítsa be a sor végét, a firmware, szinte mindig CR+LF.
Az alkalmazás konfigurálása (vagy adott esetben tárolása és kiválasztása) után az nyissa meg a kapcsolatot ("Open device" és "Open" a fenti példák képernyőképein a következővel: CuteCom y PuTTY), és megkezdheti a rendelések küldését a címre ESP8266.
Amint az a ESP8266 AT parancstábla, az aktiválás, deaktiválás, érték beállításának és hivatkozásának formátuma meglehetősen kiszámítható, de általában nem könnyű mindegyiket megjegyezni, és valószínűleg kéznél kell lennie, hogy hivatkozzon rá.
Az út küld AT parancsokat al ESP8266 wifi modul -tól Arduino Nagyon egyszerű: ① konfigurálja a kommunikációt Serial.begin(115200);
(vagy Serial1, Serial2… több hardveres soros porttal rendelkező kártyákon), és ② küldje el a parancsokat a formátum használatával 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()
{
}
|
A fenti példa bemutatja, hogyan kell elküldeni a ESP8266 wifi modul AT rendelés -tól Arduino. Ebben az esetben illusztrálva van AT+CWJAP
, amely hozzáférési ponthoz való csatlakozásra szolgál. Ez a parancs argumentumként a hozzáférési pont azonosítóját (SSID) és a kulcs, mindkettő idézőjelben, így objektummá válnak Srtring
és idézőjelek közé tegye őket az escape kód segítségével (\"
). A megrendelés befejezéséhez használja \r\n
ami megfelel annak CR
y LF
.
Ne feledje, hogy a soros port nem mindig azonosítható Serial
(bizonyos lemezeken lehet Serial1
, Serial2
…) a használt portobjektum a makróhoz való hozzárendelésével lett meghatározva PUERTO_SERIE
. A használt kártya típusának felismerése egy kis intelligenciát adhat a soros port kiválasztásához; Később áttekintjük, hogyan tudhatja meg a típusát Arduino. A többi definíció a szokásos, amely lehetővé teszi az állandó értékek "megnevezését", hogy elkerülje az ismétlődést (és a hibákat), és megkönnyítse a megváltoztatását.
A fenti példa állítólag összekapcsolja a ESP8266 wifi modul a jelzett hozzáférési ponthoz, de már korábban csatlakozott? Működött a kapcsolat? Ahhoz, hogy ezt tudjuk, meg kell "hallgatnunk", hogy mi a ESP8266
Adatok fogadása az ESP8266 wifi modulról
A fent leírt adatszippantót a számítógéphez csatlakoztatva láthatja, hogy mit Arduino címre küldött ESP8266 és a válasza. től olvasni Arduino és feldolgozza a benne található információkat, amelyekkel észlelni kell Serial.available()
ha bármilyen adat érkezett, és ha igen, töltse be Serial.read()
. A következő példa bemutatja, hogyan kell kiolvasni a választ AT+CWJAP?
, amely jelzi, ha van kapcsolat bármely hozzáférési ponttal.
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();
}
}
|
Mint egy tányéron Arduino Uno (és másoknál) a soros monitor megnyitása alaphelyzetbe állítja a programot, a soros konzolon lehet látni Arduino az Ön által elküldött információkat ESP8266 ahogy az alábbi kép képernyőképe is mutatja.
Elemezze az ESP8266 wifi modul által küldött választ
Azt már láttuk, hogyan kell elolvasni az elért információkat Arduino a ESP8266. Az a probléma, amivel meg kell küzdened, hogy nem tudod, mikor kezd megérkezni, mennyi idő alatt érkezik meg, milyen hosszú lesz... és nem túl hatékony megvárni a választ a ESP8266 anélkül fogadják, hogy a mikrovezérlő addig egyéb feladatokat is ellátni.
Ennek a körülménynek a kezelésének egyszerű módja az iterálja a kapott adatokat, konkrét válaszokat keresve amelyekkel például aktiválhatók az indikátorok (jelzők vagy logikai változók), amelyek meghatározzák, hogy folytassuk-e a keresést a kapott szövegben, és milyen műveleteket kell végrehajtani a szövegből érkező információk alapján. ESP8266. Míg a válasz megérkezik mikrovezérlő más feladatoknak szentelheti magátpéldául az érzékelőktől származó adatok fogadása és azok feldolgozása.
Keressen szöveget az ESP8266-tól kapott információban
A következőből származó szövegben való kereséshez ESP8266 tudsz hasonlítsa össze az egyes kapott leveleket azzal, amelyik megfelel a keresett üzenetnek. Szükséges lesz egy számláló (vagy mutató) használata, amely az összehasonlítandó betűre mutat; Ha a karakter, amely a ESP8266 megegyezik az üzenetben vizsgálttal, a számláló előrelép, ha eltér, akkor inicializálódik.
Ha tudni szeretné, hogy elérkezett a vég, a keresett üzenet következő karakterét veszi figyelembe, amely nulla (\0
) vagy az üzenet hosszát eltárolják, hogy a számlálóval való összehasonlítás révén megtudja, hogy az összehasonlítás befejeződött-e, és ezért a ESP8266 wifi modul elküldte a keresett üzenetet.
A következő példa a parancsot használja AT+CWLAP
amely visszaadja a hozzáférési pontok listáját, és ezeken belül a "wifi polaridad.es" nevűt keresi. Bár úgy döntöttünk, hogy ellenőrizzük, hogy az utolsó karakter nulla-e, mivel a ütköző Csak a keresett szöveget tárolja és annak hossza ismert, azt is ellenőrizni lehetne, hogy ennyi helyes levél érkezett-e. Val,-vel LED a 2. érintkezőhöz csatlakoztatva a rendszer a várt szöveget megtalálta.
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
}
}
}
}
|
Az előző példa kódjában egy módot is láthatunk válassza ki a soros portot a kártya típusától függően Arduino használt. Ez a példa feltételezi, hogy a projekthez három típusú táblája van: egy Arduino Uno, az egyik Arduino Mega 2560 és a arduino leonardo. Ha együtt dolgozik a Arduino Uno azt fogják használni Serial
és egyébként Serial1
.
Ha tányérral dolgozik arduino leonardo Ugyanezzel a módszerrel leállíthatja a programot, és megvárhatja a konzolt (a következőhöz társított soros portot). Serial
) elérhető.
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
|
Keressen különböző szövegeket az ESP8266 válaszban
Az előző példában szereplő kód arra szolgál, hogy szöveget keressen az általa küldött információkban ESP8266 de a válasz a művelettől függően eltérő információkat tartalmazhat. Tegyük fel, hogy a következő példában egy egyszerű esettel kezdjük, hogy a szöveg által küldött MCU ESP8266 es OK
amikor a műveletet helyesen hajtják végre és ERROR
Egyébként, mint a rendelésnél AT+CWJAP?
, amely annak ellenőrzésére szolgál, hogy a ESP8266 wifi modul már csatlakozik egy hozzáférési ponthoz.
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
}
}
}
}
}
|
Ugyanennek a metódusnak ez az új megvalósítása, amely több lehetséges üzenettel egyezést keres, lehetővé teszi a különböző műveletek közötti választást attól függően, hogy milyen választ kapott a ESP8266, egyszerűen kapcsolja be a LED megfelelő.
Korlátozza a válasz megérkezéséhez szükséges időt
Ez idáig nem utaltak egy releváns kérdésre: a maximális várakozási idő (időtúllépés), mielőtt a művelet sikertelennek tekintendő. Ha bármilyen okból a kapcsolat a ESP8266 wifi modul, a hozzáférési ponttal rendelkező modul, az internettel rendelkező hozzáférési pont vagy például egy feltételezett szerver nem érhető el, előfordulhat, hogy a program egy ponton korlátlan ideig várakozik, így az ilyen körülményekre választ kell adni. A maximális várakozási idő a teljes alkalmazásra konfigurálható, általában ilyenkor "nagyvonalúbb" lesz, vagy minden művelethez egyedi várakozási időket lehet programozni.
Annak ellenőrzésére, hogy (legalább) egy bizonyos időintervallum eltelt-e A számla indításának pillanatának "idejét" rendszerint kivonják az aktuális "időből", és ellenőrizzük, hogy a különbség nagyobb-e a kívánt korlátnál. Ennek az "időnek" nem kell valós idejűnek lennie, általában az azóta eltelt intervallumnak felel meg MCU kezdje el számolni az időt; Ez nem befolyásolja a programot, mivel az eltelt idő érdekes és nem az abszolút idő.
Általában annak ellenőrzésére, hogy egy bizonyos időköz eltelt-e, a következő típusú kifejezést használjuk:
1
|
(unsigned long)(millis()–milisegundos_al_empezar)>intervalo_de_tiempo
|
változó milisegundos_al_empezar
értékét tartalmazza millis()
a végrehajtás egy bizonyos pillanata, amelytől kezdve időzítik, így nem szokatlan, hogy a neve a "kronométer" szóra utal. A változó intervalo_de_tiempo
az ezredmásodpercek maximális számát tartalmazza, amely az előző kifejezést igazzá teszi, azaz az időtúllépést jelenti; Ez általában egy konstans (vagy makró), és az előző esethez hasonlóan gyakran szerepel a nevében az "IDŐTÚZ" szó. Ha nagyon rövid időközökkel dolgozik, használhatja micros()
helyett millis()
(mikroszekundum ezredmásodperc helyett), bár sokkal kevésbé gyakori és sokkal kevésbé pontos.
1
|
(unsigned long)(millis()–cronometro)>TIMEOUT
|
Egy hosszú egész szám Arduino (unsigned long
) 4 bájtot (32 bitet) foglal el, így az általa képviselt legnagyobb érték a 4294967295 (2 a 32 mínusz egy hatványához, mert nulláról indul). egy tányéron Arduino Folyamatos futás közben az ezredmásodperces számláló körülbelül 50 naponta nullázódik (visszaáll nullára). Előjel nélküli adattípusokkal történő kivonáskor ugyanaz a viselkedés reprodukálódik (a számláló megfordítása), így az időtúllépés korlátlanul szabályozható.
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;
}
}
}
|
A fenti kód a az időtúllépési korlátozás nagyon alapvető megvalósítása beépítve az azt megelőző példához képest jelölt sorokat. Mivel az időtúllépés ellenőrzésére a től érkező adatok feldolgozása után kerül sor ESP8266 wifi modul, a művelet akkor is sikeresnek tekinthető, ha a fogadás tovább tart, mint a kiszabott várakozási idő.
Több AT-parancs által meghatározott összetett művelet végrehajtása
Példahivatkozás az alkalmazás céljára, amely kihasználja a ESP8266 wifi modul, tegyük fel információkat tárolnak egy webszolgáltatáson keresztül elérhető adatbázisban hogy nyomon kövesse a hőmérsékletet. A következő kód bizonyos időközönként beolvassa az analóg bemenetre csatlakoztatott szenzort, kiszámítja az átlagértéket és hosszabb időintervallum után elküldi a webszervernek (stílus Tárgyak internete) a kérelem HTTP (POZDÁLÁS, SZEREZÉS…).
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”);
}
}
|
Ebben a hőmérséklet-rögzítési példában egy webszerverhez ötpercenként hozzáférnek. Bár a rendelkezésre állás nem kimondottan magas, várható, hogy a javaslat működni fog, de ha nagyobb felvételi gyakoriságra lenne szükség, akkor más forrásokat kellene megvalósítani, pl. adatpuffer küldésre vár, hogy küldjön néhányat, amikor a szerver részt vehet, és tárolja azokat, amikor nem elérhető. Ha az adatok rögzítésének gyakorisága még nagyobb lenne, más típusú protokollokat kellene javasolni a protokoll alternatívájaként. HTTP vagy akár cserélni TCP által UDP hogy az adatok nagy részét a szükséges sebességgel el tudja küldeni még néhány elvesztése árán is.
A hőmérséklet küldésére vonatkozó feladatot a következő műveletek alkotják:
- Állítsa vissza a wifi modult
- Kapcsolat bontása az aktuális hozzáférési ponttal (ha létezik alapértelmezett kapcsolat)
- Állítsa be a beállításokat. A példa esetében feltételezzük, hogy konfigurálni kell a csatlakozási módot (egyszerű) és a Wi-Fi kommunikációban betöltött szerepet (állomás).
- Csatlakozás hozzáférési ponthoz
- Ellenőrizze, hogy a kapcsolat megfelelő-e (valójában ez a belépési pont) Ha nincs kapcsolat, kezdje elölről a folyamatot
- Csatlakozás a szerverhez
- Küldje el a kérést HTTP a tárolandó adatokkal
A műveletek sorrendjének nem kell pontosan ilyennek lennie (bár a művelet igen), és minden lépéshez több szükséges is lehet ESP8266 AT parancsokPéldául a fent felsorolt konfigurációhoz kettőre van szükség: AT+CIPMUX=0
y AT+CWMODE=1
.
Adatstruktúra, amely az ESP8266 műveleteit reprezentálja
Az előző példákban, bár nagyon alapvető módon, már javasoltak egy általános megoldást a problémára: használjunk olyan adatstruktúrát, amely tárolja a lehetséges válaszokat és az egyes esetekben megteendő intézkedéseket; küldjön egy műveletet, várja meg a választ, és folytassa a válasz jelentésének megfelelően. Mivel minden összetett művelethez többre lesz szükség ESP8266 AT parancsok, az adatszerkezetnek össze kell kapcsolnia egy műveletet más, későbbi vagy előző művelettel, amelyet minden esetben az adatkezelő válaszától függően kell végrehajtani. ESP8266.
Az előző példákban egy üzenetet kerestek a válaszában ESP8266 és sikerként vagy hibaként értelmezték. Az összes beérkezett szöveg átvétele (és elemzése) mellett, Az általános minimum elérése érdekében tanácsos az üzenet kitöltésére is odafigyelni vagy más szóval az elérhetőségére a ESP8266 wifi modul új rendelések fogadására. Ily módon a változás olyan állapotba, amelyet például "wifi elérhető"-nek hívhatunk, a hozzáférési pont nevének fogadása és a szöveg fogadása lehet. ERROR
vagy a szöveget OK
azt jelentené, hogy a ESP8266 befejezte a választ, és most már elküldheti a következőt AT parancs az ESP8266-ra.
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;
|
A fenti kód egy vektort (operacion
) a teljes feladatot alkotó egymást követő műveletek szövegének tárolására. Kétdimenziós tömböt használnak (mensaje
) a három elemzett válasszal. A fentiek szerint a helyes vagy helytelen választ jelentő üzenet mellett meg kell keresni azokat az üzeneteket, amelyek a válasz végét jelentik. Nem minden műveletnek lesz ugyanannyi lehetséges válasza; Ha kevesebb a válasz, akkor üres üzenet használható, amely a lehető legkevesebb ciklust veszi fel az elemzésben (még így sem a legoptimálisabb módszer). Logikusan szükséges, hogy a keresett válaszok minimális száma (a példában három) tartalmazza az összes működési lehetőséget, még akkor is, ha nem mindegyik lehetséges.
Ha a lehetséges válaszokról beszélünk, az már látható, hogy ez a példa nem túl hasznos tetszőleges formátumú adatok fogadásához egy ESP8266 wifi modul, de a helyzet az, hogy a használattal összefüggésben mikrovezérlők nem szokványos; A legáltalánosabb az általuk csatlakoztatott érzékelők által gyűjtött adatok elküldése és/vagy információk fogadása arról, hogy mit kell tenni az általa vezérelt működtetőkkel. Nagyon értékes információ, amely nagyon jól megjósolható.
Az előző adatszerkezetben, ahogyan az elemzett lehetséges válaszok kifejezésére, egy kétdimenziós mátrixot is használnak az egyes esetekben végrehajtandó művelet meghatározására (siguiente_operacion
). Pontosabban, háromféle üzenetre válaszoltunk: ① tetszőleges szöveg (LITERAL
) annak ellenőrzésére, hogy van-e kapcsolat a Wi-Fi hozzáférési ponttal és a szerverrel, ② egy szöveget a folyamat hibáinak észlelésére (FALLO
) és ③ egy szöveg, amely jelzi, hogy a művelet sikeresen befejeződött (ACIERTO
).
Végül van még két vektor a maximális várakozási idő beállítására a feladás előtt (timeout
) és adja meg (configuracion
) ha a művelet válasz megvárása nélkül fejeződik be (ESPERAR_RESPUESTA
) és a kommunikáció végét jelző üzenetek. Ez az utolsó vektor, hogy példát mutasson a memória mentésére, egy konfigurációs bájt bitjeivel működik a különböző állapotok jelzésére.
Az első ESP8266 AT parancsok Az adatszerkezetben mindig választ várnak, amely lehet siker- vagy hibaüzenet. Hiba esetén a modul újraindul és újraindul, és ha az üzenet azt jelzi, hogy a művelet helyes, akkor továbblép a következőre.
Amikor csatlakozik a szerverhez, a minta megváltozik. Ebben az esetben szükséges ① elküldeni a továbbítandó adatcsomag hosszát és ② összeállítani a kérést HTTP rögzített szöveggel plusz a (hőmérséklet) értékkel, amelyet a szerveren tárolni küldenek. Ezen adatok elkészítése minden szállítmánynál megtörténik, és két részre kell osztani (közölni kell a hosszt) vagy háromra (kérelem elküldése) HTTP) On ESP8266 AT rendelés. Csak az utolsó rész vár válaszra, amelyre a művelet fel van osztva.
Ebben az esetben problémamentesen fog működni (esetleg a modul foglaltságára figyelmeztetve), de ha nagyobb az adathossz, akkor kisebb darabokra kell osztani az adatblokkokat, és akár egy várakozást is kell megvalósítani, mivel a hőmérséklet leolvasással történik, hogy a modulnak legyen ideje az adatok kitöltésére ütköző.
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();
|
Más, korábban már ismertetett makróval együtt a fenti példakód megmutatja, hogyan definiálhatók a különböző állapotok, amelyekkel megadható, hogy várjon-e válaszra, és adott esetben milyen üzenet jelzi, hogy a válasz befejeződött.
Mivel a kód különböző pontjain egy művelet kerül elküldésre (amikor van az átlaghőmérséklet küldésének ideje, ha egy művelet várakozási idejét túllépjük, amikor az aktuális művelet sikeresen befejeződött...), de hogyan kell ezt csinálni globálisan létrehozott, makróként határozták meg ENVIAR_OPERACION
amely a szállítással kapcsolatos lépéseket csoportosítja.
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();
|
A következő a példa fő programjának kódja. A legkülsősebb feladat az, aki a hőmérséklet mintavételéért felelős, hogy kiszámítsa az átlagot, és meghatározott időnként elküldi a szerverre a ESP8266 wifi modul. Az egyes műveletek elküldése után a válasz elemzi, hogy melyik legyen a következő, vagy hogy az információküldési feladat befejeződött-e.
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
}
}
}
|
Logikusan több optimalizálási művelet is végrehajtható az előző kódon, de ez egy példa, hogy megértsük, hogyan a ESP8266 Általánosságban csak néhány szempontra érdemes koncentrálni, az első az adatstruktúra. Úgy tűnik, ez a logikus használjon programozási nyelv adatszerkezetét (struct
) a feldolgozott információ képviseletére: az ESP8266 AT parancsok és az elemzett üzeneteket.
Használj egy szerkezetet (struct
) az adatok tárolása a példatömbök helyett (azok alapján) triviális, és bár elegánsabb kódot eredményezhet, az eredmény javulását nem jelenti. Az igazi alternatívát a használata jelenti struct
végrehajtása az alábbiak szerint, változó hosszúságú struktúrákban, amelyek „belső” adatokat tartalmaznak amelyekre hivatkoznak. Ily módon például nem szükséges, hogy egy műveletnek fix számú válasza legyen az elemzéshez.
Ez a megközelítés azt sugallja, hogy ez a legjobb módja a megoldás megvalósításának, de a hátránya, hogy szükség lenne rá dinamikus memóriafoglalás használata, kockázatos gyakorlat a mikrovezérlő amihez gondosan meg kell mérni, hogy mennyi memória lesz felhasználva futás közben, mivel a fordító aligha tud minket figyelmeztetni erre, és van bizonyos lehetőség a memória (vagy a verem) kimerítésére, ami végzetes következményekkel járhat a program végrehajtására nézve.
A kód optimalizálása során érdemes megjegyezni, hogy egy ilyen típusú programban, amely nagy mennyiségű szöveget használ, memóriaterületet takaríthat meg SRAM szöveges karakterláncok tárolása a programmemóriában (vaku) a makróval F()
. A következő képernyőképeken a különböző program- és dinamikus memóriaeloszlás látható normál szöveghasználattal és makró használatával F()
.
Tekintettel azokra a műveletekre, amelyeket a től érkező információk szerint hajtanak végre ESP8266 wifi modul, alternatívájaként a kódból érkező üzenet ellenőrzése és az egyik vagy másik végrehajtása a kapott adatok szerint tárolható ebben az adatstruktúrában állapotjelzők helyett az egyes feladatokat végrehajtó funkciókra mutatnak (jelzők), amelyek egy bizonyos állapotra figyelmeztetnek, hogy az alkalmazás felelős például a fő hurkon belüli kezelésért.
Az alábbiakban bemutatunk egy példát a kérések adatainak tárolására szolgáló struktúrákra ESP8266 (az adattípus operacion_esp8266
) és válaszaik (az adattípus 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;
|
A műveletet reprezentáló struktúraként (a ESP8266 wifi modul) utal arra a struktúrára, amellyel a válaszokat meghatározzák, és a válaszok szerkezetére a műveletek szerkezetére, előbb mindkettőt deklarálni kell, az új adattípus meghatározásával, majd a tartalmának meghatározásával.
Az előző példa úgy véli, hogy az azt tartalmazó program az a állapotjelző, amelynek meg kell felelnie egy olyan kódból elérhető változónak, amely az említett érték által jelzett műveletek végrehajtásáért felelős. Ha a válaszában ESP8266 Egy bizonyos szöveg elemzésekor az állapot azt az értéket veszi fel, amely a megfelelő válasz szerkezetét jelzi.
Amint korábban említettük, egy másik alternatíva az állapotjelző helyettesítésére vagy kiegészítésére függvényt tárolunk a referenciastruktúrában (mutató), amelyet akkor hívnak meg, ha bizonyos szöveggel találkozik a válaszában ESP8266 wifi modul.
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;
|
Az előző példában hozzá lett adva ahhoz az adatstruktúrához, amely a következőtől származó válasz feldolgozására szolgál ESP8266 wifi modul típusú adatot visszaadó (feltételezett) függvényre mutató mutató float
(lehet egy analóg leolvasás súlyozott értéke), és amelyhez két bájt van megadva argumentumként (kettő unsigned char
amely lehet az a tű, amelyről az analóg bemenetet olvassák, és az, amely aktiválja egy hipotetikus integrált ENABLE-t).
fejlesztés alatt MCU, ellentétben azzal, ami a nagyobb rendszerek fejlesztési stílusában előfordul, nem olyan ritka a globális változók használata az összeállítást vezérlő alkalmazás (globális) viselkedésének meghatározásakor, így nem lesz különösebben ritka az ilyen típusú definíciók megjelenése. mint paraméterek nélküli függvények, amelyek nem adnak vissza értékeket, ilyesmi void (*accion)();
Ha az adatok ilyen ábrázolási módjával dolgozik, használja struct
változó hosszúságú adatok esetén dinamikusan kell lefoglalni a memóriát malloc()
(o new()
, ha objektumokat használ), amely a lefoglalt memória mennyiségét használja paraméterként, és egy mutatót ad vissza a lefoglalt memóriaterület elejére. Val vel sizeof()
A tárolt típuson, megszorozva a felhasznált elemek számával, megkaphatja a szükséges memóriamennyiséget. Az alábbi képernyőképeken látható egy példa a használatára és anélkül. malloc()
; Első esetben legyen óvatos a program által használt memóriával, be kell tölteni azt a könyvtárat, amely ezt a funkciót tartalmazza.
Ha a műveletek a ESP8266 wifi modul a program végrehajtása során változni fog, fel kell szabadítani a nem használt memóriát free()
(o delete()
, abban az esetben, ha tárgyak). Bár joggal feltételezhető, hogy a fordító (GCC) optimalizálja a programot, hogy elkerülje a memória particionálását, a teljesítmény biztosan nem lesz olyan optimális, mint a statikusan lefoglalt memóriával való munkavégzés.
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
}
}
}
|
Bár ebben a példában (mindkét megvalósításban) nincs sok értelme, a művelet általánosítása érdekében, hogy más esetekben is alkalmazni lehessen, meg kell jegyezni, hogy Az adatküldés mindig ugyanazt a protokollt ismétli: értesítse a küldendő bájtok számát, várja meg a jelzőt (>) és küldje el az adatokat.
Mivel ebben a példában csak egyszer használjuk (a teljes kérés egy csomagban történik), nem tűnik túl hasznosnak, de általában szükség lehet több küldésre ugyanazon művelet során, beleértve azokat az eseteket is, amikor jelentős mennyiségű adatot kell továbbítani, amelyet töredezettnek kell lennie, hogy elkerülje a memória túlcsordulását ESP8266.
Ennek a viselkedésnek a megvalósításához a kapcsolat utolsó két eleme használható úgy, hogy minden adatküldéskor az adatok a megfelelő értékekkel töltődnek fel: az első esetben az elküldött bájtok száma, a második esetben pedig a ( része) kérés.át kell továbbítani.
A hozzárendelés és az elküldés megismétléséhez a különböző továbbítandó elemek vektorban tárolhatók. Ez az új vektor lesz az, amely meghatározza az összetett művelet végét, és nem az utolsó művelet, mint eddig.
1 megjegyzés