Opérations de base sur un module wifi ESP8266 d'Arduino
Quand expressif lancé les premiers modules sur le marché Wifi avec l'intégré ESP8266 et l' firmware avec lequel le gérer à l'aide des commandes AT, ce qui nous intéressait, nous, les utilisateurs, c'était de l'intégrer dans des assemblys avec microcontrôleurs et les problèmes se réduisaient à connaître le (autrefois) sombre Tableau des commandes AT ESP8266, les besoins alimentaires ou Mise à jour du micrologiciel ESP8266.
Puis des alternatives sont rapidement arrivées pour programmer le ESP8266 et implémentations de modules Wifi de formats très différents qui soulèvent d’autres préoccupations : quel module wifi ESP8266 choisir en fonction de la gamme des différentes antennes (y compris externes) ou de l'intégration physique de ces nouveaux modules dans nos assemblages.
Il est certain qu'en raison de tous ces changements, l'accent n'a peut-être pas été mis sur les aspects les plus fondamentaux, sur la gestion la plus élémentaire du système. Module Wi-Fi ESP8266. Bien que polarité.es Vous pouvez trouver des informations sur l'utilisation du ESP8266 et il existe quelques applications destinées à expliquer de manière générique le fonctionnement du Module Wi-Fi ESP8266 en utilisant les commandes AT, notamment dans l'article sur bibliothèque pour faire des requêtes HTTP depuis Arduino avec le module wifi ESP8266, les impressions des lecteurs suggèrent qu'il serait utile d'ajouter quelques informations de base supplémentaires pour aider les utilisateurs du ESP8266 pour réaliser leurs propres implémentations.
Discutez des opérations de base pour travailler avec le ESP8266 et proposer des solutions génériques est un objectif de plusieurs parties très différentes ; Pour aider à suivre le contenu de l’article, l’index suivant peut servir de guide :
- Contrôlez le module wifi ESP8266 depuis l'ordinateur via le port série
- Mettre à jour le firmware avec Esptool
- Envoyer les commandes au module
- Recevoir des données de l'ESP8266
- Analyser la réponse en recherchant des textes dans le contenu
- Limiter le temps d'attente pour recevoir la réponse
- Exécuter une opération complexe définie par plusieurs commandes AT
Contrôlez le module wifi ESP8266 depuis l'ordinateur via le port série
D'une assiette Arduino et en utilisant votre IDE il est possible de surveiller le fonctionnement d'un Module Wi-Fi ESP8266, envoyer le Commandes AT ESP8266 et voyez la réponse mais il est beaucoup plus pratique de le faire depuis un ordinateur avec une application de type terminal.
Selon le tableau Arduino utilisé, un seul port série matériel peut être disponible, ce qui ajoute un peu d'inconvénient à l'envoi et à la réception. Changer la vitesse de communication est beaucoup plus confortable dans une application de communication série à partir d'un ordinateur et de certaines cartes mères. Arduino (et dans certaines circonstances) ne prennent pas bien en charge les vitesses les plus élevées des communications série, en particulier 115200 XNUMX bauds, qui est la vitesse par défaut des dernières versions du firmware.
À Propos De Quel programme utiliser pour surveiller le ESP8266 en utilisant le port série, il existe de nombreux choix en fonction des besoins et des préférences ; ces derniers temps, j'utilise davantage le classique MignonCom (celui de la capture d'écran ci-dessus) car il est très confortable pour moi de répéter certains Module wifi ESP8266 aux commandes dans les tests de projet.
Quelques recommandations ont déjà été données ici sur les programmes fonctionnant comme une console série ; Par exemple, quand on parle de PuTTY pour contrôler les périphériques série UART depuis l'ordinateur. PuTTYEn plus d'être une excellente application, elle est disponible pour la plupart des systèmes d'exploitation de bureau. De plus, comme PuTTY peut être utilisé comme console avec à la fois le port série et le Famille de protocoles Internet (TCP/IP), y compris ceux qui opèrent sur TLS, devient un outil courant qui compense largement le (peu) temps passé à le configurer et à s'habituer à son utilisation.
En plus du logiciel de communication série, pour connecter le Module Wi-Fi ESP8266 au port USB Un ordinateur nécessite également un convertisseur USB à la série TTL. Comme dans le cas des logiciels, il existe plusieurs versions, à partir desquelles elles servent uniquement à convertir le port USB sur un port série TTL (qui peuvent être obtenus à partir d'un euro) à ceux qui peuvent émuler différents protocoles (comme SPI o I2C).
Tout comme un programme qui fonctionne comme une console série, le matériel permettant de communiquer avec l'ordinateur via USB avec un circuit logique (pas seulement le ESP8266) sera un outil courant dans le travail d'un développeur d'applications microcontrôlées, cela vaut la peine de l'avoir dans la boîte à outils le plus tôt possible et de travailler avec lui Module Wi-Fi ESP8266 C'est une excellente opportunité d'en obtenir un.
Le convertisseur USB a UART TTL Il peut également être utilisé pour surveiller le comportement d'un circuit qui utilise le ESP8266, pour ce faire, les sorties que l'on souhaite surveiller sont connectées en série à l'entrée de données (RX) du convertisseur avec une diode rapide (la 1N4148, par exemple) et une résistance (2K2, par exemple) en parallèle l'une avec l'autre. Une telle configuration fonctionne comme un renifleur série matériel.
Bien que le renifleur dans l'image ci-dessus soit certainement rudimentaire (entre autres, il n'a pas tampon) suffit à contrôler le fonctionnement d'un assemblage avec Arduino et l' ESP8266.
En supprimant le renifleur du schéma précédent, le schéma montrant comment connecter un Module Wi-Fi ESP8266 à une assiette Arduino. En plus de l'alimenter en 3V3, la broche de réinitialisation et la broche d'activation de l'intégré doivent être connectées à un niveau haut (enable). Bien entendu, la broche RX de l’un doit se connecter au TX de l’autre.
Pour simplifier le schéma précédent, une plaque a été représentée Arduino alimenté en 3V3 et pour lequel une tension sur le port série est également supposée être de 3V3. Si vous utilisez un microcontrôleur avec un niveau de signal différent sur le port série (normalement 5 V) sera nécessaire, afin de ne pas endommager le ESP8266, utiliser un convertisseur de niveau comme ceux des schémas ci-dessous. Ce circuit se retrouve fréquemment dans de nombreuses implémentations de modules commerciaux.
Mettre à jour le micrologiciel ESP8266
Les Commandes AT ESP8266, sa terminaison, la vitesse par défaut du module... dépendent de la version du Micrologiciel ESP8266. Il est préférable de s'assurer que vous disposez de la même version dans tous les modules et, si possible, qu'il s'agisse de la dernière version.
Malheureusement, la plupart des Modèles de modules Wi-Fi ESP8266 Ils ne disposent que de 4 Mbits, la version la plus récente ne peut donc pas y être installée. La dernière version (officielle) du firmware pouvant être installée sur Module Wi-Fi ESP8266 avec 4 Mbits (la plupart) est 0.9.4 qui inclut la version 0.2 du Commandes AT ESP8266.
En résumé, pour mettre à jour le firmware il vous faut :
-
Téléchargez la version du firmware correspondante. la dernière version (officielle) d'un module doté de 4 Mbits de mémoire se trouve dans le dossier Espressif sur github. Dans le Site Expressif Vous pouvez télécharger la version la plus récente du firmware, mais il est très important de vérifier que le module sur lequel il est installé dispose de suffisamment de mémoire.
-
Téléchargez la dernière version de l'outil d'installation du micrologiciel. Mon favori est tremble qui est écrit dans Python, donc cela fonctionne sur n’importe quelle plateforme. En plus d'être téléchargé, il peut également être installé avec
pip install esptool
(opip2
opython -m pip
…). Bien sûr, expressif Il propose également son propre outil mais n'est actuellement disponible que pour Windows. -
Préparer les fichiers téléchargés; décompressez-les dans un dossier accessible et, si nécessaire, rendez l'outil exécutable tremble, dans mon cas, puisque GNU / Linuxavec
chmod +x esptool
-
Connectez le module à l'ordinateur à l'aide d'un convertisseur USB UART TTL ça marche en 3V3 ou utilisez un convertisseur de niveau s'il fonctionne à 5 V. En plus de l'alimentation, vous devrez connecter le TX au RX du convertisseur USB UART TTL, RX vers TX, GPIO0 à bas niveau (GND) et peut-être GPIO2 à haut niveau (dans mes tests, cela a fonctionné à la fois en le connectant à bas niveau et en le déconnectant). Si le module a la connexion GPIO15 libre (comme cela se produit dans l'ESP-12), il doit être connecté à un niveau bas. RESET, qui serait normalement à un niveau haut pendant le fonctionnement, peut être laissé non connecté ou connecté à un niveau haut au moyen d'une résistance (10K, par exemple), car avant de commencer l'enregistrement, il peut être nécessaire de réinitialiser l'appareil en le connectant. à un niveau bas.
En allumant le module, il sera disponible pour la mise à jour mais, Si une erreur de connexion s’affiche, il faudra la réinitialiser connecter RESET à un niveau bas pendant un instant, puis le laisser à l'antenne (sans connexion) pour le processus de mise à jour.
Le module a pics de consommation d'un demi-ampère (jusqu'à 600 mA, selon certains utilisateurs) il est donc important d'utiliser une alimentation capable de supporter cette consommation, notamment pour la mise à jour du firmware. -
Exécutez l'outil pour mettre à jour le firmware. Dans mon cas, j'ai enregistré les documents de l'outil et du firmware à l'étape 3 dans le même dossier, je lance donc depuis la console :
cd ~/Datos/firmwareESP8266
(passage au dossier contenant l'outil et le firmware)./esptool.py --baud 115200 --port /dev/ttyUSB0 write_flash \
0x00000 ./boot_v1.1.bin \
0x01000 ./user1.bin \
0x7C000 ./esp_init_data_default.bin \
0x7E000 ./blank.bin
--baud
définit la vitesse du ESP8266 (115200 XNUMX bauds dans mon cas) et--port
le port série auquel il se connecte (dans mon cas, émulé, le premier USB). Les différents documents qui composent le firmware suiventwrite_flash
précédé de l'adresse, avec le document user1.bin contenant la charge utile de la mise à jour.
Envoyer des commandes au module wifi ESP8266
Pour contrôler la ESP8266 depuis un ordinateur, nous devrons commencer par configurer l'application pour lequel il suffira de ① choisir le port sur lequel le convertisseur est connecté USB UART TTL, quelque chose comme /dev/USB0
sous GNU/Linux et similaire ou quelque chose comme COM6
sous Windows, ② choisissez la vitesse à laquelle le ESP8266, probablement 115200 8 bauds, ③ définit XNUMX bits de données plus un bit d'arrêt, sans parité ni prise de contact, et ④ définit la fin de la ligne, en fonction du firmware, presque toujours CR+LF.
Une fois l'application configurée (ou, le cas échéant, stockée et sélectionnée), elle est ouvrir la connexion ("ouvrir l'appareil" et "ouvrir", respectivement, dans les captures d'écran des exemples ci-dessus avec MignonCom y PuTTY) et vous pouvez commencer à envoyer des commandes à ESP8266.
Comme on peut le voir dans le Tableau des commandes AT ESP8266, le format pour activer, désactiver, définir une valeur et s'y référer est assez prévisible, mais en général il n'est pas facile de tous les retenir et vous aurez probablement besoin de l'avoir sous la main pour vous y référer.
Comment étancher leurs soif ? ENVOYER Commandes AT al Module Wi-Fi ESP8266 dès Arduino C'est très simple : ① configurer les communications avec Serial.begin(115200);
(ou Serial1, Serial2… sur les cartes avec plusieurs ports série matériels) et ② envoyez les commandes en utilisant le 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()
{
}
|
L'exemple ci-dessus montre comment envoyer le Module wifi ESP8266 aux commandes dès Arduino. Dans ce cas, il est illustré AT+CWJAP
, qui est utilisé pour se connecter à un point d’accès. Cette commande utilise comme arguments l'identifiant du point d'accès (SSID) et la clé, toutes deux entre guillemets, pour qu'elles deviennent un objet Srtring
et entouré de guillemets en utilisant le code d'échappement (\"
). Pour finaliser la commande, utilisez \r\n
ce qui correspond à CR
y LF
.
Rappelons que le port série n'est pas toujours identifié avec Serial
(sur certaines assiettes cela peut être Serial1
, Serial2
…) l'objet port utilisé a été défini en l'attribuant à la macro PUERTO_SERIE
. La détection du type de carte utilisée pourrait ajouter un peu d'intelligence à la sélection du port série ; Nous verrons plus tard comment déterminer le type de Arduino. Le reste des définitions sont les définitions habituelles qui permettent de "nommer" les valeurs constantes pour éviter de les répéter (et de faire des erreurs) et faciliter leur modification.
L'exemple ci-dessus est censé connecter le Module Wi-Fi ESP8266 au point d'accès indiqué mais était-il déjà connecté auparavant ? La connexion a-t-elle fonctionné ? Pour le savoir, nous devons « écouter » ce que disent les ESP8266
Recevez des données du module wifi ESP8266
En connectant le renifleur de données expliqué ci-dessus à l'ordinateur, vous pouvez voir ce qui Arduino a envoyé le ESP8266 et sa réponse. A lire depuis Arduino et traiter les informations qu'il contient, il faudra détecter avec Serial.available()
si des données sont arrivées et si c'est le cas, chargez-les avec Serial.read()
. L'exemple suivant montre comment lire la réponse de AT+CWJAP?
, qui signalera s'il existe une connexion à un point d'accès.
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();
}
}
|
Comme dans une assiette Arduino Uno (et dans d'autres) l'ouverture du moniteur série réinitialise le programme, il peut être utilisé pour voir dans la console série Arduino les informations que vous envoyez à ESP8266 comme le montre la capture d'écran de l'image ci-dessous.
Analyser la réponse envoyée par le module wifi ESP8266
Nous avons déjà vu comment lire les informations qui parviennent Arduino de l' ESP8266. Le problème auquel vous devez faire face est que vous ne savez pas quand cela commencera à arriver, combien de temps cela prendra pour arriver, quelle sera la durée... et il n'est pas très efficace d'attendre la réponse du ESP8266 est reçu sans laisser le microcontrôleur effectuer d'autres tâches entre-temps.
Un moyen simple de gérer cette situation est itérer sur les données reçues à la recherche de réponses concrètes avec lequel, par exemple, activez des indicateurs (drapeaux ou variables booléennes) qui détermineront s'il faut continuer la recherche dans le texte reçu et quelles actions doivent être effectuées en fonction des informations provenant du ESP8266. Pendant que la réponse arrive microcontrôleur peut se consacrer à d’autres tâches, par exemple, recevoir des données de capteurs et les traiter.
Rechercher un texte dans les informations reçues de l'ESP8266
Pour rechercher le texte provenant du ESP8266 peut être comparez chaque lettre reçue avec celle qui correspond au message que vous recherchez. Il faudra utiliser un compteur (ou un pointeur) qui pointe vers la lettre à comparer ; Si le personnage qui arrive du ESP8266 est le même que celui examiné dans le message, le compteur avance, s'il est différent il s'initialise.
Pour savoir que la fin est atteinte, on consulte le caractère suivant du message recherché, qui sera zéro (\0
) soit on mémorise la longueur du message pour, en la comparant avec le compteur, savoir si la comparaison est terminée et donc la Module Wi-Fi ESP8266 a envoyé le message recherché.
L'exemple suivant utilise la commande AT+CWLAP
qui renverra une liste de points d'accès et parmi ceux-ci, celui appelé "wifi polaridad.es" est recherché. Bien que nous ayons choisi de vérifier que le dernier caractère est zéro, comme le tampon Il stocke uniquement le texte recherché et sa longueur est connue, il peut également être vérifié si un tel nombre de lettres correctes ont été reçues. Avec un DEL connecté à la broche 2, il est signalé que le texte attendu a été trouvé.
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
}
}
}
}
|
Dans le code de l'exemple précédent, vous pouvez également voir un moyen de choisir le port série en fonction du type de carte Arduino utilisé. Cet exemple suppose que vous disposez de trois types de tableaux pour le projet : un Arduino Unoune Arduino Mega 2560 et un Arduino Leonardo. Si vous travaillez avec un Arduino Uno il sera utilisé Serial
et sinon Serial1
.
Si vous travaillez avec une assiette Arduino Leonardo Vous pouvez utiliser la même méthode pour arrêter le programme et attendre que la console (le port série associé à Serial
) est disponible.
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
|
Rechercher divers textes dans la réponse ESP8266
Le code de l'exemple précédent permet de rechercher du texte dans les informations envoyées par le ESP8266 mais la réponse peut inclure des informations différentes selon l'opération. Supposons, pour commencer par un cas simple dans l'exemple suivant, que le texte envoyé par le MCU ESP8266 es OK
lorsque l'opération est effectuée correctement et ERROR
Sinon, comme pour la commande AT+CWJAP?
, qui sert à vérifier si le Module Wi-Fi ESP8266 est déjà connecté à un point d’accès.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
#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
}
}
}
}
}
|
Cette nouvelle implémentation de la même méthode, qui recherche une correspondance avec plusieurs messages possibles, permet de choisir entre différentes actions en fonction de la réponse reçue du ESP8266, allumez simplement le DEL cela correspond.
Limitez le temps nécessaire pour recevoir une réponse
Jusqu'à présent, aucune référence n'a été faite à une question pertinente : la temps d'attente maximum (timeout) avant de considérer qu'une opération a échoué. Si, pour une raison quelconque, la connexion avec le Module Wi-Fi ESP8266, le module avec le point d'accès, le point d'accès avec Internet ou, par exemple, un hypothétique serveur n'est pas disponible, le programme peut être bloqué à un moment donné en attendant indéfiniment, il faudra donc articuler une réponse à de telles circonstances. Le temps d'attente maximum peut être configuré pour l'ensemble de l'application, il sera généralement plus "généreux" dans ce cas, ou des temps d'attente individuels peuvent être programmés pour chaque opération.
Pour vérifier qu'au moins un certain intervalle de temps s'est écoulé L'« heure » du moment où le compte est ouvert est généralement soustraite de l'« heure » actuelle et on vérifie que la différence est supérieure à la limite souhaitée.. Ce "temps" ne doit pas nécessairement être le temps réel, il correspond généralement à l'intervalle qui s'est écoulé depuis le MCU commencez à compter le temps ; Cela n'affecte pas le programme puisque ce qui est intéressant c'est le temps écoulé et non le temps absolu.
Habituellement, pour vérifier si un certain intervalle s'est écoulé, une expression du type est utilisée :
1
|
(unsigned long)(millis()–milisegundos_al_empezar)>intervalo_de_tiempo
|
Laissez variable milisegundos_al_empezar
contient la valeur de millis()
d'un certain moment dans l'exécution à partir duquel il est chronométré, il n'est donc pas inhabituel que son nom fasse référence au mot « chronomètre ». La variable intervalo_de_tiempo
contient le nombre maximum de millisecondes qui rendent l'expression précédente vraie, c'est-à-dire qu'elle représente le délai d'attente ; Il s'agit généralement d'une constante (ou d'une macro) et, comme dans le cas précédent, le mot "TIMEOUT" apparaît souvent dans son nom. Si vous travaillez avec des intervalles très courts, vous pouvez utiliser micros()
au lieu de millis()
(microsecondes au lieu de millisecondes) bien que ce soit beaucoup moins courant et beaucoup moins précis.
1
|
(unsigned long)(millis()–cronometro)>TIMEOUT
|
Un entier long dans Arduino (unsigned long
) occupe 4 octets (32 bits), donc la plus grande valeur qu'il peut représenter est 4294967295 (2 à la puissance 32 moins un, car il commence à zéro). sur une assiette Arduino Lorsqu'il fonctionne en continu, le compteur de millisecondes se réinitialise (revient à zéro) environ tous les 50 jours. Lors de la soustraction avec des types de données non signés, le même comportement est reproduit (retournement du compteur), il est donc viable de contrôler le délai d'attente indéfiniment.
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;
}
}
}
|
Le code ci-dessus montre un implémentation très basique de la limitation du délai d'attente incorporant les lignes marquées par rapport à l'exemple qui le précède. Étant donné que la vérification du délai d'attente est effectuée après le traitement des données provenant du Module Wi-Fi ESP8266, l'opération peut être considérée comme réussie même si la réception prend plus de temps que le temps d'attente imposé.
Exécuter une opération complexe définie par plusieurs commandes AT
Pour avoir un exemple de référence du but de l'application qui exploite le Module Wi-Fi ESP8266, supposons que ce soit stocker des informations dans une base de données accessible via un service Web pour suivre la température. Le code suivant lit un capteur connecté à une entrée analogique à intervalles de temps déterminés, calcule la valeur moyenne et, après un intervalle de temps plus long, l'envoie au serveur Web (style IdO) à travers un demander HTTP (POSTER, OBTENIR…).
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”);
}
}
|
Dans cet exemple d'enregistrement de la température, un serveur Web est consulté toutes les cinq minutes. Bien que la disponibilité ne soit pas particulièrement élevée, on peut s'attendre à ce que la proposition fonctionne, mais si une fréquence d'enregistrement plus élevée était nécessaire, d'autres ressources devraient être mises en œuvre, par exemple un tampon de données en attente d'être envoyé, pour en envoyer plusieurs lorsque le serveur peut y assister et les stocker lorsqu'il n'est pas disponible. Si la fréquence à laquelle les données doivent être enregistrées était encore plus grande, d'autres types de protocoles devraient être proposés comme alternative au HTTP ou même remplacer TCP par UDP pouvoir envoyer la plupart des données à la vitesse requise, même au prix d'en perdre certaines.
Les opérations qui composent la tâche à effectuer pour envoyer la température seraient :
- Réinitialiser le module wifi
- Se déconnecter du point d'accès actuel (dans le cas où une connexion par défaut existe)
- Définissez les paramètres. Pour l'exemple, on suppose que le mode de connexion (simple) et le rôle dans les communications Wi-Fi (station) doivent être configurés.
- Se connecter au point d'accès
- Vérifiez que la connexion est correcte (en fait, c'est le point d'entrée) S'il n'y a pas de connexion, recommencez le processus depuis le début
- Connecter au serveur
- Envoyer la demande HTTP avec les données à stocker
L'ordre des opérations ne doit pas nécessairement être exactement comme celui-ci (bien que l'opération le soit) et chaque étape peut nécessiter plusieurs étapes. Commandes AT ESP8266Par exemple, la configuration répertoriée ci-dessus en nécessiterait deux : AT+CIPMUX=0
y AT+CWMODE=1
.
Une structure de données pour représenter les opérations sur l'ESP8266
Dans les exemples précédents, bien que de manière très basique, une solution générique au problème est déjà suggérée : utiliser une structure de données qui stocke les réponses possibles et les actions qui doivent être prises dans chaque cas; envoyez une action, attendez une réponse et procédez en fonction de ce que signifie la réponse. Puisque chaque opération complexe nécessitera plusieurs Commandes AT ESP8266, la structure de données doit relier une opération avec d'autres, ultérieures ou précédentes, qui doivent être effectuées dans chaque cas en fonction de la réponse du ESP8266.
Dans les exemples précédents, un message a été recherché dans la réponse du ESP8266 et cela a été interprété comme un succès ou une erreur. Outre une réception (et analyse) de l'ensemble des textes reçus, Pour avoir un minimum générique, il convient de veiller également à la finalisation du message ou, en d'autres termes, à la disponibilité du Module Wi-Fi ESP8266 pour recevoir de nouvelles commandes. De cette façon, le passage à un état que nous pourrions appeler, par exemple, « wifi disponible », pourrait consister à recevoir le nom du point d'accès et à recevoir le texte ERROR
ou le texte OK
signifierait que le ESP8266 vous avez terminé la réponse et vous pouvez maintenant envoyer la suivante Commande AT vers 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;
|
Le code ci-dessus utilise un vecteur (operacion
) pour stocker le texte des opérations successives qui constituent la tâche complète. Un tableau à deux dimensions est utilisé (mensaje
) avec les trois réponses analysées. Comme expliqué ci-dessus, il faut rechercher les messages qui représentent la fin de la réponse en plus du message qui représente une réponse correcte ou incorrecte. Toutes les opérations n’auront pas le même nombre de réponses possibles ; Lorsqu'il y a moins de réponses, on peut utiliser un message vide qui consomme le moins de cycles possible dans son analyse (même si ce n'est pas la manière la plus optimale). Logiquement, il faudra que le nombre minimum de réponses recherchées (trois dans l'exemple) englobe toutes les possibilités de fonctionnement, même si elles ne sont pas toutes possibles.
En parlant des réponses possibles, on peut déjà voir que cet exemple n'est pas très utile pour recevoir des données dans un format arbitraire depuis un Module Wi-Fi ESP8266, mais le problème est que, dans le cadre d'une utilisation avec microcontrôleurs ce n'est pas habituel ; Le plus courant est d'envoyer les données collectées par les capteurs qu'ils ont connectés et/ou de recevoir des informations sur ce qu'il faut faire avec les actionneurs qu'ils contrôlent. Des informations très précieuses, qui peuvent très bien être prédites.
Dans la structure de données précédente, tout comme pour exprimer les réponses possibles analysées, une matrice bidimensionnelle est également utilisée pour déterminer l'opération qui doit être effectuée dans chaque cas (siguiente_operacion
). Concrètement, nous avons choisi de répondre à trois types de messages : ① un texte arbitraire (LITERAL
) pour vérifier s'il existe une connexion au point d'accès Wi-Fi et au serveur, ② un texte pour détecter les erreurs dans le processus (FALLO
) et ③ un texte indiquant que l'opération s'est déroulée avec succès (ACIERTO
).
Enfin, il existe deux autres vecteurs pour définir le temps d'attente maximum avant d'abandonner (timeout
) et précisez (configuracion
) si l'opération se termine sans attendre de réponse (ESPERAR_RESPUESTA
) et des messages indiquant la fin de la communication. Ce dernier vecteur, pour illustrer un exemple d'économie de mémoire, fonctionne avec les bits d'un octet de configuration pour indiquer les différents états.
Les premières Commandes AT ESP8266 de la structure de données attendent toujours une réponse, qui peut être un message de réussite ou d'erreur. Lorsqu'une erreur se produit, le module est redémarré et il redémarre et si le message indique que l'opération est correcte, il passe au suivant.
Une fois connecté au serveur, le modèle change. Dans ce cas il faut ① envoyer la longueur du paquet de données à transmettre et ② composer la requête HTTP avec un texte fixe plus la valeur (de la température) qui est envoyée pour être stockée sur le serveur. La préparation de ces données est effectuée à chaque envoi et il faut la diviser en deux (indiquer la longueur) ou trois (envoyer la demande HTTP) Pour Commande ESP8266 AT. Seule la dernière des parties qui composent l’opération attendra une réponse.
Dans ce cas, cela fonctionnera sans problème (peut-être en avertissant que le module est occupé) mais lorsque la longueur des données est plus grande, il sera nécessaire de diviser les blocs de données en morceaux plus petits et il peut même être nécessaire d'implémenter une attente, car se fait avec la lecture de la température, pour donner au module le temps d'envoyer les données sans remplir son tampon.
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();
|
Avec d'autres macros déjà expliquées précédemment, l'exemple de code ci-dessus montre comment sont définis les différents états avec lesquels spécifier s'il faut attendre une réponse et, le cas échéant, quel message indique que l'opération est terminée.
Comme à différents points du code une opération sera envoyée (quand il sera temps d'envoyer la température moyenne, si le temps d'attente d'une opération est dépassé, quand l'opération en cours est terminée avec succès...) mais comment faire est établi à l'échelle mondiale, il a été défini comme un macro ENVIAR_OPERACION
qui regroupe les étapes impliquées dans l’expédition.
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();
|
Ce qui suit est le code du programme principal de l'exemple. La tâche la plus externe est celle chargée d'échantillonner la température pour calculer la moyenne et, à intervalles réguliers, elle est envoyée au serveur à l'aide du Module Wi-Fi ESP8266. Une fois chaque opération envoyée, la réponse est analysée pour déterminer laquelle est la suivante ou si la tâche d'envoi d'informations est terminée.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
#include “ESP8266_operacion_compleja_varias_ordenes_AT.h”
#define PIN_TEMPERATURA A0 // Pin analógico al que se conecta la salida del sensor de temperatura LM35
#define INTERVALO_LECTURA_TEMPERATURA 30000 // Leer la temperatura cada 30 segundos (30*1000)
#define INTERVALO_GRABACION_TEMPERATURA 300000 // Grabar la media de la temperatura cada 5 minutos (5*60*1000)
unsigned long muestras=0; // Número de veces que se ha medido la temperatura (para calcular la media)
float temperatura; // de -55.0 °C a +150 °C | de 0 V a 2.050 V | de -550 mV a +1500 mV | analogRead*5.0/1023.0*100-55.0 analogRead/2.46-55.0
float media_temperaturas=0.0;
unsigned long cronometro_lectura_temperatura;
unsigned long cronometro_grabacion_temperatura;
char *mensaje_fallo=“ERROR\r\n”;
char *mensaje_acierto=“OK\r\n”;
char *sin_enlace=“link is not\r\n”;
char *mensaje_vacio=“\f”;
char *operacion[CANTIDAD_OPERACIONES]; // Matriz de punteros a constantes de caracteres con las operaciones que se envían al ESP8266 (no solo órdenes AT, aunque seguro que algunas son órdenes AT)
char *mensaje[CANTIDAD_OPERACIONES][CANTIDAD_RESPUESTAS]; // Mensajes de respuesta
unsigned char siguiente_operacion[CANTIDAD_OPERACIONES][CANTIDAD_RESPUESTAS];
unsigned char configuracion[CANTIDAD_OPERACIONES];
unsigned int timeout[CANTIDAD_OPERACIONES];
unsigned char numero_caracter[CANTIDAD_RESPUESTAS];
unsigned int longitud_peticion;
char texto_longitud_peticion[4]; // 3 caracteres para almacenar la longitud de la petición en formato texto
char valor_enviado[9]; // signo + 4 enteros + punto + 2 decimales + \0 = 9
unsigned long cronometro_esp8266;
unsigned char operacion_actual; // Número de operación que se está procesando
unsigned char proxima_operacion; // Siguiente operación que se procesará cuando termine la actual
char lectura_serie;
boolean grabando_datos=false;
boolean esperando_respuesta;
void setup()
{
#include “inicializar_operaciones.h”
longitud_peticion=strlen(operacion[ENVIAR_PREFIJO_PETICION])+strlen(operacion[ENVIAR_SUFIJO_PETICION]);
SERIE.begin(VELOCIDAD); // Configurar el puerto serie de Arduino a la velocidad del ESP8266
//delay(8000); // En fase de pruebas se puede introducir un tiempo de espera para conectar una consola/sniffer
cronometro_lectura_temperatura=millis();
cronometro_grabacion_temperatura=millis();
}
void loop()
{
if((unsigned long)(millis()–cronometro_lectura_temperatura)>INTERVALO_LECTURA_TEMPERATURA)
{
cronometro_lectura_temperatura=millis();
temperatura=analogRead(PIN_TEMPERATURA)/2.46–55.0;
muestras++;
media_temperaturas=(float)temperatura/(float)muestras+media_temperaturas*(float)(muestras–1)/(float)(muestras);
}
if(grabando_datos)
{
if((unsigned long)(millis()–cronometro_esp8266)>timeout[operacion_actual]) // Si se ha superado el tiempo de espera máximo
{
operacion_actual=siguiente_operacion[operacion_actual][FALLO]; // Pasar a la operación correspondiente al error
ENVIAR_OPERACION
}
else // Si no se ha superado el tiempo de espera máximo
{
if(configuracion[operacion_actual]&ESPERAR_RESPUESTA) // Si la siguiente operación depende de la respuesta a la actual desde el ESP8266 hay que leer la información que llegue desde el puerto serie
{
while(SERIE.available())
{
lectura_serie=SERIE.read();
for(unsigned char numero_respuesta=0;numero_respuesta<CANTIDAD_RESPUESTAS;numero_respuesta++) // Comparar la letra cargada desde el puerto serie con la correspondiente de los mensajes disponibles
{
if(lectura_serie==mensaje[operacion_actual][numero_respuesta][numero_caracter[numero_respuesta]]) // Si el dato que ha llegado es igual al que correspondería del mensaje buscado…
{
numero_caracter[numero_respuesta]++; // Como el carácter coincide, se puede comparar con el siguiente lo próximo que llegue por el puerto serie
if(mensaje[operacion_actual][numero_respuesta][numero_caracter[numero_respuesta]]==0) // Si el carácter que toca es \0 es que se ha terminado de analizar el mensaje
{
if(esperando_respuesta) // Todavía no se ha encontrado un mensaje que determine la siguiente operación
{
proxima_operacion=siguiente_operacion[operacion_actual][numero_respuesta]; // La próxima operación que habrá que procesar será la que indique el mensaje encontrado para la operación actual
esperando_respuesta=false; // Ya se ha encontrado un mensaje que determina la siguiente operación
}
if(configuracion[operacion_actual]&(1<<numero_respuesta)) // Si el mensaje encontrado es uno de los que terminan la operación…
{
if(operacion_actual+1==CANTIDAD_OPERACIONES) // Se ha completado la última operación de la tarea compleja
{
grabando_datos=false; // Se ha terminado la tarea compleja (grabar datos en el servidor)
}
else // No es la última operación de la tarea compleja, hay que seguir realizando otras operaciones
{
operacion_actual=proxima_operacion; // Ejecutar la siguiente operación
ENVIAR_OPERACION
}
}
}
}
else // Si la letra recibida no es igual que la correspondiente del mensaje
{
numero_caracter[numero_respuesta]=0; // Empezar a comparar desde la primera letra del mensaje
}
}
}
}
else // Si no hay que esperar datos desde el puerto serie
{
operacion_actual=siguiente_operacion[operacion_actual][ACIERTO];
ENVIAR_OPERACION
}
}
}
else
{
if((unsigned long)(millis()–cronometro_grabacion_temperatura)>INTERVALO_GRABACION_TEMPERATURA)
{
cronometro_grabacion_temperatura=millis();
dtostrf(media_temperaturas,4,2,valor_enviado); // snprintf(valor_enviado,9,”%+3.2f”,media_temperaturas); // printf y derivadas no funcionan en AVR
snprintf(texto_longitud_peticion,4,“%d”,longitud_peticion+strlen(valor_enviado));
grabando_datos=true;
operacion_actual=VERIFICAR_CONEXION;
operacion[ENVIAR_DATOS]=valor_enviado;
operacion[ENVIAR_CANTIDAD]=texto_longitud_peticion;
ENVIAR_OPERACION
}
}
}
|
Logiquement, plusieurs actions d'optimisation peuvent être réalisées sur le code précédent mais, comme il s'agit d'un exemple pour comprendre comment le ESP8266 De manière générique, il convient de se concentrer uniquement sur certains aspects, le premier étant la structure des données. Il semble que la chose logique est utiliser une structure de données de langage de programmation (struct
) pour représenter les informations en cours de traitement: le Commandes AT ESP8266 et les messages analysés.
Utiliser une structure (struct
) pour stocker les données au lieu des exemples de tableaux (basés sur ceux-ci) est trivial et, bien que cela puisse donner lieu à un code plus élégant, cela n'implique aucune amélioration du résultat. La véritable alternative posée par l’utilisation de struct
est de mettre en œuvre, comme expliqué ci-dessous, longueurs variables dans les structures qui contiennent des données « internes » auxquels ils font référence. De cette manière, par exemple, il ne serait pas nécessaire qu’une opération ait un nombre fixe de réponses à analyser.
Cette approche suggère que c'est la meilleure façon de mettre en œuvre la solution mais l'inconvénient est qu'il faudrait utiliser l'allocation dynamique de mémoire, une pratique risquée en travaillant avec un microcontrôleur ce qui nécessite une mesure minutieuse de la quantité de mémoire qui sera utilisée au moment de l'exécution, puisque le compilateur pourra difficilement nous en avertir et qu'il existe une certaine possibilité d'épuiser la mémoire (ou la pile) avec des conséquences fatales pour l'exécution du programme.
Dans le cadre de l'optimisation du code, il est intéressant de rappeler que, dans un programme de ce type, qui utilise une grande quantité de texte, peut économiser de l'espace mémoire SRAM stocker des chaînes de texte dans la mémoire du programme (flash) avec la macro F()
. Dans les captures d'écran suivantes, vous pouvez voir les différents programmes et la distribution dynamique de la mémoire avec une utilisation normale du texte et l'utilisation de la macro. F()
.
En ce qui concerne les actions exécutées en fonction des informations provenant du Module Wi-Fi ESP8266, au lieu de vérifier le message à partir du code et d'exécuter l'un ou l'autre en fonction de ce qui est reçu, peut être stocké dans cette structure de données des pointeurs vers les fonctions qui exécutent chaque tâche au lieu d'indicateurs d'état (drapeaux) qui avertissent d'un certain état que l'application est chargée de gérer, par exemple, au sein de la boucle principale.
Ce qui suit est un exemple de structures pour stocker les données des requêtes adressées au ESP8266 (le type de données operacion_esp8266
) et leurs réponses (le type de données 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;
|
En tant que structure qui représente l'opération (les données envoyées au Module Wi-Fi ESP8266) fait référence à la structure avec laquelle les réponses sont définies, et la structure des réponses à la structure des opérations, il faut d'abord déclarer les deux, en définissant le nouveau type de données, puis en définissant son contenu.
L'exemple précédent considère que le programme qui l'inclut a choisi d'utiliser un indicateur de statut, qui doit correspondre à une variable accessible depuis le code chargé d'effectuer l'une ou l'autre opération comme indiqué par ladite valeur. Si dans la réponse de ESP8266 Lorsqu'un certain texte est analysé, l'état prend la valeur qui indique la structure de la réponse correspondante.
Comme dit précédemment, une autre alternative, soit pour remplacer ou compléter un indicateur d'état, serait stocker une fonction dans la structure de référence (un pointeur) qui serait appelé à rencontrer certains textes dans la réponse du Module Wi-Fi 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
|
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;
|
Dans l'exemple précédent, il a été ajouté à la structure de données utilisée pour traiter la réponse du Module Wi-Fi ESP8266 un pointeur vers une fonction (supposée) qui renvoie une donnée de type float
(pourrait être la valeur pondérée d'une lecture analogique) et à laquelle deux octets sont fournis comme arguments (deux unsigned char
qui pourrait être la broche à partir de laquelle l'entrée analogique est lue et celle qui active l'ENABLE d'un hypothétique intégré).
En développement pour MCU, contrairement à ce qui se produit dans le style de développement des grands systèmes, il n'est pas si rare d'utiliser des variables globales lors de la définition du comportement (global) de l'application qui contrôle un assembly, il ne sera donc pas particulièrement rare de trouver ce type de définitions comme des fonctions sans paramètres et qui ne renvoient pas de valeurs, quelque chose comme void (*accion)();
Si vous travaillez avec cette façon de représenter les données, en utilisant struct
de données de longueur variable, il sera nécessaire d'allouer dynamiquement de la mémoire avec malloc()
(o new()
, si des objets sont utilisés), qui utilisera la quantité de mémoire allouée comme paramètre et renverra un pointeur vers le début de la zone mémoire réservée. Avec sizeof()
Sur le type stocké, multiplié par le nombre d'éléments utilisés, vous pouvez obtenir la quantité de mémoire nécessaire. Un exemple avec et sans utilisation peut être vu dans les captures d'écran ci-dessous. malloc()
; Attention à la mémoire utilisée par le programme dans le premier cas, vous devez charger la bibliothèque qui contient cette fonction.
Si les opérations sur le Module Wi-Fi ESP8266 variera tout au long de l'exécution du programme, il faudra libérer la mémoire qui n'est pas utilisée avec free()
(o delete()
, dans le cas d'être des objets). Bien qu'il soit raisonnable de s'attendre à ce que le compilateur (GCC) optimisera le programme pour éviter le partitionnement de la mémoire, les performances ne seront sûrement pas aussi optimales que de travailler avec de la mémoire allouée statiquement.
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
}
}
}
|
Bien que dans cet exemple (dans les deux implémentations) cela n'ait pas beaucoup de sens, afin de généraliser l'opération pour pouvoir l'appliquer à d'autres cas, il convient de noter que L'envoi de données répète toujours le même protocole : notifiez le nombre d'octets qui seront envoyés, attendez l'indicateur (>) et envoyez les données.
Comme dans cet exemple il n'est utilisé qu'une seule fois (la requête entière est faite dans un seul paquet), cela ne semble pas très utile mais, en général, il peut être nécessaire d'effectuer plusieurs envois dans la même opération, y compris les cas où ils doivent être transmis des quantités importantes de données qui doivent être fragmentées pour éviter de déborder la mémoire du ESP8266.
Pour mettre en œuvre ce comportement, les deux derniers éléments de la connexion peuvent être utilisés pour qu'à chaque envoi de données, les données soient remplies avec les valeurs correspondantes : dans le premier cas, le nombre d'octets envoyés et dans le second, le ( partie de la demande à transmettre.
Pour répéter l'affectation et l'envoi des différents éléments qui doivent être transmis peuvent être stockés dans un vecteur. Ce nouveau vecteur sera celui qui déterminera la fin de l'opération complexe et non la dernière opération comme jusqu'à présent.
1 commentaire