• 20 hours
  • Medium

Free online content available in this course.

course.header.alt.is_certifying

Got it!

Last updated on 7/13/17

Programmez un écran LCD

Log in or subscribe for free to enjoy all this course has to offer!

Créer des interfaces avec des matrices de LED vous paraît fastidieux ? Ça tombe bien, il existe dans le commerce des afficheurs LCD ou LED déjà préconçus pour fournir une interface de lecture simplifiée et qui permettent tout un tas d’usages.

Nous allons voir dans ce chapitre comment utiliser l'un de ces afficheurs : un écran LCD 16 caractères sur deux lignes. Comme nous n'allons pas réinventer ce qui existe déjà, nous allons surtout apprendre à utiliser la bibliothèque qui est liée à ce matériel. Vous concevrez aussi quelques programmes pour avoir une idée des possibilités de ces afficheurs, qui permettent de lire des informations, même si l'Arduino n'est plus connecté à votre ordinateur.

Alles, c'est parti !

L'écran LCD

Les écrans LCD existent depuis 1971. Ils n'ont pas cessé de se développer depuis, et équipent maintenant bien des appareils à affichage embarqué (appareils photo, digicodes, montres, téléphones...).

LCD est l'abbréviation anglaise de "liquid crystal display" qui veut dire : afficheur à cristaux liquides. Je ne vais pas entrer dans le détail du fonctionnement de tels afficheurs. Il faut juste savoir que cette technologie permet de créer des écrans plats qui consomment peu d’énergie.

L'écran LCD que je vous propose d'acquérir (ou en tous cas d'étudier) est un écran permettant l'affichage de 16x2 caractères, c'est-à-dire deux lignes de 16 caractères.

Le coût de ce type d'écran varie entre 7€ et 15€ (tout dépend d'où vous le commandez et des fonctionnalités dont il dispose, entre autre le rétro-éclairage).

Il en existe de plusieurs formes. Voici celui que j'utilise :

Afficheur LCD 16x2, affichage blanc sur fond bleu (www.mchobby.be)
Afficheur LCD 16x2, affichage blanc sur fond bleu (www.mchobby.be)

Pourquoi celui-ci ?

Pour une question de goût personnel. En effet il en existe d'autres avec des couleurs d'affichage différentes. À vous de choisir. Cet écran est de plus rétro-éclairé, ce qui permet de lire de jour comme de nuit.

L'important c'est que vous choisissiez un écran compatible avec la bibliothèque fournie par l'Arduino pour les écrans à cristaux liquides. On repère ce type d'écran LCD car il dispose de 16 trous (où peuvent être soudées des broches de connexion). Voici un autre exemple d'écran LCD :

Afficheur LCD 16x2, affichage noir sur fond vert, non rétro-éclairé (www.arduino.cc)
Afficheur LCD 16x2, affichage noir sur fond vert, non rétro-éclairé (www.arduino.cc)

On voit bien en haut de l'afficheur, 16 marques de soudure.

C’est une bonne façon de repérer les afficheurs compatibles avec la bibliothèque LCD. Ces afficheurs peuvent communiquer avec l’Arduino via cette bibliothèque grâce au pilote Hitachi HDD44780.  Il peut être intéressant de lire cette présentation du HD44780 car elle renseigne correctement sur bien des questions qu'on peut se poser dans l'utilisation (et la connexion) de ce matériel.

Pour la connexion, je vais vous en parler juste après.

Il faut savoir qu'il y a deux façons de piloter l'écran :

  • soit en utilisant les 16 connexions (mode 8 bits),

  • soit en utilisant 4 connexions de moins (mode 4 bits), ce qui économise des pins de l'Arduino.

Bon, je ne peux plus reculer. Je suis obligé de vous faire un point (léger) sur les notions de nombre décimal, binaire et  hexadécimal...

Décimal, binaire et hexadécimal

Le système décimal est en base 10. Ce qui veut dire qu'on passe à la dizaine supérieure toutes les dix unités (ou bien on augmente le nombre des milliers toutes les 10 centaines...).

