dimanche 2 décembre 2018

Afficheur LCD Nokia 5110 et Arduino

Dans cet article, je vais tenter de vous expliquer de la façon la plus claire et complète possible comment piloter un petit écran à cristaux liquide de type "Nokia 5110" au moyen d'un Arduino Uno: vous saurez comment procéder pour brancher l'afficheur et pour programmer l'Arduino afin que l'écran affiche du texte et des images.


"Nokia 5110" est, en fait, le nom d'un modèle de téléphone portable commercialisé entre 1998 et 2001 qui utilisait ce type d'écran. Il s'agit d'un afficheur LCD monochrome associé à un contrôleur Philips PCD8544, avec une résolution de 84 X 48 pixels (sa taille réelle est de 3,5 cm par 2,5 cm environ).  Vous pouvez y afficher du texte et des dessins mais, bien entendu, ce ne sera pas de la haute résolution...

Pour faciliter les branchements avec un microcontrôleur, il existe  sur le marché deux types de breakout: le modèle rouge commercialisé par Sparkfun, et le modèle bleu commercialisé par Adafruit. Des clones de ces deux modèles sont proposés pour environ la moitié du prix par les revendeurs asiatiques. J'ai moi-même utilisé le modèle de type Sparkfun, mais vous pouvez sans problème utiliser les informations que je vous présente ici avec le modèle de type Adafruit.  Vous devrez souder vous-même une barrette de 8 connecteurs (mâles ou femelles, selon votre préférence).



Téléchargement et installation des bibliothèques

Je vous recommande l'utilisation de la bibliothèque Adafruit-PCD8544-Nokia-5110-LCD-library qui, comme son nom l'indique, a été mise au point par la compagnie Adafruit. Vous devez également installer la bibliothèque Adafruit-GFX-Library, qui comporte les routines permettant de dessiner à l'écran ("GXF" dans le sens de "graphics").

Au cas où ça vous intéresserait: il existe aussi une bibliothèque conçue par Carlos Rodrigues qui offre beaucoup moins de possibilités,  mais est moins gourmande en ressources. Ça pourrait s'avérer intéressant si vous désirez uniquement afficher du texte (caractères de 5 X 8 pixels). Je n'ai pas fait l'essai de cette bibliothèque allégée, puisque la bibliothèque proposée par Adafruit a parfaitement répondu à mes besoins.

Connexions

