Affichage des articles dont le libellé est Affichage. Afficher tous les articles
Affichage des articles dont le libellé est Affichage. Afficher tous les articles

lundi 2 août 2021

Ecran OLED SSD1351

 

Ecran OLED SSD1351

 

Je me suis laissé tenter par un écran OLED SSD1351. Ces modules deviennent relativement abordables (environ 10€ chez WorldChips).

Les écrans SSD1306 existent en version couleur (blanc, bleu, bleu avec les premières lignes jaunes) mais cela reste de l'affichage monochrome :

Ce SSD1351 est un vrai écran 65536 couleurs, 128x128, 16 bits.

1. Le côté matériel

Ce module est équipé de trous de fixation.

Si j'avais une critique à formuler, je dirais que le choix du câble livré n'est pas des plus heureux : JST XH 7 broches d'un coté, DUPONT femelle de l'autre. Pour une application sérieuse il faudrait envisager de remplacer les connecteurs DUPONT par un deuxième JST XH.

2. Le côté logiciel

Contrairement aux écrans I2C SSD1306, cet écran se pilote par le bus SPI, plus rapide.

Une librairie existe : Adafruit SSD1351, installable depuis l'IDE ARDUINO.

Deux types de branchement sont possibles :

  • SPI logiciel : on a le libre choix des sorties utilisées
  • SPI hardware (plus rapide) :
    • DIN (MOSI) : 11
    • CLK : 13

Après avoir installé la librairie on peut charger l'exemple test.ino. On a le choix entre deux constructeurs :

// Option 1: use any pins but a little slower
//Adafruit_SSD1351 tft = Adafruit_SSD1351(SCREEN_WIDTH, SCREEN_HEIGHT, CS_PIN, DC_PIN, MOSI_PIN, SCLK_PIN, RST_PIN);  

// Option 2: must use the hardware SPI pins
// (for UNO thats sclk = 13 and sid = 11) and pin 10 must be
// an output. This is much faster - also required if you want
// to use the microSD card (see the image drawing example)
Adafruit_SSD1351 tft = Adafruit_SSD1351(SCREEN_WIDTH, SCREEN_HEIGHT, &SPI, CS_PIN, DC_PIN, RST_PIN);

Pour ma part j'ai choisi la deuxième version (CLK sur 13, DIN sur 11), plus rapide, en conservant les définitions des broches du sketch (CS_PIN = 5, DC_PIN = 4, RST_PIN = 6)

Après chargement, différents tests en mode texte et graphique se déroulent.

Avec la plus petite police utilisée cet écran est capable d'afficher 16 lignes de 21 caractères.

