Pagrindinės operacijos su ESP8266 wifi moduliu iš Arduino
Kai Espresas rinkoje pasirodė pirmieji moduliai wiFi su integruotu ESP8266 ir mikroprograma su kuriuo jį tvarkyti naudojant AT komandas, o mes, vartotojus, domėjomės jos integravimu į rinkinius mikrovaldikliai ir problemos buvo sumažintos iki (buvusios) tamsos pažinimo ESP8266 AT komandų lentelė, maitinimo poreikius arba ESP8266 programinės įrangos atnaujinimas.
Tada greitai atsirado alternatyvų programuoti ESP8266 ir modulių diegimai wiFi labai skirtingų formatų, kurie kėlė kitų rūpesčių: kurį ESP8266 wifi modulį pasirinkti priklausomai nuo skirtingų antenų (įskaitant išorines) diapazono arba fizinio šių naujų modulių integravimo į mūsų mazgus.
Be abejo, dėl visų šių pokyčių nebuvo akcentuojami patys pagrindiniai aspektai, elementariausias ESP8266 wifi modulis. Nors poliškumas.es Galite rasti informacijos apie naudojimą ESP8266 ir yra keletas programų, skirtų bendrai paaiškinti, kaip veikia ESP8266 wifi modulis naudojant AT komandas, ypač straipsnyje apie biblioteką, kad pateiktumėte HTTP užklausas iš Arduino su ESP8266 wifi moduliu, skaitytojų įspūdžiai rodo, kad būtų naudinga pridėti šiek tiek daugiau pagrindinės informacijos, kuri padėtų naudotojams ESP8266 įgyvendinti savo įgyvendinimus.
Aptarkite pagrindines darbo su ESP8266 bendrų sprendimų siūlymas yra kelių labai skirtingų dalių tikslas; Kad būtų lengviau sekti straipsnio turinį, ši rodyklė gali būti kaip vadovas:
- Valdykite ESP8266 wifi modulį iš kompiuterio per nuoseklųjį prievadą
- Atnaujinkite programinę-aparatinę įrangą naudodami esptool
- Siųsti užsakymus į modulį
- Gaukite duomenis iš ESP8266
- Išanalizuokite atsakymą, ieškodami tekstų turinyje
- Apribokite atsakymo laukimo laiką
- Vykdykite sudėtingą operaciją, apibrėžtą keliomis AT komandomis
Valdykite ESP8266 wifi modulį iš kompiuterio per nuoseklųjį prievadą
Iš lėkštės Arduino ir naudojant savo IDE galima stebėti, kaip veikia a ESP8266 wifi modulis, atsiųskite ESP8266 AT komandos ir pamatyk atsakymą, bet daug patogiau tai padaryti iš kompiuterio su terminalo tipo programa.
Priklausomai nuo to, kokia lenta Arduino naudojamas, gali būti prieinamas tik vienas aparatinės įrangos nuoseklusis prievadas, o tai šiek tiek apsunkina siuntimą ir gavimą. Ryšio spartos keitimas yra daug patogesnis nuosekliojo ryšio programoje iš kompiuterio ir kai kurių pagrindinių plokščių. Arduino (ir tam tikromis aplinkybėmis) nepalaiko didesnio nuosekliojo ryšio greičio, ypač 115200 XNUMX bodų, kuris yra numatytasis naujausių versijų greitis. mikroprograma.
Apie Kokią programą naudoti norint stebėti ESP8266 naudojant nuoseklųjį prievadą, galima rinktis iš daugybės pagal poreikius ir pageidavimus; Pastaruoju metu daugiau naudoju klasiką CuteCom (tas, kuris pateiktas aukščiau esančioje ekrano kopijoje), nes man labai patogu pakartoti tam tikrus ESP8266 wifi modulio AT užsakymai projekto testavimo metu.
Kai kurios rekomendacijos čia jau pateiktos programoms, kurios veikia kaip serijinė konsolė; Pavyzdžiui, kai kalbame apie PuTTY, skirtas valdyti UART serijinius įrenginius iš kompiuterio. PuTTYBe to, kad ji yra puiki programa, ji yra prieinama daugeliui stalinių kompiuterių operacinių sistemų. Be to, kaip PuTTY gali būti naudojamas kaip konsolė su nuosekliuoju prievadu ir interneto protokolų šeima (TCP/IP), įskaitant tuos, kurie veikia TLS, tampa įprastu įrankiu, kuris daugiau nei atperka už (mažą) laiką, sugaištą jo konfigūravimui ir pripratimui prie jo naudojimo.
Be serijinio ryšio programinės įrangos, prijungti ESP8266 wifi modulis iki uosto USB Kompiuteriui taip pat reikalingas keitiklis USB į serialus TTL. Kaip ir programinės įrangos atveju, yra keletas versijų, iš kurių jos naudojamos tik prievadui konvertuoti USB nuosekliajame prievade TTL (kuriuos galima gauti nuo vieno euro) į tuos, kurie gali emuliuoti skirtingus protokolus (pvz., SPI o I2C).
Kaip ir programa, kuri veikia kaip nuoseklioji konsolė, aparatinė įranga, per kurią galima susisiekti su kompiuteriu USB su logine grandine (ne tik ESP8266) bus įprastas įrankis mikrovaldomų programų kūrėjo darbe, verta kuo greičiau turėti įrankių dėžėje ir dirbti su juo ESP8266 wifi modulis Tai puiki galimybė jį gauti.
Keitiklis USB a UART TTL Jis taip pat gali būti naudojamas stebėti grandinės, kuri naudoja ESP8266Norėdami tai padaryti, išėjimai, kuriuos norite stebėti, nuosekliai prijungiami prie keitiklio duomenų įvesties (RX) su greituoju diodu ( 1N4148, pavyzdžiui) ir rezistorius (pavyzdžiui, 2K2) lygiagrečiai vienas kitam. Tokia sąranka veikia kaip aparatinės įrangos serijinis snifferis.
Nors aukščiau esančiame paveikslėlyje esantis uostiklis tikrai yra elementarus (be kita ko, jis neturi buferis) pakanka, kad būtų galima stebėti agregato veikimą Arduino ir ESP8266.
Pašalinus uostiklį iš ankstesnės schemos, schema, rodanti, kaip prijungti a ESP8266 wifi modulis į lėkštę Arduino. Be maitinimo 3V3, atstatymo kaištis ir integruoto įjungimo kaištis turi būti prijungti prie aukšto lygio (įjungti). Žinoma, vieno RX kaištis turi jungtis prie kito TX.
Siekiant supaprastinti ankstesnę diagramą, buvo pavaizduota plokštė Arduino maitinamas iš 3V3 ir kurių nuosekliojo prievado įtampa taip pat laikoma 3V3. Jei naudojate a mikrovaldiklis bus reikalingas kitoks signalo lygis nuosekliajame prievade (paprastai 5 V), kad nepažeistumėte ESP8266, naudoti lygio keitiklis kaip ir toliau pateiktose diagramose. Ši grandinė dažnai randama daugelyje komercinių, paruoštų modulių.
Atnaujinkite ESP8266 programinę įrangą
The ESP8266 AT komandos, jo nutraukimas, numatytasis modulio greitis... priklauso nuo versijos ESP8266 programinė įranga. Geriausia užtikrinti, kad visuose moduliuose būtų ta pati versija ir, jei įmanoma, naujausia versija.
Deja, dauguma ESP8266 wifi modulių modeliai Jie turi tik 4 Mbit, todėl naujausios versijos juose įdiegti negalima. Naujausia (oficiali) programinės įrangos versija, kurią galima įdiegti ESP8266 wifi moduliai su 4 Mbit (dauguma) yra 0.9.4, įskaitant 0.2 versiją ESP8266 AT komandos.
Apibendrinant, norint atnaujinti programinę-aparatinę įrangą, jums reikia:
-
Atsisiųskite atitinkamą programinės įrangos versiją. naujausia (oficiali) versija moduliui su 4 Mbit atmintimi, rasta espressif aplanke github. Viduje konors Espressif svetainė Galite atsisiųsti naujausią programinės aparatinės įrangos versiją, tačiau labai svarbu patikrinti, ar modulyje, kuriame ji įdiegta, yra pakankamai atminties.
-
Atsisiųskite naujausią programinės įrangos diegimo įrankio versiją. Mano mėgstamiausia yra esptool kuriame parašyta Pitonas, todėl jis veikia bet kurioje platformoje. Be atsisiuntimo, jį taip pat galima įdiegti su
pip install esptool
(opip2
opython -m pip
…). Žinoma, Espresas Ji taip pat siūlo savo įrankį, bet šiuo metu galima tik „Windows“. -
Paruoškite atsisiųstus failus; išpakuokite juos į prieinamą aplanką ir, jei reikia, padarykite įrankį vykdomą esptool, mano atveju, nuo GNU / Linux, Su
chmod +x esptool
-
Prijunkite modulį prie kompiuterio naudodami keitiklį USB UART TTL kuris veikia 3V3 arba naudokite lygio keitiklį, jei jis veikia esant 5 V. Be maitinimo, turėsite prijungti TX prie keitiklio RX USB UART TTL, RX į TX, GPIO0 žemu lygiu (GND) ir galbūt GPIO2 aukštu lygiu (mano testuose veikė tiek prijungus žemu lygiu, tiek atjungus). Jei modulis turi laisvą GPIO15 jungtį (kaip yra ESP-12), jis turi būti prijungtas prie žemo lygio. RESET, kuris veikimo metu paprastai būtų aukštas, gali būti neprijungtas arba prijungtas prie aukšto lygio naudojant rezistorių (pavyzdžiui, 10K), nes prieš pradedant įrašymą gali tekti iš naujo nustatyti įrenginį jį prijungus. iki žemo lygio.
Įjungus modulį, jį bus galima atnaujinti, bet Jei rodoma ryšio klaida, ją reikės nustatyti iš naujo akimirksniu prijunkite RESET žemu lygiu ir palikite jį įjungti (neprisijungus) atnaujinimo procesui.
Modulis turi pusės amperų suvartojimo piko (kai kurių vartotojų teigimu, iki 600 mA), todėl svarbu naudoti maitinimo šaltinį, galintį palaikyti šį suvartojimą, ypač atnaujinant programinę-aparatinę įrangą. -
Paleiskite įrankį, kad atnaujintumėte programinę-aparatinę įrangą. Mano atveju įrankį ir programinės įrangos dokumentus išsaugojau 3 veiksme tame pačiame aplanke, todėl paleidžiu iš konsolės:
cd ~/Datos/firmwareESP8266
(pakeiskite į aplanką, kuriame yra įrankis ir programinė įranga)./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
nustato greitį ESP8266 (mano atveju 115200 XNUMX bodų) ir--port
nuoseklusis prievadas, prie kurio jis jungiasi (mano atveju, emuliuotas, pirmasis USB). Įvairūs dokumentai, sudarantys programinę-aparatinę įrangą, atsiliekawrite_flash
prieš tai nurodomas adresas su user1.bin dokumentu, kuriame yra naujinimo naudingoji apkrova.
Siųsti komandas į ESP8266 wifi modulį
Norėdami kontroliuoti ESP8266 nuo kompiuterio turėsime pradėti sukonfigūruoti programą kuriam pakaks ① pasirinkti prievadą, prie kurio prijungtas keitiklis USB UART TTL, Kažkas kaip /dev/USB0
GNU/Linux ir panašiai ar panašiai COM6
sistemoje Windows ② pasirinkite greitį, kuriuo ESP8266, tikriausiai 115200 8 bodų, ③ nustatykite XNUMX duomenų bitus ir vieną sustojimo bitą be pariteto ar rankos paspaudimo ir ④ nustatykite eilutės pabaigą, priklausomai nuo mikroprograma, beveik visada CR+LF.
Kai programa sukonfigūruojama (arba, jei reikia, išsaugoma ir pasirinkta), ji yra atidarykite ryšį (atitinkamai „atidaryti įrenginį“ ir „atidaryti“, aukščiau pateiktų pavyzdžių ekrano kopijose su CuteCom y PuTTY) ir galite pradėti siųsti užsakymus ESP8266.
Kaip matyti iš ESP8266 AT komandų lentelė, suaktyvinimo, išjungimo, reikšmės nustatymo ir nuorodų į ją formatas yra gana nuspėjamas, tačiau apskritai nėra lengva juos visus prisiminti ir tikriausiai turėsite jį turėti po ranka, kad galėtumėte į jį kreiptis.
Būdas siųsti AT užsakymus al ESP8266 wifi modulis nuo Arduino yra labai paprasta: ① konfigūruokite ryšius su Serial.begin(115200);
(arba Serial1, Serial2… plokštėse su keliais aparatūros nuosekliaisiais prievadais) ir ② siųskite komandas naudodami formatą 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()
{
}
|
Aukščiau pateiktame pavyzdyje parodyta, kaip išsiųsti ESP8266 wifi modulio AT užsakymai nuo Arduino. Šiuo atveju tai iliustruojama AT+CWJAP
, kuris naudojamas prisijungti prie prieigos taško. Ši komanda kaip argumentus naudoja prieigos taško identifikatorių (SSID) ir raktą, abu kabutėse, todėl jie tampa objektu Srtring
ir įdėkite juos į kabutes naudodami pabėgimo kodą (\"
). Norėdami užbaigti užsakymą, naudokite \r\n
kuris atitinka CR
y LF
.
Atsiminti, kad nuoseklusis prievadas ne visada identifikuojamas Serial
(tam tikrose plokštelėse tai gali būti Serial1
, Serial2
…) naudojamas prievado objektas buvo apibrėžtas priskiriant jį makrokomandai PUERTO_SERIE
. Naudojamos plokštės tipo aptikimas gali suteikti šiek tiek intelektualumo renkantis nuoseklųjį prievadą; Vėliau aptarsime, kaip galite sužinoti tipą Arduino. Likę apibrėžimai yra įprasti, leidžiantys „įvardyti“ pastovias reikšmes, kad jos nesikartotų (ir nepadarytų klaidų) ir būtų lengviau jas pakeisti.
Aukščiau pateiktas pavyzdys turėtų sujungti ESP8266 wifi modulis prie nurodyto prieigos taško, bet ar jis jau buvo prijungtas anksčiau? Ar ryšys suveikė? Kad žinotume, turime „klausytis“ to, kas ESP8266
Gaukite duomenis iš ESP8266 wifi modulio
Prijungę aukščiau paaiškintą duomenų sniferį prie kompiuterio, galite pamatyti, ką Arduino išsiuntė į ESP8266 ir jo atsakymas. Skaityti iš Arduino ir apdoroti joje esančią informaciją, kurią reikės aptikti Serial.available()
jei gauta kokių nors duomenų ir jei taip, įkelkite juos Serial.read()
. Toliau pateiktame pavyzdyje parodyta, kaip perskaityti atsakymą iš AT+CWJAP?
, kuri praneš, ar yra ryšys su kuriuo nors prieigos tašku.
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();
}
}
|
Kaip lėkštėje Arduino One (ir kituose) atidarius nuoseklųjį monitorių programa iš naujo nustatoma, ją galima pamatyti serijos pulte Arduino informaciją, kurią siunčiate ESP8266 kaip rodo toliau esančio vaizdo ekrano kopija.
Išanalizuokite ESP8266 wifi modulio atsiųstą atsakymą
Jau matėme, kaip skaityti informaciją, kuri pasiekia Arduino iš ESP8266. Problema, su kuria tenka susidurti, yra ta, kad nežinai, kada jis pradės atvykti, kiek laiko užtruks, kokio ilgio... ir nėra labai efektyvu laukti atsakymo iš ESP8266 gaunamas neleisdamas mikrovaldiklis tuo tarpu atlikti kitas užduotis.
Paprastas būdas valdyti šią aplinkybę yra kartoti gautus duomenis ieškodami konkrečių atsakymų su kuriais, pavyzdžiui, suaktyvinami indikatoriai (vėliavos arba Būlio kintamieji), kurie nustatys, ar tęsti paiešką gautame tekste ir kokius veiksmus reikia atlikti remiantis informacija, gaunama iš ESP8266. Kol atsakymas ateina mikrovaldiklis gali atsiduoti kitoms užduotims, pavyzdžiui, gauti duomenis iš jutiklių ir juos apdoroti.
Ieškokite teksto iš ESP8266 gautoje informacijoje
Norėdami ieškoti teksto, gauto iš ESP8266 tu gali kiekvieną gautą laišką palyginkite su tuo, kuris atitinka jūsų ieškomą žinutę. Reikės naudoti skaitiklį (arba rodyklę), nurodantį lyginamą raidę; Jei simbolis, kuris ateina iš ESP8266 yra toks pat kaip ir tiriamasis pranešime, skaitiklis juda į priekį, jei skiriasi, inicijuojamas.
Norint žinoti, kad pabaiga pasiekta, ieškomas kitas ieškomo pranešimo simbolis, kuris bus lygus nuliui (\0
) arba pranešimo ilgis išsaugomas, kad palyginus jį su skaitikliu sužinotumėte, ar palyginimas baigtas ir todėl ESP8266 wifi modulis išsiuntė norimą žinutę.
Toliau pateiktame pavyzdyje naudojama komanda AT+CWLAP
kuris grąžins prieigos taškų sąrašą ir juose bus ieškoma vieno, vadinamo „wifi polaridad.es“. Nors pasirinkome patikrinti, ar paskutinis simbolis yra nulis, kaip buferis Jame saugomas tik ieškomas tekstas ir žinomas jo ilgis, taip pat būtų galima patikrinti, ar gautas toks skaičius teisingų raidžių. Su LED prijungtas prie 2 kaiščio, pranešama, kad buvo rastas laukiamas tekstas.
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
}
}
}
}
|
Ankstesnio pavyzdžio kode taip pat galite pamatyti būdą, kaip pasirinkite nuoseklųjį prievadą, atsižvelgdami į plokštės tipą Arduino naudojamas. Šiame pavyzdyje daroma prielaida, kad projektui turite trijų tipų lentas: vieną Arduino One, Vienas „Arduino Mega 2560“ ir arduino leonardo. Jei dirbate su a Arduino One jis bus naudojamas Serial
ir kitaip Serial1
.
Jei dirbate su lėkšte arduino leonardo Tą patį metodą galite naudoti norėdami sustabdyti programą ir laukti konsolės (nuosekliojo prievado, susieto su Serial
) yra.
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
|
Ieškokite įvairių tekstų ESP8266 atsakyme
Ankstesniame pavyzdyje pateiktas kodas naudojamas ieškant teksto informacijoje, kurią siunčia ESP8266 bet atsakymas gali apimti skirtingą informaciją, priklausomai nuo operacijos. Tarkime, pradedant nuo paprasto atvejo kitame pavyzdyje, kad tekstas atsiųstas MCU ESP8266 es OK
kai operacija atliekama teisingai ir ERROR
Kitu atveju, kaip su užsakymu AT+CWJAP?
, kuris skirtas patikrinti, ar ESP8266 wifi modulis jau prijungtas prie prieigos taško.
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
}
}
}
}
}
|
Šis naujas to paties metodo įgyvendinimas, ieškant atitikmenų su keliais galimais pranešimais, leidžia pasirinkti skirtingus veiksmus, atsižvelgiant į atsakymą, gautą iš ESP8266, tiesiog įjunkite LED atitinkamas.
Apribokite laiką, kurio reikia atsakymui gauti
Iki šiol nebuvo daroma nuoroda į atitinkamą problemą: maksimalus laukimo laikas (skirtasis laikas), kol bus laikoma, kad operacija nepavyko. Jei dėl kokių nors priežasčių ryšys su ESP8266 wifi modulis, modulis su prieigos tašku, prieigos taškas su internetu ar, pavyzdžiui, hipotetinis serveris nepasiekiamas, programa gali būti užblokuota viename taške laukiant neribotam laikui, todėl į tokias aplinkybes teks reaguoti. Maksimalus laukimo laikas gali būti sukonfigūruotas visai programai, dažniausiai jis tokiu atveju bus „došnesnis“ arba kiekvienai operacijai galima užprogramuoti individualius laukimo laikus.
Norėdami patikrinti, ar praėjo (bent) tam tikras laiko intervalas Sąskaitos paleidimo momento "laikas" paprastai atimamas iš esamo "laiko" ir patikrinama, ar skirtumas yra didesnis nei norima riba. Šis „laikas“ nebūtinai turi būti realus laikas, paprastai jis atitinka intervalą, kuris praėjo nuo MCU pradėti skaičiuoti laiką; Tai neturi įtakos programai, nes įdomu yra praėjęs laikas, o ne absoliutus laikas.
Paprastai norint patikrinti, ar praėjo tam tikras intervalas, naudojama tokio tipo išraiška:
1
|
(unsigned long)(millis()–milisegundos_al_empezar)>intervalo_de_tiempo
|
Kintamas milisegundos_al_empezar
yra vertė millis()
tam tikras vykdymo momentas, nuo kurio nustatomas laikas, todėl nėra neįprasta, kad jo pavadinimas reiškia žodį „chronometras“. Kintamasis intervalo_de_tiempo
yra didžiausias milisekundžių skaičius, dėl kurio ankstesnė išraiška yra teisinga, tai yra, jis reiškia skirtąjį laiką; Paprastai tai yra konstanta (arba makrokomanda) ir, kaip ir ankstesniu atveju, jos pavadinime dažnai pasirodo žodis „TIMEOUT“. Jei dirbate labai trumpais intervalais, galite naudoti micros()
vietoj millis()
(mikrosekundės, o ne milisekundės), nors ji yra daug rečiau paplitusi ir daug ne tokia tiksli.
1
|
(unsigned long)(millis()–cronometro)>TIMEOUT
|
Ilgas sveikasis skaičius Arduino (unsigned long
). lėkštėje Arduino Nepertraukiamai veikiant milisekundžių skaitiklis bus nustatytas iš naujo (grįš į nulį) maždaug kas 50 dienų. Atimant iš nepasirašytų duomenų tipų, atkuriama ta pati elgsena (skaitiklio apvertimas), todėl galima valdyti skirtąjį laiką neribotą laiką.
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;
}
}
}
|
Aukščiau pateiktas kodas rodo a labai paprastas laiko apribojimo įgyvendinimas įtraukiant eilutes, pažymėtas atsižvelgiant į pavyzdį, esantį prieš jį. Kadangi skirtasis laikas patikrinimas atliekamas apdorojus duomenis, gautus iš ESP8266 wifi modulis, operacija gali būti laikoma sėkminga, net jei priėmimas užtrunka ilgiau nei nustatytas laukimo laikas.
Vykdykite sudėtingą operaciją, apibrėžtą keliomis AT komandomis
Kad būtų pavyzdinė nuoroda į programos, kuri išnaudoja ESP8266 wifi modulis, tarkime, kad taip saugoti informaciją duomenų bazėje, pasiekiamoje per žiniatinklio paslaugą stebėti temperatūrą. Šis kodas nuskaito jutiklį, prijungtą prie analoginės įvesties kas tam tikrą laiko intervalą, apskaičiuoja vidutinę reikšmę ir po ilgesnio laiko siunčia ją į žiniatinklio serverį (stilius DI) per a peticija HTTP (PASKELBTI, GAUTI…).
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”);
}
}
|
Šiame temperatūros įrašymo pavyzdyje žiniatinklio serveris pasiekiamas kas penkias minutes. Nors prieinamumas nėra itin didelis, tikimasi, kad pasiūlymas pasiteisins, tačiau jei reikėtų didesnio įrašymo dažnio, reikėtų panaudoti kitus išteklius, pvz. duomenų buferis laukia siuntimo, išsiųsti kelis, kai serveris gali dalyvauti, ir saugoti juos, kai jis nepasiekiamas. Jei duomenų registravimo dažnumas būtų dar didesnis, reikėtų pasiūlyti kitų tipų protokolus kaip alternatyvą HTTP ar net pakeisti TCP iki UDP kad būtų galima siųsti daugumą duomenų reikiamu greičiu net kai kurių praradimo kaina.
Operacijos, sudarančios užduotį, kurią reikia atlikti norint siųsti temperatūrą, būtų šios:
- Iš naujo nustatykite wifi modulį
- Atsijungti nuo dabartinio prieigos taško (jei yra numatytasis ryšys)
- Nustatykite nustatymus. Pavyzdžiui, daroma prielaida, kad turi būti sukonfigūruotas ryšio režimas (paprastas) ir vaidmuo „Wi-Fi“ ryšiuose (stotis).
- Prisijunkite prie prieigos taško
- Patikrinkite, ar ryšys yra teisingas (iš tikrųjų tai yra įėjimo taškas) Jei ryšio nėra, pradėkite procesą nuo pradžių
- Prisijunkite prie serverio
- Siųsti prašymą HTTP su saugotinais duomenimis
Veiksmų tvarka nebūtinai turi būti tokia (nors operacija yra) ir kiekvienam žingsniui gali prireikti kelių ESP8266 AT komandosPavyzdžiui, aukščiau nurodytai konfigūracijai reikės dviejų: AT+CIPMUX=0
y AT+CWMODE=1
.
Duomenų struktūra, vaizduojanti ESP8266 operacijas
Ankstesniuose pavyzdžiuose, nors ir labai paprastai, jau siūlomas bendras problemos sprendimas: naudoti duomenų struktūrą, kurioje saugomi galimi atsakymai ir veiksmai, kurių reikia imtis kiekvienu atveju; išsiųskite veiksmą, palaukite atsakymo ir tęskite pagal tai, ką reiškia atsakymas. Kadangi kiekvienai sudėtingai operacijai reikės kelių ESP8266 AT komandos, duomenų struktūra turi susieti operaciją su kitomis, vėlesnėmis ar ankstesnėmis, kurios turi būti atliekamos kiekvienu atveju, atsižvelgiant į ESP8266.
Ankstesniuose pavyzdžiuose pranešimo buvo ieškoma atsakyme ESP8266 ir tai buvo interpretuojama kaip sėkmė arba klaida. Be viso gauto teksto priėmimo (ir analizės), Norint turėti bendrą minimumą, patartina atkreipti dėmesį ir į pranešimo užbaigimą arba, kitaip tariant, į prieinamumą ESP8266 wifi modulis gauti naujų užsakymų. Tokiu būdu pakeitimas į būseną, kurią galėtume vadinti, pavyzdžiui, „wifi pasiekiamas“, galėtų gauti prieigos taško pavadinimą ir gauti tekstą. ERROR
arba tekstą OK
reikštų, kad ESP8266 Jūs baigėte atsakymą ir dabar galite siųsti kitą AT komanda į 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;
|
Aukščiau pateiktame kode naudojamas vektorius (operacion
) išsaugoti nuoseklių operacijų, sudarančių užbaigtą užduotį, tekstą. Naudojamas dvimatis masyvas (mensaje
) su trimis analizuojamais atsakymais. Kaip paaiškinta aukščiau, reikia ieškoti pranešimų, kurie reiškia atsakymo pabaigą, be pranešimo, kuris reiškia teisingą ar neteisingą atsakymą. Ne visos operacijos turės tiek pat galimų atsakymų; Kai atsakymų yra mažiau, galima naudoti tuščią pranešimą, kurio analizėje sunaudojama kuo mažiau ciklų (netgi tai nėra pats optimaliausias būdas). Logiškai mąstant, minimalus ieškomų atsakymų skaičius (pavyzdyje trys) turės apimti visas veikimo galimybes, net jei jos nėra įmanomos.
Kalbant apie galimus atsakymus, jau dabar matyti, kad šis pavyzdys nėra labai naudingas norint gauti savavališko formato duomenis iš ESP8266 wifi modulis, bet reikalas tas, kad naudojant su mikrovaldikliai tai nėra įprasta; Dažniausiai yra siunčiami jų prijungtų jutiklių surinkti duomenys ir (arba) gaunama informacija, ką daryti su jo valdomomis pavaromis. Labai vertinga informacija, kurią galima labai gerai nuspėti.
Ankstesnėje duomenų struktūroje, kaip tai daroma norint išreikšti galimus analizuojamus atsakymus, dvimatė matrica taip pat naudojama norint nustatyti operaciją, kurią reikia atlikti kiekvienu atveju (siguiente_operacion
). Tiksliau, pasirinkome atsakyti į trijų tipų pranešimus: ① savavališką tekstą (LITERAL
), kad patikrintumėte, ar yra ryšys su „Wi-Fi“ prieigos tašku ir serveriu, ② tekstą, kad aptiktų proceso klaidas (FALLO
) ir ③ tekstas, nurodantis, kad operacija buvo sėkmingai baigta (ACIERTO
).
Galiausiai yra dar du vektoriai, skirti nustatyti maksimalų laukimo laiką prieš pasiduodant (timeout
) ir nurodykite (configuracion
) jei operacija baigiama nelaukiant atsakymo (ESPERAR_RESPUESTA
) ir pranešimai, nurodantys ryšio pabaigą. Šis paskutinis vektorius, iliustruojantis, kaip galima išsaugoti atmintį, veikia su konfigūracijos baito bitais, kad parodytų skirtingas būsenas.
Pirmas ESP8266 AT komandos duomenų struktūros visada laukite atsakymo, kuris gali būti sėkmės arba klaidos pranešimas. Įvykus klaidai, modulis paleidžiamas iš naujo ir paleidžiamas iš naujo, o jei pranešimas rodo, kad operacija yra teisinga, pereinama prie kitos.
Kai prisijungiate prie serverio, modelis pasikeičia. Tokiu atveju reikia ① išsiųsti perduodamo duomenų paketo ilgį ir ② sudaryti užklausą HTTP su fiksuotu tekstu ir verte (temperatūros), kuri siunčiama saugoti serveryje. Šių duomenų parengimas atliekamas kiekvienoje siuntoje ir juos reikia padalyti į dvi (pranešti ilgį) arba tris (atsiųsti užklausą HTTP) Remdamasi ESP8266 AT užsakymas. Tik paskutinė dalis, į kurią padalinta operacija, lauks atsakymo.
Tokiu atveju jis veiks be problemų (gal perspėja, kad modulis užimtas), tačiau kai duomenų ilgis yra didesnis, teks dalyti duomenų blokus į mažesnes dalis ir netgi gali tekti palaukti, nes atliekama su temperatūros rodmenimis, kad modulis turėtų laiko siųsti duomenis jų neužpildydamas buferis.
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();
|
Kartu su kitomis makrokomandomis, kurios jau buvo paaiškintos anksčiau, aukščiau pateiktas pavyzdinis kodas parodo, kaip apibrėžiamos skirtingos būsenos, kuriomis nurodoma, ar laukti atsakymo ir, jei taikoma, koks pranešimas rodo, kad jis baigtas.
Kadangi skirtinguose kodo taškuose bus siunčiama operacija (kai ateina laikas siųsti vidutinę temperatūrą, jei viršijamas operacijos laukimo laikas, kai sėkmingai baigta esama operacija...), bet kaip tai padaryti sukurtas visame pasaulyje, jis buvo apibrėžtas kaip makrokomandas ENVIAR_OPERACION
kuri sugrupuoja siuntimo veiksmus.
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();
|
Toliau pateikiamas pagrindinės pavyzdžio programos kodas. Labiausiai išorinė užduotis yra ta, kuri yra atsakinga už temperatūros mėginių ėmimą, kad būtų galima apskaičiuoti vidurkį ir kas tam tikrą laikotarpį ji siunčiama į serverį naudojant ESP8266 wifi modulis. Išsiuntus kiekvieną operaciją, atsakymas analizuojamas, siekiant nustatyti, kuri yra kita, ar informacijos siuntimo užduotis buvo atlikta.
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
}
}
}
|
Logiška, kad ankstesniame kode gali būti atlikti keli optimizavimo veiksmai, tačiau tai yra pavyzdys, kaip suprasti, kaip ESP8266 Apskritai verta sutelkti dėmesį tik į kai kuriuos aspektus, iš kurių pirmasis yra duomenų struktūra. Atrodo, kad tai logiška naudoti programavimo kalbos duomenų struktūrą (struct
) atstovauti tvarkomai informacijai: ESP8266 AT komandos ir analizuojamus pranešimus.
Naudokite struktūrą (struct
) saugoti duomenis vietoj pavyzdinių masyvų (pagrįstų jais) yra nereikšminga ir, nors tai gali lemti elegantiškesnį kodą, tai nereiškia, kad rezultatas pagerės. Tikra alternatyva, kurią suteikia naudojimas struct
yra įgyvendinti, kaip paaiškinta toliau, kintamo ilgio struktūrose, kuriose yra „vidinių“ duomenų kuriuos jie nurodo. Tokiu būdu, pavyzdžiui, operacijai nebūtina turėti fiksuoto skaičiaus atsakymų, kuriuos reikia analizuoti.
Šis metodas rodo, kad tai yra geriausias būdas įgyvendinti sprendimą, tačiau trūkumas yra tas, kad jis būtų būtinas naudoti dinaminį atminties paskirstymą, rizikinga praktika dirbant su a mikrovaldiklis todėl reikia atidžiai įvertinti, kiek atminties bus naudojama vykdymo metu, nes kompiliatorius vargu ar sugebės mus apie tai įspėti ir yra tam tikra galimybė išeikvoti atmintį (ar steką) su lemtingomis pasekmėmis programos vykdymui.
Kodo optimizavimo eilutėje įdomu prisiminti, kad tokio tipo programoje, kuri naudoja daug teksto, gali sutaupyti vietos atmintyje SRAM teksto eilučių saugojimas programos atmintyje (blykstė) su makrokomandu F()
. Toliau pateiktose ekrano kopijose galite pamatyti skirtingą programą ir dinaminės atminties paskirstymą, kai įprastai naudojamas tekstas ir naudojant makrokomandą F()
.
Kalbant apie veiksmus, kurie atliekami pagal informaciją, gaunamą iš ESP8266 wifi modulis, kaip alternatyva žinutės tikrinimui iš kodo ir vieno ar kito atlikimui pagal tai, kas gauta, gali būti saugomi šioje duomenų struktūroje nuorodas į funkcijas, kurios atlieka kiekvieną užduotį, o ne būsenos indikatorius (vėliavos), kurios įspėja apie tam tikrą būseną, kad programa yra atsakinga už valdymą, pavyzdžiui, pagrindinėje kilpoje.
Toliau pateikiamas struktūrų pavyzdys, skirtas saugoti užklausų duomenis ESP8266 (duomenų tipas operacion_esp8266
) ir jų atsakymai (duomenų tipas 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;
|
Kaip struktūrą, vaizduojančią operaciją (duomenis, kurie siunčiami į ESP8266 wifi modulis) nurodo struktūrą, kuria apibrėžiami atsakymai, ir atsakymų į operacijų struktūrą struktūrą, pirmiausia reikia deklaruoti abu, apibrėždami naują duomenų tipą ir tada apibrėždami jo turinį.
Ankstesniame pavyzdyje manoma, kad programa, kurioje ji yra, pasirinko naudoti a būsenos indikatorius, kuris turi atitikti kintamąjį, pasiekiamą iš kodo, kuris yra atsakingas už vienos ar kitos operacijos atlikimą, kaip nurodo minėta reikšmė. Jei atsakyme į ESP8266 Kai analizuojamas tam tikras tekstas, būsena įgauna reikšmę, kuri nurodo atitinkamo atsakymo struktūrą.
Kaip minėta anksčiau, būtų kita alternatyva pakeisti arba papildyti būsenos indikatorių išsaugoti funkciją atskaitos struktūroje (rodyklė), kuris būtų iškviestas atsakyme iš tam tikro teksto ESP8266 wifi modulis.
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;
|
Ankstesniame pavyzdyje jis buvo įtrauktas į duomenų struktūrą, kuri naudojama apdoroti atsakymą iš ESP8266 wifi modulis žymeklis į (tariamą) funkciją, kuri grąžina tipo duomenis float
(gali būti svertinė analoginio skaitymo reikšmė) ir kuriai kaip argumentai pateikiami du baitai (du unsigned char
kuris gali būti kaištis, iš kurio skaitoma analoginė įvestis, ir tas, kuris aktyvuoja hipotetinio integruoto ĮJUNGTI).
Kuriamas skirtas MCU, priešingai nei vyksta didesnių sistemų kūrimo stiliuje, nėra taip neįprasta naudoti visuotinius kintamuosius, kai apibrėžiamos (visuotinės) programos, valdančios agregatą, elgseną, todėl tokio tipo apibrėžimų nebus ypač retai. kaip funkcijos be parametrų ir kurios negrąžina reikšmių, panašiai void (*accion)();
Jei dirbate šiuo duomenų vaizdavimo būdu, naudokite struct
kintamo ilgio duomenų, reikės dinamiškai paskirstyti atmintį malloc()
(o new()
, jei naudojami objektai), kuris kaip parametrą naudos skirtą atminties kiekį ir grąžins žymeklį į rezervuotos atminties srities pradžią. Su sizeof()
Išsaugomo tipo, padauginus iš naudojamų elementų skaičiaus, galite gauti reikiamą atminties kiekį. Pavyzdys su jo naudojimu ir be jo galima pamatyti toliau pateiktose ekrano kopijose. malloc()
; Pirmuoju atveju būkite atsargūs su programos naudojama atmintimi, turite įkelti biblioteką, kurioje yra ši funkcija.
Jei operacijos su ESP8266 wifi modulis programos vykdymo metu skirsis, reikės atlaisvinti nenaudojamą atmintį free()
(o delete()
, jei jie yra objektai). Nors pagrįstai galima tikėtis, kad kompiliatorius (GCC) optimizuos programą, kad būtų išvengta atminties skaidymo, našumas tikrai nebus toks optimalus, kaip dirbant su statiškai paskirstyta atmintimi.
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
}
}
}
|
Nors šiame pavyzdyje (abiejuose įgyvendinimuose) tai nėra labai prasminga, tačiau norint apibendrinti operaciją, kad būtų galima ją pritaikyti kitiems atvejams, reikia pažymėti, kad Duomenų siuntimas visada kartoja tą patį protokolą: praneškite baitų skaičių, kuris bus išsiųstas, palaukite indikatoriaus (>) ir išsiųskite duomenis.
Kadangi šiame pavyzdyje jis naudojamas tik vieną kartą (visa užklausa pateikiama viename pakete), tai neatrodo labai naudinga, tačiau apskritai gali prireikti atlikti kelis siuntimus per tą pačią operaciją, įskaitant atvejus, kai jie turi būti turi būti perduodami dideli duomenų kiekiai, kurie turi būti suskaidyti, kad būtų išvengta atminties perpildymo ESP8266.
Norint įgyvendinti šį elgesį, galima naudoti du paskutinius ryšio elementus, kad kiekvieną kartą siunčiant duomenis, duomenys būtų užpildyti atitinkamomis reikšmėmis: pirmuoju atveju – išsiųstų baitų skaičius, o antruoju – ( prašymo dalis. būti perduota.
Norėdami pakartoti priskyrimą ir siuntimą, skirtingi elementai, kuriuos reikia perduoti, gali būti saugomi vektoriuje. Šis naujas vektorius bus tas, kuris nulems sudėtingos operacijos pabaigą, o ne paskutinę operaciją, kaip iki šiol.
1 komentaras