Mga pangunahing operasyon sa isang ESP8266 wifi module mula sa Arduino
Kapag Espressif inilunsad ang mga unang module sa merkado wifi kasama ang pinagsamang ESP8266 at firmware kung saan haharapin ito gamit ang mga utos ng AT, kung ano ang interesado sa aming mga gumagamit ay ang pagsasama nito sa mga asembliya mga microcontroller at ang mga problema ay nabawasan sa pag-alam sa (dating) dilim ESP8266 AT command table, mga pangangailangan sa pagpapakain o Pag-update ng firmware ng ESP8266.
Pagkatapos ay mabilis na dumating ang mga alternatibo upang i-program ang ESP8266 at mga pagpapatupad ng module wifi ng iba't ibang mga format na nagdulot ng iba pang mga alalahanin: kung aling ESP8266 wifi module ang pipiliin depende sa hanay ng iba't ibang antenna (kabilang ang mga panlabas) o ang pisikal na pagsasama ng mga bagong module na ito sa aming mga asembliya.
Tiyak, dahil sa lahat ng mga pagbabagong ito, maaaring hindi nabigyan ng diin ang pinakapangunahing aspeto, ang pinakapangunahing pamamahala ng ESP8266 wifi module. Kahit na polarity.es Makakahanap ka ng impormasyon sa paggamit ng ESP8266 at may ilang mga application na nilayon upang ipaliwanag sa isang generic na paraan ang pagpapatakbo ng ESP8266 wifi module gamit ang mga AT command, lalo na sa artikulo sa library upang gumawa ng mga HTTP query mula sa Arduino gamit ang ESP8266 wifi module, iminumungkahi ng mga impression ng mga mambabasa na magiging kapaki-pakinabang na magdagdag ng ilang higit pang pangunahing impormasyon upang matulungan ang mga gumagamit ng ESP8266 upang isagawa ang kanilang sariling mga pagpapatupad.
Talakayin ang mga pangunahing operasyon upang gumana sa ESP8266 at ang pagmumungkahi ng mga generic na solusyon ay isang layunin ng maraming magkakaibang bahagi; Upang makatulong sa pagsunod sa nilalaman ng artikulo, ang sumusunod na index ay maaaring magsilbing gabay:
- Kontrolin ang ESP8266 wifi module mula sa computer sa pamamagitan ng serial port
- I-update ang firmware gamit ang esptool
- Magpadala ng mga order sa module
- Tumanggap ng data mula sa ESP8266
- Suriin ang tugon sa pamamagitan ng paghahanap ng mga teksto sa nilalaman
- Limitahan ang oras ng paghihintay para matanggap ang tugon
- Magsagawa ng kumplikadong operasyon na tinukoy ng maraming AT command
Kontrolin ang ESP8266 wifi module mula sa computer sa pamamagitan ng serial port
Mula sa isang plato Arduino at gamit ang iyong IDE posibleng masubaybayan ang operasyon ng a ESP8266 wifi module, ipadala ang ESP8266 AT command at makita ang sagot ngunit ito ay mas maginhawang gawin ito mula sa isang computer na may isang terminal type application.
Depende kung saang board Arduino ginamit, isang hardware serial port lamang ang maaaring available, na nagdaragdag ng kaunting abala sa pagpapadala at pagtanggap. Ang pagpapalit ng bilis ng mga komunikasyon ay mas komportable sa isang serial communications application mula sa isang computer at ilang motherboard. Arduino (at sa ilang pagkakataon) ay hindi sumusuporta sa mas mataas na bilis ng mga serial na komunikasyon, lalo na ang 115200 baud, na siyang default na bilis ng mga pinakabagong bersyon ng firmware.
Tungkol sa Anong programa ang gagamitin upang masubaybayan ang ESP8266 gamit ang serial port, maraming mapagpipilian ayon sa mga pangangailangan at kagustuhan; lately mas ginagamit ko ang classic CuteCom (yung nasa screenshot sa itaas) kasi sobrang kumportable ko na ulitin yung certain ESP8266 wifi module AT mga order sa pagsubok ng proyekto.
Ang ilang mga rekomendasyon ay naibigay na dito sa mga program na gumagana bilang isang serial console; Halimbawa, kapag pinag-uusapan PuTTY para sa pagkontrol sa mga serial device ng UART mula sa computer. PuTTYBilang karagdagan sa pagiging isang mahusay na application, ito ay magagamit para sa karamihan ng mga desktop operating system. Higit pa rito, bilang PuTTY ay maaaring gamitin upang kumilos bilang isang console na may parehong serial port at ang Pamilya ng Internet protocol (TCP/IP), kabilang ang mga nagpapatakbo sa TLS, ay nagiging isang pangkaraniwang tool na higit pa sa binabayaran ang (maliit na) oras na ginugol sa pag-configure nito at pagsanay sa paggamit nito.
Bilang karagdagan sa serial communications software, upang ikonekta ang ESP8266 wifi module sa daungan USB Ang isang computer ay nangangailangan din ng isang converter USB sa serye TTL. Tulad ng sa kaso ng software, mayroong ilang mga bersyon, kung saan ginagamit lamang ang mga ito upang i-convert ang port USB sa isang serial port TTL (na maaaring makuha mula sa isang Euro) sa mga maaaring tularan ang iba't ibang mga protocol (tulad ng SPI o I2C).
Tulad ng isang program na gumagana bilang isang serial console, ang hardware upang makipag-ugnayan sa computer sa pamamagitan ng USB na may logic circuit (hindi lamang ang ESP8266) ay magiging isang karaniwang tool sa gawain ng isang microcontrolled na developer ng application, ito ay nagkakahalaga ng pagkakaroon nito sa toolbox sa lalong madaling panahon at magtrabaho kasama nito ESP8266 wifi module Ito ay isang mahusay na pagkakataon upang makakuha ng isa.
Ang converter USB a UART TTL Maaari rin itong gamitin upang subaybayan ang pag-uugali ng isang circuit na gumagamit ng ESP8266, para magawa ito, ang mga output na gusto mong subaybayan ay konektado sa serye sa data input (RX) ng converter na may mabilis na diode (ang 1N4148, halimbawa) at isang risistor (2K2, halimbawa) na kahanay sa bawat isa. Ang ganitong setup ay gumagana tulad ng isang hardware serial sniffer.
Bagaman ang sniffer sa imahe sa itaas ay tiyak na hindi pa ganap (bukod sa iba pang mga bagay na wala ito nagpapahina ng lakas) ay sapat na upang masubaybayan ang pagpapatakbo ng isang pagpupulong na may Arduino at ESP8266.
Ang pag-alis ng sniffer mula sa nakaraang pamamaraan, ang eskematiko na nagpapakita kung paano kumonekta a ESP8266 wifi module sa isang plato Arduino. Bilang karagdagan sa pagpapakain nito sa 3V3, ang reset pin at ang activation pin ng integrated ay dapat na konektado sa isang mataas na antas (paganahin). Siyempre, ang RX pin ng isa ay dapat kumonekta sa TX ng isa pa.
Upang gawing simple ang nakaraang diagram, isang plato ang kinakatawan Arduino pinapagana sa 3V3 at kung saan ang boltahe sa serial port ay ipinapalagay din na 3V3. Kung gagamit ka ng a microcontroller na may ibang antas ng signal sa serial port (karaniwang 5 V) ay kinakailangan, upang hindi masira ang ESP8266, gumamit ng a level converter tulad ng mga nasa diagram sa ibaba. Ang circuit na ito ay madalas na matatagpuan sa maraming komersyal na off-the-shelf na mga pagpapatupad ng module.
I-update ang ESP8266 firmware
ang ESP8266 AT command, ang pagwawakas nito, ang default na bilis ng module... depende sa bersyon ng ESP8266 firmware. Pinakamabuting tiyakin na mayroon kang parehong bersyon sa lahat ng mga module at, kung maaari, na ito ang pinakabagong bersyon.
Sa kasamaang palad, karamihan sa mga ESP8266 wifi module na mga modelo Mayroon lamang silang 4Mbit, kaya hindi mai-install sa kanila ang pinakabagong bersyon. Ang pinakabagong (opisyal) na bersyon ng firmware na maaaring i-install sa ESP8266 wifi modules na may 4 Mbit (karamihan) ay 0.9.4 na kinabibilangan ng bersyon 0.2 ng ESP8266 AT command.
Sa buod, upang i-update ang firmware na kailangan mo:
-
I-download ang kaukulang bersyon ng firmware. Ang pinakabagong (opisyal) na bersyon para sa isang module na may 4 Mbit ng memorya, na matatagpuan sa folder ng Espressif sa github. Sa Website ng espressif Maaari mong i-download ang pinakabagong bersyon ng firmware, ngunit napakahalaga na i-verify na ang module kung saan ito naka-install ay may sapat na memorya.
-
I-download ang pinakabagong bersyon ng tool sa pag-install ng firmware. Ang paborito ko ay esptool na nakasulat sa Sawa, kaya gumagana ito sa anumang platform. Bilang karagdagan sa pag-download, maaari din itong mai-install gamit ang
pip install esptool
(opip2
opython -m pip
…). Syempre, Espressif Nag-aalok din ito ng sarili nitong tool ngunit kasalukuyang magagamit lamang para sa Windows. -
Maghanda ng mga na-download na file; i-unzip ang mga ito sa isang naa-access na folder at, kung kinakailangan, gawing executable ang tool esptool, sa aking kaso, mula noong GNU / Linux, Sa
chmod +x esptool
-
Ikonekta ang module sa computer gamit ang isang converter USB UART TTL na gumagana sa 3V3 o gumamit ng level converter kung gumagana ito sa 5 V. Bilang karagdagan sa kapangyarihan, kakailanganin mong ikonekta ang TX sa RX ng converter USB UART TTL, RX hanggang TX, GPIO0 sa mababang antas (GND) at marahil GPIO2 sa mataas na antas (sa aking mga pagsubok ay nagtrabaho ito sa parehong pagkonekta nito sa mababang antas at pagdiskonekta nito). Kung ang module ay may libreng koneksyon ng GPIO15 (tulad ng nangyayari sa ESP-12) dapat itong konektado sa mababang antas. Ang RESET, na karaniwang nasa mataas na antas sa panahon ng operasyon, ay maaaring iwanang hindi nakakonekta o nakakonekta sa isang mataas na antas sa pamamagitan ng isang risistor (10K, halimbawa), dahil bago simulan ang pag-record ay maaaring kailanganing i-reset ang device sa pamamagitan ng pagkonekta nito sa mababang antas.
Sa pamamagitan ng pag-power up sa module magiging available itong i-update ngunit, Kung may ipinapakitang error sa koneksyon, kakailanganin itong i-reset pagkonekta ng RESET sa mababang antas sa isang iglap at pagkatapos ay iiwanan ito sa hangin (nang hindi kumukonekta) para sa proseso ng pag-update.
Ang module ay may kalahating ampere consumption peak (hanggang sa 600 mA, ayon sa ilang mga gumagamit) kaya mahalagang gumamit ng power supply na may kakayahang suportahan ang pagkonsumo na ito, lalo na para sa pag-update ng firmware. -
Patakbuhin ang tool upang i-update ang firmware. Sa aking kaso, na-save ko ang tool at mga dokumento ng firmware sa hakbang 3 sa parehong folder, kaya tumakbo ako mula sa console:
cd ~/Datos/firmwareESP8266
(palitan ang folder na naglalaman ng tool at firmware)./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
nagtatakda ng bilis ng ESP8266 (115200 baud sa aking kaso) at--port
ang serial port na kinokonekta nito (sa aking kaso, tinularan, ang unang USB). Ang iba't ibang mga dokumento na bumubuo sa firmware ay nasa likodwrite_flash
nangunguna sa address, kasama ang user1.bin na dokumento na naglalaman ng update payload.
Magpadala ng mga command sa ESP8266 wifi module
Upang kontrolin ang ESP8266 mula sa isang computer kailangan nating magsimula i-configure ang app kung saan ito ay sapat na upang ① piliin ang port kung saan ang converter ay konektado USB UART TTL, parang /dev/USB0
sa GNU/Linux at katulad o katulad nito COM6
sa Windows, ② piliin ang bilis kung saan ang ESP8266, malamang na 115200 baud, ③ itakda ang 8 bits ng data kasama ang one stop bit, nang walang parity o handshake, at ④ itakda ang dulo ng linya, depende sa firmware, halos palaging CR+LF.
Kapag ang application ay na-configure (o, kung saan naaangkop, naka-imbak at napili), ito ay buksan ang koneksyon ("bukas na device" at "bukas", ayon sa pagkakabanggit, sa mga screenshot ng mga halimbawa sa itaas na may CuteCom y PuTTY) at maaari kang magsimulang magpadala ng mga order sa ESP8266.
Tulad ng makikita sa ESP8266 AT command table, ang format para sa pag-activate, pag-deactivate, pagtatakda ng isang halaga at pagtukoy dito ay medyo predictable, ngunit sa pangkalahatan ay hindi madaling matandaan ang lahat ng ito at malamang na kakailanganin mo itong nasa kamay upang sumangguni dito.
Ang paraan ng magpadala AT mga order al ESP8266 wifi module mula sa Arduino ay napakasimple: ① i-configure ang mga komunikasyon sa Serial.begin(115200);
(o Serial1, Serial2… sa mga board na may ilang hardware serial port) at ② ipadala ang mga command gamit ang 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()
{
}
|
Ang halimbawa sa itaas ay nagpapakita kung paano ipadala ang ESP8266 wifi module AT mga order mula sa Arduino. Sa kasong ito ito ay inilalarawan AT+CWJAP
, na ginagamit upang kumonekta sa isang access point. Ginagamit ng command na ito bilang argumento ang access point identifier (SSID) at ang susi, pareho sa mga panipi, kaya sila ay naging isang bagay Srtring
at ilakip ang mga ito sa mga quote gamit ang escape code (\"
). Upang kumpletuhin ang order, gamitin \r\n
na tumutugma sa CR
y LF
.
Upang tandaan na ang serial port ay hindi palaging nakikilala sa Serial
(sa ilang mga plato ito ay maaaring Serial1
, Serial2
…) ang port object na ginamit ay tinukoy sa pamamagitan ng pagtatalaga nito sa macro PUERTO_SERIE
. Ang pagtukoy sa uri ng board na ginamit ay maaaring magdagdag ng kaunting katalinuhan sa pagpili ng serial port; Mamaya ay tatalakayin natin kung paano mo malalaman ang uri ng Arduino. Ang natitirang mga kahulugan ay ang mga karaniwang kahulugan na nagbibigay-daan sa iyo na "pangalanan" ang mga pare-parehong halaga upang maiwasang maulit ang mga ito (at magkamali) at gawing mas madaling baguhin ang mga ito.
Ang halimbawa sa itaas ay dapat na ikonekta ang ESP8266 wifi module sa ipinahiwatig na access point ngunit nakakonekta na ba ito dati? Nagtrabaho ba ang koneksyon? Upang malaman ito, kailangan nating "makinig" sa kung ano ang ESP8266
Tumanggap ng data mula sa ESP8266 wifi module
Sa pamamagitan ng pagkonekta sa data sniffer na ipinaliwanag sa itaas sa computer makikita mo kung ano Arduino ay nagpadala sa ESP8266 at ang kanyang tugon. Upang basahin mula sa Arduino at iproseso ang impormasyon sa loob nito na kakailanganing makita Serial.available()
kung may dumating na data at sa kasong iyon, i-load ito Serial.read()
. Ang sumusunod na halimbawa ay nagpapakita kung paano basahin ang tugon mula sa AT+CWJAP?
, na mag-uulat kung mayroong koneksyon sa anumang access point.
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();
}
}
|
Parang nasa plato Arduino uno (at sa iba pa) ang pagbubukas ng serial monitor ay nagre-reset sa programa, maaari itong magamit upang makita sa serial console Arduino ang impormasyon na iyong ipinadala ESP8266 gaya ng ipinapakita ng screenshot ng larawan sa ibaba.
Suriin ang tugon na ipinadala ng ESP8266 wifi module
Nakita na natin kung paano basahin ang impormasyong umaabot Arduino mula sa ESP8266. Ang problemang kailangan mong harapin ay hindi mo alam kung kailan ito magsisimulang dumating, gaano katagal bago ito dumating, kung ano ang haba nito... at hindi masyadong mahusay na maghintay ng tugon mula sa ESP8266 ay tinatanggap nang hindi nagpapaalam sa microcontroller magsagawa ng iba pang mga gawain sa pansamantala.
Ang isang simpleng paraan upang pamahalaan ang sitwasyong ito ay ulitin ang mga datos na natanggap na naghahanap ng mga konkretong sagot kung saan, halimbawa, i-activate ang mga indicator (mga flag o Boolean variable) na tutukuyin kung magpapatuloy sa paghahanap sa natanggap na text at kung anong mga aksyon ang dapat isagawa batay sa impormasyong dumating mula sa ESP8266. Habang dumating ang tugon microcontroller maaaring mag-alay sa iba pang mga gawain, halimbawa, pagtanggap ng data mula sa mga sensor at pagproseso nito.
Maghanap ng text sa impormasyong natanggap mula sa ESP8266
Para hanapin ang text na nagmumula sa ESP8266 maaari ihambing ang bawat titik na natanggap sa isa na tumutugma sa mensahe na iyong hinahanap. Kakailanganin na gumamit ng counter (o isang pointer) na tumuturo sa liham na ihahambing; Kung ang karakter na nagmula sa ESP8266 ay kapareho ng sinusuri sa mensahe, ang counter advances, kung ito ay naiiba ito ay pinasimulan.
Upang malaman na ang wakas ay naabot na, ang susunod na karakter ng hinanap na mensahe ay kinonsulta, na magiging zero (\0
) o ang haba ng mensahe ay naka-imbak sa, sa pamamagitan ng paghahambing nito sa counter, malaman kung ang paghahambing ay tapos na at samakatuwid ay ang ESP8266 wifi module ay nagpadala ng nais na mensahe.
Ang sumusunod na halimbawa ay gumagamit ng command AT+CWLAP
na magbabalik ng listahan ng mga access point at sa loob ng mga ito ay may hinahanap na tinatawag na "wifi polaridad.es". Bagama't pinili naming i-verify na ang huling character ay zero, bilang ang nagpapahina ng lakas Iniimbak lamang nito ang hinanap na teksto at alam ang haba nito, maaari din itong suriin kung ang naturang bilang ng mga tamang titik ay natanggap. Na may a LED konektado sa pin 2 iniulat na ang inaasahang teksto ay natagpuan.
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
}
}
}
}
|
Sa code ng nakaraang halimbawa maaari mo ring makita ang isang paraan upang piliin ang serial port depende sa uri ng board Arduino ginamit. Ipinapalagay ng halimbawang ito na mayroon kang tatlong uri ng mga board para sa proyekto: isa Arduino uno, A Arduino Mega 2560 at arduino leonardo. Kung nagtatrabaho ka sa isang Arduino uno ito ay gagamitin Serial
at kung hindi man Serial1
.
Kung nagtatrabaho ka sa isang plato arduino leonardo Maaari mong gamitin ang parehong paraan upang ihinto ang programa at maghintay para sa console (ang serial port na nauugnay sa Serial
) mayroon pa.
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
|
Maghanap ng iba't ibang teksto sa tugon ng ESP8266
Ang code sa nakaraang halimbawa ay ginagamit upang maghanap ng teksto sa impormasyong ipinadala ng ESP8266 ngunit ang tugon ay maaaring magsama ng iba't ibang impormasyon depende sa operasyon. Ipagpalagay, upang magsimula sa isang simpleng kaso sa susunod na halimbawa, na ang teksto na ipinadala ng MCU ESP8266 es OK
kapag ang operasyon ay ginawa ng tama at ERROR
Kung hindi, tulad ng sa utos AT+CWJAP?
, na nagsisilbing patunay kung ang ESP8266 wifi module ay nakakonekta na sa isang access point.
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
}
}
}
}
}
|
Ang bagong pagpapatupad na ito ng parehong paraan, na naghahanap ng tugma na may ilang posibleng mensahe, ay nagbibigay-daan sa iyong pumili sa pagitan ng iba't ibang mga aksyon depende sa tugon na natanggap mula sa ESP8266, i-on lang ang LED katumbas.
Limitahan ang oras na kinakailangan upang makatanggap ng tugon
Hanggang ngayon ay walang ginawang sanggunian sa isang nauugnay na isyu: ang maximum na oras ng paghihintay (timeout) bago isaalang-alang ang isang operasyon na nabigo. Kung sa anumang kadahilanan ang koneksyon sa ESP8266 wifi module, ang module na may access point, ang access point na may Internet o, halimbawa, isang hypothetical server ay hindi magagamit, ang programa ay maaaring ma-block sa isang punto na naghihintay nang walang katiyakan, kaya ang isang tugon ay kailangang ipahayag sa mga ganitong pangyayari. Maaaring i-configure ang maximum na oras ng paghihintay para sa buong application, kadalasan ito ay magiging mas "mapagbigay" sa kasong iyon, o maaaring i-program ang mga indibidwal na oras ng paghihintay para sa bawat operasyon.
Upang suriin na (hindi bababa sa) isang tiyak na agwat ng oras ang lumipas Ang "oras" ng sandali kung saan sinimulan ang account ay karaniwang ibinabawas mula sa kasalukuyang "oras" at na-verify na ang pagkakaiba ay mas malaki kaysa sa nais na limitasyon. Ang "oras" na ito ay hindi kailangang maging totoong oras, karaniwan itong tumutugma sa pagitan na lumipas mula noong MCU simulan ang pagbibilang ng oras; Hindi ito nakakaapekto sa programa dahil ang kawili-wili ay lumipas na oras at hindi ang ganap na oras.
Karaniwan, upang suriin kung lumipas na ang isang tiyak na agwat, ginagamit ang isang expression ng uri:
1
|
(unsigned long)(millis()–milisegundos_al_empezar)>intervalo_de_tiempo
|
Iba-iba milisegundos_al_empezar
naglalaman ng halaga ng millis()
ng isang tiyak na sandali sa pagpapatupad kung saan ito na-time, kaya hindi karaniwan na ang pangalan nito ay tumutukoy sa salitang "chronometer." Ang variable intervalo_de_tiempo
naglalaman ng maximum na bilang ng mga millisecond na ginagawang totoo ang nakaraang expression, ibig sabihin, kinakatawan nito ang timeout; Ito ay karaniwang isang pare-pareho (o isang macro) at, tulad ng sa nakaraang kaso, ang salitang "TIMEOUT" ay madalas na lumilitaw sa pangalan nito. Kung nagtatrabaho ka sa napakaikling mga pagitan maaari mong gamitin micros()
sa halip ng millis()
(microseconds sa halip na milliseconds) bagama't ito ay hindi gaanong karaniwan at hindi gaanong tumpak.
1
|
(unsigned long)(millis()–cronometro)>TIMEOUT
|
Isang mahabang integer sa Arduino (unsigned long
) ay sumasakop ng 4 na byte (32 bits), kaya ang pinakamalaking halaga na maaari nitong katawanin ay 4294967295 (2 sa kapangyarihan ng 32 minus one, dahil nagsisimula ito sa zero). sa isang plato Arduino Habang patuloy na tumatakbo ang millisecond counter ay magre-reset (bumalik sa zero) humigit-kumulang bawat 50 araw. Kapag ang pagbabawas gamit ang mga hindi naka-sign na uri ng data, ang parehong pag-uugali ay ginawa (pag-flip sa counter) kaya posible na kontrolin ang timeout nang walang katiyakan.
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;
}
}
}
|
Ang code sa itaas ay nagpapakita ng a napakapangunahing pagpapatupad ng limitasyon sa timeout pagsasama ng mga linyang minarkahan na may paggalang sa halimbawa na nauuna dito. Dahil ang pag-verify ng timeout ay isinasagawa pagkatapos ng pagproseso ng data na dumarating mula sa ESP8266 wifi module, ang operasyon ay maaaring ituring na matagumpay kahit na ang pagtanggap ay mas matagal kaysa sa ipinataw na oras ng paghihintay.
Magsagawa ng kumplikadong operasyon na tinukoy ng maraming AT command
Upang magkaroon ng halimbawang sanggunian ng layunin ng application na nagsasamantala sa ESP8266 wifi module, kumbaga mag-imbak ng impormasyon sa isang database na na-access sa pamamagitan ng isang serbisyo sa web upang masubaybayan ang temperatura. Ang sumusunod na code ay nagbabasa ng sensor na konektado sa isang analog input sa bawat tiyak na agwat ng oras, kinakalkula ang average na halaga at, pagkatapos ng mas mahabang agwat ng oras, ipinapadala ito sa web server (style IoT) sa pamamagitan ng a petisyon HTTP (POST, GET…).
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”);
}
}
|
Sa halimbawang ito ng pagtatala ng temperatura, ina-access ang isang web server tuwing limang minuto. Bagama't hindi masyadong mataas ang kakayahang magamit, inaasahan na gagana ang panukala, ngunit kung kinakailangan ang mas mataas na dalas ng pag-record, kailangang ipatupad ang ibang mga mapagkukunan, halimbawa, isang buffer ng data naghihintay na ipadala, upang magpadala ng ilan kapag ang server ay maaaring dumalo at mag-imbak ng mga ito kapag hindi ito magagamit. Kung ang dalas kung saan kailangang itala ang data ay mas malaki, ang ibang mga uri ng mga protocol ay kailangang imungkahi bilang isang kahalili sa HTTP o kahit palitan TCP sa pamamagitan ng UDP upang maipadala ang karamihan ng data sa kinakailangang bilis kahit na ang halaga ng pagkawala ng ilan.
Ang mga operasyong bumubuo sa gawaing isasagawa upang ipadala ang temperatura ay:
- I-reset ang module ng wifi
- Idiskonekta mula sa kasalukuyang access point (kung sakaling mayroong default na koneksyon)
- Itakda ang mga setting. Para sa halimbawa, ipinapalagay na ang mode ng koneksyon (simple) at ang papel sa mga komunikasyon sa Wi-Fi (istasyon) ay dapat na i-configure.
- Kumonekta sa access point
- I-verify na tama ang koneksyon (sa totoo lang, ito ang entry point) Kung walang koneksyon, simulan ang proseso mula sa simula
- Kumonekta sa server
- Ipadala ang kahilingan HTTP kasama ang data na iimbak
Ang pagkakasunud-sunod ng mga operasyon ay hindi kailangang maging eksakto tulad nito (bagaman ang operasyon ay) at ang bawat hakbang ay maaaring mangailangan ng ilang ESP8266 AT commandHalimbawa, ang configuration na nakalista sa itaas ay mangangailangan ng dalawa: AT+CIPMUX=0
y AT+CWMODE=1
.
Isang istruktura ng data na kumakatawan sa mga operasyon sa ESP8266
Sa mga nakaraang halimbawa, bagama't sa isang napakapangunahing paraan, ang isang generic na solusyon sa problema ay iminungkahi na: gumamit ng istraktura ng data na nag-iimbak ng mga posibleng tugon at mga aksyon na dapat gawin sa bawat kaso; magpadala ng aksyon, maghintay ng tugon, at magpatuloy ayon sa ibig sabihin ng tugon. Dahil ang bawat kumplikadong operasyon ay mangangailangan ng ilang ESP8266 AT command, ang istraktura ng data ay dapat mag-ugnay ng isang operasyon sa iba, kasunod o nakaraan, na dapat isagawa sa bawat kaso depende sa tugon ng ESP8266.
Sa mga nakaraang halimbawa, isang mensahe ang hinanap sa loob ng tugon ng ESP8266 at ito ay binibigyang kahulugan bilang tagumpay o pagkakamali. Bilang karagdagan sa isang pagtanggap (at pagsusuri) ng lahat ng tekstong natanggap, Upang magkaroon ng pangkaraniwang minimum, ipinapayong dumalo din sa pagkumpleto ng mensahe o, sa madaling salita, sa pagkakaroon ng ESP8266 wifi module para makatanggap ng mga bagong order. Sa ganitong paraan, ang pagbabago sa isang estado na maaari naming tawagan, halimbawa, "wifi available", ay maaaring pagtanggap ng pangalan ng access point at pagtanggap ng text ERROR
o ang teksto OK
ay nangangahulugan na ang ESP8266 natapos mo na ang tugon at maaari mo na ngayong ipadala ang susunod AT command sa 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;
|
Ang code sa itaas ay gumagamit ng vector (operacion
) upang iimbak ang teksto ng sunud-sunod na mga operasyon na bumubuo sa kumpletong gawain. Ginagamit ang isang two-dimensional array (mensaje
) kasama ang tatlong tugon na sinusuri. Gaya ng ipinaliwanag sa itaas, kinakailangang hanapin ang mga mensaheng kumakatawan sa dulo ng tugon bilang karagdagan sa mensaheng kumakatawan sa tama o maling tugon. Hindi lahat ng operasyon ay magkakaroon ng parehong bilang ng mga posibleng sagot; Kapag may mas kaunting mga tugon, maaaring gumamit ng walang laman na mensahe na kumukonsumo ng pinakamaliit na posibleng bilang ng mga cycle sa pagsusuri nito (kahit na, hindi ito ang pinakamainam na paraan). Sa lohikal na paraan, kakailanganin para sa pinakamababang bilang ng mga sagot na hinahangad (tatlo sa halimbawa) upang maisama ang lahat ng mga posibilidad sa pagpapatakbo, kahit na hindi lahat ng mga ito ay posible.
Kung pinag-uusapan ang mga posibleng sagot, makikita na ang halimbawang ito ay hindi masyadong kapaki-pakinabang para sa pagtanggap ng data na may arbitrary na format mula sa isang ESP8266 wifi module, ngunit ang bagay ay iyon, sa konteksto ng paggamit sa mga microcontroller ito ay hindi karaniwan; Ang pinakakaraniwang bagay ay ang magpadala ng data na nakolekta ng mga sensor na kanilang ikinonekta at/o tumanggap ng impormasyon tungkol sa kung ano ang gagawin sa mga actuator na kinokontrol nito. Napakahalaga ng impormasyon, na maaaring mahulaan nang mahusay.
Sa nakaraang istraktura ng data, tulad ng ginagawa upang ipahayag ang mga posibleng tugon na nasuri, ginagamit din ang isang dalawang-dimensional na matrix upang matukoy ang operasyon na dapat gawin sa bawat kaso (siguiente_operacion
). Sa partikular, pinili naming tumugon sa tatlong uri ng mga mensahe: ① isang arbitrary na teksto (LITERAL
) para i-verify kung may koneksyon sa Wi-Fi access point at sa server, ② isang text para makakita ng mga error sa proseso (FALLO
) at ③ isang text na nagsasaad na matagumpay na nakumpleto ang operasyon (ACIERTO
).
Sa wakas, may dalawa pang vector upang itakda ang maximum na oras ng paghihintay bago sumuko (timeout
) at tukuyin (configuracion
) kung natapos ang operasyon nang hindi naghihintay ng tugon (ESPERAR_RESPUESTA
) at mga mensaheng nagsasaad ng pagtatapos ng komunikasyon. Ang huling vector na ito, upang ilarawan ang isang halimbawa kung paano mai-save ang memorya, ay gumagana sa mga piraso ng isang configuration byte upang ipahiwatig ang iba't ibang mga estado.
Ang una ESP8266 AT command ng istraktura ng data ay palaging inaasahan ang isang tugon, na maaaring ang tagumpay o mensahe ng error. Kapag may naganap na error, ang module ay ire-restart at ito ay magsisimula muli at kung ang mensahe ay nagpapahiwatig na ang operasyon ay tama, ito ay lilipat sa susunod.
Kapag nakakonekta ka sa server, nagbabago ang pattern. Sa kasong ito, kinakailangan na ① ipadala ang haba ng data packet na ipapadala at ② isulat ang kahilingan HTTP na may nakapirming teksto kasama ang halaga (ng temperatura) na ipinadala upang maiimbak sa server. Ang paghahanda ng data na ito ay isinasagawa sa bawat kargamento at kinakailangang hatiin ito sa dalawa (ipaalam ang haba) o tatlo (ipadala ang kahilingan HTTP) la ESP8266 AT order. Tanging ang huling bahagi kung saan nahahati ang operasyon ang maghihintay ng tugon.
Sa kasong ito ito ay gagana nang walang mga problema (maaaring nagbabala na ang module ay abala) ngunit kapag ang haba ng data ay mas malaki ito ay kinakailangan upang hatiin ang mga bloke ng data sa mas maliliit na piraso at maaaring kailanganin pa na magpatupad ng isang paghihintay, bilang ay tapos na sa pagbabasa ng temperatura, upang bigyan ang module ng oras na ipadala ang data nang hindi pinupunan ito nagpapahina ng lakas.
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();
|
Kasama ng iba pang mga macro na naipaliwanag na dati, ipinapakita ng halimbawang code sa itaas kung paano tinukoy ang iba't ibang estado kung saan tutukuyin kung maghihintay ng tugon at, kung naaangkop, anong mensahe ang nagsasaad na tapos na ito.
Tulad ng sa iba't ibang mga punto sa code ang isang operasyon ay ipapadala (kapag oras na upang ipadala ang average na temperatura, kung ang oras ng paghihintay ng isang operasyon ay lumampas, kapag ang kasalukuyang operasyon ay matagumpay na nakumpleto...) ngunit kung paano ito gagawin ay itinatag sa buong mundo, ito ay tinukoy bilang isang macro ENVIAR_OPERACION
kung aling mga pangkat ang mga hakbang na kasangkot sa pagpapadala.
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();
|
Ang sumusunod ay ang code ng pangunahing programa ng halimbawa. Ang pinaka panlabas na gawain ay ang namamahala sa pag-sample ng temperatura upang kalkulahin ang average at, bawat tiyak na tagal ng panahon, ito ay ipinadala sa server gamit ang ESP8266 wifi module. Kapag naipadala na ang bawat operasyon, susuriin ang tugon upang matukoy kung alin ang susunod o kung natapos na ang gawain ng pagpapadala ng impormasyon.
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
}
}
}
|
Sa lohikal na paraan, maraming mga pagkilos sa pag-optimize ang maaaring isagawa sa nakaraang code ngunit, dahil ito ay isang halimbawa upang maunawaan kung paano ang ESP8266 Sa pangkaraniwang paraan, nararapat lamang na tumuon sa ilang aspeto, ang una ay ang istruktura ng data. Tila ang lohikal na bagay ay gumamit ng isang programming language data structure (struct
) upang kumatawan sa impormasyong pinoproseso: ang ESP8266 AT command at ang mga mensaheng sinusuri.
Gumamit ng istraktura (struct
) na mag-imbak ng data sa halip na mga halimbawang array (batay sa mga ito) ay walang halaga at, bagama't maaari itong magresulta sa mas eleganteng code, hindi ito nagpapahiwatig ng anumang pagpapabuti sa resulta. Ang tunay na alternatibong dulot ng paggamit ng struct
ay ipatupad, tulad ng ipinaliwanag sa ibaba, mga variable na haba sa mga istruktura na naglalaman ng "panloob" na data na tinutukoy nila. Sa ganitong paraan, halimbawa, hindi kinakailangan para sa isang operasyon na magkaroon ng isang nakapirming bilang ng mga tugon upang suriin.
Iminumungkahi ng diskarte na ito na ito ang pinakamahusay na paraan upang ipatupad ang solusyon ngunit ang kawalan ay kinakailangan ito gumamit ng dynamic na paglalaan ng memorya, isang mapanganib na kasanayan sa pagtatrabaho sa a microcontroller na nangangailangan ng maingat na pagsukat kung gaano karaming memory ang gagamitin sa runtime, dahil ang compiler ay halos hindi makapagbabala sa amin tungkol dito at mayroong isang tiyak na posibilidad na maubos ang memorya (o ang stack) na may nakamamatay na kahihinatnan para sa pagpapatupad ng programa.
Sa linya ng pag-optimize ng code, ito ay kagiliw-giliw na tandaan na, sa isang programa ng ganitong uri, na gumagamit ng isang malaking halaga ng teksto, maaaring makatipid ng espasyo sa memorya SRAM pag-iimbak ng mga string ng teksto sa memorya ng programa (flash) kasama ang macro F()
. Sa mga sumusunod na screenshot makikita mo ang iba't ibang programa at dynamic na pamamahagi ng memory na may normal na paggamit ng text at paggamit ng macro F()
.
Sa paggalang sa mga aksyon na isinagawa ayon sa impormasyon na dumating mula sa ESP8266 wifi module, bilang isang alternatibo sa pagsuri sa mensahe mula sa code at pagsasagawa ng isa o sa isa pa ayon sa kung ano ang natanggap, ay maaaring maimbak sa istruktura ng data na ito mga pointer sa mga function na gumaganap sa bawat gawain sa halip na mga indicator ng status (mga flag) na nagbabala sa isang partikular na estado na ang application ay may pananagutan sa pamamahala, halimbawa, sa loob ng pangunahing loop.
Ang sumusunod ay isang halimbawa ng mga istruktura upang mag-imbak ng data ng mga kahilingan sa ESP8266 (ang uri ng data operacion_esp8266
) at ang kanilang mga tugon (ang uri ng data 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;
|
Bilang istraktura na kumakatawan sa operasyon (ang data na ipinadala sa ESP8266 wifi module) ay tumutukoy sa istraktura kung saan tinukoy ang mga tugon, at ang istraktura ng mga tugon sa istruktura ng mga operasyon, kailangang ideklara muna ang dalawa, sa pamamagitan ng pagtukoy sa bagong uri ng data, at pagkatapos ay pagtukoy sa mga nilalaman nito.
Isinasaalang-alang ng nakaraang halimbawa na ang program na kinabibilangan nito ay piniling gumamit ng a tagapagpahiwatig ng katayuan, na dapat tumutugma sa isang variable na naa-access mula sa code na responsable para sa pagsasagawa ng isa o iba pang mga operasyon tulad ng ipinahiwatig ng nasabing halaga. Kung sa tugon ng ESP8266 Kapag nasuri ang isang partikular na teksto, kinukuha ng estado ang halaga na nagpapahiwatig ng istruktura ng kaukulang tugon.
Gaya ng sinabi dati, ang isa pang alternatibo, maaaring palitan o umakma sa indicator ng status, ay mag-imbak ng isang function sa istraktura ng sanggunian (isang pointer) na matatawag kapag nakatagpo ng ilang teksto sa tugon mula sa ESP8266 wifi module.
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;
|
Sa nakaraang halimbawa, idinagdag ito sa istruktura ng data na ginagamit upang iproseso ang tugon mula sa ESP8266 wifi module isang pointer sa isang (dapat) function na nagbabalik ng isang data ng uri float
(maaaring ang timbang na halaga ng isang analog na pagbabasa) at kung saan dalawang byte ang ibinigay bilang mga argumento (dalawang unsigned char
na maaaring ang pin kung saan binabasa ang analog input at ang isa na nagpapagana sa ENABLE ng isang hypothetical integrated).
Sa pag-unlad para sa MCU, salungat sa kung ano ang nangyayari sa istilo ng pag-develop para sa mas malalaking sistema, karaniwan nang gumamit ng mga global na variable kapag tinutukoy ang (global) na pag-uugali ng application na kumokontrol sa isang pagpupulong, kaya hindi magiging bihira na makahanap ng ganitong uri ng mga kahulugan bilang mga pag-andar na walang mga parameter at hindi nagbabalik ng mga halaga, tulad ng void (*accion)();
Kung nagtatrabaho ka sa ganitong paraan ng pagkatawan ng data, gamit struct
ng data ng variable na haba, kakailanganing dynamic na maglaan ng memorya gamit ang malloc()
(o new()
, kung ginagamit ang mga bagay), na gagamit ng halaga ng memorya na inilalaan bilang isang parameter at ibabalik ang isang pointer sa simula ng lugar ng memorya na nakalaan. Sa sizeof()
Sa uri na naka-imbak, na pinarami ng bilang ng mga elemento na ginamit, maaari mong makuha ang halaga ng memorya na kinakailangan. Ang isang halimbawa na mayroon at hindi ginagamit ito ay makikita sa mga screenshot sa ibaba. malloc()
; Mag-ingat sa memorya na ginamit ng programa sa unang kaso, kailangan mong i-load ang library na naglalaman ng function na ito.
Kung ang mga operasyon sa ESP8266 wifi module ay mag-iiba sa buong pagpapatupad ng programa, kakailanganing palayain ang memorya na hindi ginagamit free()
(o delete()
, sa kaso ng pagiging mga bagay). Bagaman makatwirang asahan na ang compiler (GCC) ay i-optimize ang programa upang maiwasan ang memory partitioning, tiyak na ang pagganap ay hindi magiging pinakamainam gaya ng pagtatrabaho sa statically allocated memory.
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
}
}
}
|
Bagaman sa halimbawang ito (sa parehong mga pagpapatupad) ito ay hindi gaanong makatuwiran, upang gawing pangkalahatan ang operasyon upang mailapat ito sa iba pang mga kaso, dapat tandaan na ang pagpapadala ng data ay palaging inuulit ang parehong protocol: ipaalam ang bilang ng mga byte na ipapadala, hintayin ang indicator (>) at ipadala ang data.
Dahil sa halimbawang ito ito ay ginagamit nang isang beses lamang (ang buong kahilingan ay ginawa sa isang packet), ito ay tila hindi masyadong kapaki-pakinabang ngunit, sa pangkalahatan, maaaring kailanganin na magsagawa ng ilang mga pagpapadala sa parehong operasyon, kabilang ang mga kaso kung saan sila ay dapat maipadala ang malalaking halaga ng data na dapat hati-hatiin upang maiwasan ang pag-apaw sa memorya ng ESP8266.
Upang ipatupad ang pag-uugali na ito, ang huling dalawang elemento ng koneksyon ay maaaring gamitin upang sa bawat oras na maipadala ang data, ang data ay mapupuno ng mga kaukulang halaga: sa unang kaso, ang bilang ng mga byte na ipinadala at sa pangalawa, ang ( bahagi ng) kahilingan. ipapasa.
Upang ulitin ang pagtatalaga at pagpapadala ng iba't ibang elemento na dapat ipadala ay maaaring maimbak sa isang vector. Ang bagong vector na ito ang siyang tutukoy sa pagtatapos ng kumplikadong operasyon at hindi sa huling operasyon hanggang ngayon.
1 puna