1°/ Structuration d'un sketch (= programme)

  • un programme arduino est appelé un sketch.
  • Il contient au moins 2 fonctions :
    • void setup() : initialise les variables globales, les communications en protocole série, senseurs, connexion wifi, ... Cette fonction est exécutée une seule fois après le boot,
    • void loop() : le point d'entrée d'exécution (= le main() d'un programme). A la fin de son exécution, le µC l'exécute de nouveau. loop() est donc appelée cycliquement, jusqu'à ce que le µC crashe, reboote, s'arrête, ...
  • Le sketch peut bien entendu contenir d'autres fonctions.
  • Comme dans un programme C, les variables peuvent être locales aux fonctions, ou bien globales à tout le sketch.
  • Généralement, les variables globales sont déclarées au début du sketch, après les #include et #define.

2°/ Lire/écrire sur les pins GPIO

  • le package (= enveloppe plastique) d'un µC expose des pins de connexion qui sont utilisées pour le connecter aux autres composants d'un circuit.
  • Une partie de ces pins ont une fonction bien précise alors que d'autres peuvent être librement utilisées par un utilisateur pour être connectées à des circuits tels que des senseurs, des LEDs, des interrupteurs, etc.
  • Ces pins sont appelées GPIO : Global Purpose Input/Output.
  • Un µC n'étant quasi jamais utilisé directement mais intégré sur une carte de développement, seules une partie de ces GPIO sont réellement utilisables par le développeur.
  • Par exemple, l'esp8266 a 33 pins au total, et 17 GPIOs. Mais seules 11 sont réellement utilisables puisque 6 sont toujours utilisées pour connecter le µC à une mémoire flash contenant le micro-code a exécuter.
  • De plus, selon les constructeurs de la carte de développement, il peut y avoir encore moins que 11 GPIOs utilisables. Par exemple, les pins 1 et 3 sont généralement déjà connectées au convertisseur serie-usb qui permet à l'µC de communiquer avec un ordinateur au travers d'un cable USB.
  • Enfin, même si les cartes de développement ont toutes une structure physique avec les GPIOs accessibles sur le pourtour de la carte, l'emplacement d'une GPIO précise peut varier d'une carte à une autre.
  • En conclusion, pour un même projet, il peut être compliqué de l'adapter à différentes cartes de développement même si elles sont basées sur le même µC. C'est encore plus compliqué si on change de µC.

 

  • Parmi les GPIOs, il existe des pins digitales et analogiques :
    • digital : permet de lire/écrire un signal numérique, c.a.d. un signal à 2 états : HIGH/LOW signal. HIGH correspond au voltage le plus haut (3.3V sur un esp8266, 5V sur un ATmega328), et LOW à 0V.
    • analogique : permet de lire/écrire un signal qui varie dans le temps, entre les niveaux haut et bas. Même si le signal physique varie de façon continue, ce n'est pas le cas du point de vue µC puisque ce dernier discrétise le signal afin d'obtenir une valeur numérique. La plage de variation acceptable, le nombre de pas, la vitesse d'acquisiation, ... dépendent du µC. Par exemple, un esp8266 accepte un signal variant entre 0 et 1V, et discrétise sur 1024 pas. (NB : 4096 pas pour un esp32)
  • ATTENTION ! Une GPIO digitale peut être utilisée aussi bien en lecture qu'écriture, alors qu'en analogique, un seul sens est possible (pour des raisons électroniques)
  • Sur une carte de développement basée sur un esp8266, il y a généralement une seule entrée analogique et aucune sortie, alors qu'avec un esp32, il y a généralement 3-4 entrées et 2 sorties analogiques.

 

  • Pour simplifier la programmation des µC, les sketch n'utilise pas le nom technique ou bien le n° de pin physique du package du µC. Par exemple, la GPIO5 de l'esp8266 est la pin n° 24.
  • On utilise plutôt des surnoms ou des numéros qui sont les mêmes quel que soit le constructeur de la carte de développement. ATTENTION, ces surnoms n'ont pas forcément de rapport avec le nom "officiel" de la GPIO. Par exemple, la GPIO5 de l'esp8266 est renommée D1. Mais parfois, cela correspond : la GPIO12 de l'esp32 est renommée 12.
  • En conclusion, il faut toujours se baser sur les surnoms.

 

  • Pour spécifier le sens d'utilisation d'une GPIO digitale, on utilise la fonction pinMode().
  • Généralement, ce sens ne varie pas au cours de l'exécution, donc on fait l'initialisation dans setup(). Au cas où le sens change, il suffit de réutiliser pinMode().
  • Exemple :
void setup() {
  pinMode(D3, OUTPUT);
  pinMode(D2, INPUT);
  ...
}

 

  • Les fonctions pour lire et écrire changent selon le type de GPIO
  • Exemple :
int val = analogRead(A0);
byte b = digitalRead(D2);
...
analogWrite(25, 1234); // write 1234 on pin 25 of an esp32, which corresponds to 3.3*1234/4096 = 0.9942V
digitalWrite(D3,HIGH); // on an esp8266, D3 now outputs 3.3V
digitalWrite(D3,LOW); // on an esp8266, D3 now outputs 0V

 

3°/ Communication série

  • La plupart des cartes de développement ont un circuit qui permet d’envoyer un programme dans la mémoire flash liée au µC, au travers d'un câble USB.
  • En fait, ce circuit permet de convertir les communications utilisant un protocole série en un protocole USB.
  • Ce circuit est relié directement à 2 GPIO du µC, qui sont elles-mêmes reliées à une partie du µC capable d'envoyer recevoir des données via un protocole série.
  • Il est donc possible d'envoyer recevoir des données entre le µC et un PC, en initialisant ce protocole série. 
  • Cela est particulièrement utile pour faire du débogage en envoyant des messages depuis le µC.
  • Pour utiliser la communication série, le langage arduino fourni directement une classe nommée Serial.
  • L'initialisation se fait généralement dans setup(), en donnant une vitesse en bauds.
  • Ensuite, une méthode println() permet d'envoyer des lignes de texte, et read() permet de lire un octet (NB : pas de méthode pour lire des lignes !)
  • Exemple :
...
void setup() {
  Serial.begin(115200); // initialize serial connection at 115200 bauds
  Serial.println("hello");
  ...
}

 

Remarques

  • Les vitesse de communication maximales dépendent du µC. Par exemple, un ATmega328 (sur les cartes arduino) autorise seulement 9600 bauds.
  • Certains modules, comme par exemple les GPS, utilisent également un protocole série pour communiquer avec le µC. Cela pose problème sur un esp8266 puisque le circuit série est déjà utilisé pour communiquer avec le PC. Fort heureusement, on peut faire de la communication série en utilisant n'importe quelles GPIOs digitales. Mais dans ce cas, il faut émuler le protocole série par du logiciel, ce qui est moins performant que de passer par l'électronique interne du µC.
  • l'esp32 fourni 3 couples de GPIO capables nativement de faire des communications série. 

 

 

4°/ Interruptions

  • Certains µC sont capable de surveiller une GPIO digitale (pas possible pour analogique) et de vérifier s'il y a un changement d'état.
  • Dans ce cas, le µC peut interrompre l'exécution en cours, et appeler une fonction callback nommée gestionnaire d'interruption.
  • Après la fin de cette fonction, l'exécution reprend son cours là où elle avait été interrompue.
  • Ce mécanisme est particulièrement utile pour détecter les appuis sur des boutons, les changements de position d'un switch, ... En effet, la façon basique de détecter un changement est de récupérer régulièrement l'état d'une GPIO, grâce à digitalRead(). Malheureusement, il est ainsi possible de rater un changement qui aurait lieu entre 2 lectures.
  • Avec une interruption, on est assuré de réagir à tous les changements d'état.

Exemple : pin D3 d'une carte basée sur un esp8266

volatile byte state;
...
void ICACHE_RAM_ATTR mycallback() {
  state = digitalRead(D3);
  ...
}
...
void setup() {
  ...
  attachInterrupt(digitalPinToInterrupt(D3), mycallback, CHANGE);
  ...
}
Remarques
  • Il y a deux contraintes pour mettre en place un gestionnaire d'interruption :
    • le code de la fonction DOIT être en mémoire RAM et pas dans la mémoire flash (NB : comme c'est le cas par défaut), sinon le µC peut crasher. Pour forcer la mise en RAM, on utilise ICACHE_RAM_ATTR devant le nom de la fonction.
    • les variables globales manipulées par la fonction DOIVENT être également en RAM et pas en registre/cache. En effet, si un telle valeur est mise en registre, elle sera perdue puisqu'au moment du retour à l'exécution courante, les registres vont être restaurés avec leur valeur d'avant l'interruption. Pour ce faire, on utilise le mot-clé volatile devant le type de la variable.
  • Le nom du gestionnaire d'interruption est libre, puisqu'il est donné en paramètre de attachInterrupt().
  • Le troisième paramètre de attachInterrupt() indique le type de changement détecté :
    • CHANGE détecte un changement détat du signal de LOW vers HIGH ou l'inverse.
    • RISING seulement de LOW vers HIGH,
    • FALLING seulement de HIGH vers LOW.
  • digitalPinToInterrupt() est utilisé pour convertir le surnom de la GPIO en un numéro utilisé par le µC pour gérer les interruptions. Cette numérotation étant spécifique à chaque µC, on n'utilise jamais ce numéro dans le code mais on appelle digitalPinToInterrupt().
  • Le nombre de GPIO utilisables avec les interruptions dépend du type de µC. Sur esp8266/32, toutes les pins digitales peuvent être surveillées.
 
5°/ Pulse Width Modulation (PWM)
  • PWM est un mécanisme qui utilise un GPIO digitale (pas possible pour analogique) pour émettre un signal cyclique composé d'impulsion plus ou moins large par rapport à la période du signal.
  • Pendant la pulsation, le signal est à l'état haut et bas le reste du temps.
  • Le ratio entre le temps passé à l'état haut et celui à l'état bas pour une même période est appelé le duty cycle. Il est généralement exprimé en %, comme le montre la figure ci-dessous avec 3 exemples de duty cycle.

Duty Cycle Examples

 

  • Le deuxième paramètre d'un signal PWM est la fréquence du signal, ce qui donne la durée de la période (= temps passé haut + temps passé bas).
  • Par exemple, si la fréquence PWM est de 100Hz, la période est de 1/100 s, soit 10ms. Par conséquent, si le duty cycle est fixé à :
    • 10% : le signal est bas pendant 9ms puis haut pendant 1ms.
    • 50% : le signal est bas pendant 5ms puis haut pendant 5ms.
    • 80% : le signal est bas pendant 2ms puis haut pendant 8ms.

 

  • Ce principe est utilisé pour alimenter des composants tels qu'un moteur pour faire varier la vitesse de rotation, une LED pour faire varier sa brillance.
  • En effet, même si l'alimentation est effectivement faite par intermittence, si la fréquence est suffisamment élevée, un humain observera un phénomène continu mais moins "intense" qu'avec une alimentation en permanence à l'état haut.

 

 

  • Les 3 fonctions utilisées pour mettre en place un signal PWM sur un esp8266 ont des noms commençant par analog...() bien que l'on utilise une GPIO digitale. Cela vient du fait que le PWM "simule" un signal analogique puisqu'on peut faire varier son niveau moyen en jouant sur la fréquence et le duty cycle.
  • Ces fonctions sont :
    • analogWriteRange(range) : fixe le nombre de pas de discrétisation de la période, ce qui donne le nombre de valeur possibles pour le duty cycle (sans compter le 0%). Par exemple, si range = 2, il y a 2 pas de discrétisation donc les seules valeur possibles du duty cycle sont 0%, 50% et 100%. Si range = 100, il y a 100 pas, donc 101 valeurs possibles pour le duty cycle : 0%, 1%, 2%, ... 99% et 100%
    • analogWriteFreq(freq) : fixe la fréquence du signal Hertz. La plage de valeur de freq dépend du µC et de la valeur de range : plus range est petit plus feq peut être élevé. Par exemple, sur un esp8266, la fréquence peut aller jusqu'à 40KHz.
    • analogWrite(pin, dc) : démarre la génération PWM sur la GPIO pin. dc indique le nombre de pas de discrétisation de la période passés à l'état haut, donc permet de fixer indirectement le duty cycle. Par exemple ;
      • si range = 2 et dc = 1, alors on obtient un duty cycle de 50%
      • si range = 10 et dc = 7, alors on obtient un duty cycle de 70%
      • si range = 25 et dc = 10, alors on obitent un duty cycle de 40%
      • ...

Exemple sur une esp8266/arduino :

analogWriteRange(100);
analogWirteFreq(10000); // 10KHz
analogWrite(D3,13); // duty cycle = 13/range = 13/100 =>  13%

 

Remarques :

  • selon le µC, il y a plus ou moins de GPIOs digitales capables de produire un signal PWM. Sur l'esp8266/32, presque toutes en sont capables.

 6°/ Wifi

  • les esp8266/32 intègre nativement un support bluetooth et wifi, ce qui n'est pas le cas de l'ATmega328
  • De plus, ils peuvent être programmés pour agir comme un client wifi, un point d'accès (AP) wifi, ou bien les deux :
    • Un client se connecte à un AP et reçoit en retour une adresse IP,
    • Un AP fournit des connexions Wifi et des IPs aux clients, mais n'a pas forcément d'IP
    • La combinaison des eux permet à l'AP d'avoir une IP et de partciper aux communications entre µC.

 

  • Un sketch nécessitant d'utiliser le Wifi doit forcément inclure le fichier .h contenant les déclarations des fonctions/classes/constantes/... liées au Wifi.
  • Malheureusement, le nom de ce fichier n'est pas standardisé et il change selon le µC.
  • Par exemple, pour un arduino et esp32, il faut inclures WiFi.h, et pour les esp8266, c'est ESP8266WiFi.h


6.1°/ client Wifi

  • Généralement, on écrit une fonction qui sera appelée dans setup().
  • Cette fonction essaie à l'infini d'établir une connexion à un point d'acces dont on connait le SSID et le mot de passe.

Exemple :

#include <ESP8266WiFi.h>
...
void setupWifi() {
     
  const char *ssid = "ssid_wifi_ap"; // the ssid of the AP        
  const char *password = "pass_ap"; // the password of the AP  
  
  // comment 2 following lines if not needed
  WiFi.setAutoConnect(false);  // see comments   
  ret = WiFi.setSleepMode(WIFI_NONE_SLEEP); // always active => big consumption

  ret = WiFi.mode (WIFI_STA); // setup as a wifi client
  ret = WiFi.begin(ssid,password); // try to connect
  while (WiFi.status() != WL_CONNECTED) { // check connection
    delay(500); 
    Serial.print(".");
  } 
  // debug messages
  Serial.print("Connected, IP address: ");
  Serial.println(WiFi.localIP());
}

 

Remarques

  • setAutoConnect(false) permet d'éviter que le µC se connecte automatiquement au dernier AP qu'il a utilisé. En effet, ses informations sont stockées en mémoire flash et par défaut, le µC tente lors du boot de s'y connecter. Au mieux, cela ralentit la connexion à un nouvel AP, mais dans certains cas, cela empêche totalement cette connexion. Il est donc conseillé de désactiver cette connexion automatique quand le µC est nomde et va souvent changer d'AP. On la laisse active uniquement s'il se connecte toujours au même AP.
  • setSleepMode(WIFI_NONE_SLEEP) permet de garder le circuit Wifi toujours actif. Ce n'est pas le mode par défaut où ce circuit peut parfois être mis en pause. Ces pauses impliquent que des réceptions peuvent être manquées par le µC, ce qui nécessite de renvoyer les données. Dans certaines applications, cette réémission n'est pas acceptable, d'où la fait de garder le wifi toujours actif. En revanche, ce mode consomme beaucoup d'énergie électrique ce qui pose problème si le µC est alimenté sur batterie/pile (cf. section sur la consommation)

6.2°/ Point d'accès + client Wifi access

  • Comme un AP agit comme un serveur DHCP, il faut obligatoirement fixer un adresse et un masque de sous-réseau, ainsi qu'une passerelle pour que l'AP soit en mesure d'attribuer des IPs pour ce sous-réseau.
  • Dans l'exemple ci-dessous, on suppose que l'AP fournit des adresses de classe C, comme 192.168.0.XXX
  • Il faut également définir un canal Wifi.

Apparté :

  • La norme Wifi 2.4GHz définit 13 canaux, correspondant à 13 fréquences autour de 2.4GHz.
  • Si deux AP sont proches l'un de l'autre, cela risque de provoquer des interférences s'ils utilisent des fréquences trop proche. Dans ce cas, des paquets de données sont corrompus et doivent être rémis.
  • Pour régler ce type de problème, on utilise des canaux séparé d'au moins 4 en valeur.
  • Par exemple, dans une même pièce, on peut mettre jusqu'à 4 AP, avec comme canaux 1, 5, 9 et 13.

 

Exemple :

#include <ESP8266WiFi.h>
...
void setupAP() {
  IPAddress local_IP(192,168,0,1);
  IPAddress gateway(192,168,0,1);
  IPAddress subnet(255,255,255,0);

  ret = WiFi.mode(WIFI_AP_STA); // AP + client
  int channel = 1; // choose between 1 and 13
  const char *ssid = "ssid_wifi_ap";        
  const char *password = "pass_ap";  

 // CAUTION: on other µC, 2 following lines may be exchanged to work
  ret = WiFi.softAP(ssid, password, channel); 
  ret = WiFi.softAPConfig(local_IP, gateway, subnet);

  // debug messages
  IPAddress myIP = WiFi.softAPIP();
  Serial.print("AP IP address: ");
  Serial.println(myIP);
}

 

Remarques :

  • en tant qu'AP, un esp8266/32 peut accepter au maximum 4 clients, mais il est déconseillé d'atteindre ce nombre, surtout si l'AP est lui-même un client est doit faire quelque chose d'autre. Dans ce cas, le µC peut vite être surchargé et planter.
  • il est donc conseillé d'utiliser un µC comme AP uniquement dans des applications où seulement 2 µC "nomades" doivent communiquer.

 

7°/ Connexion et communcation TCP

  • Une fois qu'un µC possède une IP, il est possible de créer une connexion TCP
  • A µC can act as a TCP client, or a TCP server., soit comme un client, soit comme un serveur.

 

7.1°/ client TCP

  • Généralement, on écrit une fonction chargée de demander la connexion et qui stocke l'état de cette connexion das une variable globale.
  • Comme il est fréquent qu'une connexion TCP soit interrompue, cette fonction est plutôt appelée si nécessaire au début de la fonction loop(), pour être sur de pouvoir communiquer dans la suite de l'exécution.
  • Cette fonction doit utiliser une instance de la classe WiFiClient, qui contient une méthode connect() pour demander la connexion.
  • Cette classe contient également des méthodes :
    • available() pour tester si des octets peuvent être lus,
    • write() pour écrire 1 seul octet,
    • read() pour lire un seul octet,
    • println() pour écrire une ligne de texte, transformée en une suite d'octets avant d'être envoyée.
  • Malheureusement, il n'existe pas de fonction pour lire directement une ligne de texte. Il faut l'écrire soi-même.

Exemple :

#include <ESP8266WiFi.h>
...
WiFiClient client;
byte connState;
const char* ipServ = "192.168.0.1";
int portServ = 12345;
byte buf[1024];
int idx = 0;
...

void setup() {
  Serial.begin(115200);
  connState = 0;
  // establish the wifi connection
  ...
}

bool doConnection() {
  if (client.connect(ipServ, portServ)) {
    connState = 1;
    Serial.println("connected to server")
    // special for esp8266: disable buffering small mesg
    client.setNoDelay(true);
    return true;
  }
  else {
    connState = 0;
    Serial.println("connection failed")
    return false;
}

void loop() {
  if (connState == 0) {
    if (! doConnection()) { delay(1000); }
  }
  if (connState == 1) {
    client.write(10); // write a byte equal to 10
    client.println("10"); // write 3 bytes: ascii code of 1, ascii code of 0, ascii code of new_line
    // wait something from the server
    while (!client.available()) {} // see comments below
    // read what is available
    while (client.available()) {
      buf[idx++] = client.read(); // read & store a byte
    }
    Serial.println(String(buf)); // print the content of buf as a string
    for(int i=0;i<idx;i++) buf[i] = 0; // reset buf
  }
}

 

Remarques :

  • contrairement à un OS classique, lire sur une socket grâce à la fonction WiFiClient.read() n'est pas bloquant. S'il n'y a rien à lire, la fonction renvoie donc une valeur invalide.
  • C'est pourquoi il faut toujours vérifier que quelque chose est disponible AVANT de lire. Pour cela, on utilise available().
  • Cependant, il est possible d'attendre qu'au moins un octet soit disponible à la lecture avec une boucle "bizarre" : while(!client.available()) {}. Sur un processeur classique, cela ne peut pas se faire sinon on le charge à 100%. Mais sur un µC, cela fonctionne parfaitement et c'est même la seule façon de faire.

 

7.2°/ serveur TCP

  • Pour attendre une connexion, le µC doit utiliser une instance de WiFiServer, dont le constructeur permet de fixer le port de connexion.
  • Cette classe contient une méthode available() qui teste s'il y a une demande de connexion client.
  • Attention : cette fonction n'est pas bloquante comme sur un OS classique. Elle renvoie directement null si aucune demande n'est faite. Il faut donc l'appeler en boucle.
  • Dès qu'une demande est accepté, cette fonction renvoie un objet instance de WiFiClient qui permet de communiquer avec le client, comme vu en section 7.1

Exemple :

#include <ESP8266WiFi.h>
...
WiFiServer server(12345);
WiFiClient client;
byte connState;
byte buf[1024];
int idx = 0;
...

void setup() {
  Serial.begin(115200);
  connState = 0;
  // establish the wifi connection
  ...
}

void waitConnection() {
  client = server.available(); // test if there is an incoming connection and if yes, accept it.
  if (client) {
    connState = 1;
    Serial.println("client connected")
    // special for esp8266: disable buffering small mesg
    client.setNoDelay(true);
  }
}

void loop() {
  if (connState == 0) {
    waitConnection();
  }
  if (connState == 1) {
    // wait something from the client
    while (!client.available()) {}
    // read what is available
    while (client.available()) {
      buf[idx++] = client.read(); // read & store a byte
    }
    Serial.println(String(buf)); // print the content of buf as a string
    for(int i=0;i<idx;i++) buf[i] = 0; // reset buf
  }
}

 

 

8°/ A propos de la consommation électrique

  • Utiliser le wifi (et/ou le bluetooth) sur un µC est ce qui consomme le plus d'énergie électrique.
  • Par exemple, envoyer des données en Wifi sur un ESP32 soutire jusqu'à 250mA de la source d'alimentation, et environ 150mA en réception.
  • Si le circuit Wifi est actif mais non communicant, le courant soutiré est entre 80 et 100mA.
  • Ce ne sont pas des valeurs énormes mais elles sont tout de même suffisamment élevées pour poser des problèmes d'alimentation quand le µC fonctionne sur batterie/pile.
  • Par exemple, une batterie 1000mAh est capable de délivrer 1A pendant une heure, ou bien 100mA pendant 10h.
  • Cela veut dire qu'une telle batterie tiendrait seulement 1000/250 = 4 heures pour alimenter un µC constamment en train d'envoyer des données sur le Wifi.
  • Et même si le µC n'envoie des données que quelques fois par jour, le fait d'avoir le wifi actif ne permettrait de tenir qu'au maximum 10h.
  • Ce n'est évidemment pas applicable. Une solution de maison intelligente basée sur des boîtiers à µC, qu'il faut recharger toutes les 10h n'aurait pas beaucoup de succès.
  • Il faut donc mettre en place des stratégies de réduction de la consommation.

 

  • La première solution est de mettre régulièrement en pause le circuit wifi et de le réveiller juste le temps nécessaire pour vérifier s'il y a des données à recevoir depuis l'AP.
  • Ce mode s'appelle "modem sleep" et c'est le mode par défaut de fonctionnement du circuit wifi sur un esp8266/32.
  • Ce mode est possible grâce au fait qu'un AP émet régulièrement des trames dites de "balise" pour synchroniser le réseau (par ex tous les 100ms). Toutes les X trames de balise, la trame va contenir une information appelée DTIM (Delivery Traffic Information Map), qui permet à un client wifi de savoir s'il y a des données en attente sur l'AP pour lui. La trame contient également le temps avant la prochaine DTIM.
  • Par conséquent, il suffit au µC de couper le circuit wifi entre deux trames contenant un DTIM et de se réveiller juste avant que la prochaine trame arrive.
  • Avec cette "astuce", la consommation tombe en moyenne à 20mA, mais cela dépend du X (=nb balises entre 2 DTIM) qui est fixé par l'AP.
  • En revanche, plus X est grand plus la latence de réception sera grande, ce qui peut poser problème à certaines applications où l'on a besoin d'une latence de communication la plus faible possible entre l'émetteur et le récepteur.
  • Et si X est trop grand, il peut même y avoir des problèmes pour conserver la connexion wifi entre les client et l'AP.
  • Malheureusement, même cette stratégie n'est pas très efficace puisqu'avec une batterie 1000mAh, il faudrait recharger au bout de 1000/20 = 50 heures. Pas terrible !

 

  • Pour vraiment réduire la consommation, il faut passer à des modes beaucoup plus contraignants et qui coupent l'alimentation de plus ou moins de parties du µC.
  • Ces modes ne sont utilisables que pour des applications où les µC envoient de façon sporadiques et qu'il n'y a quasi rien à faire entre deux communications. De plus, ce n'est pas adapté pour les cas où un µC doit pouvoir recevoir n'importe quand des données. C'est notamment le cas d'une solution où les µC se contentent de mesurer une grandeur, d'envoyer la valeur lue à un serveur, d'attendre sa réponse, et enfin s'endormir pour un temps fixe.
  • Sur un esp8266/32, il y a principalement 3 modes :
    • light-sleep : le CPU, l'horloge, et le wifi sont en pause mais l'état du CPU est mis en RAM. Il est possible de réveiller le CPU via un changement d'état sur une GPIO, connectée par exemple à un bouton poussoir. Dans ce mode, la consommation tombe à environ 1mA, et l'exécution reprend là où elle s'était arrêtée. En revanche, le µC ne peut rien faire pendant l'attente.
    • deep-sleep : presque tout est arrêté excepté le circuit RTC (Real Time Clock) qui permet de compter le temps qui passe. Grâce à la RTC, le µC peut être programmé pour se réveiller au bout d'un temps paramétrable. On peut aussi le réveiller ĝrace à une GPIO. Cependant, contrairement au light-sleep, le µC reboote après le réveil et donc recommence entièrement le code du sketch. Dans ce mode, la consommation tombe à environ 10µA.
    • hibernation : tout est arrêté et le µC ne redémarre qu'avec un changement sur une GPIO précise (GPIO16 sur l'esp8266). Dans ce mode, la consommation tombe à 2µA.

 

  • ATTENTION : les consommations annoncées ci-dessus ne tiennent compte que du µC seul. La consommation réelle est plus élevée, notamment à cause des composants actifs de la carte de développement : convertisseur série-usb, régulateur de tension, .... Par exemple, il est courant d'avoir une consommation réelle entre 50 et 100µA en deep-sleep.

 

  • A part ces 3 modes, il est également possible de complètement couper le circuit wifi s'il n'est pas nécessaire avec : WiFi.mode(WIFI_OFF)
  • Au contraire, pur qu'il soit toujours actif et avoir une latence minimale, on utilise : WiFi.setSleepMode(WIFI_NONE_SLEEP)