Arduinon ESP8266 wifi-moduulin perustoiminnot
Kun Espressif lanseerasi ensimmäiset moduulit markkinoille wifi integroidun kanssa ESP8266 ja firmware jonka kanssa käsitellä sitä AT-komennoilla, mikä meitä käyttäjiä kiinnosti oli integroida se kokoonpanoihin mikro-ohjaimet ja ongelmat rajoittuivat (entisen) pimeyden tuntemiseen ESP8266 AT -komentotaulukko, ruokintatarpeet tai ESP8266 laiteohjelmistopäivitys.
Sitten vaihtoehdot saapuivat nopeasti ohjelmoimaan ESP8266 ja moduulien toteutukset wifi hyvin erilaisia muotoja, jotka herättivät muita huolenaiheita: mikä ESP8266 wifi-moduuli valita riippuen eri antennien kantamasta (mukaan lukien ulkoiset) tai näiden uusien moduulien fyysisestä integroinnista kokoonpanoihimme.
Kaikista näistä muutoksista johtuen ei varmaankaan ole painotettu alkeellisia puolia, alkeellisinta hallintaa. ESP8266 wifi-moduuli. Siitä huolimatta napaisuus.es Löydät tietoa käytöstä ESP8266 ja on joitain sovelluksia, joiden tarkoituksena on selittää yleisellä tavalla järjestelmän toimintaa ESP8266 wifi-moduuli käyttämällä AT-komentoja, erityisesti artikkelissa kirjasto HTTP-kyselyjen tekemiseen Arduinosta ESP8266 wifi-moduulilla, lukijoiden vaikutelmat viittaavat siihen, että olisi hyödyllistä lisätä joitakin perustietoja, jotka auttavat käyttäjiä ESP8266 toteuttamaan omia toteutuksiaan.
Keskustele perustoiminnoista, joita voit käyttää ESP8266 ja yleisten ratkaisujen ehdottaminen on useiden hyvin erilaisten osien tavoite; Artikkelin sisällön seuraamisen helpottamiseksi seuraava hakemisto voi toimia oppaana:
- Ohjaa ESP8266 wifi-moduulia tietokoneesta sarjaportin kautta
- Päivitä laiteohjelmisto esptoolilla
- Lähetä tilaukset moduuliin
- Vastaanota tietoja ESP8266:sta
- Analysoi vastaus etsimällä tekstejä sisällöstä
- Rajoita vastauksen saamisen odotusaikaa
- Suorita monimutkainen toiminto, joka on määritelty useilla AT-komennoilla
Ohjaa ESP8266 wifi-moduulia tietokoneesta sarjaportin kautta
lautaselta Työläs ja käyttämällä sinun IDE on mahdollista seurata a ESP8266 wifi-moduuli, Lähetä ESP8266 AT-komennot ja katso vastaus, mutta se on paljon kätevämpää tehdä tietokoneelta päätetyyppisellä sovelluksella.
Riippuen miltä levyltä Työläs Käytettynä vain yksi laitteiston sarjaportti voi olla käytettävissä, mikä lisää hieman vaivaa lähettämiseen ja vastaanottamiseen. Viestintänopeuden muuttaminen on paljon mukavampaa sarjaviestintäsovelluksessa tietokoneesta ja joistakin emolevyistä. Työläs (ja joissakin olosuhteissa) eivät tue hyvin sarjaliikenteen suurempia nopeuksia, etenkään 115200 XNUMX baudia, joka on uusimpien versioiden oletusnopeus. firmware.
Noin Mitä ohjelmaa käyttää valvomaan ESP8266 käyttämällä sarjaporttia, on monia valittavia tarpeiden ja mieltymysten mukaan; Viime aikoina olen käyttänyt klassista enemmän CuteCom (yllä olevassa kuvakaappauksessa), koska minun on erittäin mukava toistaa tiettyjä ESP8266 wifi-moduulin AT-tilaukset projektitestauksessa.
Tässä on jo annettu joitakin suosituksia ohjelmista, jotka toimivat sarjakonsolina; Esimerkiksi kun puhutaan PuTTY UART-sarjalaitteiden ohjaamiseen tietokoneesta. PuTTYSen lisäksi, että se on erinomainen sovellus, se on saatavana useimpiin työpöytäkäyttöjärjestelmiin. Lisäksi as PuTTY voidaan käyttää konsolina sekä sarjaportin että Internet-protokollaperhe (TCP/IP), mukaan lukien ne, jotka toimivat TLS, tulee yleiseksi työkaluksi, joka enemmän kuin korvaa sen määrittämiseen ja sen käyttöön totutteluun käytetyn (vähän) ajan.
Sarjaliikenneohjelmistojen lisäksi yhdistää ESP8266 wifi-moduuli satamaan USB Tietokone vaatii myös muuntimen USB sarjaan TTL. Ohjelmistojen tapaan on olemassa useita versioita, joista niitä käytetään vain portin muuntamiseen USB sarjaportissa TTL (jotka saa yhdestä eurosta) niihin, jotka voivat emuloida erilaisia protokollia (esim SPI o I2C).
Aivan kuten ohjelma, joka toimii sarjakonsolina, laitteisto, jolla kommunikoidaan tietokoneen kanssa USB logiikkapiirillä (ei vain ESP8266) tulee olemaan yleinen työkalu mikroohjatun sovelluskehittäjän työssä, se kannattaa ottaa työkalupakkiin mahdollisimman pian ja työskennellä sen kanssa ESP8266 wifi-moduuli Se on loistava tilaisuus hankkia sellainen.
Muunnin USB a UART TTL Sitä voidaan käyttää myös valvomaan piiriä käyttävän piirin käyttäytymistä ESP8266, tätä varten valvottavat lähdöt kytketään sarjaan muuntimen datatuloon (RX) nopealla diodilla ( 1N4148esimerkiksi) ja vastus (esimerkiksi 2K2) rinnakkain toistensa kanssa. Tällainen kokoonpano toimii kuin laitteistosarjan haistaja.
Vaikka yllä olevan kuvan nuuskija on varmasti alkeellinen (muun muassa sillä ei ole puskuri) riittää valvomaan kokoonpanon toimintaa Työläs ja ESP8266.
Poistamalla haistaja edellisestä järjestelmästä, kaavio, joka näyttää kuinka kytketään a ESP8266 wifi-moduuli lautaselle Työläs. Sen lisäksi, että se syötetään 3V3:lla, integroidun reset-nasta ja aktivointinasta on kytkettävä korkealle tasolle (aktivointi). Tietenkin toisen RX-nastan on yhdistettävä toisen TX-liitäntään.
Edellisen kaavion yksinkertaistamiseksi on esitetty levy Työläs 3V3 ja joiden sarjaportin jännitteen oletetaan myös olevan 3V3. Jos käytät a mikro-ohjain eri signaalitaso sarjaportissa (yleensä 5 V) on tarpeen, jotta laite ei vaurioidu. ESP8266, Käytä tason muunnin kuten alla olevissa kaavioissa. Tämä piiri löytyy usein monista kaupallisista valmiista moduulitoteutuksista.
Päivitä ESP8266 laiteohjelmisto
Las ESP8266 AT-komennot, sen päättäminen, moduulin oletusnopeus... riippuu versiosta ESP8266 laiteohjelmisto. On parasta varmistaa, että sinulla on sama versio kaikissa moduuleissa ja jos mahdollista, että se on uusin versio.
Valitettavasti suurin osa ESP8266 wifi-moduulimallit Niissä on vain 4 Mbit, joten uusinta versiota ei voi asentaa niihin. Laiteohjelmiston uusin (virallinen) versio, johon voidaan asentaa ESP8266 wifi-moduulit 4 Mbit (useimmat) on 0.9.4, joka sisältää version 0.2 ESP8266 AT-komennot.
Yhteenvetona, tarvitsemasi laiteohjelmiston päivittäminen:
-
Lataa vastaava laiteohjelmistoversio. uusin (virallinen) versio moduulille, jossa on 4 Mbit muistia, löytyy githubin Espressif-kansiosta. että Espressifin verkkosivusto Voit ladata laiteohjelmiston uusimman version, mutta on erittäin tärkeää varmistaa, että moduulissa, johon se on asennettu, on tarpeeksi muistia.
-
Lataa laiteohjelmiston asennustyökalun uusin versio. Suosikkini on esptool joka on kirjoitettu Python, joten se toimii millä tahansa alustalla. Sen lisäksi, että se voidaan ladata, se voidaan myös asentaa
pip install esptool
(opip2
opython -m pip
…). Tietysti, Espressif Se tarjoaa myös oman työkalunsa, mutta on tällä hetkellä saatavana vain Windowsille. -
Valmistele ladatut tiedostot; pura ne helppokäyttöiseen kansioon ja tee työkalusta tarvittaessa suoritettava esptool, minun tapauksessani alkaen GNU / Linux, With
chmod +x esptool
-
Liitä moduuli tietokoneeseen muuntimen avulla USB UART TTL joka toimii 3V3:ssa tai käytä tasomuunninta, jos se toimii 5 V:lla. Tehon lisäksi sinun on kytkettävä muuntimen TX RX:ään USB UART TTL, RX to TX, GPIO0 alhaisella tasolla (GND) ja ehkä GPIO2 korkealla tasolla (omissa testeissäni se on toiminut sekä kytkemällä sitä matalalla tasolla että irrottamalla sen). Jos moduulissa on vapaa GPIO15-liitäntä (kuten ESP-12:ssa), se on kytkettävä matalalle tasolle. RESET, joka normaalisti olisi käytön aikana korkealla tasolla, voidaan jättää kytkemättä tai liittää korkealle tasolle vastuksen avulla (esim. 10K), koska ennen tallennuksen aloittamista laite saattaa olla tarpeen nollata kytkemällä se. matalalle tasolle.
Kun moduuli käynnistetään, se on päivitettävissä, mutta Jos näyttöön tulee yhteysvirhe, se on nollattava kytkemällä RESET hetkeksi matalalle tasolle ja jättämällä sen sitten lähetykseen (ilman yhteyttä) päivitysprosessia varten.
Moduulilla on puolen ampeerin kulutushuiput (jopa 600 mA, joidenkin käyttäjien mukaan), joten on tärkeää käyttää virtalähdettä, joka pystyy tukemaan tätä kulutusta, erityisesti laiteohjelmiston päivityksessä. -
Päivitä laiteohjelmisto suorittamalla työkalu. Minun tapauksessani olen tallentanut työkalun ja laiteohjelmiston asiakirjat vaiheessa 3 samaan kansioon, joten käytän konsolista:
cd ~/Datos/firmwareESP8266
(vaihda kansioon, joka sisältää työkalun ja laiteohjelmiston)./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
asettaa nopeuden ESP8266 (115200 baudia minun tapauksessani) ja--port
sarjaportti, johon se liitetään (minun tapauksessani emuloitu ensimmäinen USB). Laiteohjelmiston muodostavat erilaiset asiakirjat jäävät taaksewrite_flash
edeltää osoite ja user1.bin-asiakirja, joka sisältää päivityksen hyötykuorman.
Lähetä komennot ESP8266 wifi-moduuliin
Hallitaksesi ESP8266 tietokoneelta, josta meidän on aloitettava määritä sovellus jolle riittää ① valitsemaan portti, johon muunnin on kytketty USB UART TTL, vähän niin kuin /dev/USB0
GNU/Linuxissa ja vastaavassa tai vastaavassa COM6
Windowsissa ② valitse nopeus, jolla ESP8266, luultavasti 115200 8 baudia, ③ aseta XNUMX databittiä plus yksi pysäytysbitti ilman pariteettia tai kättelyä ja ④ aseta rivin loppu riippuen firmware, melkein aina CR+LF.
Kun sovellus on määritetty (tai tarvittaessa tallennettu ja valittu), se on avaa yhteys ("open laite" ja "open", vastaavasti, yllä olevien esimerkkien kuvakaappauksissa CuteCom y PuTTY) ja voit alkaa lähettää tilauksia osoitteeseen ESP8266.
Kuten voidaan nähdä ESP8266 AT -komentotaulukko, aktivoinnin, deaktivoinnin, arvon asettamisen ja siihen viittaamisen muoto on varsin ennakoitavissa, mutta yleisesti ottaen niitä ei ole helppo muistaa ja tarvitset todennäköisesti sen käsillä, jotta voit viitata siihen.
Tapa lähettää AT käskyt al ESP8266 wifi-moduuli alkaen Työläs on hyvin yksinkertainen: ① määritä viestintä Serial.begin(115200);
(tai Serial1, Serial2… levyillä, joissa on useita laitteiston sarjaportteja) ja ② lähettää komennot muodossa 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()
{
}
|
Yllä oleva esimerkki näyttää, kuinka lähettää ESP8266 wifi-moduulin AT-tilaukset alkaen Työläs. Tässä tapauksessa se on kuvattu AT+CWJAP
, jota käytetään yhteyden muodostamiseen tukiasemaan. Tämä komento käyttää argumentteina tukiaseman tunnistetta (SSID) ja avain, molemmat lainausmerkeissä, joten niistä tulee esine Srtring
ja kirjoita ne lainausmerkkeihin käyttämällä estokoodia (\"
). Suorita tilaus loppuun käyttämällä \r\n
joka vastaa CR
y LF
.
Muista, että sarjaporttia ei aina tunnisteta Serial
(tietyillä levyillä se voi olla Serial1
, Serial2
…) käytetty porttiobjekti on määritetty määrittämällä se makrolle PUERTO_SERIE
. Käytetyn kortin tyypin tunnistaminen voisi lisätä älykkyyttä sarjaportin valintaan; Myöhemmin käymme läpi, kuinka voit selvittää tyypin Työläs. Loput määritelmät ovat tavallisia, joiden avulla voit "nimetä" vakioarvot välttääksesi niiden toistamisen (ja virheiden tekemisen) ja helpottaaksesi niiden vaihtamista.
Yllä olevan esimerkin on tarkoitus yhdistää ESP8266 wifi-moduuli ilmoitettuun tukiasemaan, mutta oliko se jo yhdistetty aiemmin? Onko yhteys toiminut? Tietääksemme tämän, meidän on "kuunneltava" mitä ESP8266
Vastaanota tiedot ESP8266 wifi-moduulista
Yhdistämällä yllä selitetyn datan haistelijan tietokoneeseen näet mitä Työläs on lähettänyt osoitteeseen ESP8266 ja hänen vastauksensa. Lukemaan alkaen Työläs ja käsitellä siinä olevat tiedot, se on tarpeen havaita Serial.available()
jos tietoja on saapunut ja jos on, lataa se Serial.read()
. Seuraava esimerkki näyttää, kuinka vastaus luetaan AT+CWJAP?
, joka ilmoittaa, onko yhteys mihin tahansa tukiasemaan.
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();
}
}
|
Kuin lautasella Arduino Uno (ja muissa) sarjanäytön avaaminen nollaa ohjelman, sitä voidaan käyttää sarjakonsolissa Työläs tiedot, joille lähetät ESP8266 kuten alla olevan kuvan kuvakaappaus osoittaa.
Analysoi ESP8266 wifi-moduulin lähettämä vastaus
Olemme jo nähneet, kuinka luetaan saapuva tieto Työläs alkaen ESP8266. Ongelma, jota sinun on käsiteltävä, on se, että et tiedä milloin se alkaa saapua, kuinka kauan sen saapuminen kestää, kuinka pitkä se on... ja ei ole kovin tehokasta odottaa vastausta ESP8266 vastaanotetaan antamatta mikro-ohjain suorittaa muita tehtäviä sillä välin.
Yksinkertainen tapa hallita tätä tilannetta on iteroida saatuja tietoja ja etsiä konkreettisia vastauksia jolla esimerkiksi aktivoidaan indikaattoreita (lippuja tai Boolen muuttujia), jotka määrittävät, jatketaanko hakua vastaanotetusta tekstistä ja mitä toimia tulee tehdä tekstistä saapuvien tietojen perusteella. ESP8266. Kun vastaus saapuu mikro-ohjain voi omistautua muihin tehtäviinesimerkiksi vastaanottaa dataa antureilta ja käsitellä niitä.
Etsi tekstiä ESP8266:lta saaduista tiedoista
Etsiäksesi tekstiä, joka tulee kohteesta ESP8266 voit vertaa jokaista vastaanotettua kirjettä siihen, joka vastaa etsimääsi viestiä. On tarpeen käyttää laskuria (tai osoitinta), joka osoittaa verrattavaan kirjaimeen; Jos hahmo, joka saapuu ESP8266 on sama kuin viestissä tutkittava, laskuri etenee, jos se on eri, se alustetaan.
Tietääkseen, että loppu on saavutettu, etsitään haetun viestin seuraavaa merkkiä, joka on nolla (\0
) tai viestin pituus tallennetaan, jotta sitä vertaamalla laskuriin saadaan selville, onko vertailu päättynyt ja siksi ESP8266 wifi-moduuli on lähettänyt halutun viestin.
Seuraava esimerkki käyttää komentoa AT+CWLAP
joka palauttaa luettelon tukiasemista ja niistä etsitään "wifi polaridad.es". Vaikka olemme päättäneet varmistaa, että viimeinen merkki on nolla, koska puskuri Se tallentaa vain haetun tekstin ja sen pituus on tiedossa, voisi myös tarkistaa, onko tullut näin paljon oikeita kirjaimia. Kanssa LED kytketty nastaan 2 ilmoitetaan, että odotettu teksti on löydetty.
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
}
}
}
}
|
Edellisen esimerkin koodissa näet myös tavan Valitse sarjaportti kortin tyypin mukaan Työläs käytetty. Tässä esimerkissä oletetaan, että sinulla on kolme tyyppistä levyä projektia varten: yksi Arduino Uno, One Arduino Mega 2560 ja arduino leonardo. Jos työskentelet a Arduino Uno sitä käytetään Serial
ja muuten Serial1
.
Jos työskentelet lautasen kanssa arduino leonardo Voit käyttää samaa tapaa pysäyttääksesi ohjelman ja odottaa konsolia (sarjaportti, joka liittyy Serial
) on käytettävissä.
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
|
Etsi erilaisia tekstejä ESP8266-vastauksesta
Edellisen esimerkin koodia käytetään tekstin etsimiseen lähettämistä tiedoista ESP8266 mutta vastaus voi sisältää erilaisia tietoja operaatiosta riippuen. Oletetaan, että seuraavassa esimerkissä aloitetaan yksinkertaisella tapauksella, että MCU ESP8266 es OK
kun toimenpide suoritetaan oikein ja ERROR
Muuten, kuten tilauksen kanssa AT+CWJAP?
, jonka avulla varmistetaan, onko ESP8266 wifi-moduuli on jo yhdistetty tukiasemaan.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
#if defined(ARDUINO_AVR_LEONARDO)||defined(ARDUINO_AVR_MEGA2560) /* ¿Es una placa Arduino Mega 2560 o Arduino Leonardo? */
#define SERIE Serial1 /* Si es una placa Arduino Mega 2560 o Arduino Leonardo usar Serial1 */
#else /* En este proyecto solamente uso Placas Leonardo, Mega 2560 y Uno, así que tiene que ser un Arduino Uno si llega hasta aquí */
#define SERIE Serial /* Si es una placa Arduino Uno usar Serial */
#endif
#define VELOCIDAD 115200 // Velocidad (en baudios) al que está configurado el módulo wifi ESP8266 (Cuidado con la placa utilizada, no todas o siempre son capaces de trabajar a una velocidad tan alta)
#define ORDEN “AT+CWJAP?\r\n” // Verificar que está conectado a un punto de acceso
#define CANTIDAD_MENSAJES 2 // Se distingue entre dos mensajes: acierto y error que se identificarán con true y false
#define MENSAJE_ACIERTO “OK”
#define MENSAJE_ERROR “ERROR”
#define LONGITUD_MENSAJE 6 // Se necesita guardar, al menos, 5 letras y el terminador \0 (Un pequeño desperdicio al hacer una matriz en la que todos los elementos ocupan como el mayor. Es admisible porque son muy pocos elementos y así no se complica este ejemplo inicial)
#define PIN_LED_ACIERTO 2 // Pin al que se conecta el LED que informa del acierto
#define PIN_LED_ERROR 3 // Pin al que se conecta el LED que informa del error
#include <string.h> // strncpy
boolean esperando=true; // Todavía no se ha encontrado el final del mensaje
char buffer_mensaje; // Para almacenar la última letra cargada desde el ESP8266
byte led_estado[CANTIDAD_MENSAJES]; // Un LED (pin) para cada estado
char mensaje[CANTIDAD_MENSAJES][LONGITUD_MENSAJE]; // Mensajes de acierto y error
byte posicion_mensaje[CANTIDAD_MENSAJES]; // Un contador de posición para cada mensaje
void setup()
{
led_estado[true]=PIN_LED_ACIERTO;
led_estado[false]=PIN_LED_ERROR;
for(byte numero_mensaje=0;numero_mensaje<CANTIDAD_MENSAJES;numero_mensaje++)
{
pinMode(led_estado[numero_mensaje],OUTPUT); // Establecer el pin del LED
digitalWrite(led_estado[numero_mensaje],LOW); // Apagar el LED
posicion_mensaje[numero_mensaje]=0; // Inicializar a cero el número de letra a analizar de cada mensaje
}
strncpy(mensaje[true],MENSAJE_ACIERTO,LONGITUD_MENSAJE); // Preparar el mensaje de acierto
strncpy(mensaje[false],MENSAJE_ERROR,LONGITUD_MENSAJE); // Preparar el mensaje de error
SERIE.begin(VELOCIDAD); // Configurar el puerto serie de Arduino a la velocidad del ESP8266
SERIE.print(ORDEN); // Enviar la orden (verificar si existe conexión a un punto de acceso) al módulo wifi ESP8266
}
void loop()
{
if(esperando) // Buscará infinitamente hasta que llegue el texto esperado (y si no existe el punto de acceso nunca llegará ¡Es un ejemplo!)
{
while(SERIE.available()) // Si ha llegado algún dato por el puerto serie…
{
buffer_mensaje=SERIE.read(); // …almacenarlo en el buffer
for(byte numero_mensaje=0;numero_mensaje<CANTIDAD_MENSAJES;numero_mensaje++)
{
if(buffer_mensaje==mensaje[numero_mensaje][posicion_mensaje[numero_mensaje]]) // Si el dato que ha llegado es igual al que correspondería del mensaje buscado…
{
posicion_mensaje[numero_mensaje]++; // Pasar a la siguiente letra del mensaje
if(mensaje[numero_mensaje][posicion_mensaje[numero_mensaje]]==0) // ¿Ha terminado de analizarse todo el mensaje actual? (la última letra de la cadena de texto es \0)
{
esperando=false; // Si se ha encontrado algún mensaje y ya no se está esperando
digitalWrite(led_estado[numero_mensaje],HIGH); // Encender el LED correspondiente al mensaje encontrado
}
}
else // Si la letra que ha llegado por el puerto serie no corresponde con la buscada del mensaje…
{
posicion_mensaje[numero_mensaje]=0; // …empezar desde la primera letra del texto buscado
}
}
}
}
}
|
Tämä saman menetelmän uusi toteutus, joka etsii vastinetta useista mahdollisista viesteistä, antaa sinun valita eri toiminnoista riippuen ESP8266, kytke vain virta päälle LED vastaava.
Rajoita vastauksen saamiseen kuluvaa aikaa
Tähän mennessä ei ole viitattu asiaankuuluvaan asiaan: the suurin odotusaika (aikakatkaisu), ennen kuin toiminnon katsotaan epäonnistuneen. Jos jostain syystä yhteys ESP8266 wifi-moduuli, tukiaseman sisältävä moduuli, Internet-yhteyspiste tai esimerkiksi hypoteettinen palvelin ei ole käytettävissä, ohjelma voi olla estetty jossain kohdassa odottamassa määräämättömäksi ajaksi, joten tällaisiin olosuhteisiin on vastattava. Maksimi odotusaika voidaan konfiguroida koko sovellukselle, yleensä se on silloin "anteliaampi" tai kullekin toiminnolle voidaan ohjelmoida omat odotusajat.
Tarkistaaksesi, että (ainakin) tietty aikaväli on kulunut Tilin aloitushetken "aika" vähennetään yleensä nykyisestä "ajasta" ja varmistetaan, että ero on suurempi kuin haluttu raja. Tämän "ajan" ei tarvitse olla reaaliaikaista, se vastaa yleensä aikaväliä, joka on kulunut MCU alkaa laskea aikaa; Tämä ei vaikuta ohjelmaan, koska kiinnostavaa on kulunut aika, ei absoluuttinen aika.
Yleensä sen tarkistamiseksi, onko tietty aika kulunut, käytetään tyyppiä olevaa lauseketta:
1
|
(unsigned long)(millis()–milisegundos_al_empezar)>intervalo_de_tiempo
|
muuttuja milisegundos_al_empezar
sisältää arvon millis()
tietystä suoritushetkestä, josta alkaen se on ajastettu, joten ei ole epätavallista, että sen nimi viittaa sanaan "kronometri". Muuttuja intervalo_de_tiempo
sisältää millisekuntien enimmäismäärän, joka tekee edellisestä lausekkeesta tosi, eli se edustaa aikakatkaisua; Se on yleensä vakio (tai makro), ja, kuten edellisessä tapauksessa, sana "TIMEOUT" esiintyy usein sen nimessä. Jos työskentelet hyvin lyhyin väliajoin, voit käyttää micros()
sijaan millis()
(mikrosekuntia millisekuntien sijasta), vaikka se on paljon harvinaisempaa ja paljon vähemmän tarkka.
1
|
(unsigned long)(millis()–cronometro)>TIMEOUT
|
Pitkä kokonaisluku sisään Työläs (unsigned long
) vie 4 tavua (32 bittiä), joten suurin arvo, jota se voi edustaa, on 4294967295 (2 potenssiin 32 miinus yksi, koska se alkaa nollasta). lautasella Työläs Kun millisekunnin laskuri on käynnissä jatkuvasti, se nollautuu (palaa nollaan) noin 50 päivän välein. Kun vähennetään etumerkittömistä tietotyypeistä, sama käyttäytyminen toistuu (laskurin kääntäminen), joten aikakatkaisua voidaan hallita loputtomiin.
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;
}
}
}
|
Yllä oleva koodi näyttää a aikakatkaisurajoituksen hyvin yksinkertainen toteutus sisältäen sitä edeltävään esimerkkiin merkityt rivit. Koska aikakatkaisun varmistus suoritetaan osoitteesta saapuneiden tietojen käsittelyn jälkeen ESP8266 wifi-moduuli, toimintoa voidaan pitää onnistuneena, vaikka vastaanotto kestää kauemmin kuin määrätty odotusaika.
Suorita monimutkainen toiminto, joka on määritelty useilla AT-komennoilla
Saadaksesi esimerkkiviittauksen sovelluksen tarkoituksesta, joka hyödyntää ESP8266 wifi-moduuli, oletetaan että on tallentaa tietoja tietokantaan, johon pääsee verkkopalvelun kautta seurata lämpötilaa. Seuraava koodi lukee analogiseen tuloon kytketyn anturin tietyn aikavälin välein, laskee keskiarvon ja lähettää sen pidemmän aikavälin jälkeen web-palvelimelle (tyyli Esineiden internet) kautta a adressi HTTP (LÄHETÄ, HANKI…).
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”);
}
}
|
Tässä lämpötilan tallennusesimerkissä web-palvelinta käytetään viiden minuutin välein. Vaikka saatavuus ei ole erityisen korkea, on odotettavissa, että ehdotus toimisi, mutta jos korkeampi tallennustaajuus olisi tarpeen, jouduttaisiin toteuttamaan muita resursseja, esim. datapuskuri odottaa lähettämistä, lähettää useita, kun palvelin voi osallistua ja tallentaa ne, kun se ei ole käytettävissä. Jos tietojen tallennustiheys olisi vieläkin suurempi, vaihtoehtona olisi ehdotettava muuntyyppisiä protokollia. HTTP tai edes vaihtaa TCP mukaan UDP pystyä lähettämään suurimman osan tiedoista vaaditulla nopeudella jopa osan menettämisen kustannuksella.
Toiminnot, jotka muodostavat tehtävän lämpötilan lähettämiseksi, olisivat:
- Nollaa wifi-moduuli
- Katkaise yhteys nykyiseen tukiasemaan (jos oletusyhteys on olemassa)
- Aseta asetukset. Esimerkissä oletetaan, että yhteystila (yksinkertainen) ja rooli Wi-Fi-viestinnässä (asema) on määritettävä.
- Yhdistä tukiasemaan
- Varmista, että yhteys on oikea (itse asiassa tämä on sisääntulopiste) Jos yhteyttä ei ole, aloita prosessi alusta
- Yhdistä palvelimeen
- Lähetä pyyntö HTTP tallennettavien tietojen kanssa
Toimintojen järjestyksen ei tarvitse olla täsmälleen tällainen (vaikka operaatio on) ja jokainen vaihe voi vaatia useita ESP8266 AT-komennotEsimerkiksi yllä lueteltu kokoonpano tarvitsee kaksi: AT+CIPMUX=0
y AT+CWMODE=1
.
Tietorakenne, joka edustaa ESP8266:n toimintoja
Edellisissä esimerkeissä, vaikkakin hyvin yksinkertaisella tavalla, ongelmaan ehdotetaan jo yleistä ratkaisua: käyttää tietorakennetta, joka tallentaa mahdolliset vastaukset ja toimenpiteet, jotka on tehtävä kussakin tapauksessa; lähetä toiminto, odota vastausta ja jatka sen mukaan, mitä vastaus tarkoittaa. Koska jokainen monimutkainen toimenpide vaatii useita ESP8266 AT-komennot, tietorakenteen on linkitettävä toiminto muihin, myöhempiin tai edellisiin, jotka on suoritettava jokaisessa tapauksessa riippuen ESP8266.
Aiemmissa esimerkeissä viestiä etsittiin vastauksesta ESP8266 ja se tulkittiin menestykseksi tai virheeksi. Kaiken vastaanotetun tekstin vastaanottamisen (ja analysoinnin) lisäksi Yleisen vähimmäismäärän saamiseksi on suositeltavaa huolehtia myös viestin valmistumisesta tai toisin sanoen sen saatavuuteen ESP8266 wifi-moduuli vastaanottaa uusia tilauksia. Tällä tavalla muutos tilaan, jota voisimme kutsua esimerkiksi "wifi käytettävissä", voisi olla tukiaseman nimen vastaanottaminen ja tekstin vastaanottaminen ERROR
tai tekstiä OK
tarkoittaisi, että ESP8266 olet saanut vastauksen valmiiksi ja voit nyt lähettää seuraavan AT-komento ESP8266:een.
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;
|
Yllä oleva koodi käyttää vektoria (operacion
) tallentaaksesi koko tehtävän muodostavien peräkkäisten toimintojen tekstin. Käytetään kaksiulotteista taulukkoa (mensaje
) kolmella analysoitavalla vastauksella. Kuten edellä on selitetty, oikeaa tai väärää vastausta edustavan viestin lisäksi on tarpeen etsiä viestejä, jotka edustavat vastauksen loppua. Kaikilla operaatioilla ei ole samaa määrää mahdollisia vastauksia; Kun vastauksia on vähemmän, voidaan käyttää tyhjää viestiä, joka kuluttaa analyysissaan mahdollisimman vähän jaksoja (se ei kuitenkaan ole optimaalisin tapa). Loogisesti on välttämätöntä, että haettujen vastausten vähimmäismäärä (esimerkissä kolme) sisältää kaikki toimintamahdollisuudet, vaikka ne eivät olisikaan mahdollisia.
Mahdollisista vastauksista puhuttaessa on jo nähtävissä, että tämä esimerkki ei ole kovin hyödyllinen tiedon vastaanottamiseen mielivaltaisessa muodossa. ESP8266 wifi-moduuli, mutta asia on, että käytön yhteydessä mikro-ohjaimet se ei ole tavallista; Yleisin asia on lähettää niiden liittämien antureiden keräämiä tietoja ja/tai vastaanottaa tietoa siitä, mitä sen ohjaamille toimilaitteille tehdään. Erittäin arvokasta tietoa, joka voidaan ennustaa erittäin hyvin.
Edellisessä tietorakenteessa, aivan kuten se tehdään mahdollisten analysoitavien vastausten ilmaisemiseksi, kaksiulotteista matriisia käytetään myös määrittämään kussakin tapauksessa suoritettava toiminto (siguiente_operacion
). Erityisesti olemme päättäneet vastata kolmentyyppisiin viesteihin: ① mielivaltainen teksti (LITERAL
) varmistaaksesi, onko yhteys Wi-Fi-tukiasemaan ja palvelimeen, ② teksti prosessin virheiden havaitsemiseksi (FALLO
) ja ③ teksti, joka osoittaa, että toiminto on suoritettu onnistuneesti (ACIERTO
).
Lopuksi on vielä kaksi vektoria, joilla asetetaan maksimi odotusaika ennen luovuttamista (timeout
) ja määritä (configuracion
) jos toiminto päättyy odottamatta vastausta (ESPERAR_RESPUESTA
) ja viestit, jotka osoittavat viestinnän päättymisen. Tämä viimeinen vektori, joka havainnollistaa esimerkkiä muistin säästämisestä, toimii konfigurointitavun bittien kanssa osoittamaan eri tilat.
Ensimmäinen ESP8266 AT-komennot Tietorakenteesta odotetaan aina vastausta, joka voi olla onnistumis- tai virheilmoitus. Virheen sattuessa moduuli käynnistetään uudelleen ja se käynnistyy uudelleen ja jos viesti osoittaa, että toiminta on oikein, siirrytään seuraavaan.
Kun olet muodostanut yhteyden palvelimeen, kuvio muuttuu. Tässä tapauksessa on tarpeen ① lähettää lähetettävän datapaketin pituus ja ② laatia pyyntö HTTP kiinteällä tekstillä plus arvo (lämpötila), joka lähetetään tallennettavaksi palvelimelle. Näiden tietojen valmistelu suoritetaan jokaisessa lähetyksessä ja se on tarpeen jakaa kahteen (ilmoita pituus) tai kolmeen (lähetä pyyntö) HTTP) On ESP8266 AT tilaus. Vain viimeinen osa, johon toimenpide on jaettu, odottaa vastausta.
Tässä tapauksessa se toimii ilman ongelmia (ehkä varoittaa, että moduuli on varattu), mutta kun datan pituus on suurempi, on tarpeen jakaa tietolohkot pienempiin osiin ja saattaa jopa olla tarpeen toteuttaa odotus, koska tehdään lämpötilalukemalla, jotta moduulille jää aikaa lähettää tiedot täyttämättä sitä puskuri.
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();
|
Yllä oleva esimerkkikoodi näyttää yhdessä muiden jo aiemmin selostettujen makrojen kanssa, kuinka eri tilat määritellään, joilla määritetään, onko vastausta odotettava ja mikä viesti ilmoittaa, että se on valmis.
Koska koodin eri kohdissa lähetetään toiminto (kun on aika lähettää keskilämpötila, jos toimenpiteen odotusaika ylittyy, kun nykyinen toiminto on suoritettu onnistuneesti...) mutta miten se tehdään perustettu maailmanlaajuisesti, se on määritelty makroksi ENVIAR_OPERACION
joka ryhmittelee toimitukseen liittyvät vaiheet.
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();
|
Seuraava on esimerkin pääohjelman koodi. Ulkopuolisin tehtävä on se, joka vastaa lämpötilan näytteenotosta keskiarvon laskemiseksi ja joka tietyn ajanjakson, se lähetetään palvelimelle käyttämällä ESP8266 wifi-moduuli. Kun jokainen toiminto on lähetetty, vastaus analysoidaan sen määrittämiseksi, kumpi on seuraava vai onko tiedon lähetystehtävä suoritettu.
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
}
}
}
|
Loogisesti edelliselle koodille voidaan suorittaa useita optimointitoimenpiteitä, mutta koska tämä on esimerkki, jotta voidaan ymmärtää, kuinka ESP8266 Yleisesti ottaen kannattaa keskittyä vain joihinkin näkökohtiin, joista ensimmäinen on tietorakenne. Näyttää siltä, että asia on looginen käytä ohjelmointikielen tietorakennetta (struct
) edustamaan käsiteltävää tietoa: ESP8266 AT-komennot ja viestit, jotka analysoidaan.
Käytä rakennetta (struct
) tietojen tallentaminen esimerkkitaulukoiden sijaan (niiden perusteella) on triviaalia ja vaikka se saattaakin johtaa tyylikkäämpään koodiin, se ei tarkoita parannuksia tulokseen. Todellinen vaihtoehto käytön struct
on toteutettava, kuten alla selitetään, muuttuvat pituudet rakenteissa, jotka sisältävät "sisäistä" dataa joihin he viittaavat. Tällä tavalla esimerkiksi operaatiolla ei tarvitsisi olla kiinteää määrää analysoitavia vastauksia.
Tämä lähestymistapa viittaa siihen, että se on paras tapa toteuttaa ratkaisu, mutta haittapuolena on, että se olisi tarpeen käytä dynaamista muistin varausta, riskialtista käytäntöä työskennellä a mikro-ohjain mikä edellyttää huolellista mittaamista sen suhteen, kuinka paljon muistia käytetään ajon aikana, koska kääntäjä tuskin voi varoittaa meitä tästä ja on olemassa tietty mahdollisuus tyhjentää muisti (tai pino), millä on kohtalokkaat seuraukset ohjelman suorittamiselle.
Koodin optimoinnin yhteydessä on mielenkiintoista muistaa, että tämän tyyppisessä ohjelmassa, joka käyttää paljon tekstiä, voi säästää muistitilaa SRAM tekstijonojen tallentaminen ohjelmamuistiin (salama) makron kanssa F()
. Seuraavissa kuvakaappauksissa näet eri ohjelman ja dynaamisen muistin jakautumisen normaalilla tekstinkäytöllä ja makroa käyttämällä F()
.
Mitä tulee toimiin, jotka suoritetaan osoitteesta tulevien tietojen mukaan ESP8266 wifi-moduuliVaihtoehtona viestin tarkistamiselle koodista ja jommankumman suorittamiselle vastaanotetun mukaan, voidaan tallentaa tähän tietorakenteeseen. osoittimia toimintoihin, jotka suorittavat kunkin tehtävän tilailmaisimien sijaan (liput), jotka varoittavat tietystä tilasta, että sovellus on vastuussa esimerkiksi pääsilmukan hallinnasta.
Seuraavassa on esimerkki rakenteista, joilla pyyntöjen tiedot tallennetaan ESP8266 (tietotyyppi operacion_esp8266
) ja niiden vastaukset (tietotyyppi 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;
|
Rakenteena, joka edustaa toimintoa (tiedot, jotka lähetetään ESP8266 wifi-moduuli) viittaa rakenteeseen, jolla vastaukset määritellään, ja vastausten rakenteeseen operaatioiden rakenteeseen, on välttämätöntä ilmoittaa molemmat ensin, määrittämällä uuden tietotyypin ja määrittämällä sitten sen sisällön.
Edellisessä esimerkissä katsotaan, että sen sisältävä ohjelma on valinnut a tilailmaisin, jonka on vastattava koodista saatavilla olevaa muuttujaa, joka on vastuussa yhden tai muun toiminnon suorittamisesta mainitun arvon osoittamana. Jos vastauksessa ESP8266 Kun tiettyä tekstiä analysoidaan, tila ottaa arvon, joka ilmaisee vastaavan vastauksen rakenteen.
Kuten aiemmin mainittiin, toinen vaihtoehto, joko tilailmaisimen korvaaminen tai täydentäminen, olisi tallentaa funktion viiterakenteeseen (osoitin), jota kehotetaan kohtaamaan tietyn tekstin vastauksessa ESP8266 wifi-moduuli.
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;
|
Edellisessä esimerkissä se on lisätty tietorakenteeseen, jota käytetään lähettämän vastauksen käsittelemiseen ESP8266 wifi-moduuli osoitin (oletettuun) funktioon, joka palauttaa tyyppisen tiedon float
(voi olla analogisen lukeman painotettu arvo) ja jolle annetaan kaksi tavua argumentteina (kaksi unsigned char
joka voi olla nasta, josta analoginen tulo luetaan, ja se, joka aktivoi hypoteettisen integroidun ENABLE:n).
Kehityksessä MCU, toisin kuin suurempien järjestelmien kehitystyylissä, ei ole niin harvinaista käyttää globaaleja muuttujia määriteltäessä kokoonpanoa ohjaavan sovelluksen (globaalia) käyttäytymistä, joten tämän tyyppisten määritelmien löytäminen ei ole erityisen harvinaista. funktioina ilman parametreja ja jotka eivät palauta arvoja, jotain sellaista void (*accion)();
Jos käytät tätä tapaa esittää tiedot, käytä struct
vaihtuvamittaista dataa, on tarpeen varata muistia dynaamisesti malloc()
(o new()
, jos objekteja käytetään), joka käyttää parametrina varatun muistin määrää ja palauttaa osoittimen varatun muistialueen alkuun. Kanssa sizeof()
Tallennetusta tyypistä kerrottuna käytettyjen elementtien määrällä saat tarvittavan määrän muistia. Esimerkki sen käyttämisestä ja ilman sitä voidaan nähdä alla olevissa kuvakaappauksissa. malloc()
; Ole varovainen ohjelman käyttämän muistin kanssa ensimmäisessä tapauksessa, sinun on ladattava kirjasto, joka sisältää tämän toiminnon.
Jos toiminnot ESP8266 wifi-moduuli vaihtelee ohjelman suorittamisen aikana, on tarpeen vapauttaa muisti, jota ei käytetä free()
(o delete()
, jos ne ovat esineitä). Vaikka on kohtuullista olettaa, että kääntäjä (GCC) optimoi ohjelman välttääkseen muistin osioinnin, suorituskyky ei varmasti ole yhtä optimaalinen kuin työskentely staattisesti varatun muistin kanssa.
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
}
}
}
|
Vaikka tässä esimerkissä (molemmissa toteutuksissa) ei ole paljon järkeä, operaation yleistämiseksi, jotta sitä voidaan soveltaa muihin tapauksiin, on huomattava, että Tietojen lähetys toistaa aina samaa protokollaa: ilmoita lähetettävien tavujen määrä, odota ilmaisinta (>) ja lähetä tiedot.
Koska tässä esimerkissä sitä käytetään vain kerran (koko pyyntö tehdään yhdessä paketissa), se ei vaikuta kovin hyödylliseltä, mutta yleensä voi olla tarpeen suorittaa useita lähetyksiä samassa toiminnossa, mukaan lukien tapaukset, joissa ne on siirrettävä merkittäviä tietomääriä, jotka on pirstaloitava, jotta vältetään muistin täyttyminen ESP8266.
Tämän käyttäytymisen toteuttamiseksi voidaan käyttää yhteyden kahta viimeistä elementtiä siten, että joka kerta kun data lähetetään, tieto täytetään vastaavilla arvoilla: ensimmäisessä tapauksessa lähetettyjen tavujen määrä ja toisessa ( osa pyyntöä.
Toistaaksesi osoituksen ja lähettämisen eri elementit, jotka on lähetettävä, voidaan tallentaa vektoriin. Tämä uusi vektori määrittää monimutkaisen operaation lopun, eikä viimeinen operaatio kuten tähän asti.
1 kommentti