Une image simple est d'imaginer un compteur de voiture (les anciens, ceux qui tournent). On voit bien qu'à chaque tour (donc 10 unités) des centaines de mètres, on fait tourner d'un cran les kilomètres. Ce système nous est familier car on l'utilise tout le temps. Voici les 16 premiers nombres du système décimal :

 

$\(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16.\)$

 

Le système binaire est en base 2, c'est-à-dire que chaque fois qu'on passe deux unités (0 puis 1). Comme on ne peut pas parler de dizaine (puisque c'est en base 10) on va parler de bit. Le bit en position 0 est celui le plus à droite du nombre, puis le bit en position 1, puis 2... Donc pour augmenter les bits, on ajoute 1 au bit de gauche et on remet le bit de droite à 0. Voici donc les 16 premiers nombres du système binaire :

 

$\(0000, 0001,0010, 0011, 0100, 0101, 0110, 0111, 1000, 1001, 1010, 1011, 1100, 1101, 1110, 1111.\)$

 

Prenez votre temps pour comprendre le principe d'augmentation du nombre.

Enfin le système hexadécimal est en base 16. Donc sa dizaine ne change que toutes les 16 unités. Comme nos chiffres s'arrêtent à 9, il nous a fallu inventer des chiffres après 9. Les informaticiens ont donc utilisé des lettres. Du coup, voici les 16 premiers nombres en hexadécimal :

 

$\(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F.\)$

 

Ces trois systèmes de numération sont utilisés en informatique. Voici le même nombre écrit en décimal, binaire et hexadécimal : 213 (décimal), 1101 0101 (binaire), D5 (hexadécimal).

Vous pouvez assez facilement passer de l'une à l'autre des numérations par un calcul mathématique. Mais, vous pouvez faire ça encore plus simplement avec des outils dédiés (calculatrice en mode programmeur sur votre ordinateur, site de conversions, etc.) ou même avec un petit programme sur votre Arduino !

 En voici un exemple :

void setup() {
  Serial.begin(9600); // communication série
  int nombre=220; // nombre à convertir
  Serial.println("************");
  Serial.print ("Dec : ");
  Serial.println (nombre,DEC); //converti en décimal
  Serial.print("BIN : ");
  Serial.println(nombre,BIN); // converti en binaire
  Serial.print("HEX : ");
  Serial.println(nombre,HEX); // converti en hexadécimal
}

void loop() {

}

Ce programme affichera le nombre 220 en décimal, binaire et hexadécimal.

  • Si vous voulez placer un nombre binaire dans une variable, ajoutez un B majuscule avant la suite de 1 et 0 de ce nombre.  Exemple : int nombre=B10010  le B signifie que votre nombre est écrit en binaire.

  • Pour enregistrer un nombre en hexadécimal, il faut ajouter "0x" (zéro et x minuscule) devant ce nombre.
    Exempleint nombre=0xFA12F  le "Ox" signifie que votre nombre est en hexadécimal.

Quel est l'intérêt de ces trois systèmes ?

  • Le système décimal est celui qu'on utilise tous les jours, il est lisible facilement nous les humains ^^.

  • Le système binaire est le celui qu'utilise la machine. Il est facile de construire un nombre en allumant ou éteignant des connexions. En effet, avec 4 LED côte à côte, vous pouvez créer (en les allumant pour 1 et en les éteignant pour 0) les nombres entre 0 et 16. Par exemple : allumé, éteint, éteint, allumé correspond à 1001 soit 9 en décimal.

  • Le système hexadécimal, permet de coder les nombres de 8 bits (donc 16 positions binaires) sur seulement 2 caractères. En effet, le nombre binaire 1111 1111 correspond à FF en hexadécimal (255 en décimal). C'est donc un gain de place pour le codage

Quel rapport avec notre afficheur ?

Et bien c'est ce dont je parlais, soit on utilise 8 broches (plus les autres pour l'alimentation) pour coder l'information (donc 16 pins qui se mettront à 1 ou 0 pour former un nombre de 8 bits) ou seulement 4 broches (plus celles de l'alimentation) mais dans ce cas le nombre 8 bits sera séparé en deux :

  • Les quatre premiers bits seront envoyés. On appelle ces bits les bits de poids fort (les quatre plus à gauche). 

  • Puis les 4 seconds. On appelle ces bit les bits de poids faible (les 4 plus à droite). 