Une dernière chose (compilé pour l'ARDUINO UNO) :

Le croquis utilise 18624 octets (64%) de l'espace de stockage de programmes. Le maximum est de 28672 octets.
Les variables globales utilisent 726 octets (28%) de mémoire dynamique, ce qui laisse 1834 octets pour les variables locales. Le maximum est de 2560 octets.

D'un point de vue mémoire FLASH ou RAM, la librairie est assez gourmande, ce qui peut être gênant. Il n'est pas interdit d'avoir recours à un ESP8266 ou ESP32 si le logiciel se trouve à l'étroit.

3. Photos



4. Conclusion

Ces écrans permettent d'imaginer des interfaces graphiques plus cossues que leurs homologues SSD1306 128x32 et 128x64, et ceci en couleurs !


Cordialement

Henri


jeudi 24 juin 2021

ESP32 : HELTEC WiFi Kit 32

 


ESP32 : HELTEC WiFi Kit 32


Certains d'entre vous ont certainement remarqué ces petites cartes HELTEC équipées d'un ESP32 et d'un écran OLED 0.96".

On les trouve chez différents revendeurs, y compris sous d'autres marques.

Celle-ci par exemple, fabriquée par DIYMORE, que j'ai acheté :

https://fr.aliexpress.com/item/32847022581.html?spm=a2g0s.9042311.0.0.63436c37qjZ3Li

Il s'agit d'un clone, strictement identique à l'original : 

https://heltec.org/project/wifi-kit-32/

Ses caractéristiques :

  • ESP32 dual-core 240MHz
  • 4MB de mémoire FLASH
  • 520 KB de mémoire RAM
  • convertisseur USB CP2102
  • écran OLED I2C SSD1306 128x64
  • LED blanche utilisateur (LED_BUILTIN)

Sa largeur est la même que celle de la WEMOS D1 LOLIN32, ce qui permet de l'enficher sur une breadboard, tout en disposant de deux rangées de broches libres sur les côtés pour les raccordements de fils DUPONT. C'est appréciable.

D'autre part, cette carte est une bonne alternative d'affichage pour certaines personnes qui s'obstinent, encore à notre époque, à utiliser, y compris sur ESP8266 ou ESP32, des écrans LCD alphanumériques 2x16 ou 4x20, gros, moches et dépassés.

1. Le WIFI

Apparemment cette carte a un petit peu plus de mal à se connecter à mon réseau WIFI qu'une WEMOS D1 MINI. Même une carte ESP32 DevKit C fait mieux.

Depuis mon bureau, assez mal situé d'un point de vue WIFI, la connexion avec la HELTEC est impossible. Depuis la chambre voisine, 3 mètres plus près, c'est OK.

On va conclure que dans une situation normale, la carte fonctionne plutôt bien, sans être exceptionnelle.

2. L'écran OLED

On pourrait croire qu'il suffit d'installer le package ESP32 et une librairie SSD1306 pour faire fonctionner cette carte.

C'est possible, mais ce n'est pas la solution la plus aisée. Heureusement, HELTEC fournit un package pour sa carte. 

2.1. La méthode facile

Pour utiliser ces cartes, il suffit d'installer la librairie HELTEC. Elle est directement installable depuis le Gestionnaire de Bibliothèques de l'IDE ARDUINO : il suffit de rechercher Heltec ESP32 Dev-Boards.

Ensuite, redémarrer l'IDE pour voir apparaître les exemples dans le menu "Fichiers / Exemples / Heltec ESP32 Dev-Boards.

Il sera possible ainsi à peu de frais de commencer à s'amuser avec cette carte.

Il y a un inconvénient : le nombre de polices de caractères est très limité.

2.2. La méthode compliquée

Après tout, ces modules sont de vulgaires cartes ESP32 équipées d'un écran OLED SSD1306. Il n'y a pas de raison d'installer un package particulier pour si peu de chose. On devrait pouvoir s'en sortir avec le package ESP32 standard et la librairie SSD1306 de notre choix.

Tout d'abord, dans le menu "Outils / Type de Carte" choisissons la carte "Heltec WiFi Kit 32". Car elle existe dans le package ESP32 standard !

2.2.1. L'écran I2C

Le premier réflexe qui vient à l'esprit lorsque l'on connecte un écran I2C à un microcontrôleur est d'utiliser le logiciel I2C_Scanner pour vérifier que l'écran est bien visible sur le bus. Or, avec cette carte cela ne donne aucun résultat.

Le schéma nous apprend que SDA et SCL sont situés sur les GPIOs 4 et 15, au lieu de 21 et 22.

Un second essai en configurant Wire pour utiliser 4 et 15 ne donne aucun résultat non plus.

Surprise : dans les exemples Heltec il y a un exemple "Heltec ESP32 Dev-Boards / ESP32 / I2C_scanner. Ce sketch affiche bien un device I2C en 0x3C.

En examinant le code de la librairie, la broche RST de l'écran est configurée en sortie et basculée à HIGH. Essayons de faire la même chose avec un code classique I2C_Scanner légèrement modifié :

i2c_scanner.ino

Gagné !

I2C scanning with SDA=4, CLK=15

Found device at 0x3c
Found 1 I2C devices by scanning.

2.2.2. La librairie AdaFruit

Maintenant le but de la manip est de déterminer si la librairie Adafruit_SSD1306 est compatible avec cette carte. A priori il n'y a pas de raison d'en douter.

2.2.2.1. Installation

Il faut installer la librairie à l'aide du Gestionnaire de bibliothèques : rechercher Adafruit SSD1306.

Il faut également installer Adafruit GFX Library.

Cette librairie a pas mal évolué ces derniers temps et il n'est plus nécessaire de modifier le fichier Adafruit_SSD1306.h pour préciser quelle est la taille de l'écran utilisé : elle alloue son buffer écran dynamiquement, ce qui n'est pas plus mal.

Elle permet également l'utilisation d'un bus I2C autre que le bus par défaut, ce qui va grandement nous aider.

Les manipulations décrites ci-dessous ne fonctionneront qu'avec les dernières versions de la librairie.

2.2.2.2. Le sketch

Rappel : dans le menu "Outils / Type de Carte" choisir la carte "Heltec WiFi Kit 32".

L'exemple utilisé est : ssd1306_128x64_i2c.ino

Les modifications à apporter sont mineures :

Cette portion du code d'origine :

#define OLED_RESET     4 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3D ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

Est à remplacer par :

#define SCREEN_ADDRESS 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire1, RST_OLED);

Ensuite dans la fonction setup() il faut ajouter cette ligne (en gras) :

void setup() {
  Serial.begin(115200);
  Wire1.begin(SDA_OLED, SCL_OLED);
  // etc.

Les constantes SDA_OLED, SCL_OLED et RST_OLED sont déclarées dans le package ESP32 pour la carte HELTEC WIFI KIT 32. Il n'y a pas à s'en soucier.

Explications : au lieu d'utiliser l'objet standard Wire, nous utilisons un autre objet, Wire1, qui sera initialisé à l'aide des bonnes broches SDA et SCL dans la fonction setup().

Le sketch complet :

adafruit-ssd1306.ino

Et l'image de départ de la démo Adafruit :

3. Hello server

Petit bonus : un petit serveur HTTP qui permet de se connecter à un point d'accès et d'afficher le résultat de la connexion sur l'écran OLED :

HelloServer.ino

Avant de compiler il faut renseigner ssid et password, et choisir la carte "Heltec WiFi Kit 32".

Son fonctionnement :

  • au démarrage :
    • il affiche "Connecting to SSID"
    • la LED blanche s'allume
  • à la connexion :
    • il affiche "Connected to SSID" et l'adresse IP
    • la LED blanche s'éteint
  • en cas de perte de connexion WIFI :
    • il affiche "Reconnecting to SSID"
    • la LED blanche se rallume
  • à la reconnexion :
    • il affiche "Connected to SSID" et l'adresse IP
    • la LED blanche s'éteint

Le mécanisme de reconnexion utilise les événements de connexion / déconnexion WIFI.

Accessoirement on peut se connecter à l'adresse IP avec un navigateur pour allumer ou étendre la LED.

Il sera ainsi facile de placer la carte à différents endroits de l'habitation pour vérifier que la couverture WIFI est correcte, et que le serveur a un temps de réaction raisonnable.

4. Téléchargements

Le projet se trouve ici :

https://bitbucket.org/henri_bachetti/heltec-wifi-kit-32

5. Conclusion

Nous voilà donc à même de pouvoir utiliser soit le package HELTEC, soit le package standard ESP32 + la librairie Adafruit.

La librairie Adafruit est intéressante à plus d'un titre :

Tout d'abord beaucoup de développeurs sur ARDUINO, ESP8266 ou ESP32 l'utilisent. Ils ne seront donc pas dépaysés.

La librairie Adafruit est maintenue et évolue fréquemment, et en bien, et même en très bien.

Elle propose un nombre de polices de caractères important, et il est possible de convertir des polices TTF existantes.

https://learn.adafruit.com/adafruit-gfx-graphics-library/using-fonts

Voici une petite carte bien sympathique qui devrait plaire à beaucoup. Son petit format est intéressant.


Cordialement

Henri

6. Mises à jour

26/06/2021 : 3. Hello server


mercredi 27 mai 2020

MAX7219 : affichage matriciel




MAX7219 : affichage matriciel



Nous allons parler aujourd'hui de modules MAX7219 permettant de réaliser un afficheur matriciel à 64 LEDs.
Nous allons examiner certains aspects que l'on ne voit pas dans les nombreux tutoriels qui foisonnent sur le WEB :
  • alimentation et découplage
  • affichage de caractères accentués
  • affichage clignotant
  • utilisation avec un ESP32 (y compris les touches capacitives)
  • éviter certains pièges
Ces modules existent sous forme unitaire comme ceci :
Module DIP

Module CMS


Dans le premier cas le circuit MAX7219 est un modèle DIP apparent.

Le deuxième module est équipé d'un circuit CMS situé sous l'afficheur, plus facile à organiser en panneau multi-modules jointifs.

Ils existent aussi sous forme de panneaux de 4 modules CMS ou plus :

Module quadruple


1. Le matériel

1.1. Pilotage

Ces modules se pilotent en SPI. ils sont équipés de 5 broches d'entrée (VCC, GND, DIN, CS, CLK).
Il peuvent être chaînés, ils possèdent donc également 5 broches de sortie (VCC, GND, DOUT, CS, CLK) que l'on reliera aux broches d'entrée du module suivant:


1.2. Alimentation

En fonction du nombre de modules et de la luminosité prévue il faut compter environ 250mA pour 4 modules alimentés affichant du texte avec la luminosité maximale.
La consommation dépendra aussi de la police de caractères utilisées (certaines polices allument plus de LEDs que d'autres).

Le câblage devra donc être réalisé avec des fils de section suffisante.

Bien entendu si les afficheurs sont amenés à afficher des bitmaps plus ou moins pleins, cette consommation sera également supérieure.

Le courant maximal par module (ce courant correspond à l'affichage de 4 carrés pleins à luminosité maximale) dépend de l'implémentation du constructeur, en particulier de la valeur d'une résistance ISET (voir la datasheet) qui fixe ce courant.

1.2.1. Alimentation par USB
Si l'on alimente un ARDUINO ou un ESP32 par son connecteur USB il faudra tenir compte de deux contraintes :
  • le courant maximal fourni par l'alimentation ou le port USB de l'ordinateur
  • la courant maximal admissible par la diode ou le fusible de protection de la carte
La diode de protection d'une carte ARDUINO ou ESP32 admet en général assez peu de courant :
  • ESP32 DEV-KIT : diode 1A
  • ARDUINO NANO : diode 1A
  • ARDUINO MEGA : fusible 500mA
On voit que la limite est assez vite atteinte si l'on désire utiliser plusieurs afficheurs.

1.2.2. Alimentation par VIN
Il est pratiquement impossible de piloter un grand nombre de ces afficheurs en alimentant un ARDUINO par VIN pour ensuite alimenter les afficheurs par la broche 5V.
Je vous renvoie à cet article :
Voir le paragraphe 3.2. Broche VIN.

Si l’on alimente l'ARDUINO en 7.5V, le courant maximal disponible sur la broche 5V sera de 480mA.

1.2.3. Alimentation dédiée
Pour piloter un grand nombre d'afficheurs il serait préférable d'alimenter les afficheurs directement en 5V à l'aide d'une alimentation dédiée de puissance suffisante. Le microcontrôleur pourra également être alimenté directement en 5V à l'aide de la même alimentation.

Sur les modules quadruples (256 LEDs) en ma possession le courant maximal (toutes les LEDs allumées à luminosité maximale) est égal à 650mA, c'est à dire 160mA par module, donc 2.5mA par LED. Pendant la phase de maquettage j'alimente les afficheurs avec une alimentation 5V séparée, afin d'éviter de surcharger le port USB sur lequel est branché l'ESP32.

Pour un projet définitif il faut faire un bilan sérieux des consommations. Exemple avec 2 afficheurs quadruples + ESP32 :
  • connexion WIFI ESP32 : 450mA maxi
  • ESP32 connecté : 120mA maxi
  • affichage plein sur un seul afficheur (test des LEDs au démarrage) :
    • 1 afficheur : 650mA
    • ESP32 : 120mA
  • affichage de texte sur deux afficheurs
    • 2 afficheurs : 500mA
    • ESP32 : 120mA
La consommation ne devrait pas excéder 770mA au démarrage pendant quelques secondes, et retomber à 620mA ensuite. Une alimentation 5V 1A sera nécessaire.
Si toutes les LEDs des deux afficheurs étaient allumés simultanément au démarrage il faudrait plutôt opter pour une alimentation pouvant débiter au minimum 1.5A.

Attention : une alimentation à découpage ne se comporte pas comme une alimentation linéaire.
Une alimentation linéaire peut encaisser une surcharge de faible durée sans problème car la protection de son régulateur est souvent thermique, donc lente.
Une alimentation à découpage provoque une coupure de sa sortie au moindre dépassement de son courant maximal, même bref.

1.3. Découplage

Il arrive qu'aléatoirement un ou plusieurs afficheurs n'affichent plus rien si la luminosité devient élevée, dans le cas où l'on conçoit un logiciel capable de régler celle-ci par exemple. Il s'agit probablement de pics de courant générant des baisses de tension d'alimentation et qui plantent le MAX7219.

Après différents essais, pour 8 afficheurs j'obtiens de bons résultats avec une luminosité moyenne en connectant un condensateur de 220µF en parallèle sur l'alimentation des afficheurs, entre VCC et GND.
La valeur de ce condensateur monte à 3300µF si je veux afficher sans problème des carrés pleins à luminosité maximale sur seulement 4 afficheurs.

Cette valeur est bien entendu à ajuster en fonction :
  • du nombre d'afficheurs
  • du type d'alimentation, de sa puissance
  • de la longueur des câbles d'alimentation, de leur section
Il est également possible de placer plusieurs condensateurs de plus faible valeur sur chaque afficheur ou chaque groupe d'afficheurs.

Après mise en place des condensateurs il faut tester le montage avec un petit sketch qui affiche des informations suffisamment représentatives de ce que l'on compte afficher.

2. Le logiciel

2.1. Orientation

Il faut faire attention lors de l'achat à choisir les modules en fonction de ce que l'on désire afficher. Classiquement lorsque l'on chaîne plusieurs modules en ayant l'intention d'y afficher du texte on a tendance à les aligner horizontalement, sur une ou plusieurs lignes.

On constate assez vite que l'on va se retrouver confrontés à deux problèmes :
  • un problème d'orientation de chaque module
  • un problème d'ordre des modules entre eux
La plupart des librairies considèrent que le pixel 0:0 se trouve dans le coin supérieur gauche, lorsque les broches d'entrée sont situées sur le dessus du module.
Mais il est parfaitement possible qu'un constructeur puisse choisir une orientation différente, et comme les vendeurs ne précisent pas ce genre de détail il est donc difficile de savoir comment orienter les modules sans les essayer.

Les librairies considèrent également que les modules sont chaînés de la droite vers la gauche. Si cet ordre est inversé, la chaîne ABCD sera affichée DCBA.

Pour résumer, lorsque l'on chaîne plusieurs modules ensemble, il est plus que probable que l'on obtienne un affichage mal orienté ou inversé.

Lorsque l'on dispose de modules unitaires il est facile de les disposer côte à côte et de les chaîner pour obtenir un affichage correct des caractères.

A noter que les modèles CMS offriront 4 possibilités d'orientation, ce qui ne sera pas le cas des modèles DIP. Les modèles DIP ne permettront pas non plus d'accoler les afficheurs sur plus d'une ligne, à moins de tolérer un interligne.

On ne peut donc que recommander l'achat de modules CMS simples et de les combiner selon la librairie utilisée.

Mais que se passe t-il avec un module quadruple ? Là aussi tout dépend du constructeur, et de la librairie choisie. Si ces modules sont chaînés de droite à gauche et que la librairie ne permet pas de changer l'orientation, le résultat sera celui-ci :


Il peut probablement arriver que la combinaison modules / librairie ne donne pas de résultat satisfaisant.

Il existe un certain nombre de librairies permettant de gérer ces afficheurs. Malgré tout la seule qui permette de choisir l'orientation des modules est celle-ci :

Cette autre librairie sera nécessaire :

La librairie MD_PAROLA permet de choisir entre 4 orientations :
  • PAROLA_HW : chaînage horizontal affichage inversé (en miroir)
  • GENERIC_HW : chaînage vertical
  • ICSTATION_HW : chaînage horizontal gauche-droite
  • FC16_HW : chaînage horizontal droite-gauche
La majeure partie des blocs de 4 afficheurs vendus sur ALIEXPRESS se pilotent en utilisant le paramètre FC16_HW :

La librairie possède pas mal de fonctionnalités utiles :
  • scrolling horizontal et vertical
  • justification à gauche, à droite, au centre
  • réglage de l'espace inter-caractères
  • gestion de zones d'affichage séparées
  • etc.
Une autre librairie fonctionne avec les blocs de 4 afficheurs chaînés de droite à gauche, celle de Nick Gammon :

D'autres librairies ne fonctionneront qu'avec des afficheurs simples chaînés de bas en haut avec des fils :

Il faut avouer que dans le monde des librairies MAX7219 c'est un peu la jungle.
Il est important d'évaluer les possibilités de quelques unes afin de ne pas s'engager dans une voie sans issue qui ne permettrait pas d'obtenir le résultat escompté.

2.2. Le bus SPI

La librairie MD_PAROLA permet de piloter l'afficheur en utilisant soit le bus SPI natif du microcontrôleur soit un bus SPI émulé (bitbanged SPI).
Dans le premier cas on reliera l'afficheur aux pins SPI du microcontrôleur :
  • DIN : MOSI (D11 sur un ARDUINO)
  • CLK : CLK (D13 sur un ARDUINO)
  • CS : SS (D10 sur un ARDUINO) ou un autre choix
Dans le deuxième cas, le choix des broches est libre, mais la communication sera moins rapide.

Exemple :
// Hardware SPI connection
MD_Parola P = MD_Parola(MD_MAX72XX::FC16_HW, CS_PIN, MAX_DEVICES);

// Arbitrary output pins
MD_Parola P = MD_Parola(MD_MAX72XX::FC16_HW, DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);

MAX_DEVICES représente le nombre d'afficheurs à chaîner.

Dernière chose, cette librairie fonctionne aussi bien avec un ARDUINO qu'avec un ESP8266 ou un ESP32.

2.3. Afficher des messages

La librairie MD_PAROLA, comme beaucoup d'autres d'ailleurs, ne recopie pas les messages qu'on lui demande d'afficher. Il s'en suit que ces chaînes de caractères doivent être impérativement stockées dans des variables globales ou statiques.
Une variable locale à une fonction ne conviendra pas, car son contenu n'est pas persistant.

2.4. L'UTF8

Moyennant la création d'une police de caractères adaptée et d'une petite fonction de conversion il est parfaitement possible d'afficher des caractères accentués.
Cette police est fournie dans l'exemple Parola_UFT-8_Display.

Le code de conversion :

2.5. Affichage clignotant

On pourrait bêtement penser qu'il suffit d'afficher un espace à la place des deux points d'une horloge toutes les deux secondes pour obtenir 2 points clignotants.
Il n'en est rien.
Cela marcherait avec une police de largeur fixe, celle de la librairie est à largeur variable.
Le caractère ':' fait 1 pixel de large, l'espace en fait deux. On obtiendrait donc un affichage dont la largeur change toutes les secondes, peu esthétique.

Il faut donc créer un espace simple dans notre police de caractères. J'ai utilisé le caractère 31 (0x1F) pour cet usage (l'espace étant le 32).

  1, 0,      // 31 - 'Small space'
  2, 0, 0,        // 32 - 'Space'


Il suffit donc d'utiliser ce caractère pour afficher un espace étroit à la place des 2 points, toutes les 2 secondes :

  static char timeString[10];
  struct tm timeinfo;
      // ...
      getLocalTime(&timeinfo);
      if (timeinfo.tm_sec % 2) {
        strftime(timeString, sizeof(timeString), "%H:%M", &timeinfo);
      }
      else {
        strftime(timeString, sizeof(timeString), "%H\x1f%M", &timeinfo);
      }
      hDisplay.displayText(timeString, PA_CENTER, 0, 0, PA_PRINT, PA_NO_EFFECT);


3. Le projet

Le petit projet exemple se propose d'implémenter une horloge sur la base d'un ESP32, avec les fonctionnalités suivantes :
  • affichage heure + minutes avec 2 points clignotants.
  • affichage de la date configurable :
    • jour de la semaine + jour du mois
    • jour + mois
    • jour + mois + année + saint du jour (avec scrolling)
  • luminosité réglable
  • gestion de l'heure par NTP avec changement d'heure été / hiver
  • configuration par 2 touches sensitives
  • configuration sauvegardée en FLASH
  • serveur WEB (brouillon)
La totalité des LEDs des deux afficheurs (afficheur de l'heure puis l'afficheur de la date) sont allumées au démarrage pendant une seconde chacun.

Le saint du jour est obtenu grâce au même moyen que sur le projet Afficheur TFT pour ESP8266 :
Voir paragraphe 5.1. Le service PHP.

Il conviendra d'adapter l'URL dans le fichier ephemeris.cpp si cette option est utilisée, sinon on la remplacera par une chaîne vide.

Le serveur WEB de l'ESP32 (vide pour le moment) pourra servir de page de configuration :
  • URL du serveur NTP
  • URL du serveur saint du jour
  • heure de réveil, d'alarme, etc.
  • etc.
Les deux afficheurs 4x8x8 sont câblés comme suit :
  • CLK : GPIO18
  • DIN : GPIO23
  • CS : GPIO26 et GPIO25

Les deux blocs d'afficheurs ne sont pas chaînés, ils sont simplement pilotés en parallèle avec deux pins CS différentes.

L'ESP32 est un classique DEV-KIT mais n'importe quel modèle peut convenir.

4. L'ESP8266

Attention : le hardware SPI de l'ESP8266 utilise les broches D5 D7 D8 (GPIO14 GPIO13 GPIO15) :

On a tendance à oublier, dans le code, que la broche 5 est la GPIO5 et non pas D5.

#define CLK_PIN    D5   // et non pas 5
#define DATA_PIN  D7
   // et non pas 7
#define CS_PIN      D8   // et non pas 8

5. Téléchargement

Ce projet est disponible ici : 

6. Conclusion

Il faut bien avouer que ces afficheurs matriciel sont très attrayants. Ils permettent de réaliser des affichages visibles de loin et des animations intéressantes.

Il va sans dire que ce projet n'est qu'une première version appelée à évoluer.


Cordialement

Henri


samedi 11 avril 2020

Un afficheur TFT pour DOMOTICZ ou JEEDOM (version ESP8266)



 Un afficheur TFT pour DOMOTICZ ou JEEDOM

(version ESP8266)



Dans un article de mai 2019 j'avais décrit la réalisation d'un module d'affichage d'informations pour un serveur domotique :
https://riton-duino.blogspot.com/2019/05/un-afficheur-pour-domoticz-ou-jeedom.html

Nous allons simplifier ce projet et lui apporter quelques améliorations en utilisant un ESP8266 :
  • affichage de la météo avec une icône
  • affichage du saint du jour
Pour rappel ce montage était composé des modules suivants :
  • un ARDUINO NANO
  • un module radio NRF24L01
  • un afficheur 2.8 pouces ILI9341
  • un capteur de température DHT31D
  • 5 résistances de 10K
  • une alimentation 5V
  • un buzzer 5V
Avec un ESP8266 nous pourrons :
  • remplacer le module radio NRF24L01 par le WIFI
  • éliminer les résistances car l'ESP8266 fonctionne en 3.3V
La carte utilisée sera une NodeMCU ou une WEMOS D1 MINI.

Ce projet, même s'il n'est pas réalisé dans son intégralité, peut apporter pas mal de renseignements sur différents points de programmation ESP8266 :
Nous allons aborder :
  • l'affichage d'informations sur un écran TFT SPI
  • le chargements d'images à partir du SPIFFS
  • le lecture d'un capteur de température et humidité I2C
  • la récupération de l'heure avec NTP
  • les requêtes JSON
  • les requêtes et parsing HTTP 
  • formulaire de configuration HTML et sauvegarde en EEPROM
Il vaut mieux se familiariser avec DOMOTICZ :
https://riton-duino.blogspot.com/2019/05/mysensors-presentation.html
L'adaptation des requêtes JSON à d'autres serveurs comme JEEDOM devrait se faire sans difficultés à partir du moment où l'on aura pris le temps de se familiariser avec le principe.

1. Informations affichées

1.1. Date et  heure

Le module affiche la date et l'heure. Ces informations sont obtenues en questionnant un serveur NTP.
La librairie NTP utilisée permet une correction automatique en fonction de l'heure été / hiver.

1.2. Éphéméride

Je n'ai pas trouvé de site proposant une API permettant de récupérer le nom du saint du jour sans devoir s'inscrire avec une adresse IP non fixe.

Le nom du saint du jour sera obtenu grâce à un petit serveur PHP tournant sur la RASPBERRY PI. Ce script est présent dans le projet.

1.3. Météo

1.3.1. weatherstack
La météo est plus facile à récupérer. Il suffit de s'inscrire sur un serveur proposant une API : https://weatherstack.com/ par exemple.
Le service gratuit propose la météo en temps réel et autorise 1000 requêtes par mois.
L'inscription : https://weatherstack.com/signup/free

L'abonnement gratuit ne donne pas accès à certaines fonctions, par exemple l'internationalisation. La météo sera en anglais :
  • Sunny
  • Cloudy
  • Partly cloudy
  • etc.
L'idéal est d'afficher une icône associée à la météo du jour, ce qui est fait dans ce projet.

La documentation :
https://weatherstack.com/documentation

La liste des codes météo :
https://weatherstack.com/site_resources/weatherstack-weather-condition-codes.zip

Le serveur fournit les images PNG nécessaires et nous allons les convertir en utilisant l'outil de conversion de rinkydinkelectronics :
http://www.rinkydinkelectronics.com/t_imageconverter565.php

Toutes les images converties sont présentes dans le projet. Elles devront être chargées dans le système de fichiers SPIFFS de l'ESP8266.

1.3.2. openweathermap
L'autre alternative est https://openweathermap.org/

L'abonnement gratuit est plus généreux : 1000 appels par jour.

Cette API propose aussi un nom d'icône à associer à la météo.

La liste complète des codes météo se trouve ici :

J'avoue franchement que je n'ai pas le courage dans l'immédiat de faire une nouvelle version avec cette API.

1.4. Température et humidité

Comme précédemment le module comporte un capteur de température et d'humidité. Les valeurs sont affichées sur l'écran et également envoyées au serveur domotique.

Le projet propose le choix entre 3 capteurs : HDC2080, SHT31D et HTU21.
Ces trois modules ont une précision de 0.2°C en température et 2% en humidité.

Je n'ai pas envisagé d'intégrer un DHT22 car je préfère ces capteurs, plus précis et plus fiables.

1.5. Informations diverses

Les informations à récupérer sont les suivantes :
  • température à l'étage
  • température au garage
  • température & humidité extérieures
  • température du congélateur
Ces informations proviennent de différents capteurs MYSENSORS :
https://riton-duino.blogspot.com/2018/01/un-thermometre-mysensors-sur-batterie.html
https://riton-duino.blogspot.com/2019/05/un-thermometre-hygrometre-mysensors-sur.html
https://riton-duino.blogspot.com/2018/04/un-detecteur-de-mouvement-mysensors-sur.html
https://riton-duino.blogspot.com/2019/05/un-thermometre-mysensors-pour-freezer.html
Auparavant les informations supplémentaires à afficher étaient récupérées via le module NRF24L01 et la passerelle MYSENSORS.
Avec une liaison WIFI le principe de récupération des informations sera différent. Nous allons utiliser des requêtes JSON.

2. Requêtes JSON

Les requêtes JSON sont utilisées pour :
  • récupération des informations DOMOTICZ
  • récupération des informations météo
  • envoi de la température et de l'humidité à DOMOTICZ 
Bien évidemment ces requêtes sont adaptées à mon système domotique.
Les informations à afficher seront forcément différentes sur une autre installation.

2.1. DOMOTICZ

Les URLs utilisées ici sont celles de mon serveur DOMOTICZ.
Il faut bien sûr remplacer http://192.168.1.134:8080 par l'adresse réelle du serveur et son port.

2.1.1. Dispositifs

Nous allons devoir créer des dispositifs. Domoticz ne possède pas d'interface pour faire cette opération simplement. Il faut le faire via le navigateur :

Un capteur de température / humidité :

http://192.168.1.134:8080/json.htm?type=createvirtualsensor&idx=100&sensorname=Température Salon&sensortype=82

Le buzzer est un dispositif du type lighting que l'on peut créer dans l'interface DOMOTICZ.

Par contre rien n'est prévu pour les dispositifs du type général (sous-type text).
Il sera donc impossible de faire comme dans le projet précédent, dont le principe reposait sur la récupération de données de dispositifs texte mises à jour par des scripts PYTHON tournant sur la RASPBERRY PI.

Il va falloir opérer autrement. Le plus simple est de récupérer directement la valeur des capteurs et d'afficher des messages dédiés :

http://192.168.1.134:8080/json.htm?type=devices&rid=350

Cette requête récupère les informations du capteur de température dont l'identifiant est 350 :
       
ActTime    1586603674
ServerTime    "2020-04-11 13:14:34"
Sunrise    "06:55"
Sunset    "20:18"
result  
    0  
        AddjMulti    1

        AddjMulti2    1 
        AddjValue    0
        AddjValue2    0 
        BatteryLevel    69 
        CustomImage    0 
        Data    "14.4 C, 62 %"
        Description    "" 
        DewPoint    "7.21"
        Favorite    1 
        HardwareID    4 
        HardwareName    "MYSENSORS" 
        HardwareType    "MySensors Gateway USB"
        HardwareTypeVal    41 
        HaveTimeout    false 
        Humidity    62 
        HumidityStatus    "Wet" 
        ID    "0800" 
        LastUpdate    "2020-04-11 13:11:10"
        Name    "Temp & Humidité Extérieure" 
        Notifications    "false" 
        PlanID    "0" 
        PlanIDs
                    0    0 
        Protected    false 
        ShowNotifications    true 
        SignalLevel    "-" 
        SubType    "WTGR800" 
        Temp    14.4
        Timers    "false" 
        Type    "Temp + Humidity" 
        TypeImg    "temperature" 
        Unit    0 
        Used    1 
        XOffset    "0" 
        YOffset    "0" 
        idx    "350" 
        status    "OK" 
        title    "Devices"

Ensuite on formatera un message et on l'affichera :

Out : 14.4° 62%

Reste la 5ème ligne à afficher, un éventuel message d'erreur. Ce message est "Everything is Fine" si tout va bien.
S'il s'agit d'un message d'erreur il est affiché en jaune sur fond rouge.

Par exemple si la batterie d'un détecteur de mouvement est trop faible :

Motion: Battery too low

Ou si la température du congélateur est trop haute :

Freezer Temp: High

Nous allons inclure dans le code ESP8266 les traitements effectué auparavant par les scripts PYTHON :
  • surveillance des batteries
  • surveillance de la température du congélateur
Et le buzzer sera activé si un problème est détecté.

Donc pour résumer :

Les scripts PYTHON deviennent inutiles.
La souplesse sera moindre car sur le projet précédent il suffisait de modifier les scripts pour afficher des informations différentes.
Sur la version précédente la température et l'humidité extérieures étaient auparavant affichées sur les lignes 2 et 3.
Dernièrement j'ai regroupé ces deux informations sur la ligne 3,  et ajouté la température du garage sur la ligne 2, sans modifier le code ARDUINO !

Avec la version ESP8266 il faudra modifier la configuration. Mais avec un peu de travail la mise à jour pourra se faire par OTA.

Un seul capteur devra être créé manuellement dans le navigateur, l'écran TFT du type capteur de température et humidité :

http://192.168.1.134:8080/json.htm?type=createvirtualsensor&idx=100&sensorname=ESP8266 TFT&sensortype=82


2.1.2. Récupération des IDX

Chaque dispositif DOMOTICZ possède un identifiant unique, dit IDX, que l'on peut récupérer en recherchant le dispositif par son nom.
Cela suppose de récupérer la liste de dispositifs en filtrant par type, par exemple "temp" pour recevoir la liste des capteurs de température :

http://192.168.1.134:8080/json.htm?type=devices&filter=temp&&used=true&order=Name

Dans le cas où le nombre de dispositifs est important l'ESP8266 n'aura pas assez de mémoire pour charger la réponse à la requête.
Une solution à base d'ESP32 serait préférable.

Dans le code une valeur d'IDX par défaut est prévue. Tous les noms et identifiants des dispositifs sont configurables par un formulaire HTML.


2.1.3. Envoi et récupération d'informations

L'envoi d'une requête JSON pour récupérer les infos d'un capteur se présente ainsi :

void getSensorInfo(int idx, char *temp, char *hum, char *batt, int len)
{
  String request;
  HTTPClient http;
  int httpCode;
  // https://arduinojson.org/v5/assistant/
  const size_t bufferSize = 2 * JSON_ARRAY_SIZE(1) + JSON_OBJECT_SIZE(7) + 

                                          JSON_OBJECT_SIZE(50);
  if (idx == 0) {
    strncpy(temp, "not found", len);
  }
  else {
    request = DOMOTICZ_URL;
    request += "/json.htm?type=devices&rid=";
    request += idx;
    http.begin(request);
    httpCode = http.GET();
    Serial.printf("%s %d\n", request.c_str(), httpCode);
    if (httpCode > 0) {
      DynamicJsonBuffer jsonBuffer(bufferSize);
      JsonObject& root = jsonBuffer.parseObject(http.getString());
      if (temp) {
        strncpy(temp, root["result"][0]["Temp"], len);
      }
      if (hum) {
        strncpy(hum, root["result"][0]["Humidity"], len);
      }
      if (batt) {
        strncpy(batt, root["result"][0]["BatteryLevel"], len);
      }
    }
  }
  http.end();
}


Le WEB est bien fourni en tutoriels expliquent le fonctionnement de la librairie ArduinoJson.
Un lien plus qu'indispensable pour calculer la taille du buffer nécessaire :
https://arduinojson.org/v5/assistant/

La documentation JSON DOMOTICZ est très bien faite :
 https://www.domoticz.com/wiki/Domoticz_API/JSON_URL%27s#Retrieve_status_of_specific_device

3. Le schéma

Le schéma est réalisé à l'aide de KICAD.
Il n'y a pas de routage de PCB pour l'instant.

Pour récupérer le projet voir plus bas :  7. Téléchargements.

Sur le schéma apparaissent 3 modules capteurs de température et humidité. Bien entendu un seul sera utilisé, au choix.
Ces trois modules ont une précision de 0.2°C en température et 2% en humidité.

Un transistor a été ajouté afin de pouvoir commander le buzzer en 5V.

4. IDE ARDUINO


J'utilise JSON 5. Quelques modifications seront nécessaires pour utiliser JSON 6.

Il faut ajouter une de ces 3 librairie au choix pour le capteur de température / humidité :

Dans l'IDE, dans le menu "Outils/Type de Carte" choisir "NodeMCU" ou "Wemos D1 R1" en fonction de la carte choisie.

Dans le menu "Outils / Flash Size" choisir 4M (1M SPIFFS).

5. Le code

Pour récupérer le projet voir plus bas :  7. Téléchargements.

5.1. Le service PHP

Le petit service PHP permettant de mettre à disposition le nom du saint du jour est à installer dans le répertoire /var/www/html/ de la RASPBERRY PI :

https://bitbucket.org/henri_bachetti/domoticz-esp8266-tft-display/src/master/apache/ephemeris.php

Bien entendu il faudra installer APACHE et PHP :

$ sudo apt-get install apache2
$ sudo apt-get install php5


Il est facile de le tester depuis son PC avec un navigateur :

http://192.168.1.134/ephemeris.php

Le navigateur affichera :

Le Saint du Jour



5.2. Configuration

Il faudra tout d'abord entrer le SSID, le mot de passe de la box et le nom du serveur NTP dans le sketch : esp8266-tft-display.ino

const char* ssid = "........";
const char* password = "........";


String ntpUrl("pool.ntp.org");

Tout le reste est dans le fichier config.h :

Le capteur de température à utiliser est choisi par option de compilation :

#define SENSOR      HDC2080
//#define SENSOR      SHT31D
//#define SENSOR      HTU21D


Il faut également configurer les accès à api.weatherstack.com :

#define METEO_URL         "http://api.weatherstack.com"
#define METEO_CITY        "Paris"
#define METEO_KEY             "................................"
#define METEO_PERIOD      2 // 2 Hours


La clé METEO_KEY sera récupérée en s'incrivant ici :
https://weatherstack.com/signup/free

Ensuite il faut renseigner le nom et l'identifiant du dispositif DOMOTICZ :

// sensor names in DOMOTICZ
#define THIS_SENSOR_NAME      "ESP8266 TFT"

5.3. DOMOTICZ

Créer manuellement le dispositif dans le navigateur :

http://192.168.1.134:8080/json.htm?type=createvirtualsensor&idx=100&sensorname=ESP8266 TFT&sensortype=82

Remplacer bien évidemment l'adresse IP, le port et éventuellement le nom du dispositif, qui doit être le même que dans le code (THIS_SENSOR_NAME).

5.4. Adaptations

L'écran TFT est assez grand pour afficher confortablement 4 à 5 lignes d'informations. Au delà il faudra utiliser soit une police de plus petite taille soit un écran plus grand.

5.5. Aspect serveur

Le code ESP8266 comporte une partie serveur HTTP. Un formulaire de configuration est prévu afin de pouvoir changer certains paramètres :
  • URL de DOMOTICZ
  • URL du service PHP
  • serveur NTP
  • ville pour la météo
  • clé d'accès api.weatherstack.com
  • période d'affichage de la météo
  • utilisation de l'API weatherstack.com
  • période d'affichage de la température
  • période d'affichage des informations
  • nom, identifiants et rôle des dispositifs

Les données de départ sont celles que l'on a configurées dans le sketch et fichier config.h, sauf la ville et la clé d'accès weatherstack : https://weatherstack.com/dashboard?logged_in=1

Le compteur d'utilisation de l'API weatherstack.com peut être consulté sur le dashboard weatherstack.

Auparavant les dispositifs (noms, identifiants) étaient configurés dans le code. Dernièrement, suite à une réinstallation de DOMOTICZ, la configuration a été étendue aux dispositifs, afin de rendre le système plus souple.

Les dispositifs à afficher sont configurés comme suit :
  • idx : l'identifiant du dispositif
  • prompt : le message à afficher sur l'écran
  • Temp : est-ce un capteur de température ? 
  • Humidité : est-ce un capteur d'humidité ? 
  • Battery : le capteur est-il alimenté par batterie ?
Ces renseignements sont à récupérer en affichant la fenêtre "Réglages / Dispositifs" de DOMOTICZ.
 
Pour que la surveillance du capteur de température du congélateur soit effectuée, le dispositif DOMOTICZ doit s'appeler "Freezer".

Tous les capteurs alimentés par batterie seront également surveillés.

Les données sont sauvegardées d'une part en RAM pour être utilisées immédiatement, mais également en EEPROM et seront donc relues au prochain démarrage.

5.6. Difficultés

Le code de gestion de l'afficheur TFT (tft.cpp et tft.h) est le même que dans le projet précédent, aux définition des broches près.
L'adaptation du code à l'ESP8266 et aux requêtes JSON a été très rapide, de l'ordre d'une petite journée.
La librairie Adafruit est parfaitement compatible ARDUINO et ESP8266.

6. Chargement

Pendant le chargement de l'ESP8266, le buzzer émet un bip continu. Ceci est dû à la broche GPIO16 choisie (la LED rouge). Il est conseillé de le débrancher si plusieurs chargements sont prévus pour des modifications.

En fonctionnement normal, le buzzer émet un seul bip après la connexion au réseau WIFI.

Il faut charger les icônes à l'aide du menu "Outils /  ESP8266 Sketch Data Upload".

Avant cela, si ce n'est déjà fait, il faut installer le plugin :
https://github.com/esp8266/arduino-esp8266fs-plugin

Il peut arriver que les images ne soient pas chargées. L'IDE se contente d'afficher ceci :

[SPIFFS] data    : /home/riton/projects/domoticz-esp8266-tft-display/arduino/esp8266-tft-display/data
[SPIFFS] size    : 1004
[SPIFFS] page    : 256
[SPIFFS] block   : 8192
/0010.raw
/0029.raw
/0033.raw
/0040.raw
/0013.raw
/0035.raw
/0019.raw
/0003.raw
/0001.raw
/0018.raw
/0028.raw
/0002.raw
/0026.raw
/0016.raw
/0007.raw
/0037.raw
/0020.raw
/0009.raw
/0021.raw
/0008.raw
/0024.raw
/0011.raw
/0004.raw
/0012.raw
/0025.raw
/0034.raw
/0006.raw
/0032.raw
/0017.raw
/0027.raw
/0036.raw
[SPIFFS] upload  : /tmp/arduino_build_710250/esp8266-tft-display.spiffs.bin
[SPIFFS] address  : 0x300000
[SPIFFS] reset    : nodemcu
[SPIFFS] port     : /dev/ttyUSB1
[SPIFFS] speed    : 115200
[SPIFFS] python   : python3
[SPIFFS] uploader : /home/riton/.arduino15/packages/esp8266/hardware/esp8266/2.5.2/tools/upload.py


Dans ce cas on peut le faire manuellement :

$ python esptool.py --baud 115200 --port /dev/ttyUSB1 write_flash 0x300000 /tmp/arduino_build_710250/esp8266-tft-display.spiffs.bin

Il faut installer esptool :
https://github.com/espressif/esptool

Ensuite après la connexion au serveur, l'heure s'affichera, ainsi que les autres informations :


7. Téléchargement

Pour télécharger le projet :
https://bitbucket.org/henri_bachetti/domoticz-esp8266-tft-display

Cette page vous donne toutes les informations nécessaires :
https://riton-duino.blogspot.com/p/migration-sous-bitbucket.html

8. Consommation

Ce montage consomme 130mA sous 5V, c'est à dire 0.65W.

9. Conclusion

Ce dispositif est plus complet et plus agréable que le précédent.

Cela n'empêche pas l'ancien modèle d'être encore utilisé. Il a simplement changé d'emplacement. Le nouveau se trouve dans le salon, l'ancien dans le bureau.

Ce genre de projet est assez amusant à mettre en œuvre et rend service au quotidien.
La fonction de surveillance des niveaux de batteries est un plus indéniable et permet d'éviter qu'une batterie ne tombe en décharge profonde.

La surveillance de la température du congélateur a déjà fait la preuve de son utilité dans la version précédente, suite à une panne de groupe compresseur en fin d'année dernière.
Dans ce genre de situation, il faut réagir vite car même avec un congélateur ayant une isolation tenant 72H, l'achat du remplaçant prend du temps, et le temps de descente en température du nouveau congélateur après branchement n'est pas négligeable.


Cordialement
Henri

10. Mises à jour

12/04/2020 : configuration HTML
14/08/2020 : configuration des devices
11/10/2025 : support des requêtes JSON Domoticz 2025


mercredi 20 novembre 2019

Afficheur OLED SSD1306 : comparons



Afficheur OLED SSD1306 : comparons


Le but de cet article n'est pas de faire un nième tutorial sur les afficheurs OLED SSD1306, mais plutôt de faire une comparaison des différentes librairies existantes.

Comme vous l'avez peut-être remarqué la librairie AdaFruit occupe une place phénoménale en mémoire RAM. Il existe heureusement une alternative.

J'ai déjà parlé de ces petits afficheurs :
https://riton-duino.blogspot.com/2018/09/lcd-tft-et-arduino.html
Voir  4. Les petits afficheurs OLED

1. Câblage

Le câblage est simple (je ne vais pas vous faire un schéma) :
  • VCC sur 3.3V de l'ARDUINO
  • GND sur GND de l'ARDUINO
  • SDA sur A4 de l'ARDUINO
  • SCL sur A5 de l'ARDUINO
J'ai utilisé un afficheur I2C de 128x64 pixels, comme sur la photo ci-dessus.

Pour vérifier l'adresse I2C  de l'afficheur (en général 0x3C), il suffit d'utiliser ce sketch :
https://gist.github.com/tfeldmann/5411375

2. Les librairies

Dans ce comparatif nous allons essayer d'écrire une application affichant les objets suivants :
  • un titre centré en haut de l'écran
  • un texte justifié à gauche
  • un texte justifié à droite
  • un texte suivi d'une valeur, grande taille, justifié à gauche
  • un indicateur de capacité de batterie en haut à gauche
  • un logo en haut à droite
L'indicateur de capacité batterie est un rectangle de 14 ou 16 pixels de haut, 6 de large, plus ou moins plein. Si la capacité batterie est supérieure à 10%, l'affichage est fixe, sinon il clignote.


Quand ces applications seront écrites nous comparerons la facilité de mise en œuvre et l'occupation mémoire.

1.1. Librairie AdaFruit

Cette librairie peut être récupérée ici :
https://github.com/adafruit/Adafruit_SSD1306

Voici le sketch :

#define SSD1306_128_64

#include <Adafruit_SSD1306.h>

Adafruit_SSD1306 display(-1);

void setup()
{
  Serial.begin(115200);
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.setTextColor(WHITE);
}

void loop()
{
  display.clearDisplay();
  printCentered("SSD1306 TUTO", 0, 1);
  displayLogo(0, 100);
  printLeft("LEFT JUSTIFIED", 20, 1);
  printRight("RIGHT JUSTIFIED", 30, 1);
  printValue(100, 50, 2);
  displayBatteryLevel(0, 0, 0);
  displayLogo(112, 0);
  display.display();
  delay(500);
}

void printLeft(const char *s, int y, int size)
{
  display.setTextSize(size);
  display.setCursor(0, y);
  display.print(s);
}

void printRight(const char *s, int y, int size)
{
  int16_t x1, y1;
  uint16_t w, h;

  display.setTextSize(size);
  display.getTextBounds(s, 0, 0, &x1, &y1, &w, &h);
  display.setCursor(display.width() - w, y);
  display.print(s);
}

void printCentered(const char *s, int y, int size)
{
  int16_t x1, y1;
  uint16_t w, h;

  display.setTextSize(size);
  display.getTextBounds(s, 0, 0, &x1, &y1, &w, &h);
  display.setCursor((display.width() - w) / 2, y);
  display.print(s);
}

void printValue(int value, int y, int size)
{
  char s[20];
  int16_t x1, y1;
  uint16_t w, h;

  sprintf(s, "VALUE: %d", value);
  display.getTextBounds(s, 0, 0, &x1, &y1, &w, &h);
  display.setTextSize(size);
  display.setCursor(0, y);
  display.print(s);
}

static const unsigned char PROGMEM logo16_glcd_bmp[] =
{ B00000000, B11000000,
  B00000001, B11000000,
  B00000001, B11000000,
  B00000011, B11100000,
  B11110011, B11100000,
  B11111110, B11111000,
  B01111110, B11111111,
  B00110011, B10011111,
  B00011111, B11111100,
  B00001101, B01110000,
  B00011011, B10100000,
  B00111111, B11100000,
  B00111111, B11110000,
  B01111100, B11110000,
  B01110000, B01110000,
  B00000000, B00110000
};

void displayLogo(int x, int y)
{
  display.drawBitmap(x, y,  logo16_glcd_bmp, 16, 16, WHITE);
}

void displayBatteryLevel(int batteryLevel, int x, int y)
{
  static bool flash = false;
  if (flash || batteryLevel > 10) {
    display.drawRect(x, y, 6, 16, WHITE);
    display.fillRect(x, y + ((16 - batteryLevel / 6)), 6, batteryLevel / 6, WHITE);
  }
  flash = !flash;
}


1.2. Librairie Greiman

Cette librairie peut être récupérée ici :
https://github.com/greiman/SSD1306Ascii.git

Voici le sketch :

#include "SSD1306Ascii.h"
#include "SSD1306AsciiAvrI2c.h"

SSD1306AsciiAvrI2c display;

void setup()
{
  Serial.begin(115200);
  display.begin(&Adafruit128x64, 0x3C);
  display.setFont(System5x7);
}

void loop()
{
  printCentered("SSD1306 TUTO", 0, 1);
  displayLogo(0, 100);
  printLeft("LEFT JUSTIFIED", 2, 1);
  printRight("RIGHT JUSTIFIED", 3, 1);
  printValue(100, 6, 2);
  displayBatteryLevel(0, 0, 0);
  displayLogo(112, 0);
  delay(500);
}

void printLeft(const char *s, int y, int size)
{
  if (size == 1) {
    display.set1X();
  }
  else {
    display.set2X();
  }
  display.setCursor(0, y);
  display.print(s);
}

void printRight(const char *s, int y, int size)
{
  size_t w;

  if (size == 1) {
    display.set1X();
  }
  else {
    display.set2X();
  }
  w = display.strWidth(s);
  display.setCursor(display.displayWidth() - w, y);
  display.print(s);
}

void printCentered(const char *s, int y, int size)
{
  size_t w;

  if (size == 1) {
    display.set1X();
  }
  else {
    display.set2X();
  }
  w = display.strWidth(s);
  display.setCursor((display.displayWidth() - w) / 2, y);
  display.print(s);
}

void printValue(int value, int y, int size)
{
  char s[20];
  size_t w;

  sprintf(s, "VALUE: %d", value);
  w = display.strWidth(s);
  if (size == 1) {
    display.set1X();
  }
  else {
    display.set2X();
  }
  display.setCursor(0, y);
  display.print(s);
}

void displayLogo(int x, int y)
{
  //  rien ici pour l'instant
}

GLCDFONTDECL(Batt6x14) = {
  0x0, 0x0, // size of zero indicates fixed width font,
  6,     // width
  14,     // height
  0x20,
  7,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // space
  0xff, 0x01, 0x01, 0x01, 0x01, 0xff, 0x3f, 0x20, 0x20, 0x20, 0x20, 0x3f,        // Battery Empty
  0xff, 0x01, 0x01, 0x01, 0x01, 0xff, 0x3f, 0x38, 0x38, 0x38, 0x38, 0x3f,        // Battery 20%
  0xff, 0x01, 0x01, 0x01, 0x01, 0xff, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,             // Battery 40%
  0xff, 0xc1, 0xc1, 0xc1, 0xc1, 0xff, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,              // Battery 60%
  0xff, 0xf1, 0xf1, 0xf1, 0xf1, 0xff, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,                 // Battery 80%
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,                      // Battery 100%
};

void displayBatteryLevel(int batteryLevel, int x, int y)
{
  static bool flash = false;

  display.set1X();
  display.setCursor(x, y);
  if (flash || batteryLevel > 10) {
    display.setFont(Batt6x14);
    display.print((char)(' ' + 1 + round(batteryLevel / 20)));
    display.setFont(System5x7);
  }
  else {
    display.setFont(Batt6x14);
    display.print(' ');
    display.setFont(System5x7);
  }
  flash = !flash;
}


3. Comparaison

3.1. Occupation mémoire

Le résultat de la compilation avec la librairie AdaFruit :
Le croquis utilise 14222 octets (44%) de l'espace de stockage de programmes. Le maximum est de 32256 octets.
Les variables globales utilisent 1544 octets (75%) de mémoire dynamique, ce qui laisse 504 octets pour les variables locales. Le maximum est de 2048 octets.
La mémoire disponible faible, des problèmes de stabilité pourraient survenir.

On sait déjà que l'application sera très limitée en taille mémoire dynamique (les variables globales).

Avec les nouvelles versions de la librairie AdaFruit le buffer dédié à l'écran est alloué dynamiquement par la méthode begin(), ce qui fait que lors de la compilation on a l'impression qu'il y a suffisamment de mémoire : 

  if ((!buffer) && !(buffer = (uint8_t *)malloc(WIDTH * ((HEIGHT + 7) / 8))))
    return false;

Dans le cas d'un écran 128x32 : ((HEIGHT + 7) / 8) = 624 bytes. Après compilation la quantité de mémoire disponible devra être au minimum de 624 bytes + de l'espace pour la pile. On se fait assez vite piéger.

Avec un écran de 128x64 il faudra 1136 bytes + la pile.

Le résultat de la compilation avec la librairie Greiman :

Le croquis utilise 5852 octets (18%) de l'espace de stockage de programmes. Le maximum est de 32256 octets.
Les variables globales utilisent 274 octets (13%) de mémoire dynamique, ce qui laisse 1774 octets pour les variables locales. Le maximum est de 2048 octets.


On remarque vite que l'application est beaucoup moins limitée en taille mémoire dynamique, et que l'on sera beaucoup plus à l'aise pour créer des variables globales.

D'un point de vue occupation mémoire FLASH (programme), la librairie AdaFruit n'est pas catastrophique, mais la quantité de mémoire RAM (données) qu'elle monopolise limite son utilisation à des applications utilisant peu de données globales ou statiques.

Le développement d'une application conséquente avec la librairie AdaFruit se fera donc de préférence sur une carte ARDUINO MEGA, alors que la librairie Greiman se contentera facilement d'un ATMEGA328.

3.2. Principe de fonctionnement

La librairie AdaFruit travaille avec un espace mémoire tampon interne à la librairie (ce qui explique la taille mémoire occupée en RAM).
- on efface la zone tampon avec clearDisplay()
- on écrit avec print(), drawRect(), fillRect(), etc.
- on affiche avec display()
La librairie ne met à jour que les pixels qui ont changé par rapport au dernier affichage.
Avec cette librairie on a donc tendance à ré-afficher la totalité de l'écran, car le rafraîchissement est invisible.

La librairie Greiman travaille différemment, en direct avec l'écran
- on n'efface pas
- on écrit avec print() et l'affichage se fait dans la foulée
Avec cette librairie on préfère afficher sans effacer la totalité de l'écran, car le rafraîchissement serait trop visible.

Une autre différence de taille (c'est le cas de le dire) est que la librairie AdaFruit est capable de positionner son curseur en absolu, en nombre de pixels X et Y.

Avec la librairie Greiman, si le positionnement se fait en absolu dans le sens X (colonnes), il se fait en nombre de lignes de texte (une ligne faisant 8 pixels) dans le sens Y (lignes). La librairie Greiman est tout de même capable de faire du scrolling sur l'axe X, en pixels.
En bref, la librairie Greiman favorise un travail en ligne de texte, la librairie AdaFruit favorise un travail en mode graphique pur.

La librairie Greiman n'oblige pas à effacer un message précédemment affiché avant de le remplacer par un autre, par contre si le nouveau message est plus court que le précédent, la fin du premier message subsistera. On peut combler (padding) avec des espaces avant ou après le message, suivant que l'on justifie à droite, à gauche ou au centre.

On peut aussi positionner le curseur avec la méthod setCursor(x, y) et effacer la ligne avec la méthode clearToEOL() avant de ré-afficher :

  display.setCursor(0, 2);
  display.clearToEOL();
  display.print("A LINE");
  display.setCursor(0, 3);
  display.clearToEOL();  display.print("ANOTHER LINE");

La méthode clear() permet d'effacer une zone. Dans cet exemple on affiche deux lignes avec un retour à la ligne '\n', après avoir effacé les lignes 2 à 3 :

  display.setCursor(0, 2);
  display.clear(0, display.displayWidth(), 2, 3);
  display.print("A LINE\nANOTHER LINE");


La méthode clearField permet aussi d'effacer une zone. Cet exemple fait la même chose que le précédent :

  display.setCursor(0, 2);
  display.clearField(0, display.displayWidth(), 2);
  display.print("A LINE\nANOTHER LINE");


Les trois méthodes produisent le même résultat.

3.3. Affichage d'un indicateur de capacité batterie

Dans le sketch de la version AdaFruit l'indicateur de niveau batterie est réalisé simplement en dessinant un cadre puis un rectangle plein à l'intérieur de ce cadre.
Pour effacer, l'indicateur, on se contente de ne pas l'afficher.

Dans le sketch de la version Greiman l'indicateur de niveau batterie est réalisé à l'aide d'une police de caractères spéciale (Batt6x14) que j'ai fabriqué moi-même.
Cette police possède 7 caractères dont le premier est 0x20 : un ESPACE.

Pour afficher l'indicateur 0%, 20%, 40%, 60%, 80%, 100% il suffit d'afficher le caractère ESPACE (' ' ou 0x20) + n (0x21, 0x22, 0x23, 0x24, 0x25, 0x26).

Le premier caractère ESPACE (0x20) sert à effacer le bitmap dans le cas où l'on veut faire clignoter l'indicateur, comme dans l'exemple ci-dessus.

3.4. Routines graphiques

La librairie AdaFruit possède un jeu de routines graphiques assez complet que la librairie Greiman ne possède pas.

AdaFruit propose en outre un outil Windows de création de bitmaps :
https://learn.adafruit.com/monochrome-oled-breakouts/arduino-library-and-examples
Je ne l'ai pas essayé, ne possédant pas de machine Windows et n'ayant pas du tout l'intention d'utiliser ce système d'exploitation dépassé (alergie profonde). Je vous laisse faire avec plaisir.

Avec la librairie Greiman, il n'y a pas de possibilité d'affichage de bitmaps, mais on pourrait en créer (avec plus ou moins de facilité) en utilisant la même méthode que pour l'indicateur de capacité batterie, comme vu précédemment.

4. Conclusion

Personnellement, depuis que j'ai découvert la librairie Greiman, je l'utilise en lieu et place de la librairie AdaFruit, trop gourmande. Avec un afficheur de 128x64 pixels, mon besoin n'est pas de créer des oeuvres d'art graphique.


Cordialement
Henri