Affichage OLED SSD1306 en MicroPython, exemple avec un baromètre numérique BME280 I2C • Domotique et objets connectés à faire soi-même

Je vous propose aujourd’hui d’apprendre comment détecter les appareils connectés au bus i2c en MicroPython. Pour ce tutoriel, nous allons récupérer les mesures renvoyées par un capteur environnement BME280 qui permet de mesurer la température, la pression atmosphérique et l’humidité. Les données seront ensuite affichées sur un écran OLED monochrome SSD1360 de 128×64 pixels très classique dans les projets Arduino et DIY. Je vous conseille d’utiliser l’éditeur de code uPiCraft pour développer en MicroPython si vous êtes sur Windows. Sous Linux/Raspberry Pi ou macOS, suivez ce tutoriel pour découvrir comment utiliser rshell.

Matériel et circuit pour un projet ESP8266 ou ESP32

Pour ce tutoriel, j’ai utilisé une Wemos d1 mini à base d’ESP8266. La broche SCL se trouve sur la broche D1 (GPIO5) et la broche SDA sur D2 (GPIO4). L’écran OLED et le BME280 doivent être alimentés en 3V3.

izf0hiaamd34qbl5ov5g-4489212

Le bus i2c se trouve sur les broche GPIO22 (SCL) et GPIO21 (SDA). Cependant, la broche 21 est absente sur la Wemos LoLin32 Lite que j’utilise actuellement. Heureusement, la librairie I2C permet de choisir d’autre broches comme nous allons le voir plus tard.

Scanner les appareils connectés sur le bus i2c en MicroPython

Le bus i2c est pris en charge nativement par MicroPython. Toutes les méthodes sont détaillées sur la documentation en ligne ici. On dispose des méthodes suivantes pour se connecter à un capteur et lire des données dans les registres. Les méthodes sont accessibles depuis la classe machine.

  • I2C.init(scl,sda,freq=400000), initialise le bus i2c. On doit indiquer les broches sda et scl. Il est également possible de modifier la fréquence du bus.
  • I2C.deinit(), arrête le bus i2c
  • I2C.scan(), scan le bus i2c et retourne les adresses des appareils trouvés
  • I2C.start(), génère une condition Start sur le bus
  • I2C.stop(), ou un Stop
  • I2C.readinto(), lit les bytes sur le bus et stocke dans un buffer
  • I2C.write(), écrit le buffer sur le bus
  • I2C.readfrom(addr, nbytes, stop=True), lit nbytes sur l’esclave. Renvoi un objet
  • I2C.readfrom_into(addr, buf, stop=True), idem mais stocke dans un buffer les bytes renvoyés
  • I2C.writeto(addr, buf, stop=True), permet d’écrire le contenu d’un buffer à l’esclave se trouvant à l’adresse indiquée
  • I2C.readfrom_mem(addr, memaddr, nbytes, *, addrsize=8), lit à l’adresse mémoire de l’esclave nbytes
  • I2C.readfrom_mem_into(addr, memaddr, buf, *, addrsize=8), idem mais stocke dans un buffer les nbytes renvoyées par l’esclave
  • I2C.writeto_mem(addr, memaddr, buf, *, addrsize=8), écrit le buffer dans la mémoire de l’esclave indiqué

Par défaut MicroPython convertit automatiquement les valeurs hexa et décimales. En général, les fabricants indiquent l’adresse i2c en hexa. Ce petit morceau de code fait donc la conversion inverse. Vous pourrez identifier plus facilement les appareils connectés. Ensuite dans le code, vous pouvez utiliser indifféremment l’adresse en hexa ou en decimal, MicroPython fait la conversion automatique.

Créer un nouveau script et collez le code ci-dessous. Enregistrez le script sous le nom de scanneri2c.py par exemple puis lancez l’exécution en appuyant sur la touche F5.

uPicraft va le téléverser et lancer le script. Si le câblage est correct, le scanner doit détecter l’écran OLED (0x3c typiquement) et le capteur BME280 (0x76 en général). Vous pouvez également utiliser un BME180 qui ne retournera pas le taux d’humidité.

Maintenant regardons de plus près comment on utilise le bus i2c en MicroPython. Tout d’abord, on doit créer un objet I2C qui va se connecter au bus i2c et communiquer avec les périphériques connectés. Sur un ESP8266, la broche SCL se trouve sur la broche D1 (GPIO5) et la broche SDA sur D2 (GPIO4). Cependant, la librairie n’impose pas d’utiliser les broches officielles. Comme avec du code Arduino, on pourra attribuer d’autres broches. Ici, j’ai connecté le bus i2c sur les broches 22 et 18 de carte la ESP32 Wemos Lolin32 Lite.

import machine
i2c = machine.I2C(scl=machine.Pin(22), sda=machine.Pin(18)) # ESP8266 5/4

Ensuite la méthode i2c. scan() permet de récupérer les adresses des appareils sous la forme d’un tableau hexa.

Lire les mesures d’un BMP180/BME280 en MicroPython