Cela diminue donc par deux la vitesse de communication.

Rassurez-vous, nous n'allons pas coder (même si c'est tout à fait possible) nous-mêmes la communication entre l'Arduino et l'afficheur LCD !

Si vous avez jeté un œil aux explications sur le protocole de communication du HD44780  (qui sont bien faites mais pas forcément facilement compréhensibles), vous avez vu que pour échanger des informations, on utilise un protocole précis qui permet à chaque partie (Arduino et écran LCD) de se comprendre. C'est à cause de ce protocole que nous devons utiliser plus que 8 pins (ou 4 pins) pour connecter l'écran LCD. En effet, il nous faut aussi des pins pour l'adresse, le timing de l'échange d'info, l'alimentation de l'écran... Regardons de plus près comment connecter un écran LCD à l’Arduino en mode 4 bits !

Connectez l’écran LCD à l’Arduino en mode 4 bits

Comme l'Arduino (malgré ses 16 MHz) n'est pas une bête de course, nous n'utiliserons que le mode 4 bits. Même si la communication est deux fois plus lente, ce type d'afficheur ne sera de toute façon pas utilisé pour des changements d'information rapides. Le mode 4 bits est donc largement suffisant, plus simple et moins gourmand en pins.

Voici une image pour la connexion des différentes broches :

Connexion d'un écran LCD avec l'Arduino
Connexion d'un écran LCD avec l'Arduino

Alors ça peut paraître un peu ardu comme ça, mais la connexion respecte une certaine logique (heureusement ;) ). Voici un schéma que j'ai tenté de simplifier :

Connexion écran LCD avec Arduino.
Connexion écran LCD avec Arduino.

 En partant de la gauche, voici à quoi servent les pins :

  • Les deux premiers pins tout à gauche servent à l'alimentation de l'écran.

  • Le troisième pin est connecté à un potentiomètre et sert pour régler l'affichage (le contraste de l'écran).

  • Le quatrième, noté RS, est connecté au pin 12 de l'Arduino dans notre exemple. Il sert à sélectionner la zone mémoire de l'écran LCD dans laquelle nous allons écrire (Register Select).

  • Le cinquième doit toujours être connecté au ground. C'est un sélecteur de mode lecture ou écriture. On peut le connecter à un pin, mais dans notre cas c'est inutile. Comme il doit recevoir un signal à 0V, on le connecte au ground (état R/W).

  • Le sixième, noté E, est connecté au pin 11 de l'Arduino dans notre exemple. Il permet de lancer ou non l'écriture dans les zones mémoires (Enable).

  • Les quatre suivants (reliés au ground) servent pour la communication 8 bits. Pour la communication 4 bits, il est conseillé de les relier au ground. Ils représentent les bits de poids fort. 

  • Les quatre qui suivent,  notés 2, 3, 4, 5, se connectent dans notre exemple sur les pins 2, 3, 4, 5 de l'Arduino.  Ils servent pour la communication (8 bits ou 4 bits) et doivent toujours être connectés. Ils représentent les bits de poids faible (ou servent pour envoyer d'abord les bits de poids faible, puis les bits de poids fort)

  • Les deux pins tout à droite servent pour alimenter la LED du rétro-éclairage.

En mode 4 bits, il est finalement important de bien repérer les 6 pins en bleu sur le schéma.

Je vous laisse brancher votre LCD en suivant ce modèle et ensuite mettre sous tension l'Arduino...

Si vous tournez le potentiomètre, vous voyez le contraste changer.

Voyons maintenant comment écrire sur votre écran LCD...

Écrivez sur un écran LCD

