“LADIES AND GENTLEMEN, BOYS AND GIRLS. CHILDREN OF ALL AGES” (That last part is for Ronnie [“guilty as charged” - Ronnie]). Welcome to part 6 of Micro This Micro That! This month (August 2021), we’ll take a look at using the SSD1302 128×64 I2C OLED Display with our Microcontrollers. For all intents and purposes, it’s pretty much the same between the ESP8266, ESP32 and RPi Pico with a few exceptions. Those exceptions are where we connect the wiring for the I2C device and the way we access the I2C device. For many reasons, I selected the ESP8266 for this month’s project. Lately, both the ESP32 and RPi Pico MicroPython firmware have started to support Software I2C which works on all output pins as opposed to the limited Hardware I2C which supports only the two I2C bus structures. The ESP8266 still uses the hardware-only I2C methodology. To use the hardware-only option on any of the microcontrollers, you need to import the I2C and Pin classes from the machine library, then define the scl (clock) and sda (data) pins using the GPIO number. The frequency parameter is optional. from machine import Pin, I2C # construct an I2C bus i2c = I2C(scl=Pin(5), sda=Pin(4), freq=100000)

« MESDAMES ET MESSIEURS, GARÇONS ET FILLES. ENFANTS DE TOUS LES ÂGES » (Cette dernière partie est pour Ronnie [« Je plaide coupable » - Ronnie]

Ce mois-ci (août 2021), nous allons examiner l'utilisation de l'écran OLED SSD1302 128×64 I2C avec nos microcontrôleurs. A toutes fins utiles, c'est plus ou moins la même chose entre l'ESP8266, l'ESP32 et le RPi Pico à quelques exceptions près. Ces exceptions sont l'endroit où nous connectons les fils du dispositif I2C et la façon dont nous accédons au dispositif I2C. Pour de nombreuses raisons, j'ai choisi l'ESP8266 pour le projet de ce mois-ci.

Récemment, les microprogrammes MicroPython de l'ESP32 et du RPi Pico ont commencé à prendre en charge le logiciel d'I2C qui fonctionne sur toutes les broches de sortie, par opposition au matériel limité d'I2C qui ne prend en charge que les deux structures de bus I2C. L'ESP8266 utilise toujours la méthodologie du seul matériel I2C 'hardware-only).

Pour utiliser l'option hardware-only sur l'un des microcontrôleurs, vous devez importer les classes I2C et Pin de la bibliothèque de la machine, puis définir les broches scl (horloge) et sda (données) en utilisant le numéro GPIO. Le paramètre de fréquence est facultatif.

from machine import Pin, I2C

# construire un bus I2C

i2c = I2C(scl=Pin(5), sda=Pin(4), freq=100000)

If, on the other hand, you want to use the software I2C support, you can do it like this… from machine import Pin, SoftI2C # construct an I2C bus i2c = SoftI2C(scl=Pin(5), sda=Pin(4), freq=100000) Very similar, but, of course, if you are using the software solution, you really have to be sure you define the pins. In the earlier versions of the RPi MicroPython firmware, you could simply use i2c = I2C(0) And use the defined pins for bus 0 (or 1). This, however, created a number of problems, since there were so many options for the I2C bus pins. So, to be safe and avoid confusion, always define your pins.

Si, par contre, vous voulez utiliser le support du logiciel I2C, vous pouvez le faire comme ceci :

from machine import Pin, SoftI2C

# construire un bus I2C

i2c = SoftI2C(scl=Pin(5), sda=Pin(4), freq=100000)

Très similaire, mais, bien sûr, si vous utilisez la solution logicielle, vous devez vraiment vous assurer de définir les broches. Dans les versions précédentes du firmware MicroPython du RPi, vous pouviez simplement utiliser :

i2c = I2C(0)

et vous servir des broches définies pour le bus 0 (ou 1). Cependant, cela a créé un certain nombre de problèmes, car il y avait un grand nombre d'options pour les broches du bus I2C. Ainsi, pour être sûr et éviter toute confusion, définissez toujours vos broches.

The Wiring In this month’s project, the wiring is really simple. There’s only 4 wires. 3 volts, ground, data and clock. On my breadboard, I used the following pins. Of course, the red and black pins are Voltage and ground, the yellow is clock, and the white is data. You can use whatever color wires you wish. The ESP8266 has very limited memory, so if you are using that microcontroller, you might want to back off your files and reflash with the latest and greatest firmware version from http://micropython.org . Scanning the I2C Port Once we have the wiring done and the firmware flashed, we want to make sure that everything is working correctly before we try to do a bunch of coding. We’ll use the REPL window in Thonny to do a quick scan of the I2C bus. »> from machine import Pin, I2C »> i2c = I2C(scl=Pin(5), sda=Pin(4)) »> devices = i2c.scan() »> for dev in devices: print(hex(dev)) 0x3c »> We can see that there is only one I2C device in our project and it is at address 0x3c, which is correct for our display. Before we get into the coding of this month’s project, we need to download a driver library. You can find it at https://github.com/peterhinch/micropython-font-to-py. This will enhance our ability to print to the display. We’ll use this library in a little bit. Go ahead and download the zip and unpack it somewhere where you can get to it quickly.

Le câblage

Dans le projet de ce mois-ci, le câblage est très simple. Il n'y a que 4 fils. 3 volts, masse, données et horloge. Sur ma plaque d'expérimentation, j'ai utilisé les broches suivantes.

Bien sûr, les broches rouge et noire sont la tension et la masse, la jaune est l'horloge, et la blanche les données. Vous pouvez utiliser des fils de la couleur que vous souhaitez.

L'ESP8266 a une mémoire très limitée, donc si vous utilisez ce microcontrôleur, il est préférable de sauvegarder vos fichiers et de les re-flasher avec la dernière et meilleure version du firmware sur http://micropython.org .

Scanner le port I2C

Une fois le câblage effectué et le firmware flashé, nous voulons nous assurer que tout fonctionne correctement avant d'essayer de coder. Nous allons utiliser la fenêtre REPL de Thonny pour effectuer un scan rapide du bus I2C.

from machine import Pin, I2C
i2c = I2C(scl=Pin(5), sda=Pin(4))
devices = i2c.scan()
for dev in devices :
      print(hex(dev))

0x3c

Nous pouvons voir qu'il n'y a qu'un seul périphérique I2C dans notre projet et qu'il est à l'adresse 0x3c, ce qui est correct pour notre afficheur.

Avant d'entrer dans le codage du projet de ce mois-ci, nous devons télécharger une bibliothèque de pilotes. Vous pouvez la trouver sur https://github.com/peterhinch/micropython-font-to-py. Elle nous permettra d'améliorer notre capacité à imprimer sur l'écran. Nous allons utiliser cette bibliothèque dans un petit moment. Allez-y, téléchargez le fichier zip et décompressez-le dans un endroit où vous pourrez l'atteindre rapidement.

The Basic Code We will start with a simple program to talk to the display. To use the display, you’ll have to get a copy of the base driver library for the ssd1306. If you are using the Raspberry Pi Pico, you can find it at https://github.com/makerportal/rpi-pico-ssd1306. Unzip it and copy the code onto the Pico. If you are using the ESP32, you can get the driver at https://github.com/micropython/micropython/blob/master/drivers/display/ssd1306.py. Again, copy that to the device. If you are using the ESP8266, the driver is already built into the latest firmware. This test program will simply verify that we can write to the OLED and that it shows us what was sent to it. from machine import Pin, I2C import ssd1306 # using default address 0x3C i2c = I2C(sda=Pin(4), scl=Pin(5)) display = ssd1306.SSD1306_I2C(128, 64, i2c) display.text('Hi, Human!', 0, 0, 1) display.show() Save the file as displaybasic1.py and run it. If everything is working correctly, you will see something like this.

Le code de base

Nous allons commencer par un programme simple pour parler à l'écran. Pour utiliser l'écran, vous devez obtenir une copie de la bibliothèque de pilotes de base pour le ssd1306. Si vous utilisez le Raspberry Pi Pico, vous pouvez la trouver sur https://github.com/makerportal/rpi-pico-ssd1306. Décompressez-la et copiez le code sur le Pico. Si vous utilisez l'ESP32, vous pouvez obtenir le pilote à l'adresse https://github.com/micropython/micropython/blob/master/drivers/display/ssd1306.py. Là encore, copiez-le sur le périphérique. Si vous utilisez l'ESP8266, le pilote est déjà intégré dans le dernier firmware.

Ce programme de test va simplement vérifier que nous pouvons écrire sur l'afficheur OLED et qu'il nous montre ce qui lui a été envoyé.

from machine import Pin, I2C import ssd1306

# utiliser l'adresse par défaut 0x3C i2c = I2C(sda=Pin(4), scl=Pin(5)) display = ssd1306.SSD1306_I2C(128, 64, i2c)

display.text('Hi, Human!', 0, 0, 1) display.show()

Sauvegardez le fichier en tant que displaybasic1.py et exécutez-le. Si tout fonctionne correctement, vous verrez quelque chose comme ceci :

Let’s take a closer look at a couple of the lines of code. When we create the display object, we send the driver the width and height in pixels of the display and the bus that it is on. If you are using a smaller or larger display, your values will be a bit different. display = ssd1306.SSD1306_I2C(128, 64, i2c) The next line is the way we send the text to the display. The parameters are text string, column (x), row (y), and color. In our case, we are going to display it in only white (the 1). display.text('Hi, Human!', 0, 0, 1) Finally, to actually display the text, we use the show method. display.show() That’s it. We’ll look at the graphics capability and other options of the “regular” driver in a later article. If you get the expected results, then we’ll look at the library we downloaded earlier.

Examinons de plus près quelques-unes des lignes de code. Lorsque nous créons l'objet d'affichage, nous envoyons au pilote la largeur et la hauteur en pixels de l'écran et le bus sur lequel il se trouve. Si vous utilisez un écran plus petit ou plus grand, vos valeurs seront un peu différentes.

display = ssd1306.SSD1306_I2C(128, 64, i2c)

La ligne suivante est la façon dont nous envoyons le texte à l'écran. Les paramètres sont la chaîne de texte, la colonne (x), la ligne (y), et la couleur. Dans notre cas, nous allons l'afficher uniquement en blanc (le 1).

display.text('Hi, Human!', 0, 0, 1)

Enfin, pour afficher réellement le texte, nous utilisons la méthode show.

display.show()

C'est tout. Nous examinerons la capacité graphique et les autres options du pilote « normal » dans un prochain article. Si vous obtenez les résultats escomptés, nous nous pencherons alors sur la bibliothèque que nous avons téléchargée précédemment.

Better Displays If you are one of the lucky people who have great eyesight, then you can read the display from 3 feet or more without problems. However, for an old man like me, while the display is bright, trying to read anything greater than about 16 inches away is a strain. Wouldn’t it be nice to be able to use a bigger and denser font? That’s what we are here to talk about. (I know, it took me 4 pages to get to the real reason we are here. Sorry about that.) The distribution zip of micropython-font-to-py contains a really large number of files, but we need only a few for right now. In the writer folder, you’ll need to copy the following files to your microcontroller; font6.py, font10.py, courier20.py, freesans20.py, ssd1306_setup.py and writer.py We’ll be modifying the writer_demo.py file, so you can either copy that as well, or just get the code from the repository for this month. The first four files are the font files, the ssd1306_setup.py file allows you to set your I2C pin configuration, and the writer.py file is the actual driver that does all the magic. We’ll start by modifying the ssd1306_setup.py file to set our configuration. As usual, the imports come first. There is no change to these three lines: import machine from machine import Pin from ssd1306 import SSD1306_SPI, SSD1306_I2C If you are using a ssd1306 that has 128×64 resolution, then you don’t need to change anything here. However, if you are using a 128×32 ssd1306, change the height value to 32. I show it commented out here. WIDTH = const(128) HEIGHT = const(64) # HEIGHT = const(32)

Affichages améliorés

Si vous faites partie des personnes chanceuses qui ont une excellente vue, vous pouvez lire l'écran à une distance d'un mètre ou plus sans problème. Cependant, pour un vieil homme comme moi, bien que l'écran soit lumineux, essayer de lire quoi que ce soit à plus de 40 cm de distance est une épreuve. Ne serait-il pas agréable de pouvoir utiliser une police plus grande et plus dense ? C'est ce dont nous voulons parler ici. (Je sais, il m'a fallu 4 pages pour arriver à la vraie raison pour laquelle nous sommes ici. Désolé.)

Le zip de distribution de micropython-font-to-py contient un très grand nombre de fichiers, mais nous n'avons besoin que de quelques-uns pour l'instant. Dans le dossier writer, vous devez copier les fichiers suivants sur votre microcontrôleur : font6.py, font10.py, courier20.py, freesans20.py, ssd1306_setup.py et writer.py.

Nous allons modifier le fichier writer_demo.py ; vous pouvez donc soit le copier, soit récupérer le code dans le dépôt de ce mois-ci. Les quatre premiers fichiers sont les fichiers de police, le fichier ssd1306_setup.py vous permet de configurer votre broche I2C, et le fichier writer.py est le pilote réel qui fait toute la magie. Nous allons commencer par modifier le fichier ssd1306_setup.py pour définir notre configuration.

Comme d'habitude, les importations viennent en premier. Il n'y a aucun changement à ces trois lignes :

import machine

from machine import Pin

from ssd1306 import SSD1306_SPI, SSD1306_I2C

Si vous utilisez un ssd1306 qui a une résolution de 128×64, vous n'avez rien à changer ici. Cependant, si vous utilisez un ssd1306 128×32, changez la valeur de la hauteur à 32. Je le montre commenté ici :

WIDTH = const(128)

HEIGHT = const(64)

# HEIGHT = const(32)

The other thing that needs to be changed is in the setup function, down near the end of the function. The first part allows you to use an SPI based display. I’ve just got it here for reference. Since this driver was originally written for the Pyboard, we will have to change a few things here. In order to make things easier for our three possible microcontrollers, I’ve commented everything out in the I2C portion of the function except the portion following the last else. Make sure that you fix the indentation so that the lower portion of the code falls under the starting if statement (if use_spi:). Once again, make sure the I2C pin numbers match your setup (code shown above). At this point, we need to edit or create the writer_demo.py file. I’m going to leave out most of the comments here, but they will be in the file in my distribution. I’ll show you the main parts of the demo file and then I’ll explain how you can change it. import machine from ssd1306_setup import WIDTH, HEIGHT, setup from writer import Writer import time

L'autre chose qui doit être modifiée se trouve dans la fonction de configuration, vers la fin de la fonction. La première partie vous permet d'utiliser un écran basé sur SPI. Je l'ai mis ici uniquement pour référence. Comme ce pilote a été écrit à l'origine pour la Pyboard, nous devrons en modifier quelques éléments. Afin de rendre les choses plus faciles pour nos trois microcontrôleurs possibles, j'ai commenté tout ce qui se trouve dans la partie I2C de la fonction, sauf la partie qui suit le dernier else. Assurez-vous de fixer l'indentation de façon à ce que la partie inférieure du code tombe sous l'instruction if de départ (if use_spi:). Une fois encore, assurez-vous que les numéros des broches I2C correspondent à votre configuration (code ci-dessus).

A ce stade, nous devons modifier ou créer le fichier writer_demo.py. Je vais laisser de côté la plupart des commentaires ici, mais ils seront dans mon fichier de diffusion.

Je vais vous montrer les parties principales du fichier de démonstration et ensuite j'expliquerai comment vous pouvez le modifier.

import machine

from ssd1306_setup import WIDTH, HEIGHT, setup

from writer import Writer

import time

Again, we start with the support file imports. We also need to import the font file(s) that we want to include. Since I purposely chose to use the ESP8266, memory is at a premium, so I’m going to deal with only one font file at a time in this demo. For now, we’ll begin with just the font10.py file. I’ve commented out the other two in our code (I’ve chosen to ignore the courier20.py font, but you can certainly include it if you wish). # Font # import freesans20 # import font6 import font10 Now that the imports are done, we’ll create a test function. The original author chose to make the function generic in nature, so he included the parameter use_spi. I chose to include this as well, and it is set to False by default. We call the setup function from the ssd1306_setup.py library with both parameters (use_spi and soft (software I2C)) set to False. It’s important to remember to comment out the fonts that you won’t be using and uncomment the font that you will be using. def test(use_spi=False): ssd = setup(False, False) wri = Writer(ssd, font10) # wri = Writer(ssd, font6) # wri = Writer(ssd,freesans20) The base (always used) code is almost done. You can always use this code in your own project.

Là encore, nous commençons par importer les fichiers de support. Nous devons également importer le ou les fichiers des polices que nous voulons inclure. Comme j'ai délibérément choisi d'utiliser l'ESP8266, la mémoire est limitée, je vais donc traiter un seul fichier de police à la fois dans cette démo. Pour l'instant, nous allons commencer avec le seul fichier font10.py. J'ai commenté les deux autres dans notre code (j'ai choisi d'ignorer la police courier20.py, mais vous pouvez certainement l'inclure si vous le souhaitez).

# Police # import freesans20 # import font6 import font10

Maintenant que les importations sont faites, nous allons créer une fonction de test. L'auteur initial a choisi de rendre la fonction générique par nature ; il a donc inclus le paramètre use_spi. J'ai choisi de l'inclure également, et il est défini à False par défaut. Nous appelons la fonction setup de la bibliothèque ssd1306_setup.py avec les deux paramètres (use_spi et soft (software I2C)) réglés sur False. Il est important de se rappeler de commenter les polices que vous n'utiliserez pas et de décommenter celles que vous utiliserez.

def test(use_spi=False) :

  ssd = setup(False, False)
  wri = Writer(ssd, font10)
  # wri = Writer(ssd, font6)
  # wri = Writer(ssd,freesans20)

Le code de base (toujours utilisé) est presque terminé. Vous pouvez toujours utiliser ce code dans votre propre projet.

You will also want to include the next line (first line below) as well. This ensures that the display starts at row 0, column 0, at startup. The next steps are to get the current time and date (time.localtime()) and format it to show the date on the first line and the time on the second line. Finally, we use ssd.show() to actually display the information. The information that we get from the localtime call is returned as (2021, 8, 4, 8, 52, 49, 2, 216). Year, Month, Day, Hour, Minute, Second, Milliseconds. Remember the data is zero based, so the date information is dt[1], dt[2], dt[0] for the crazy americans. If you live in one of the saner countries, feel free to format it as you wish! (code shown above) This is where I deviate (moreso) from the demo code that the author provides. I want to show how to display the time every second and what you have to do to overwrite the previous information. I chose to do this for a period of 2 minutes. If you feel that is too long or short, go ahead and change the 120 in the for loop to a different value. We set the text position to row 18 column 0 (shown below) to overwrite the previous time display, verify that the seconds have a leading zero, send the string out, tell the driver to display the new information and then sleep for 1 second. The value of row 18 will change depending on the font you are using. I had to try various values to come up with that. I found that if you are using font6, then you should use 14, for font10 use 18, and for freesans20, 20 works well. You can tweek these values to suit your needs. Finally, we call our test function to start the fun. test(False) Save the file as writer_demo2.py (just to make sure the original one is still there), and run the program. There is a chance that, if you are using the ESP8266, then you might get a memory error when you try to run it. The author’s documentation suggests that you should be able to use the file writer_minimal.py to replace writer.py. However, when I tried to use it, I got errors. So, if you are having memory issues, try to remove any unused files from your device and/or try a smaller font file.

Vous voudrez également inclure la ligne suivante (première ligne en dessous). Elle garantit que l'affichage commence à la ligne 0, colonne 0, au démarrage. Les étapes suivantes consistent à obtenir l'heure et la date actuelles (time.localtime()) et à les formater pour afficher la date sur la première ligne et l'heure sur la deuxième ligne. Enfin, nous utilisons ssd.show() pour afficher réellement les informations. Les informations que nous obtenons de l'appel localtime sont retournées sous la forme (2021, 8, 4, 8, 52, 49, 2, 216). Année, Mois, Jour, Heure, Minute, Seconde, Millisecondes. Rappelez-vous que les données sont basées sur des zéros, donc les informations de date sont dt[1], dt[2], dt[0] pour ces fous d'Américains. Si vous vivez dans un pays plus sain, n'hésitez pas à le formater comme vous le souhaitez ! (code affiché ci-dessus).

C'est ici que je m'écarte (encore plus) du code de démonstration fourni par l'auteur. Je veux montrer comment afficher l'heure toutes les secondes et ce qu'il faut faire pour écraser l'information précédente. J'ai choisi de faire cela pour une période de 2 minutes. Si vous pensez que c'est trop long ou trop court, allez-y et changez la valeur 120 dans la boucle for.

Nous définissons la position du texte à la ligne 18 colonne 0 (illustrée ci-dessous) pour écraser l'affichage précédent de l'heure, vérifions que les secondes commencent par un zéro, envoyons la chaîne de caractères, demandons au pilote d'afficher les nouvelles informations, puis restons en veille pendant 1 seconde. La valeur de la ligne 18 change en fonction de la police que vous utilisez. J'ai dû essayer plusieurs valeurs pour en arriver là. J'ai trouvé que si vous utilisez la police 6, vous devez utiliser 14, pour la police 10, utilisez 18, et pour freesans20, 20 fonctionne bien. Vous pouvez modifier ces valeurs en fonction de vos besoins.

Enfin, nous appelons notre fonction de test pour commencer à nous amuser.

test(False)

Enregistrez le fichier en tant que writer_demo2.py (juste pour être sûr que l'original est toujours là) et exécutez le programme. Il est possible que, si vous utilisez l'ESP8266, vous obteniez une erreur de mémoire lorsque vous essayez de l'exécuter. La documentation de l'auteur suggère que vous devriez pouvoir utiliser le fichier writer_minimal.py pour remplacer writer.py. Cependant, lorsque j'ai essayé de l'utiliser, j'ai eu des erreurs. Donc, si vous avez des problèmes de mémoire, essayez de supprimer tous les fichiers inutilisés de votre appareil et/ou essayez un fichier de police plus petit.

Here is what each font looks like on my display. Font6.py Font10.py Freesans20.py And the basic driver again for comparison. You can see that either of the three generated by the Writer driver are much better at a distance than the basic driver. Even when using font6.py, the text is easy enough to read at about 2 feet and, at least for me, font10.py is the best when you consider the readability at a distance and the memory size. As I suggested earlier, there is a lot more to both the “original'' ssd1306 driver and the enhanced writer program. In addition, we used only a small part of the font-to-py repository. There is, as the name suggests, a helper program that will allow you to create your own font files (from ttf font files) that can be used in your own programs. We’ll look into all of these in later articles. You can find all of the code and image files on my github repository at https://github.com/gregwa1953/FCM172_MicroThisMicroThat . As always, until next time: stay safe, healthy, positive and creative!

Voici à quoi ressemble chaque police sur mon écran.

Font6.py

Font10.py

Freesans20.py

Et à nouveau le pilote de base pour comparaison.

Vous pouvez voir que les trois polices générées par le pilote Writer sont bien meilleures à distance que le pilote de base. Même en utilisant la police 6.py, le texte est assez facile à lire à environ 60 cm et, au moins pour moi, la police 10.py est la meilleure si l'on considère la lisibilité à distance et la taille de la mémoire.

Comme je l'ai suggéré précédemment, il y en a beaucoup plus dans le pilote ssd1306 « original » et dans le programme d'écriture amélioré. De plus, nous n'avons utilisé qu'une petite partie du dépôt font-to-py. Il y a, comme son nom l'indique, d'un programme d'aide qui vous permettra de créer vos propres fichiers de police (à partir de fichiers de police ttf) qui pourront être utilisés dans vos propres programmes. Nous verrons tout cela dans des articles ultérieurs.

Vous trouverez l'ensemble du code et des fichiers d'images sur mon dépôt github à l'adresse https://github.com/gregwa1953/FCM172_MicroThisMicroThat.

Comme toujours, jusqu'à la prochaine fois : restez en sécurité, en bonne santé, positif et créatif !