Grundlegende Operationen auf einem ESP8266-WLAN-Modul von Arduino
wenn Espressiv brachte die ersten Module auf den Markt Wi-Fi mit der integrierten ESP8266 und Firmware Um es mit AT-Befehlen handhaben zu können, waren wir Benutzer daran interessiert, es in Baugruppen zu integrieren Mikrocontroller und die Probleme reduzierten sich darauf, das (ehemals) Dunkle zu kennen ESP8266 AT-Befehlstabelle, Futterbedarf bzw ESP8266-Firmware-Update.
Dann kamen schnell Alternativen, um das zu programmieren ESP8266 und Modulimplementierungen Wi-Fi sehr unterschiedlicher Formate, die andere Bedenken aufkommen ließen: welches ESP8266-WLAN-Modul Sie wählen sollen abhängig von der Reichweite der verschiedenen Antennen (auch externe) oder der physischen Integration dieser neuen Module in unsere Baugruppen.
Aufgrund all dieser Veränderungen wurde der Schwerpunkt sicherlich nicht auf die grundlegendsten Aspekte, die grundlegendste Verwaltung des Unternehmens gelegt ESP8266 WLAN-Modul. Obwohl polarität.es Informationen zur Nutzung finden Sie hier ESP8266 und es gibt einige Anwendungen, die die Funktionsweise des erklären sollen ESP8266 WLAN-Modul Verwendung von AT-Befehlen, insbesondere im Artikel über Bibliothek zum Durchführen von HTTP-Anfragen von Arduino mit dem ESP8266-WLAN-ModulDie Eindrücke der Leser deuten darauf hin, dass es nützlich wäre, einige weitere grundlegende Informationen hinzuzufügen, um den Benutzern zu helfen ESP8266 eigene Implementierungen durchzuführen.
Besprechen Sie die grundlegenden Vorgänge für die Arbeit mit dem ESP8266 und das Vorschlagen allgemeiner Lösungen ist ein Ziel, das aus mehreren sehr unterschiedlichen Teilen besteht; Um den Inhalt des Artikels nachvollziehen zu können, kann der folgende Index als Orientierung dienen:
- Steuern Sie das WLAN-Modul ESP8266 vom Computer aus über die serielle Schnittstelle
- Aktualisieren Sie die Firmware mit esptool
- Senden Sie Bestellungen an das Modul
- Empfangen Sie Daten vom ESP8266
- Analysieren Sie die Antwort, indem Sie im Inhalt nach Texten suchen
- Begrenzen Sie die Wartezeit bis zum Erhalt der Antwort
- Führen Sie eine komplexe Operation aus, die durch mehrere AT-Befehle definiert ist
Steuern Sie das WLAN-Modul ESP8266 vom Computer aus über die serielle Schnittstelle
Von einem Teller Arduino und mit Ihrem IDE Es ist möglich, den Betrieb eines zu überwachen ESP8266 WLAN-Modul, Sende das ESP8266 AT-Befehle und sehen Sie sich die Antwort an, aber es ist viel bequemer, dies von einem Computer mit einer Terminalanwendung aus zu tun.
Je nachdem welches Board Arduino Bei Verwendung ist möglicherweise nur ein serieller Hardware-Port verfügbar, was das Senden und Empfangen etwas umständlicher macht. Das Ändern der Kommunikationsgeschwindigkeit ist in einer seriellen Kommunikationsanwendung von einem Computer und einigen Motherboards aus viel komfortabler. Arduino (und unter bestimmten Umständen) unterstützen die höheren Geschwindigkeiten der seriellen Kommunikation nicht gut, insbesondere 115200 Baud, was die Standardgeschwindigkeit der neuesten Versionen von ist Firmware.
Über Welches Programm soll zur Überwachung verwendet werden? ESP8266 über die serielle Schnittstelle, es gibt viele zur Auswahl, je nach Bedarf und Vorlieben; In letzter Zeit verwende ich mehr den Klassiker CuteCom (das im Screenshot oben), weil es für mich sehr bequem ist, bestimmte Dinge zu wiederholen ESP8266 WLAN-Modul bei Bestellungen bei Projekttests.
Zu Programmen, die als serielle Konsole fungieren, wurden hier bereits einige Empfehlungen gegeben; Zum Beispiel, wenn man darüber redet PuTTY zur Steuerung serieller UART-Geräte vom Computer aus. PuTTYEs ist nicht nur eine hervorragende Anwendung, sondern ist auch für die meisten Desktop-Betriebssysteme verfügbar. Darüber hinaus als PuTTY kann sowohl mit der seriellen Schnittstelle als auch als Konsole verwendet werden Internetprotokollfamilie (TCP/IP), einschließlich derjenigen, die darauf operieren TLSwird zu einem gängigen Tool, das die (geringe) Zeit, die für die Konfiguration und die Eingewöhnung in die Verwendung aufgewendet wurde, mehr als wettmacht.
Zusätzlich zur seriellen Kommunikationssoftware um die ESP8266 WLAN-Modul zum Hafen USB Auch ein Computer benötigt einen Konverter USB zur Serie TTL. Wie bei der Software gibt es mehrere Versionen, von denen sie nur der Konvertierung des Ports dienen USB an einer seriellen Schnittstelle TTL (die ab einem Euro erhältlich sind) bis hin zu solchen, die verschiedene Protokolle emulieren können (z. B SPI o I2C).
Genau wie ein Programm, das als serielle Konsole fungiert, die Hardware, über die der Computer kommuniziert USB mit einer Logikschaltung (nicht nur der ESP8266) ein gängiges Werkzeug bei der Arbeit eines mikrogesteuerten Anwendungsentwicklers sein wird, lohnt es sich, es so schnell wie möglich in der Toolbox zu haben und damit zu arbeiten ESP8266 WLAN-Modul Es ist eine ausgezeichnete Gelegenheit, einen zu bekommen.
Der Konverter USB a UART TTL Es kann auch verwendet werden, um das Verhalten einer Schaltung zu überwachen, die das verwendet ESP8266Dazu werden die Ausgänge, die Sie überwachen möchten, mit einer schnellen Diode (die.) in Reihe mit dem Dateneingang (RX) des Konverters verbunden 1N4148, z. B.) und einem Widerstand (z. B. 2K2) parallel zueinander geschaltet. Ein solches Setup funktioniert wie ein serieller Hardware-Sniffer.
Obwohl der Sniffer im Bild oben sicherlich rudimentär ist (unter anderem nicht). puffern) reicht aus, um den Betrieb einer Baugruppe zu überwachen Arduino und ESP8266.
Entfernen des Sniffers aus dem vorherigen Schema, dem Schematische Darstellung des Anschlusses von a ESP8266 WLAN-Modul auf einen Teller Arduino. Zusätzlich zur Speisung mit 3V3 müssen der Reset-Pin und der Aktivierungspin des Integrierten mit einem High-Pegel (Enable) verbunden werden. Natürlich muss der RX-Pin des einen mit dem TX-Pin des anderen verbunden sein.
Um das vorherige Diagramm zu vereinfachen, wurde eine Platte dargestellt Arduino mit 3V3 betrieben wird und für die eine Spannung am seriellen Port ebenfalls mit 3V3 angenommen wird. Wenn Sie a verwenden Mikrocontroller mit einem anderen Signalpegel am seriellen Port (typischerweise 5 V) erforderlich sein, um das Gerät nicht zu beschädigen ESP8266, benutze einen Pegelwandler wie die in den Diagrammen unten. Diese Schaltung ist häufig in vielen kommerziellen Standardmodulimplementierungen zu finden.
Aktualisieren Sie die ESP8266-Firmware
Die ESP8266 AT-Befehle, seine Terminierung, die Standardgeschwindigkeit des Moduls... hängen von der Version des ab ESP8266-Firmware. Stellen Sie am besten sicher, dass Sie in allen Modulen die gleiche Version haben und es sich nach Möglichkeit um die aktuellste Version handelt.
Leider sind die meisten ESP8266-WLAN-Modulmodelle Sie verfügen nur über 4 Mbit, daher kann die neueste Version nicht darauf installiert werden. Die neueste (offizielle) Firmware-Version, auf der installiert werden kann ESP8266 WLAN-Module mit 4 Mbit (meistens) ist 0.9.4, einschließlich Version 0.2 des ESP8266 AT-Befehle.
Zusammenfassend benötigen Sie zum Aktualisieren der Firmware Folgendes:
-
Laden Sie die entsprechende Firmware-Version herunterzu verbessern. neueste (offizielle) Version für ein Modul mit 4 Mbit Speicher, gefunden im Espressif-Ordner auf Github. Im Espressif-Website Sie können die neueste Version der Firmware herunterladen, es ist jedoch sehr wichtig zu überprüfen, ob das Modul, auf dem sie installiert ist, über genügend Speicher verfügt.
-
Laden Sie die neueste Version des Firmware-Installationstools herunter. Mein Liebling ist Espenwerkzeug was geschrieben steht Python, sodass es auf jeder Plattform funktioniert. Es kann nicht nur heruntergeladen, sondern auch mit installiert werden
pip install esptool
(opip2
opython -m pip
…). Natürlich, Espressiv Es bietet auch ein eigenes Tool an, ist jedoch derzeit nur für Windows verfügbar. -
Bereiten Sie heruntergeladene Dateien vor; Entpacken Sie diese in einen zugänglichen Ordner und machen Sie das Tool ggf. ausführbar Espenwerkzeug, in meinem Fall, seit GNU / Linuxmit
chmod +x esptool
-
Verbinden Sie das Modul über einen Konverter mit dem Computer USB UART TTL das funktioniert bei 3V3 oder verwenden Sie einen Pegelwandler, wenn dieser mit 5 V arbeitet. Zusätzlich zur Stromversorgung müssen Sie TX mit RX des Konverters verbinden USB UART TTL, RX zu TX, GPIO0 auf niedrigem Pegel (GND) und möglicherweise GPIO2 auf hohem Pegel (in meinen Tests hat es sowohl beim Verbinden auf niedrigem Pegel als auch beim Trennen funktioniert). Wenn das Modul über einen freien GPIO15-Anschluss verfügt (wie es beim ESP-12 der Fall ist), muss dieser mit einem Low-Pegel verbunden werden. RESET, das im Betrieb normalerweise auf einem hohen Pegel liegt, kann unbeschaltet bleiben oder über einen Widerstand (z. B. 10K) auf einen hohen Pegel gelegt werden, da vor Beginn der Aufzeichnung möglicherweise ein Reset des Geräts durch Anschließen erforderlich ist auf ein niedriges Niveau.
Wenn Sie das Modul einschalten, kann es aktualisiert werden. Wenn ein Verbindungsfehler angezeigt wird, muss dieser zurückgesetzt werden Schließen Sie RESET für einen Moment auf einem niedrigen Pegel an und lassen Sie es dann für den Aktualisierungsvorgang auf Sendung (ohne Verbindung).
Das Modul hat Verbrauchsspitzen von einem halben Ampere (nach Angaben einiger Benutzer bis zu 600 mA), daher ist es wichtig, ein Netzteil zu verwenden, das diesen Verbrauch unterstützen kann, insbesondere für die Aktualisierung der Firmware. -
Führen Sie das Tool aus, um die Firmware zu aktualisieren. In meinem Fall habe ich die Tool- und Firmware-Dokumente in Schritt 3 im selben Ordner gespeichert, also führe ich von der Konsole aus Folgendes aus:
cd ~/Datos/firmwareESP8266
(wechseln Sie in den Ordner, der das Tool und die Firmware enthält)./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
stellt die Geschwindigkeit des ein ESP8266 (115200 Baud in meinem Fall) und--port
der serielle Port, an den es angeschlossen ist (in meinem Fall emuliert, der erste USB). Die verschiedenen Dokumente, aus denen die Firmware besteht, liegen dahinterwrite_flash
mit vorangestellter Adresse, wobei das Dokument user1.bin die Update-Payload enthält.
Senden Sie Befehle an das WLAN-Modul ESP8266
Zur Kontrolle der ESP8266 Von einem Computer aus müssen wir beginnen Konfigurieren Sie die App Dazu reicht es aus, ① den Port auszuwählen, an den der Konverter angeschlossen ist USB UART TTL, etwas wie /dev/USB0
in GNU/Linux und ähnlichem oder so ähnlich COM6
Wählen Sie in Windows ② die Geschwindigkeit aus, mit der die ESP8266, wahrscheinlich 115200 Baud, ③ 8 Datenbits plus ein Stoppbit setzen, ohne Parität oder Handshake, und ④ Zeilenende einstellen, je nach Firmware, fast immer CR+LF.
Sobald die Anwendung konfiguriert (oder gegebenenfalls gespeichert und ausgewählt) ist, ist sie es Öffnen Sie die Verbindung („open device“ bzw. „open“ in den Screenshots der obigen Beispiele mit CuteCom y PuTTY) und Sie können damit beginnen, Bestellungen an zu senden ESP8266.
Wie in der zu sehen ist ESP8266 AT-Befehlstabelle, das Format zum Aktivieren, Deaktivieren, Festlegen eines Werts und Verweisen darauf ist ziemlich vorhersehbar, aber im Allgemeinen ist es nicht einfach, sich alle zu merken, und Sie müssen es wahrscheinlich zur Hand haben, um darauf zu verweisen.
Der Weg von SENDEN Bei Bestellungen al ESP8266 WLAN-Modul von Arduino ist ganz einfach: ① Kommunikation mit konfigurieren Serial.begin(115200);
(oder Serial1, Serial2… auf Platinen mit mehreren seriellen Hardware-Ports) und ② Senden Sie die Befehle im 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() { } |
Das obige Beispiel zeigt, wie das gesendet wird ESP8266 WLAN-Modul bei Bestellungen von Arduino. In diesem Fall ist es illustriert AT+CWJAP
, mit dem eine Verbindung zu einem Zugangspunkt hergestellt wird. Dieser Befehl verwendet als Argumente die Zugangspunktkennung (SSID) und der Schlüssel, beide in Anführungszeichen, sodass sie zu einem Objekt werden Srtring
und in Anführungszeichen mit dem Escape-Code (\"
). Um die Bestellung abzuschließen, verwenden Sie \r\n
was entspricht CR
y LF
.
Denken Sie daran, dass die serielle Schnittstelle nicht immer mit identifiziert wird Serial
(Auf bestimmten Tellern kann es sein Serial1
, Serial2
…) Das verwendete Portobjekt wurde durch Zuweisung zum Makro definiert PUERTO_SERIE
. Das Erkennen des verwendeten Kartentyps könnte die Auswahl der seriellen Schnittstelle etwas intelligenter machen; Später gehen wir darauf ein, wie Sie die Art herausfinden können Arduino. Bei den übrigen Definitionen handelt es sich um die üblichen, die es Ihnen ermöglichen, die konstanten Werte zu „benennen“, um Wiederholungen (und Fehler) zu vermeiden und es einfacher zu machen, sie zu ändern.
Das obige Beispiel soll die Verbindung herstellen ESP8266 WLAN-Modul zum angegebenen Zugangspunkt, war dieser aber schon vorher verbunden? Hat die Verbindung funktioniert? Um das zu wissen, müssen wir „zuhören“. ESP8266
Empfangen Sie Daten vom WLAN-Modul ESP8266
Indem Sie den oben erläuterten Datenschnüffler an den Computer anschließen, können Sie sehen, was Arduino hat die gesendet ESP8266 und seine Antwort. Zum Vorlesen Arduino und verarbeiten Sie die darin enthaltenen Informationen, die zur Erkennung erforderlich sind Serial.available()
ob Daten angekommen sind und wenn ja, laden Sie diese mit Serial.read()
. Das folgende Beispiel zeigt, wie die Antwort gelesen wird AT+CWJAP?
, das meldet, ob eine Verbindung zu einem Zugangspunkt besteht.
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(); } } |
Wie auf einem Teller Arduino Uno (und in anderen Fällen) Durch Öffnen des seriellen Monitors wird das Programm zurückgesetzt. Es kann zur Anzeige in der seriellen Konsole verwendet werden Arduino die Informationen, an die Sie senden ESP8266 wie der Screenshot des Bildes unten zeigt.
Analysieren Sie die vom WLAN-Modul ESP8266 gesendete Antwort
Wir haben bereits gesehen, wie man die Informationen liest, die ankommen Arduino aus dem ESP8266. Das Problem, mit dem Sie zu kämpfen haben, besteht darin, dass Sie nicht wissen, wann die Nachricht ankommt, wie lange es dauern wird, bis sie ankommt, wie lange sie dauern wird ... und es ist nicht sehr effizient, auf die Antwort von zu warten ESP8266 wird empfangen, ohne das zuzulassen Mikrocontroller in der Zwischenzeit andere Aufgaben erledigen.
Eine einfache Möglichkeit, diesen Umstand zu bewältigen, ist Iterieren Sie die erhaltenen Daten und suchen Sie nach konkreten Antworten mit denen beispielsweise Indikatoren (Flags oder boolesche Variablen) aktiviert werden, die bestimmen, ob die Suche im empfangenen Text fortgesetzt werden soll und welche Aktionen basierend auf den vom empfangenen Text ausgeführt werden sollen ESP8266. Während die Antwort eintrifft Mikrocontroller kann sich anderen Aufgaben widmen, zum Beispiel Daten von Sensoren empfangen und verarbeiten.
Suchen Sie in den vom ESP8266 empfangenen Informationen nach einem Text
Um den Text zu durchsuchen, der aus dem stammt ESP8266 kann Vergleichen Sie jeden erhaltenen Brief mit dem Brief, der der gesuchten Nachricht entspricht. Es ist notwendig, einen Zähler (oder einen Zeiger) zu verwenden, der auf den zu vergleichenden Buchstaben zeigt; Wenn das Zeichen, das aus dem kommt ESP8266 derselbe ist wie der, der in der Nachricht untersucht wird, schreitet der Zähler voran, wenn er unterschiedlich ist, wird er initialisiert.
Um zu wissen, dass das Ende erreicht wurde, wird das nächste Zeichen der gesuchten Nachricht herangezogen, das Null sein wird (\0
) oder die Länge der Nachricht wird gespeichert, um durch Vergleich mit dem Zähler zu erfahren, ob der Vergleich abgeschlossen ist und daher die ESP8266 WLAN-Modul hat die gewünschte Nachricht gesendet.
Im folgenden Beispiel wird der Befehl verwendet AT+CWLAP
Dadurch wird eine Liste der Zugangspunkte zurückgegeben und darin wird nach einem mit dem Namen „wifi polaridad.es“ gesucht. Obwohl wir uns dafür entschieden haben, zu überprüfen, ob das letzte Zeichen Null ist, da das puffern Es speichert nur den gesuchten Text und seine Länge ist bekannt, es könnte auch überprüft werden, ob so viele richtige Buchstaben eingegangen sind. Mit einem LED Bei Anschluss an Pin 2 wird gemeldet, dass der erwartete Text gefunden wurde.
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 } } } } |
Im Code des vorherigen Beispiels können Sie auch einen Weg dazu sehen Wählen Sie je nach Kartentyp den seriellen Anschluss Arduino gebraucht. In diesem Beispiel wird davon ausgegangen, dass Sie drei Arten von Platinen für das Projekt haben: eine Arduino Unoeinem Arduino Mega 2560 und Arduino Leonardo. Wenn Sie mit einem arbeiten Arduino Uno es wird genutzt Serial
und ansonsten Serial1
.
Wenn Sie mit einer Platte arbeiten Arduino Leonardo Sie können die gleiche Methode verwenden, um das Programm zu stoppen und auf die Konsole (den damit verknüpften seriellen Port) zu warten Serial
) ist verfügbar.
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 |
Durchsuchen Sie verschiedene Texte in der ESP8266-Antwort
Der Code im vorherigen Beispiel wird verwendet, um in den von gesendeten Informationen nach Text zu suchen ESP8266 Die Antwort kann jedoch je nach Vorgang unterschiedliche Informationen enthalten. Nehmen wir im nächsten Beispiel zunächst einen einfachen Fall an, bei dem der vom gesendete Text gesendet wird MCU ESP8266 es OK
wenn die Operation korrekt durchgeführt wird und ERROR
Ansonsten wie bei der Bestellung AT+CWJAP?
, was dazu dient, zu überprüfen, ob die ESP8266 WLAN-Modul bereits mit einem Access Point verbunden ist.
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 } } } } } |
Diese neue Implementierung derselben Methode, die nach einer Übereinstimmung mit mehreren möglichen Nachrichten sucht, ermöglicht es Ihnen, je nach der von Ihnen erhaltenen Antwort zwischen verschiedenen Aktionen zu wählen ESP8266, schalten Sie einfach das ein LED das entspricht.
Begrenzen Sie die Zeit, die bis zum Erhalt einer Antwort benötigt wird
Bisher gab es keinen Hinweis auf ein relevantes Thema: die Maximale Wartezeit (Timeout), bevor ein Vorgang als fehlgeschlagen betrachtet wird. Wenn aus irgendeinem Grund die Verbindung mit dem ESP8266 WLAN-ModulWenn das Modul mit dem Zugangspunkt, der Zugangspunkt mit Internet oder beispielsweise ein hypothetischer Server nicht verfügbar ist, kann das Programm an einer Stelle blockiert sein und auf unbestimmte Zeit warten, sodass auf solche Umstände eine Reaktion erfolgen muss. Die maximale Wartezeit kann für die gesamte Anwendung konfiguriert werden, meist ist sie dann „großzügiger“ oder es können für jeden Vorgang individuelle Wartezeiten programmiert werden.
Um zu überprüfen, ob (mindestens) ein bestimmtes Zeitintervall verstrichen ist Normalerweise wird die „Zeit“ des Zeitpunkts der Kontoeröffnung von der aktuellen „Zeit“ abgezogen und überprüft, ob die Differenz größer als das gewünschte Limit ist. Diese „Zeit“ muss keine Echtzeit sein, sie entspricht normalerweise dem Intervall, das seit dem vergangen ist MCU Beginnen Sie mit dem Zählen der Zeit; Dies hat keine Auswirkungen auf das Programm, da die verstrichene Zeit und nicht die absolute Zeit von Interesse ist.
Um zu überprüfen, ob ein bestimmtes Intervall abgelaufen ist, wird normalerweise ein Ausdruck des Typs verwendet:
1 | (unsigned long)(millis()–milisegundos_al_empezar)>intervalo_de_tiempo |
Variabel milisegundos_al_empezar
enthält den Wert von millis()
eines bestimmten Zeitpunkts in der Ausführung, von dem aus die Zeit gemessen wird, daher ist es nicht ungewöhnlich, dass sich sein Name auf das Wort „Chronometer“ bezieht. Die Variable intervalo_de_tiempo
enthält die maximale Anzahl von Millisekunden, die den vorherigen Ausdruck wahr macht, d. h. es stellt die Zeitüberschreitung dar; Es handelt sich normalerweise um eine Konstante (oder ein Makro) und wie im vorherigen Fall kommt häufig das Wort „TIMEOUT“ in seinem Namen vor. Wenn Sie mit sehr kurzen Intervallen arbeiten, können Sie verwenden micros()
statt millis()
(Mikrosekunden statt Millisekunden), obwohl es viel seltener und viel ungenauer ist.
1 | (unsigned long)(millis()–cronometro)>TIMEOUT |
Eine lange Ganzzahl in Arduino (unsigned long
) belegt 4 Bytes (32 Bits), daher ist der größte Wert, den es darstellen kann, 4294967295 (2 hoch 32 minus eins, weil es bei Null beginnt). auf einem Teller Arduino Bei Dauerbetrieb wird der Millisekundenzähler etwa alle 50 Tage zurückgesetzt (auf Null zurückgesetzt). Beim Subtrahieren mit vorzeichenlosen Datentypen wird das gleiche Verhalten reproduziert (Umdrehen des Zählers), sodass es sinnvoll ist, das Timeout auf unbestimmte Zeit zu steuern.
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; } } } |
Der obige Code zeigt a Sehr einfache Implementierung der Timeout-Begrenzung unter Einbeziehung der im vorangehenden Beispiel markierten Zeilen. Da die Timeout-Überprüfung nach der Verarbeitung der von der empfangenen Daten durchgeführt wird ESP8266 WLAN-Modul, kann die Operation auch dann als erfolgreich angesehen werden, wenn der Empfang länger dauert als die vorgeschriebene Wartezeit.
Führen Sie eine komplexe Operation aus, die durch mehrere AT-Befehle definiert ist
Um eine Beispielreferenz für den Zweck der Anwendung zu haben, die das ausnutzt ESP8266 WLAN-Modul, nehmen wir an, es ist so Informationen in einer Datenbank speichern, auf die über einen Webdienst zugegriffen wird um die Temperatur im Auge zu behalten. Der folgende Code liest in bestimmten Zeitintervallen einen an einen Analogeingang angeschlossenen Sensor, berechnet den Durchschnittswert und sendet ihn nach einem längeren Zeitintervall an den Webserver (style IoT) durch ein anfordern 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”); } } |
In diesem Beispiel zur Temperaturaufzeichnung wird alle fünf Minuten auf einen Webserver zugegriffen. Obwohl die Verfügbarkeit nicht besonders hoch ist, ist davon auszugehen, dass der Vorschlag funktionieren würde. Wenn jedoch eine höhere Aufzeichnungsfrequenz erforderlich wäre, müssten andere Ressourcen implementiert werden, z. B. a Datenpuffer warten darauf, verschickt zu werden, um mehrere zu senden, wenn der Server anwesend sein kann, und sie für den Fall zu speichern, wenn er nicht verfügbar ist. Wäre die Häufigkeit, mit der Daten aufgezeichnet werden müssen, noch größer, müssten alternativ andere Protokolltypen vorgeschlagen werden HTTP oder sogar ersetzen TCP von UDP um die meisten Daten mit der erforderlichen Geschwindigkeit senden zu können, auch wenn einige davon verloren gehen.
Die Operationen, aus denen sich die auszuführende Aufgabe zum Senden der Temperatur zusammensetzt, wären:
- Setzen Sie das WLAN-Modul zurück
- Trennen Sie die Verbindung zum aktuellen Zugangspunkt (falls eine Standardverbindung vorhanden ist).
- Legen Sie die Einstellungen fest. Für das Beispiel wird davon ausgegangen, dass der Verbindungsmodus (einfach) und die Rolle in der WLAN-Kommunikation (Station) konfiguriert werden müssen.
- Stellen Sie eine Verbindung zum Zugangspunkt her
- Überprüfen Sie, ob die Verbindung korrekt ist (tatsächlich ist dies der Einstiegspunkt). Wenn keine Verbindung besteht, beginnen Sie den Vorgang von vorne
- Verbinden zum Server
- Senden Sie die Anfrage HTTP mit den zu speichernden Daten
Die Reihenfolge der Vorgänge muss nicht genau so sein (obwohl dies bei der Operation der Fall ist) und jeder Schritt kann mehrere Schritte erfordern ESP8266 AT-BefehleFür die oben aufgeführte Konfiguration wären beispielsweise zwei erforderlich: AT+CIPMUX=0
y AT+CWMODE=1
.
Eine Datenstruktur zur Darstellung von Vorgängen auf dem ESP8266
In den vorherigen Beispielen wird, wenn auch auf sehr einfache Weise, bereits eine generische Lösung des Problems vorgeschlagen: Verwenden Sie eine Datenstruktur, die die möglichen Reaktionen und die jeweils durchzuführenden Aktionen speichert; Senden Sie eine Aktion, warten Sie auf eine Antwort und fahren Sie entsprechend der Bedeutung der Antwort fort. Da jeder komplexe Vorgang mehrere erfordert ESP8266 AT-Befehle, muss die Datenstruktur eine Operation mit weiteren, nachfolgenden oder vorherigen verknüpfen, die jeweils abhängig von der Antwort des ausgeführt werden müssen ESP8266.
In den vorherigen Beispielen wurde eine Nachricht innerhalb der Antwort des gesucht ESP8266 und es wurde als Erfolg oder Fehler interpretiert. Neben einer Rezeption (und Analyse) aller eingegangenen Texte, Um ein generisches Minimum zu gewährleisten, empfiehlt es sich, auch auf die Vervollständigung der Nachricht zu achten oder, mit anderen Worten, auf die Verfügbarkeit der ESP8266 WLAN-Modul um neue Aufträge zu erhalten. Auf diese Weise könnte der Wechsel in einen Zustand, den wir beispielsweise „WLAN verfügbar“ nennen könnten, darin bestehen, den Namen des Zugangspunkts und den Text zu erhalten ERROR
oder der Text OK
würde bedeuten, dass die ESP8266 Sie haben die Antwort fertiggestellt und können nun die nächste senden AT-Befehl an 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; |
Der obige Code verwendet einen Vektor (operacion
), um den Text der aufeinanderfolgenden Vorgänge zu speichern, die die vollständige Aufgabe bilden. Es wird ein zweidimensionales Array verwendet (mensaje
) mit den drei Antworten, die analysiert werden. Wie oben erläutert, muss zusätzlich zu der Nachricht, die eine richtige oder falsche Antwort darstellt, auch nach den Nachrichten gesucht werden, die das Ende der Antwort darstellen. Nicht alle Operationen haben die gleiche Anzahl möglicher Antworten; Wenn es weniger Antworten gibt, kann eine leere Nachricht verwendet werden, die die kleinstmögliche Anzahl von Zyklen für ihre Analyse benötigt (obwohl dies nicht die optimalste Methode ist). Logischerweise muss die Mindestanzahl der gesuchten Antworten (im Beispiel drei) alle Bedienmöglichkeiten umfassen, auch wenn nicht alle möglich sind.
Wenn man über die möglichen Antworten spricht, erkennt man bereits, dass dieses Beispiel nicht sehr nützlich ist, um Daten mit einem beliebigen Format von a zu empfangen ESP8266 WLAN-Modul, aber die Sache ist die, im Kontext der Verwendung mit Mikrocontroller es ist nicht üblich; Am häufigsten werden die von den angeschlossenen Sensoren gesammelten Daten gesendet und/oder Informationen darüber empfangen, was mit den von ihnen gesteuerten Aktoren geschehen soll. Sehr wertvolle Informationen, die sich sehr gut vorhersagen lassen.
In der vorherigen Datenstruktur wird ebenso wie zum Ausdrücken der möglichen Antworten, die analysiert werden, auch eine zweidimensionale Matrix verwendet, um die Operation zu bestimmen, die jeweils ausgeführt werden muss (siguiente_operacion
). Konkret haben wir uns entschieden, auf drei Arten von Nachrichten zu antworten: ① einen beliebigen Text (LITERAL
), um zu überprüfen, ob eine Verbindung zum WLAN-Zugangspunkt und zum Server besteht, ② ein Text zur Erkennung von Fehlern im Prozess (FALLO
) und ③ ein Text, der angibt, dass der Vorgang erfolgreich abgeschlossen wurde (ACIERTO
).
Schließlich gibt es noch zwei weitere Vektoren, um die maximale Wartezeit vor dem Aufgeben festzulegen (timeout
) und geben Sie an (configuracion
), wenn der Vorgang endet, ohne auf eine Antwort zu warten (ESPERAR_RESPUESTA
) und Nachrichten, die das Ende der Kommunikation anzeigen. Dieser letzte Vektor soll ein Beispiel dafür darstellen, wie Speicher eingespart werden könnte. Er arbeitet mit den Bits eines Konfigurationsbytes, um die verschiedenen Zustände anzuzeigen.
Der erste ESP8266 AT-Befehle der Datenstruktur erwarten immer eine Antwort, die eine Erfolgs- oder Fehlermeldung sein kann. Wenn ein Fehler auftritt, wird das Modul neu gestartet und startet erneut. Wenn die Meldung anzeigt, dass der Vorgang korrekt ist, wird mit dem nächsten Schritt fortgefahren.
Wenn Sie eine Verbindung zum Server hergestellt haben, ändert sich das Muster. In diesem Fall ist es notwendig, ① die Länge des zu übertragenden Datenpakets zu senden und ② die Anfrage zu verfassen HTTP mit einem festen Text plus dem Wert (der Temperatur), der zur Speicherung auf dem Server gesendet wird. Die Aufbereitung dieser Daten erfolgt bei jeder Sendung und es ist notwendig, sie in zwei (Länge mitteilen) oder drei (Anfrage senden) aufzuteilen HTTP) Um ESP8266 AT-Bestellung. Nur der letzte Teil, in den die Operation unterteilt ist, wartet auf eine Antwort.
In diesem Fall wird es ohne Probleme funktionieren (vielleicht Warnung, dass das Modul ausgelastet ist), aber wenn die Länge der Daten größer ist, ist es notwendig, die Datenblöcke in kleinere Teile zu unterteilen, und es kann sogar notwendig sein, eine Wartezeit zu implementieren, wie z wird mit der Temperaturmessung durchgeführt, um dem Modul Zeit zu geben, die Daten zu senden, ohne es zu füllen puffern.
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(); |
Zusammen mit anderen Makros, die bereits zuvor erläutert wurden, zeigt der obige Beispielcode, wie die verschiedenen Zustände definiert werden, mit denen angegeben wird, ob auf eine Antwort gewartet werden soll und ggf. welche Meldung den Abschluss anzeigt.
Wie an verschiedenen Stellen im Code ein Vorgang gesendet wird (wenn es Zeit ist, die Durchschnittstemperatur zu senden, wenn die Wartezeit eines Vorgangs überschritten wird, wenn der aktuelle Vorgang erfolgreich abgeschlossen wurde ...), aber wie das geht, erfahren Sie hier Global etabliert, wurde ein Makro definiert ENVIAR_OPERACION
Hier werden die Schritte des Versands zusammengefasst.
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(); |
Das Folgende ist der Code des Hauptprogramms des Beispiels. Die externste Aufgabe besteht darin, die Temperatur zu messen, um den Durchschnitt zu berechnen und diesen in jedem bestimmten Zeitraum mithilfe von an den Server zu senden ESP8266 WLAN-Modul. Sobald jeder Vorgang gesendet wurde, wird die Antwort analysiert, um festzustellen, welcher als nächstes erfolgt oder ob die Aufgabe des Sendens von Informationen abgeschlossen wurde.
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 } } } |
Logischerweise können am vorherigen Code mehrere Optimierungsaktionen durchgeführt werden, da dies jedoch ein Beispiel ist, um zu verstehen, wie das funktioniert ESP8266 Generell lohnt es sich nur, sich auf einige Aspekte zu konzentrieren, der erste ist die Datenstruktur. Das scheint logisch zu sein Verwenden Sie eine Programmiersprachen-Datenstruktur (struct
), um die verarbeiteten Informationen darzustellen: die ESP8266 AT-Befehle und die Nachrichten, die analysiert werden.
Verwenden Sie eine Struktur (struct
), die Daten anstelle der (auf ihnen basierenden) Beispielarrays zu speichern, ist trivial und führt zwar möglicherweise zu eleganterem Code, bedeutet aber keine Verbesserung des Ergebnisses. Die wahre Alternative durch die Verwendung von struct
ist, wie unten erläutert, zu implementieren, variable Längen in Strukturen, die „innere“ Daten enthalten auf die sie sich beziehen. Auf diese Weise wäre es beispielsweise nicht erforderlich, dass für einen Vorgang eine feste Anzahl von Antworten analysiert werden müsste.
Dieser Ansatz legt nahe, dass dies der beste Weg ist, die Lösung zu implementieren, der Nachteil besteht jedoch darin, dass dies notwendig wäre Verwenden Sie die dynamische Speicherzuweisung, eine riskante Vorgehensweise bei der Arbeit mit a Mikrocontroller Dies erfordert eine sorgfältige Messung, wie viel Speicher zur Laufzeit verwendet wird, da der Compiler uns hierüber kaum warnen kann und die Gefahr einer Erschöpfung des Speichers (bzw. des Stacks) mit fatalen Folgen für die Programmausführung besteht.
Im Hinblick auf die Optimierung des Codes ist es interessant, sich daran zu erinnern, dass in einem Programm dieser Art, das eine große Textmenge verwendet, kann Speicherplatz sparen SRAM Speichern von Textzeichenfolgen im Programmspeicher (Blitz) mit dem Makro F()
. In den folgenden Screenshots sehen Sie die unterschiedliche Programm- und dynamische Speicherverteilung bei normaler Verwendung von Text und Verwendung des Makros F()
.
In Bezug auf die Aktionen, die gemäß den von der erhaltenen Informationen ausgeführt werden ESP8266 WLAN-Modul, als Alternative zum Überprüfen der Nachricht anhand des Codes und zum Ausführen des einen oder anderen, je nach dem, was empfangen wird, kann in dieser Datenstruktur gespeichert werden Zeiger auf Funktionen, die jede Aufgabe ausführen, anstelle von Statusindikatoren (Flags), die vor einem bestimmten Zustand warnen, für dessen Verwaltung die Anwendung verantwortlich ist, beispielsweise innerhalb der Hauptschleife.
Im Folgenden finden Sie ein Beispiel für Strukturen zum Speichern der Daten der Anfragen an die ESP8266 (der Datentyp operacion_esp8266
) und ihre Antworten (der Datentyp 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; |
Als Struktur, die den Vorgang darstellt (die Daten, die an gesendet werden). ESP8266 WLAN-Modul) bezieht sich auf die Struktur, mit der die Antworten definiert werden, und die Struktur der Antworten auf die Struktur der Operationen, Es ist notwendig, beides zuerst zu deklarieren, indem Sie den neuen Datentyp und dann seinen Inhalt definieren.
Im vorherigen Beispiel wird davon ausgegangen, dass das Programm, das es enthält, sich für die Verwendung von a entschieden hat Statusanzeige, die einer Variablen entsprechen muss, auf die über den Code zugegriffen werden kann, der für die Ausführung der einen oder anderen Operation verantwortlich ist, die durch den Wert angegeben wird. Wenn in der Antwort von ESP8266 Wenn ein bestimmter Text analysiert wird, nimmt der Status den Wert an, der die Struktur der entsprechenden Antwort angibt.
Wie bereits erwähnt, wäre eine weitere Alternative, entweder eine Statusanzeige zu ersetzen oder zu ergänzen Speichern Sie eine Funktion in der Referenzstruktur (ein Zeiger), der aufgerufen wird, wenn in der Antwort von auf einen bestimmten Text gestoßen wird ESP8266 WLAN-Modul.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | typedef struct estructura_operacion_esp8266 operacion_esp8266; // Se define el tipo de datos operacion_esp8266 que corresponde con la estructura (struct) llamada estructura_operacion_esp8266 que se define más adelante typedef struct estructura_respuesta_esp8266 respuesta_esp8266; // Se define el tipo de datos respuesta_esp8266 que corresponde con la estructura (struct) llamada struct estructura_respuesta_esp8266 que se define más adelante struct estructura_operacion_esp8266 { char *peticion; // Datos que se envían al ESP8266 para iniciar una operación (como una orden AT, pero también algo como la petición a un servidor…) unsigned char cantidad_respuestas; // Número de posibles respuestas del ESP8266 que se van a analizar, que puede ser variable en cada petición (no solo OK y ERROR) unsigned char timeout; // Tiempo (segundos) que se espera la respuesta del ESP8266 antes de desistir respuesta_esp8266 *respuesta; // Respuestas (estructura) que se esperan de esta operación }; struct estructura_respuesta_esp8266 { char *mensaje; // Mensaje que se espera recibir desde el ESP8266 unsigned char posicion_mensaje; // Posición (letra) que se está comparando con la recibida desde el ESP8266 //boolean estado; // El estado se representa por un valor booleano (por ejemplo ¿se ha encontrado ya esta respuesta? para no seguir buscándola) //unsigned char *estado; // El estado se representa con un texto (de longitud variable) unsigned char estado; // El estado se establece con 8 banderas, una por bit float (*accion)(unsigned char,unsigned char); // Puntero a la función que se llama si se encuentra la respuesta operacion_esp8266 *operacion; // Puntero a operación que se ejecutará si se encuentra esta respuesta en el mensaje devuelto por el ESP8266 }; operacion_esp8266 comprobar_conexion; respuesta_esp8266 respuesta_OK; respuesta_esp8266 respuesta_ERROR; |
Im vorherigen Beispiel wurde es der Datenstruktur hinzugefügt, die zum Verarbeiten der Antwort von verwendet wird ESP8266 WLAN-Modul ein Zeiger auf eine (vermeintliche) Funktion, die Daten vom Typ zurückgibt float
(könnte der gewichtete Wert eines analogen Messwerts sein) und dem zwei Bytes als Argumente zur Verfügung gestellt werden (zwei unsigned char
Dies könnte der Pin sein, von dem der analoge Eingang gelesen wird, und der Pin, der ENABLE eines hypothetischen integrierten Signals aktiviert.
In Entwicklung für MCUIm Gegensatz zu dem, was im Entwicklungsstil für größere Systeme üblich ist, ist es nicht so ungewöhnlich, globale Variablen zu verwenden, wenn das (globale) Verhalten der Anwendung definiert wird, die eine Assembly steuert, sodass es nicht besonders selten sein wird, diese Art von Definitionen zu finden als Funktionen ohne Parameter und die keine Werte zurückgeben, so etwas wie void (*accion)();
Wenn Sie mit dieser Art der Datendarstellung arbeiten, verwenden Sie struct
Bei Daten variabler Länge ist eine dynamische Speicherzuweisung erforderlich malloc()
(o new()
, wenn Objekte verwendet werden), die die Menge des zugewiesenen Speichers als Parameter verwendet und einen Zeiger auf den Anfang des reservierten Speicherbereichs zurückgibt. Mit sizeof()
Anhand des gespeicherten Typs multipliziert mit der Anzahl der verwendeten Elemente können Sie die benötigte Speichermenge ermitteln. Ein Beispiel mit und ohne Verwendung ist in den Screenshots unten zu sehen. malloc()
; Seien Sie vorsichtig mit dem vom Programm verwendeten Speicher. Im ersten Fall müssen Sie die Bibliothek laden, die diese Funktion enthält.
Wenn die Operationen auf der ESP8266 WLAN-Modul Während der Ausführung des Programms variieren wird, muss der nicht verwendete Speicher freigegeben werden free()
(o delete()
, im Fall von Objekten). Obwohl es vernünftig ist zu erwarten, dass der Compiler (GCC) optimiert das Programm, um eine Speicherpartitionierung zu vermeiden. Die Leistung wird jedoch sicherlich nicht so optimal sein wie bei der Arbeit mit statisch zugewiesenem Speicher.
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 } } } |
Obwohl es in diesem Beispiel (in beiden Implementierungen) nicht viel Sinn macht, sollte beachtet werden, dass die Operation verallgemeinert werden kann, um sie auf andere Fälle anwenden zu können Das Senden von Daten wiederholt immer das gleiche Protokoll: Geben Sie die Anzahl der zu sendenden Bytes an, warten Sie auf die Anzeige (>) und senden Sie die Daten.
Da es in diesem Beispiel nur einmal verwendet wird (die gesamte Anfrage wird in einem Paket gestellt), scheint es nicht sehr nützlich zu sein, aber im Allgemeinen kann es notwendig sein, mehrere Sendungen im selben Vorgang durchzuführen, auch in Fällen, in denen Es müssen erhebliche Datenmengen übertragen werden, die fragmentiert werden müssen, um ein Überlaufen des Speichers zu vermeiden ESP8266.
Um dieses Verhalten zu implementieren, können die letzten beiden Elemente der Verbindung verwendet werden, sodass bei jedem Senden der Daten die Daten mit den entsprechenden Werten gefüllt werden: im ersten Fall die Anzahl der gesendeten Bytes und im zweiten Fall die ( Teil der) Anfrage. übermittelt werden.
Um die Zuordnung und das Senden der verschiedenen zu übertragenden Elemente zu wiederholen, können diese in einem Vektor gespeichert werden. Dieser neue Vektor bestimmt das Ende der komplexen Operation und nicht wie bisher die letzte Operation.
1 Kommentar