Nous allons procéder en deux étapes. Tout d'abord ce qui concerne la bibliothèque, puis les méthodes d'écritures elle-même.

Chargez la bibliothèques pour écran LCD

Alors pour charger et installer la bibliothèque qui permet une communication directe entre l'Arduino et l'écran LCD, il suffit de suivre la procédure maintenant presque habituelle :

Croquis -> Include Library -> Manage Librairies

Dans l'onglet de recherche, tapez : "LiquidCrystal". Si la bibliothèque est déjà installée, vous verrez noté "INSTALLED" à côté de son nom.

Une fois la bibliothèque LiquidCrystal chargée, vous pouvez fermer et relancer votre IDE.

Comme la dernière fois, si la bibliothèque est bien présente, dans Fichier -> Exemples, vous devriez voir un menu LiquidCrystal.

Voyons maintenant comment utiliser cette bibliothèque.

Programmez votre écran LCD

Nous commençons notre programme en incluant la bibliothèque :

#include <LiquidCrystal.h>

Comme pour toute utilisation de bibliothèque,  nous allons commencer par définir un objet avec quelques paramètres :

LiquidCrystal monEcran(12,11,5,4,3,2);

En fait la forme est de type :

LiquidCrystal nomDeVariable(RS, E, d4, d5, d6, d7);

où RS correspond au numéro du pin RS, E au numéro du pin E, et les autres paramètres aux numéros des pins pour la communication 4 bits.

Ces deux commandes (inclusion de la bibliothèque et création de l’objet écran) se situent avant le setup().

Ensuite (un peu comme avec la bibliothèque Serial), nous devons initialiser la communication. Comme pour toute utilisation de fonctions d'objet, on met le nom de l'objet, un point, et le nom de la fonction avec entre parenthèses les paramètres éventuellement attendus. Voici l’initialisation de notre objet écran :

monEcran.begin(16,2);

Cela signifie : j'initialise la communication entre l'Arduino et l'objet monEcran avec une matrice de 16 colonnes et 2 lignes.

À partir de ce moment, vous pouvez utiliser toutes les autres fonctions de la bibliothèque !

Voici un programme simple qui affiche "Bonjour, OPENCLASSROOMS" sur deux lignes :

#include <LiquidCrystal.h> // on importe la bibliothèque
LiquidCrystal monEcran(12,11,5,4,3,2); // on crée l'objet écran

void setup() {
  monEcran.begin(16,2); //on initialise la communication avec 16 colonnes et deux lignes
  monEcran.clear(); // on efface l'écran
  monEcran.print("Bonjour,"); // on écrit Bonjour
  monEcran.setCursor(0,1); //on passe à la ligne suivante
  monEcran.print("OPENCLASSROOMS"); // on finit d'écrire
}

void loop() {
}

Vous remarquerez que le retour à la ligne ne se fait pas automatiquement, il faut le prévoir.

La liste de toutes les commandes possibles sont sur la page de documentation liée à la bibliothèque.

Je vous propose pour vous entraîner, de réaliser un programme simple à base de menu...

TP : Programmez un menu simple

Dans ce TP, je vous propose d’utiliser l’afficheur LCD pour naviguer dans un menu, grâce à deux boutons.

Pour le montage, vous aurez besoin de :

  • Un écran LCD connecté comme nous venons de le voir ;

  • Deux boutons poussoir (avec résistance en pulldown) pour gérer les déplacements dans le menu, attachés aux pins 8 et 9.

Pour le programme associé, vous allez créer un menu simple structuré de la façon suivante :

  • Option 1 : LED 13, composée de 3 sous-options - "OFF", "ON" et "Clignote". "OFF" permet d'éteindre la LED, "ON" permet de l'allumer, et "Clignote" permet de la faire clignoter. Je parle ici de la LED attachée au pin analogique 13 (voir début du cours d'initiation à l'Arduino)

  • Option 2 : Analogique, composé de 5 sous-options - "A0", "A1", "A2", "A3", "A4" qui affichent les valeurs de CAN de 0 à 4. 