Mauvaise nouvelle: le pilote PCD8544 fonctionne à un niveau logique de 3,3 V.  Si vous utilisez un Arduino Uno (ou un autre modèle d'Arduino fonctionnant à un niveau logique de 5 V), il est recommandé abaisser la tension avant de l'acheminer à l'afficheur.

Bien sûr, vous trouverez sur le web tout un tas de tutoriels proposant de brancher directement les sorties 5 V de l'Arduino aux entrées 3,3 V de l'afficheur sous prétexte que les entrées de l'afficheur tolèrent les tensions de 5 V; mais ce n'est pas ce que dit le site de Sparkfun, ni celui d'Adafruit. Si vous branchez directement l'afficheur aux sorties de l'Arduino sans abaisser le niveau logique, il fonctionnera sans doute très bien, mais sa durée de vie utile pourrait être sérieusement diminuée.

J'ai donc utilisé un circuit intégré 4050, qui est spécialement conçu pour ce genre d'applications.

Voici donc le circuit complet:


Attention: le circuit illustré utilise la version Sparkfun de l'afficheur. Si vous utilisez plutôt la version Adafruit, les broches de l'afficheur ne sont pas dans le même ordre. Référez-vous plutôt aux noms des broches indiqués ci-dessous.

Alimentation:
  • La broche VCC de l'afficheur et la broche 1 du 4050 sont branchés à la sortie 3.3 V de l'Arduino.
  • La broche GND de l'afficheur et la broche 8 du 4050 sont branchés à la broche GND de l'Arduino.
Sorties de l'Arduino:
  • La broche 3 de l'Arduino est branchée à la broche 3 du 4050
  • La broche 4 de l'Arduino est branchée à la broche 5 du 4050
  • La broche 5 de l'Arduino est branchée à la broche 7 du 4050
  • La broche 11 de l'Arduino est branchée à la broche 14 du 4050
  • La broche 13 de l'Arduino est branchée à la broche 11 du 4050
(Notez que vous pouvez choisir d'autres sorties de l'Arduino si vous préférez, en faisant les changements appropriés dans le sketch. Toutefois, l'utilisation des broches 11 et 13 de l'Arduino permet une plus grande vitesse de communication avec l'afficheur).

Entrées de l'afficheur:
  • La broche SCE ou CS de l'afficheur est branchée à la broche 4 du 4050
  • La broche RST de l'afficheur est branchée à la broche 2 du 4050
  • La broche D/C de l'afficheur est branchée à la broche 6 du 4050
  • La broche DN (MOSI) ou DIN de l'afficheur est branchée à la broche 15 du 4050
  • La broche SCLK ou CLK de l'afficheur est branchée à la broche 12 du 4050
  • La broche LED de l'afficheur n'est pas branchée (je n'avais pas besoin du rétroéclairage).
En résumé, après l'abaissement du niveau logique par le 4050:
  • La broche SCE de l'afficheur reçoit le signal provenant de la broche 4 de l'Arduino
  • La broche RST de l'afficheur reçoit le signal provenant de la broche 3 de l'Arduino
  • La broche D/C de l'afficheur reçoit le signal de la broche 5 de l'Arduino
  • La broche DN/MOSI de l'afficheur reçoit le signal de la broche 11 de l'Arduino
  • La broche SCLK de l'afficheur reçoit le signal de la broche 13 de l'Arduino
Si vous n'avez pas de circuit intégré 4050 sous la main, le tutoriel de Sparkfun propose un moindre mal: insérer une résistance de protection entre les sorties de l'Arduino et l'afficheur (notez que je n'ai pas testé cette option).

Utilisation des bibliothèques:

Au début de votre sketch, lorsque vous définissez les broches de l'Arduino que vous utilisez, vous avez le choix entre deux modes:

Le mode "hardware SPI" (celui que nous avons utilisé, car il est plus rapide). Dans ce mode, les sorties 11 et 13 de l'Arduino sont nécessairement utilisées, et il ne reste qu'à indiquer le numéro des 3 autres broches (dans l'ordre: D/C, SCE ou CS , RST ):

Adafruit_PCD8544 display = Adafruit_PCD8544(5, 4, 3);

Le mode "software SPI" (que certains préfères utiliser, si les sorties 11 et 13 sont déjà affectées à d'autres tâches). Il faut alors indiquer le numéro de toutes les broches utilisées (dans l'ordre: SCLK, DIN ou DN, D/C, SCE ou CS , RST ):

Adafruit_PCD8544 display = Adafruit_PCD8544(7, 6, 5, 4, 3);

De plus, il est important de bien comprendre la numérotation des pixels: la position de chaque pixel est déterminée par une coordonnée x (numéro de colonne) et une coordonnée y (numéro de ligne). La première ligne en haut de l'écran et la première colonne à gauche portent le numéro 0. Ainsi, le premier pixel en haut à gauche se trouve aux coordonnées x = 0, y = 0. Le dernier pixel en bas à droite se trouve aux coordonnées x = 83, y = 47.

Il est possible de contrôler individuellement chacun de ces 4032 pixels, mais c'est rarement nécessaire, car la bibliothèque nous offre des raccourcis utiles pour écrire du texte ou dessiner des formes géométriques à l'écran.

Lorsque vous programmez ce qui apparaîtra à l'écran, les modifications sont d'abord apportées en mémoire, dans un buffer.  Ce n'est que lorsque vous invoquez la commande display() que le contenu du buffer est transposé à l'écran.

clearDisplay() efface à la fois le contenu du buffer et de l'écran.

Écrire du texte

Pour l'écriture de texte à l'écran, on utilise les commandes "print" ou "println" comme lorsqu'on veut faire apparaître un message dans le moniteur série. Par défaut, les polices de caractère ont 5 pixels de largeur et 8 pixels de hauteur, mais on peut grossir les caractères grâce à la commande setTextSize().

       display.setCursor(5, 5);  // le texte commencera à x = 5 et y = 5
       display.setTextColor(BLACK);   // texte en noir
       display.setTextSize(2);   // taille deux fois plus grande que normal
       display.println("Bonjour");   // écriture du texte désiré.
       display.display(); // nécessaire pour que le résultat s'affiche à l'écran

Il existe également une commande qui permet d'afficher un caractère unique:

       display.drawChar(15, 5, 'A',  BLACK, WHITE, 1);

Les arguments de drawChar sont, dans l'ordre: position x, position y, caractère ASCII devant être écrit, couleur du texte, couleur du fond.   La ligne ci-dessus demande donc d'écrire la lettre A à la position x= 15 et y = 5, en noir, sur fond blanc, à la taille par défaut de 5 X 8 pixels.

Dessiner des lignes et des formes géométriques

drawPixel() permet de dessiner un pixel spécifique en noir ou en blanc:

       drawPixel(24, 12, BLACK);  // pour mettre en noir le pixel x = 24, y = 12

drawLine() permet de dessiner une ligne droite:

       display.drawLine(3, 7, 22, 30, BLACK);

(La ligne précédente permet de tracer en noir une ligne droite de la position x = 3 , y = 7 jusqu'à la position x = 22, y = 30.)

drawRect() dessine le contour d'un rectangle (l'intérieur du rectangle demeure transparent):

       display.drawRect(10, 5, 12, 16, BLACK);

(la ligne précédente dessine en noir le contour d'un rectangle dont le coin supérieur gauche se trouve à la position x = 10, y = 5, avec une largeur de 12 pixels et une hauteur de 16 pixels.)

fillRect() dessine un rectangle plein:

       display.fillRect(20, 10, 35, 13, BLACK);

(la ligne précédente dessine un rectangle entièrement noir dont le coin supérieur gauche se trouve à la position x = 20, y = 10, avec une largeur de 35 pixels et une hauteur de 13 pixels.)

drawCircle() dessine le contour d'un cercle:

       display.drawCircle(32, 18, 12, BLACK);

(la ligne précédent dessine en noir le contour d'un cercle dont le centre se trouve à la position x = 32, y = 18, de 12 pixels de rayon).

Avec les mêmes paramètres, fillCircle() dessine un cercle plein.

Pour dessiner un rectangle aux coins arrondis, on utilise drawRoundRect() ou fillRoundRect():

       display.fillRoundRect(8, 12, 43, 17, 6, WHITE);

(la ligne précédente trace un rectangle aux coins arrondi dont le coin supérieur gauche se trouve à la position x = 8, y = 12, de 43 pixels de large et 17 pixels de haut. Les cercles de coin ont un rayon de 6 pixels, et le rectangle est tout blanc (on suppose qu'il est tracé sur fond noir).)

On peut également dessiner un triangle avec drawTriangle() ou fillTriangle():

       display.drawTriangle(5, 31, 10, 18, 34, 25, BLACK);

(la ligne précédente trace le contour d'un triangle dont les 3 coins se trouvent aux positions x= 5, y = 31 , x = 10, y = 18, et x = 34, y = 25).

Afficher une image bitmap

Finalement, la fonction drawBitmap() permet d'afficher à l'écran une image bitmap préalablement stockée en mémoire:

       display.drawBitmap(20, 0, myBitmap, 34, 48, BLACK);

(la ligne précédente dessine l'image stockée dans la variable myBitmap. Il s'agit d'une image de 34 pixels de largeur et de 48 pixels de hauteur, et son coin supérieur gauche doit se situer à la position x = 20, y = 0.)

Encore faut-il définir cette image sous la forme d'octets qui indiquent la couleur (noir ou blanc) de 8 pixels adjacents sur l'écran.  Heureusement, il existe des outils qui permettent de transformer l'image d'un fichier (bmp, jpeg ou autre) en un tableau prêt à être utilisé dans votre programme.

À cet effet, je vous recommande l'outil en ligne image2ccp.

Vous sélectionnez d'abord le fichier contenant l'image que vous désirez afficher.


Vous réglez ensuite différents paramètres (taille désirée, etc).


Vous sélectionnez le type de code désiré ("Arduino code, single bitmap"), choisissez le nom désiré pour la variable, puis cliquez sur le bouton "Générate code": il ne reste plus qu'à copier le résultat et le coller dans votre sketch Arduino!



Sketch d'exemple

Voici un sketch dans lequel j'utilise tout ce qui a été mentionné dans cet article.


Résultat

Finalement, une courte vidéo montrant l'afficheur pendant l'exécution du sketch.




(NB: Dans cet autre article, un sketch similaire a été produit pour un écran OLED SH1106 I2C).

Yves Pelletier   (TwitterFacebook)


5 commentaires:

  1. Bonjour,
    Tout d'abord félicitations pour votre blog que je lis depuis pas mal de temps, il y a des moments plus calmes mais ces temps-ci vous êtes prolifique :)
    je ne suis pas un pro de l'électronique et je me demande pourquoi on n'utilise pas la sortie 3.3v de l'arduino ?
    merci et bonne continuation

    RépondreSupprimer
    Réponses
    1. On utilise bel et bien la sortie 3.3 V de l'Arduino: elle sert à alimenter l'écran ainsi que le circuit intégré 4050. Par contre toutes les sorties numériques de l'Arduino, qui servent à communiquer avec l'écran, seraient à 5 V si on n'abaissait pas le signal au moyen du 4050.

      Supprimer
    2. Ok, je vois maintenant, merci

      Supprimer
  2. bonjour, je suis débutante en programmation et je veux bien savoir qu'elle est la fonction qui permet d'afficher des valeurs à partir d'un capteur (je ne veux pas afficher) des choses définies)
    merci d'avance.

    RépondreSupprimer
  3. bonjour, et si l'on a pas de 4050 comment fait on?
    Et bien on alimente l'écran en 3 volts et on réalise pour les 5 entrées de l'écran un pont diviseur:
    1k5 vers le négatif et 1k sur sortie de l'atmega résultat sortie en 3 volts. Ainsi fonctionne mes écrans depuis des années.

    RépondreSupprimer