On trouve quelques drivers fonctionnels sur GitHub ou internet. Inutile donc de ré-inventer la roue. Pour ce tutoriel, j’ai utilisé le driver adapté par Catdog2. Ce driver est basé sur la librairie Adafruit_I2C.py d’Adafruit. Allez sur GitHub pour récupérer le code du drivers BME280 et collez le dans un nouveau script. Enregistrez le script sous le nom bme280.py. Faites F5 pour le téléverser (rien ne va s’exécuter sur la carte).

J’ai un faible pour le BME280 car il permet d’économiser un DHT11/DHT21 ou DHT22 si l’on souhaite mesurer la température et l’humidité. On gagne aussi en compacité et en économie d’énergie, des conditions indispensables pour des projets d’objets connectés sur batterie.

Créer un nouveau script et collez le code suivant. Le début est identique. On commence par initialiser un objet I2C en lui indiquant les broches du bus puis on créé un objet bme280. On lui passe en paramètre l’objet i2c. Il est aussi possible de lui passer en paramètre l’adresse du BME280 si elle est différente de l’adresse par défaut 0x76 (avec le scanner précédent, c’est facile de la trouver). La méthode values() permet de récupérer les mesures directement formatées avec l’unité.

import machine, time, bme280
i2c = machine.I2C(scl=machine.Pin(22), sda=machine.Pin(18))
bme = bme280.BME280(i2c=i2c,address=0x76)
while True:
  print("BME280 values:")
  temp,pa,hum = bme.values 
  print(temp)
  print(pa) 
  print(hum)
  time.sleep_ms(2000)

Intégrer un affichage OLED SSD1306 en MicroPython

Maintenant qu’on dispose de mesures concrètes, on va les afficher sur un petit écran OLED monochrome très classique et déjà vu dans plusieurs tutoriels. uPiCraft embraque déjà un drivers pour les écrans SSD1306. Il se trouve dans la section Upi_lib. Copiez la librairie ssd1306.py sur la carte. Si vus n’utilisez pas uPiCraft, vous pouvez récupérer le drivers original sur GitHub.

On aura besoin de 6 lignes de code pour afficher du texte sur un écran OLED en MicroPython. Après avoir créé un objet ssd1306 qui nécessite la résolution horizontale en pixels, la résolution verticale et l’objet i2c. On peut aussi lui passer l’adresse de l’écran si elle est différente de 0x3c. Par rapport à la librairie Arduino, on peut passer la résolution de l’écran à l’initialisation sans avoir à aller modifier la librairie.

import machine, ssd1306
i2c = machine.I2C(scl=machine.Pin(22), sda=machine.Pin(18))
oled = ssd1306.SSD1306_I2C(128, 64, i2c, 0x3c)
oled.fill(0)
oled.text("Hello World", 0, 0)
oled.show()

On dispose ensuite de quelques méthodes pour gérer l’affichage :

  • poweroff(), permet d’éteindre l’écran. Pratique pour un fonctionnement sur batterie.
  • contrast(), pour régler le contraste
  • invert(), inverse les couleurs de l’écran (enfin le blanc et le noir!)
  • show(), pour actualiser l’affichage
  • fill(), pour remplir l’écran en noir (1) ou blanc (0)
  • pixel(), permet d’allumer un pixel en particulier
  • scroll(), permet de faire un scroll de l’écran.
  • text(), pour afficher sur texte à la position x,y indiquée
  • Dessiner des lignes hline(), vline() ou une ligne quelconque line()
  • Dessiner un rectangle rect() ou un rectangle rempli fill_rect()

C’est une librairie très puissante qui n’a rien à envier aux librairies Arduino (Adafruit GFX entre autre). Elle prend parfaitement en charge la classe Frame Buffer du MicroPython. Quelque soit la résolution de l’écran utilisé, on suffit d’indiquer la résolution horizontale et verticale pour avoir un affichage correct.

Code complet du projet

Voilà, nous arrivons au terme de ce tutoriel. Nous savons faire beaucoup de chose supplémentaires en MicroPython maintenant :

  • Scanner le bus i2c
  • Récupérer des données sur un capteur i2c
  • Afficher du texte ou des formes géométriques simples sur un écran OLED monochrome SSD1306

Créez un nouveau script et collez le code suivant. Modifiez les paramètres suivants au début du code en fonction de votre configuration :

  • pinScl = 22 #ESP8266 GPIO5 (D1)
  • pinSda = 18 #ESP8266 GPIO4 (D2)
  • addrOled = 60 #0x3c
  • addrBME280 = 118 #0x76
  • hSize = 64 # Hauteur ecran en pixels | display heigh in pixels
  • wSize = 128 # Largeur ecran en pixels | display width in pixels

Enregistrez et envoyez le code avec la touche F5.

J’ai testé avec plusieurs écrans (124×64, 124×32, 64×48), tout fonctionne à merveille du premier coup !

ggsxbyrhfea29wr4k3wk-5454749

64×48 pixels

wmyjz89lnbsrva0ntjbx-1152043

124×32 pixels

J’ai été vraiment très surpris de la facilité avec laquelle on peut gérer un affichage OLED avec du code MicroPython. Comme le code n’est pas compilé, on gagne un temps fou pour la mise au point. Dans le prochain tutoriel, nous verrons comment gérer plusieurs sondes Dallas DS18B20.

Avez-vous aimé cet article ?