Pour passer de l'option LED13 à l'option Analogique, vous utiliserez le premier bouton ; et pour naviguer entre les sous-options de chacune de ces deux options, vous utiliserez le deuxième bouton. 

Le passage d'un item à l'autre affiche en première ligne le titre de l'item et en seconde ligne le sous item (soit l'état de la LED 13, soit le nom du CAN et sa valeur).

(Cunégonde et Lukas, vous travaillerez en groupe, on vous appellera le "LCD" pour Lukas Cunégonde Display !)

TP : "Programmez un menu simple" - Correction

Alors vous y êtes arrivé sans problème ? Vous avez même créé un menu de 10 options tellement ça vous paraissait simple ? ;)

Pour le montage, si vous avez rencontré des problèmes pour connecter les boutons poussoir avec résistance pull down, je vous invite à revoir le chapitre sur les boutons poussoir dans mon cours d'initiation à l'Arduino.

Pour le programme , voici un exemple de solution…

/*
 * Menu avec écran LCD
 * Ce programme propose la navigation dans un menu simple
 * à l'aide de deux boutons (sur pin 8 et 9)
 * et d'un écran LCD compatible HD44780
 * Deux items : LED 13 et Lecture des CAN
 * Le menu LED 13 allume, éteint, ou fait clignoter la LED 13
 * Le menu Lecture des CAN, lit les valeurs des CAN 0,1,2 et 3 successivement
 * 
 * Nanomaitre 2015 pour OpenClassRooms
 * Ce programme est dans le domaine public
 */

#include <LiquidCrystal.h> // on importe la bibliothèque pour LCD
LiquidCrystal monEcran(12, 11, 5, 4, 3, 2); // on crée un objet LCD nommé monEcran en mode 4 bits
const int bout1 = 8; //constante du pin bouton 1
const int bout2 = 9; //constante du pin bouton 2
int posMenu = 0; //variable de position dans menu principal
int posSousMenu[2] = {0, 0}; // tableau pour stocker les positions de chaque sous-menu
int modeLed = 0;//variable du mode de la LED 13 (0=OFF, 1=ON, 2=Clignote)
boolean etatLed = 0; //état de la LED 13 (0=LOW, 1=HIGH)
int nCAN = 0; //numéro de CAN actuel
String ligne1[2] = {"LED 13 :        ", "Analogique :    "}; //tableau de titre du menu principal
String ligne2 = "OFF";//chaîne pour la ligne 2 (dépend du menu 1)
unsigned long tpsDep = millis(); //temps départ pour clignotement

void setup() {
  //configuration des pins
  pinMode(bout1, INPUT);
  pinMode(bout2, INPUT);
  pinMode(13, OUTPUT);
  //initialisation de l'écran LCD
  monEcran.begin(16, 2); //on initialise la communication avec 16 colonnes et 2 lignes
  monEcran.clear(); // on efface l'écran
}

void loop() {
  navigation(); //appel de la fonction pour naviguer dans les menus
  affichage(); //appel de la fonction pour rafraîchir l'affichage LCD
  allume(); //appel de la fonction pour gérer la LED 13
}

//fonction de navigation dans le menu
void navigation() {
  //création de variables d'état pour les boutons
  boolean etatBout1 = digitalRead(bout1);
  boolean etatBout2 = digitalRead(bout2);
  //Boucle pour naviguer dans les menus
  if (etatBout1 || etatBout2) { //si l'un des deux boutons est appuyé
    if (etatBout1) { // si bouton 1
      posMenu = (posMenu + 1) % 2; //on change le menu principal (2 positions)
    }
    if (etatBout2) { // si bouton 2
      switch (posMenu) { //l'action dépend du menu 1
        case 0: //si menu LED
          modeLed = (modeLed + 1) % 3; //on change le mode de la LED
          break;
        case 1 : //si menu CAN
          nCAN = (nCAN + 1) % 5; //on change le CAN lu
          break;
      }
    }
    delay(200); //attente pour éviter les répétitions
  }
}

