lundi 6 avril 2020

Serveur ESP32 : implémentation (6ème partie)




Serveur ESP32 : implémentation

(6ème partie)


Ceci est la suite des quatre articles précédents :
Serveur ESP32 : implémentation
Serveur ESP32 : implémentation (2ème partie)
Serveur ESP32 : implementation (3eme-partie)
Serveur ESP32 : implementation (4eme-partie)
Serveur ESP32 : implementation (5eme-partie)
Serveur ESP32 : tests automatisés
Serveur ESP32 : tests automatisés (2ème partie)

Je pensais en avoir terminé mais j'ai décidé d'aller un peu plus loin.

Dans cette 6ème partie nous allons ajouter un afficheur LCD 4 lignes ou un afficheur OLED SSD1306.

1. Les afficheurs

J'ai choisi un afficheur LCD I2C et un OLED SSD1306 I2C.

Je me suis assez vite aperçu que l'affichage sur un écran LCD I2C ne fonctionnait pas lorsqu'il était effectué dans une callback appelée par la classe AsyncWebServer, en tous cas cela fonctionne très mal.
Le LCD affiche des caractères étranges.
L'afficheur OLED fonctionne un peu mieux, il affiche un ou deux pixels en plus des messages, de manière aléatoire.

Explication : une fonction callback est une fonction appelée par le code de la classe AsyncWebServer lorsqu'une requête HTTP donnée est reçue :

  server.on("/", handleRoot);

Lorsque la requête http://xxx.xxx.xxx.xxx/ est reçue la fonction handleRoot() est appelée.

Le problème est que cette fonction est exécutée dans la tâche WIFI, alors que la fonction loop() est exécutée dans une autre tâche.
Est-ce la cause du problème ?

J'ai donc fait un essai d'affichage depuis la fonction loop() en fonction des besoins des callbacks, et cela fonctionne autrement mieux.

1.1. Les messages

Le message à afficher dépend du contexte :

L'usager est invité à présenter sa carte et à appuyer sur un bouton :

"Put your Card &"
"Press The button"


La carte n'est pas détectée :

"No Card Detected"

La carte est inconnue :

"Unknown Card"

Le crédit est à ZÉRO :

"No Credit"

La carte est désactivés :

"Card is Deactivated"

La carte est débitée :

"Please Enter"
"The door is Open"
"Credit : XX"


Un nouvel usager doit être créé :

"Put your Card &"
"Press Read Media"


Les premiers messages sont affichés dans la fonction loop() et ne posent donc aucun problème. Il n'y a aucune interaction avec les requêtes HTML.

Le dernier message est affiché dans une callback "/new.html" et le premier message sera à nouveau affiché lorsque l'usager aura été créé.
Ces messages devront être affichés tout de même dans la fonction loop().

La technique utilisée est simple :
L'affichage est géré par une classe display dont deux classes sont dérivées :
  • lcdDisplay
  • oledDisplay
La classe display possède une méthode begin() qui enregistre l'ID de la tâche courante, donc celle de main(), setup() et loop().
Chaque classe lcdDisplay oledDisplay possède un certain nombre de méthodes d'affichage de messages :
  • void displayWelcome(void);
  • void displayNoCard(void);
  • void displayUnknownCard(void);
  • void displayNoCredit(void);
  • void displayInactiveCard(void);
  • void displayEnter(int credit);
  • void displayAskForCard(void);
Exemple :
void lcdDisplay::displayWelcome(void)
{
  Serial.printf("lcdDisplay::displayWelcome %x", xTaskGetCurrentTaskHandle());
  if (m_mainTask == xTaskGetCurrentTaskHandle()) {
    Serial.printf("OK\n");
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Put your card &");
    lcd.setCursor(0, 1);
    lcd.print("Press The button");
    messageDisplayed = WELCOME;
  }
  else {
    Serial.printf("NO\n");
  }
  messageToDisplay = WELCOME;
}

 
Si l'identifiant de la tâche courante est celui de la tâche main(), l'affichage est réalisé directement, sinon une variable est messageToDisplay est positionnée.

La méthode display::process() est appelée par la fonction loop() :
Si le message désiré n'est pas encore affiché, la méthode effectue le travail :

void display::process(void)
{

  // laisse le temps aux méthodes d'affichage de positionner la variable messageToDisplay
  delay(10);
  if (messageToDisplay != messageDisplayed) {
    switch (messageToDisplay) {
      case NONE:
        clear();
        break;
      case ASK_FOR_CARD:
        displayAskForCard();
        break;
      case WELCOME:
        displayWelcome();
        break;
    }
  }
}


Seuls les messages de bienvenue et de présentation carte lors de l'ajout d'un nouvel abonné sont concernés.

2. Pages HTML

Voici les copies d'écran de la dernière version :


Hitorique

3. Téléchargement

Cette version 2.4 est disponible ici :
https://bitbucket.org/henri_bachetti/webserver-form/src/v2.4/esp32-subscriber/

Le choix de l'écran à utiliser se fait par une option de compilation :

#define NODISPLAY     0
#define USE_LCD       1
#define USE_SSD1306   2

#define SCREEN USE_LCD


Pour utiliser un SSD1306 :

#define SCREEN USE_SSD1306

4. Conclusion

Communiquer en I2C dans une callback n'est pas aussi simple qu'il n'y paraît. Quelle en est la raison ? Mystère pour l'instant.
La communication SPI a l'air de ne poser aucun problème par contre, puisqu'elle est utilisée pour la lecture des cartes RFID.

Il y a fort à parier que d'autres composants I2C devront être gérés de la même manière, des capteurs de température ou de lumière par exemple.


Cordialement
Henri

Aucun commentaire:

Enregistrer un commentaire