//fonction de rafraîchissement de l'écran LCD
void affichage() {
  monEcran.setCursor(0, 0); // on positionne le curseur en haut à gauche
  monEcran.print(ligne1[posMenu]); // on écrit le menu de la ligne 1
  monEcran.setCursor(0, 1); // on passe à la ligne suivante
  //définition du menu pour la LED 13
  String mLED[3] = {
    "OFF             ",
    "ON              ",
    "Clignote        "
  };
  switch (posMenu) { // en fonction du menu 1
    case 0: // si menu LED
      ligne2 = mLED[modeLed]; //titre pris dans tableau mLED
      break;
    case 1: // si menu CAN
      readCAN(); // appel de la construction de l'affichage
      break;
  }
  monEcran.print(ligne2); // on affiche la ligne du menu 2
}

// fonction de construction de l'affichage de lecture de CAN
void readCAN () {
  int val = analogRead(nCAN); // on lit le CAN concerné
  ligne2 = "CAN "; //on initialise la chaîne
  ligne2 += String(nCAN); //on ajoute le numéro du CAN actuel
  ligne2 += " : "; //pour présentation
  ligne2 += String(val); // on ajoute la valeur lue du CAN actuel
  ligne2 += "         "; // on ajoute des espaces pour effacer l'affichage précédent
  //la ligne de menu est construite
}

//fonction qui gère la LED 13
void allume() {
  unsigned long tpsAct = millis(); //variable du temps actuel
  if (tpsAct - tpsDep > 200) { // si plus de 200ms
    switch (modeLed) { // on agit en fonction du mode actuel
      case 0: // si OFF
        etatLed = 0; // on éteint la LED
        break;
      case 1: // si ON
        etatLed = 1; // on allume la LED
        break;
      case 2: // si Clignote
        etatLed = !etatLed; //on inverse l'état de la LED
        break;
    }
    digitalWrite(13, etatLed); //on positionne la LED dans l'état concerné
    tpsDep = tpsAct; //on initialise le temps de départ
  }
}

Ce programme est un exemple. 

Si vous voulez continuer dans votre lancée de pratique, vous pouvez tout à fait imaginer un menu plus conséquent qui permet de modifier la vitesse de clignotement, qui gère plusieurs LED, qui fait varier la vitesse d'un moteur (grâce au PWM), etc.

J'attire votre attention sur les espaces ajoutés en fin de chaîne de caractères pour les titres des menus :

On peut tout à fait effacer l'écran avec la fonction monEcran.clear() ,  à chaque passage de la boucle. Mais cette méthode écrit en fait deux lignes de caractères vides, ce qui provoque un affichage peu agréable.

Le programme permet de lire l'état des CAN en temps réel, il faut donc l'afficher à chaque tour de  loop().

En affichant une chaîne de caractères avec assez d'espaces pour remplir la ligne, on efface ainsi les caractères précédents. C'est une méthode qui améliore la qualité visuelle. Faites l'essai sans mettre les espaces pour voir. ;)

En résumé :

Vous avez appris comment connecter un écran LCD à votre carte Arduino et comment l’utiliser comme interface grâce à la bibliothèque LiquidCrystal.
Vous avez appris à ajouter un menu et des boutons de navigation sur cette interface, et à les gérer avec un programme Arduino.

Finalement, si votre Arduino est alimenté en autonomie (donc non connecté à votre ordinateur), vous avez de quoi le paramétrer et le lire, juste avec deux boutons. Une interface homme/machine assez efficace.

Le seul inconvénient est le nombre de pins utilisés pour communiquer dans ce mode de connexion. Mais comme je vous l'ai signalé au début, il existe des moyens simples de passer en mode I2C, qui n'utilisent alors que les pins A4 et A5 de l'Arduino.

Je m'arrête là pour les LCD, voyons maintenant les possibilités de commander votre Arduino à distance grâce à un capteur infrarouge et une télécommande simple !

Example of certificate of achievement
Example of certificate of achievement