samedi 26 janvier 2019

Écran OLED SH1106 I2C et Arduino

Je me suis récemment procuré un petit écran OLED de 128 X 64 pixels et. bien entendu, je me suis empressé de le faire fonctionner  en le branchant à un Arduino.



OLED vs LCD

OLED est l'acronyme de organic light-emitting diode (diode électroluminescente organique, donc).  Contrairement aux cristaux liquides des écrans LCD, les OLED produisent de la lumière et les écrans basés sur cette technologie ne nécessitent donc pas de rétroéclairage, même lorsque vous les utilisez dans l'obscurité. Les images sont plus contrastées et le temps de réponse est plus court. Par contre, on dit que la durée de vie des écrans OLED est plus courte que celle des LCDs (l'image se dégrade avec le temps).

L'écran

Mon écran a une taille de 1,3 pouce (environ 3,5 cm X 1,8 cm) et une résolution de 128 X 64 pixels. Il est basé sur le contrôleur SH1106 et utilise le protocole I2C. L'image produite est blanche sur fond noir.



Branchements

Puisqu'il s'agit d'I2C, les connexions sont assez prévisibles: sans surprise, l'écran comporte deux broches pour l'alimentation (GND et VCC), et deux broches pour le transfert d'information (SCL et SDA).

Le vendeur a spécifié dans sa description que l'écran peut aussi bien supporter une tension de 5 V qu'une tension de 3,3 V, mais j'ignore à quel point c'est vrai. Le SH1106 n'est pas conçu pour des tension de 5 V, mais le fabricant de l'écran a peut-être ajouté un régulateur de tension quelque part. Pour plus de prudence, j'ai utilisé un module abaisseur de tension bidirectionnel spécifiquement conçu pour la communication I2C dans le genre de celui qui est vendu par Adafruit.  Il s'agit peut-être d'une précaution inutile, mais ça ne peut pas faire de mal.

Tout ça pour dire que que les 4 broches de l'écran OLED sont branchés à l'Arduino Uno de la façon suivante:
  • Broche GND de l'écran à une broche GND de l'Arduino
  • Broche VCC de l'écran à la sortie 3.3 V de l'Arduino
  • Broche SCL de l'écran à la broche A5 de l'Arduino (adaptateur de niveau logique entre les deux)
  • Broche SDA de l'écran à la broche A4 de l'Arduino (adaptateur de niveau logique entre les deux)
(Si vous utilisez un modèle d'Arduino autre que l'Uno,  les broches dédiées à la communication I2C ne sont pas nécessairement A4 et A5.)



Recherche et installation d'une bibliothèque

La bibliothèque U8glib a très bonne réputation parmi les utilisateurs d'écrans OLED.  Cependant, j'ai préféré continuer d'utiliser la bibliothèque GFX d'Adafruit, pour que mes programmes déjà réalisés avec un écran LCD de style Nokia soient plus facilement transposables à mon nouvel écran.  Petit inconvénient: puisqu'Adafruit ne fabrique aucun produit contenant le contrôleur SH1106 (car ils préfèrent le SSD1306), ils n'ont pas créé de bibliothèque spécifique au SH1106.

J'ai donc installé la bibliothèque Adafruit_SH1106 de wonho-maker qui, contrairement à ce que son nom pourrait faire croire, n'est pas une bibliothèque officielle réalisée par Adafruit. Il s'agit plutôt d'une modification, réalisée par un particulier, de la bibliothèque qu'Adafruit a produite pour le SSD1306.  Cette bibliothèque nécessite à son tour la présence de la bibliothèque GFX d'Adafruit (version officielle, cette fois), ce qui représente à mes yeux un énorme avantage: toutes les routines que j'ai utilisées sur mon écran LCD Nokia continueront de fonctionner sur mon écran OLED.

Sketch 1: dessiner des formes, afficher une image bitmap

Commençons par un sketch dont la seule fonction vise à illustrer diverses possibilités de la bibliothèque GFX d'Adafruit: écrire du texte à l'écran...



...dessiner des contours de formes géométriques vides...


...dessiner des formes géométriques pleines...


... contrôler des pixels individuels...


...afficher une image bitmap.


Pour plus de détails, je vous invite à lire l'article qui concerne la première version de ce sketch (réalisé pour un écran LCD Nokia), puisque la majeure partie du programme concerne la bibliothèque GFX plutôt que la bibliothèque SH1106.

L'essentiel de mes modifications (par rapport à ma version initiale conçue pour un écran LCD) a consisté à tenir compte de la nouvelle résolution de l'écran (128 X 64 plutôt que 84 X 48) et de l'inversion des couleurs: par défaut, sur un écran OLED, on dessine en blanc sur fond noir alors que c'était l'inverse sur le LCD.  Il est bien sûr possible de mettre le fond de l'écran blanc pour y dessiner en noir, mais les résultats sont beaucoup moins réussis (présence de traînées grisâtres sur le fond blanc).

/*********************************************************************
Démonstration d'un écran OLED i2c SH1106 avec un Arduino,
en utilisant une bibliothèque d'Adafruit:
https://github.com/adafruit/Adafruit-GFX-Library
...et une bibliothèque compatible par Wohho-maker:
https://github.com/wonho-maker/Adafruit_SH1106
Plus d'infos:
https://electroniqueamateur.blogspot.com/2019/01/ecran-oled-sh1106-i2c-et-arduino.html
*********************************************************************/
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SH1106.h>
/* Puisque la bibliothèque est basée sur celle du SSD1306, le constructeur
prévoit qu'on passe le numéro de la broche RESET en argument. Mais le SH1106
n'a pas de broche RESET, alors on écrit n'importe quel entier (de préférence,
le numéro d'une broche de l'Arduino que vous n'utilisez pas). */
Adafruit_SH1106 display(23);
/* Définition d'une image bitmap: logo du blog Électronique en Amateur
Réalisée avec l'outil en ligne http://javl.github.io/image2cpp/ */
const unsigned char myBitmap [] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, 0xf0, 0x00, 0x00, 0x03, 0x9f, 0xff, 0xe0, 0x00, 0x07,
0x9f, 0xff, 0xfe, 0x00, 0x0f, 0xdf, 0x0f, 0xbe, 0x00, 0x1f, 0xde, 0x06, 0x0e, 0x00, 0x3f, 0xdc,
0x04, 0x0e, 0x00, 0x3f, 0xdc, 0x00, 0x06, 0x00, 0x3f, 0xdc, 0x00, 0x06, 0x00, 0x3f, 0xdc, 0x60,
0x06, 0x00, 0x3f, 0xdc, 0xf1, 0x8e, 0x00, 0x3f, 0xdc, 0xf3, 0xce, 0x00, 0x3f, 0xde, 0x63, 0xde,
0x00, 0x3f, 0xdf, 0x09, 0x9e, 0x00, 0x3f, 0xdf, 0xfc, 0x7e, 0x00, 0x3f, 0xde, 0x7f, 0xfe, 0x00,
0x3f, 0xde, 0x7f, 0xf6, 0x00, 0x3f, 0xdf, 0x3f, 0xe6, 0x00, 0x3f, 0xdf, 0x8f, 0x8e, 0x00, 0x3f,
0xdf, 0xe0, 0x3e, 0x00, 0x3f, 0x00, 0x3f, 0xfe, 0x00, 0x3e, 0xff, 0xc0, 0x1e, 0x00, 0x3d, 0xff,
0xff, 0xc0, 0x00, 0x3b, 0xff, 0xff, 0xfe, 0x00, 0x37, 0xff, 0xff, 0xfe, 0x00, 0x2f, 0xff, 0xff,
0xfe, 0x00, 0x0e, 0x1f, 0xff, 0xfe, 0x00, 0x1f, 0x9f, 0x9f, 0xfe, 0x00, 0x3f, 0x9f, 0x9f, 0x9e,
0x00, 0x3f, 0x9f, 0x9f, 0x9e, 0x00, 0x3f, 0x9f, 0x9f, 0x9e, 0x00, 0x3f, 0x9f, 0x9f, 0x9c, 0x00,
0x1f, 0x9f, 0x9f, 0x98, 0x00, 0x0f, 0x9f, 0x9f, 0x90, 0x00, 0x07, 0x9f, 0x9f, 0x90, 0x00, 0x00,
0x9f, 0x9f, 0x90, 0x00, 0x00, 0x9f, 0x91, 0x90, 0x00, 0x00, 0x91, 0x91, 0x90, 0x00, 0x00, 0x91,
0x91, 0x90, 0x00, 0x00, 0x91, 0x91, 0x90, 0x00, 0x00, 0x91, 0x91, 0x90, 0x00, 0x00, 0x91, 0x91,
0x90, 0x00, 0x00, 0x91, 0x91, 0x90, 0x00, 0x00, 0x91, 0x91, 0x90, 0x00, 0x00, 0x91, 0x91, 0x90,
0x00, 0x00, 0xf1, 0xd1, 0x90, 0x00, 0x00, 0x01, 0xc1, 0xf0, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00
};
void setup() {
display.begin(); // initialisation de l'afficheur
display.clearDisplay(); // ça efface à la fois le buffer et l'écran
}
void loop() {
/**************** Éxcriture de texte ***************/
// taille par défaut
display.setCursor(30, 15); // coordonnées du point de départ du texte
display.setTextColor(WHITE);
display.setTextSize(1); // taille par défaut
display.println("Petit...");
display.display(); // affichage à l'écran
delay(1000);
// deux fois plus gros
display.setCursor(30, 35); // coordonnées du point de départ du texte
display.setTextSize(2); // taille double
display.println("GROS!");
display.display(); // affichage à l'écran
delay(1000);
display.clearDisplay(); // on efface tout
/******************** Dessiner une ligne ******************************************/
// ligne horizontale au centre de l'écran
display.drawLine(0, display.height() / 2, display.width() , display.height() / 2, WHITE);
// ligne verticale au centre de l'écran
display.drawLine(display.width() / 2, 0, display.width() / 2, display.height(), WHITE);
/********************* Dessiner des contours de formes géométriques ******************/
display.drawRect( 15, 5, 30, 15, WHITE); // contour d'un rectangle
display.drawCircle(95, 15, 8, WHITE); // contour d'un cercle
display.drawRoundRect(15, 40, 30, 16, 5, WHITE); // contour d'un rectangle à coins arrondis
display.drawTriangle(95, 40, 80, 55, 110, 55, WHITE); // contour d'un triangle
display.display();
delay(1000);
/******************* Dessiner des formes géométriqeus pleines *************************/
display.fillRect( 15, 5, 30, 15, WHITE); // contour d'un rectangle
display.fillCircle(95, 15, 8, WHITE); // contour d'un cercle
display.fillRoundRect(15, 40, 30, 16, 5, WHITE); // contour d'un rectangle à coins arrondis
display.fillTriangle(95, 40, 80, 55, 110, 55, WHITE); // contour d'un triangle
display.display();
delay(1000);
display.clearDisplay();
/********************** Dessiner un pixel à la fois ***********************************************/
// on trace une fonction sinusoidale, point par point
for (int x = 1; x < 128; x++) {
int y = 32 + round(16.0 * sin(x / 5.0));
display.drawPixel(x, y, WHITE);
}
display.display();
delay(1000);
display.clearDisplay();
/**************************** Dessiner une image bitmap **********************************/
// on affiche l'image stockée dans la constante myBitmap définie au début de ce fichier.
display.fillRect(5,5,44,58,WHITE); // fond blanc derrière l'image bitmap
display.drawBitmap(10, 10, myBitmap, 34, 48, BLACK);
display.setCursor(60, 30); // coordonnées du point de départ du texte
display.setTextColor(WHITE);
display.setTextSize(1); // taille par défaut
display.println("Au revoir!");
display.display();
delay(2000);
display.clearDisplay();
}
view raw OLED_Demo.ino hosted with ❤ by GitHub

Sketch 2: mesure analogique présentée sous forme de jauge rectangulaire

Ce sketch présente à l'écran la tension à l'entrée A0­. La version initiale de ce sketch est décrite de façon plus détaillée ici. Pour en faire l'essai, vous pouvez brancher le curseur d'un potentiomètre à l'entrée A0.



/*****************************************************
Affichage d'une mesure analogique sur un écran OLED
SH1106 I2C (Arduino)
Utilisation d'une bibliothèque d'Adafruit:
https://github.com/adafruit/Adafruit-GFX-Library
...et d'une bibliothèque compatible par Wohho-maker:
https://github.com/wonho-maker/Adafruit_SH1106
Plus d'infos:
https://electroniqueamateur.blogspot.com/2019/01/ecran-oled-sh1106-i2c-et-arduino.html
*****************************************************/
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SH1106.h>
Adafruit_SH1106 display(23);
void setup() {
display.begin();
display.clearDisplay();
}
void loop() {
int valeur;
// mesure de la tension à l'entrée A0
valeur = map(analogRead(A0), 0, 1023, 0, 500);
// on écrit "tension", en petits caractères, centré en haut de l'écran:
display.setCursor(40, 8);
display.setTextColor(WHITE);
display.setTextSize(1);
display.println("Tension:");
// on écrit la valeur numérique de la tension un peu plus bas, en plus gros
display.setCursor(30, 22);
display.setTextSize(2);
display.print(valeur/100); // partie entière
display.print(","); // virgule
if ((valeur % 100) < 10){
display.print("0");
}
display.print(valeur % 100); // partie décimale, après la virgules
display.println(" V"); // unités de mesure
// enveloppe de la jauge rectangulaire
display.fillRect( 14, 45, 104, 10, BLACK);
display.drawRect( 14, 45, 104, 10, WHITE);
// partie mobile de la jauge rectangulaire
display.fillRect( 16, 47, map(valeur, 0, 500, 0, 100), 6, WHITE);
display.display();
delay(500);
display.clearDisplay();
}
view raw OLED_jauge.ino hosted with ❤ by GitHub

Sketch 3: mesure analogique présentée sous forme de graphique cartésien

Cet autre sketch présente également la tension à l'entrée A0, mais sous forme de graphique cartésien, cette fois.  Voir cet article pour la première version de ce sketch.



/*****************************************************
Affichage d'une mesure analogique sous forme de graphique
cartésien sur un écran OLED I2C SH1106 (Arduino)
en utilisant une bibliothèque d'Adafruit:
https://github.com/adafruit/Adafruit-GFX-Library
...et une bibliothèque compatible par Wohho-maker:
https://github.com/wonho-maker/Adafruit_SH1106
Plus d'infos:
https://electroniqueamateur.blogspot.com/2019/01/ecran-oled-sh1106-i2c-et-arduino.html
*****************************************************/
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SH1106.h>
Adafruit_SH1106 display(23);
const int intervalle = 500; // nombre de millisecondes entre deux mesures consécutives
int mesures[32]; // les 32 dernieres mesures
int compteur = 0; // nombre de mesures prises jusqu'à présent
void setup() {
display.begin();
display.clearDisplay();
}
void loop() {
int nouvelleValeur;
// mesure de la tension à l'entrée A0 et conversion en pixels
nouvelleValeur = 60 - map(analogRead(A0), 0, 1023, 0, 60); // car l'écran a 64 pixels de haut
if (compteur > 31) {
// l'écran est déjà rempli: on fait glisser le graphique vers la gauche
for (int i = 0; i < 31; i++) {
mesures[i] = mesures[i + 1];
}
mesures[31] = nouvelleValeur;
display.clearDisplay(); // on repart à neuf
// tracé de la courbe
for (int i = 1; i <= 31; i++) {
display.drawLine(4 * (i - 1), mesures[i - 1], 4 * i, mesures[i], WHITE);
}
for (int i = 0; i <= 5; i++) {
display.drawFastHLine(0, i * 12, 128, WHITE);
}
}
if ((compteur > 0) && (compteur <= 31)) {
// pas assez de mesures pour remplir tout l'écran: on ajoute notre nouvelle valeur
// au graphique déjà visible à l'écran
mesures[compteur] = nouvelleValeur;
// on trace une droite reliant la mesure précédente à notre nouvelle mesure
display.drawLine(4 * (compteur - 1), mesures[compteur - 1], 4 * compteur, mesures[compteur], WHITE);
compteur = compteur + 1;
}
else if (compteur == 0) {
// c'est la première mesure: on la met en variable,
// mais on ne trace rien à l'écran, sauf le quadrillage
mesures[0] = nouvelleValeur;
compteur = compteur + 1;
// 6 lignes horizontales: 0 V, 1 V, 2 V...
for (int i = 0; i <= 5; i++) {
display.drawFastHLine(0, i * 12, 128, WHITE);
}
}
display.display(); // affichage de notre travail à l'écran
delay(intervalle); // on attend un peu avant la prochaine mesure
}

Sketch 4: menus de navigation contrôlés par 4 boutons

Finalement, j'ai également adapté le sketch que j'avais écrit pour établir un système de menus contrôlé par 4 boutons poussoir.



L'écran est toujours branché à l'Arduino de la même façon que pour les circuits précédents, mais on ajoute un bouton poussoir à chacune des broches 6, 7, 8 et 9:

À lire aussi

J'ai également utilisé cet écran OLED avec un Raspberry Pi, avec une carte STM32 (Nucleo ou Blue Pill), avec un ESP8266 et avec un ESP32.

/*****************************************************
Système de menus de navigation contrôlé par 4 boutons
poussoirs sur écran OLED I2C SH1106 (Arduino).
en utilisant une bibliothèque d'Adafruit:
https://github.com/adafruit/Adafruit-GFX-Library
...et une bibliothèque compatible par Wohho-maker:
https://github.com/wonho-maker/Adafruit_SH1106
Plus d'infos:
https://electroniqueamateur.blogspot.com/2019/01/ecran-oled-sh1106-i2c-et-arduino.html
*****************************************************/
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SH1106.h>
Adafruit_SH1106 display(23);
// broches utilisées par les boutons poussoirs
#define boutonHAUT 6
#define boutonBAS 7
#define boutonGAUCHE 8
#define boutonDROITE 9
#define nombreDeSousMenus 6 // nombre d'items dans la liste du menu principal
const int nombredItems[nombreDeSousMenus] = {5, 4, 3, 6, 2, 4 }; // nombre d'items dans chacun des sous-menus
int nombreMaxDeSousMenus; // valeur maximale contenue dans le tableau nombredItems (sera calculée dans calculeMax()
int numeroMenu = 0; // numéro du menu affiché à l'écran; on commence par 0, le menu principal
int numeroItem = 1; // numéro de l'item sélectionné; on commence par 1, le premier élément en haut de la liste
int numeroTeteDeListe = 1; // numéro de l'item affiché en haut de la liste visible à l'écran (utile pour les listes plus longues que 4 éléments)
int etatBoutons = 0; // nul quand aucun bouton n'est enfoncé
int etatBoutonsPrecedent = 0; // nul si aucun bouton n'était enfoncé au précédent passage dans la boucle
unsigned long tempsAntiRebond = 0; // dernière fois qu'un changement d'état de bouton a été détecté
const unsigned long delaiAntiRebond = 50; // délai entre le dernier changement d'état de bouton et le début de l'action
// on calcule le nombre maximum d'items qu'il peut y avoir dans un sous-menu
int calculeMax (void) {
int maxim = 0;
for (int i = 0; i < nombreDeSousMenus; i++) {
if (nombredItems[i] > maxim) {
maxim = nombredItems[i];
}
}
nombreMaxDeSousMenus = maxim;
}
void setup() {
pinMode(boutonHAUT, INPUT);
pinMode(boutonBAS, INPUT);
pinMode(boutonGAUCHE, INPUT);
pinMode(boutonDROITE, INPUT);
calculeMax();
display.begin();
display.clearDisplay();
miseAjour();
}
void loop() {
int nombreDeLignes;
int lectureBoutons, lectureBAS, lectureHAUT, lectureGAUCHE, lectureDROITE;
if (numeroMenu == 0) { // menu principal
nombreDeLignes = nombreDeSousMenus;
}
else { // pas le menu principal
nombreDeLignes = nombredItems[numeroMenu - 1];
}
// on vérifie si un des boutons est enfoncé
lectureBAS = digitalRead(boutonBAS);
lectureHAUT = digitalRead(boutonHAUT);
lectureGAUCHE = digitalRead(boutonGAUCHE);
lectureDROITE = digitalRead(boutonDROITE);
// procédure anti-rebonds
lectureBoutons = (lectureBAS || lectureHAUT || lectureGAUCHE || lectureDROITE) ;
if (lectureBoutons != etatBoutonsPrecedent) {
tempsAntiRebond = millis();
}
if ((millis() - tempsAntiRebond) > delaiAntiRebond) {
if (lectureBoutons != etatBoutons) {
// le bouton est nouvellement enfoncé depuis un temps raisonnable
etatBoutons = lectureBoutons;
if ( lectureHAUT ) { // bouton flèche vers le haut (on monte d'une ligne dans la liste)
if (numeroItem > 1) {
numeroItem--;
}
else {
numeroItem = nombreDeLignes;
numeroTeteDeListe = nombreDeLignes - 2;
if (numeroTeteDeListe == 0)
{
numeroTeteDeListe = 1;
}
}
if (numeroTeteDeListe > 1) {
numeroTeteDeListe--;
}
miseAjour();
}
if ( lectureBAS ) { // bouton flèche vers le bas: on descend d'une ligne dans la liste
if (numeroItem < nombreDeLignes) {
numeroItem++;
}
else {
numeroItem = 1;
numeroTeteDeListe = 1;
}
if (numeroItem > 5) {
numeroTeteDeListe++;
}
miseAjour();
}
if ( lectureGAUCHE ) { // bouton flèche vers la gauche: on recule à la page précédente
if ((numeroMenu > 0) && (numeroMenu < 100)) {
numeroItem = numeroMenu;
numeroMenu = 0;
if (numeroItem <= 5) {
numeroTeteDeListe = 1;
}
else {
numeroTeteDeListe = numeroItem - 4;
}
}
else if (numeroMenu > 100) {
numeroItem = numeroMenu % 100;
numeroMenu = numeroMenu / 100;
}
miseAjour();
}
if ( lectureDROITE ) { // bouton flèche vers la droite: on exécute le menu sélectionné
if (numeroMenu == 0) {
numeroMenu = numeroItem;
numeroTeteDeListe = 1;
numeroItem = 1;
}
else {
numeroMenu = numeroMenu * 100 + numeroItem;
}
miseAjour();
}
}
}
etatBoutonsPrecedent = lectureBoutons;
}
void miseAjour(void) // on dessine ce qui doit apparaître à l'écran
{
char* titresSousMenus[] = {"Sous-menu 1", "Sous-menu 2", "Sous-menu 3",
"Sous-menu 4", "Sous-menu 5", "Sous-menu 6"
};
char menuStr[15], itemAStr[15], itemBStr[15], itemCStr[15], itemDStr[15], itemEStr[15] ;
char titresItems[nombreMaxDeSousMenus][15];
int nombreDeLignes;
display.clearDisplay();
if (numeroMenu < 100) { // nous sommes dans une page de menus
if (numeroMenu == 0) { // menu principal
nombreDeLignes = nombreDeSousMenus;
}
else { // pas le menu principal
nombreDeLignes = nombredItems[numeroMenu - 1];
}
if (numeroMenu == 1) { // sous-menu 1
strcpy(titresItems[0], "Item 1.1");
strcpy(titresItems[1], "Item 1.2");
strcpy(titresItems[2], "Item 1.3");
strcpy(titresItems[3], "Item 1.4");
strcpy(titresItems[4], "Item 1.5");
}
if (numeroMenu == 2) { // sous-menu 2
strcpy(titresItems[0], "Item 2.1");
strcpy(titresItems[1], "Item 2.2");
strcpy(titresItems[2], "Item 2.3");
strcpy(titresItems[3], "Item 2.4");
}
if (numeroMenu == 3) { // sous-menu 1
strcpy(titresItems[0], "Item 3.1");
strcpy(titresItems[1], "Item 3.2");
strcpy(titresItems[2], "Item 3.3");
}
if (numeroMenu == 4) { // sous-menu 1
strcpy(titresItems[0], "Item 4.1");
strcpy(titresItems[1], "Item 4.2");
strcpy(titresItems[2], "Item 4.3");
strcpy(titresItems[3], "Item 4.4");
strcpy(titresItems[4], "Item 4.5");
strcpy(titresItems[5], "Item 4.6");
}
if (numeroMenu == 5) { // sous-menu 1
strcpy(titresItems[0], "Item 5.1");
strcpy(titresItems[1], "Item 5.2");
}
if (numeroMenu == 6) { // sous-menu 2
strcpy(titresItems[0], "Item 6.1");
strcpy(titresItems[1], "Item 6.2");
strcpy(titresItems[2], "Item 6.3");
strcpy(titresItems[3], "Item 6.4");
}
display.setCursor(0, 0);
display.setTextSize(1);
display.setTextColor(WHITE);
// écriture du titre de la page
if (numeroMenu == 0) { // menu principal
strcpy(menuStr, "Menu principal");
}
else {
strcpy(menuStr, titresSousMenus[numeroMenu - 1]);
}
display.println(menuStr);
// rectangle blanc à la position de l'item sélectionné
display.fillRect(0, 10 * (numeroItem - numeroTeteDeListe + 1) - 1, 128, 10, WHITE);
// écriture du premier item de la liste
if (numeroMenu == 0) { // menu principal
strcpy(itemAStr, titresSousMenus[numeroTeteDeListe - 1]);
}
else {
strcpy(itemAStr, titresItems[numeroTeteDeListe - 1]);
}
if (numeroItem == 1) {
display.setTextColor(BLACK);
}
else {
display.setTextColor(WHITE);
}
display.setCursor(5, 10);
display.println(itemAStr);
// écriture du 2e item de la liste
if (nombreDeLignes >= 2) {
if (numeroMenu == 0) { // menu principal
strcpy(itemBStr, titresSousMenus[numeroTeteDeListe]);
}
else {
strcpy(itemBStr, titresItems[numeroTeteDeListe]);
}
if (numeroItem == 2) {
display.setTextColor(BLACK);
}
else {
display.setTextColor(WHITE);
}
display.setCursor(5, 20);
display.println(itemBStr);
}
// écriture du 3e item de la liste
if (nombreDeLignes >= 3) {
if (numeroMenu == 0) { // menu principal
strcpy(itemCStr, titresSousMenus[numeroTeteDeListe + 1]);
}
else {
strcpy(itemCStr, titresItems[numeroTeteDeListe + 1]);
}
if (numeroItem == 3) {
display.setTextColor(BLACK);
}
else {
display.setTextColor(WHITE);
}
display.setCursor(5, 30);
display.println(itemCStr);
}
// écriture du 4e item de la liste
if (nombreDeLignes >= 4) {
if (numeroMenu == 0) { // menu principal
strcpy(itemDStr, titresSousMenus[numeroTeteDeListe + 2]);
}
else {
strcpy(itemDStr, titresItems[numeroTeteDeListe + 2]);
}
if (numeroItem == 4) {
display.setTextColor(BLACK);
}
else {
display.setTextColor(WHITE);
}
display.setCursor(5, 40);
display.println(itemDStr);
}
// écriture du 5e item de la liste
if (nombreDeLignes >= 5) {
if (numeroMenu == 0) { // menu principal
strcpy(itemEStr, titresSousMenus[numeroTeteDeListe + 3]);
}
else {
strcpy(itemEStr, titresItems[numeroTeteDeListe + 3]);
}
if (numeroItem >= 5) {
display.setTextColor(BLACK);
}
else {
display.setTextColor(WHITE);
}
display.setCursor(5, 50);
display.println(itemEStr);
}
}
else { // ce n'est pas une page de menu
/* C'est ici que vous pourrez accomplir les actions découlant d'un choix de menu
Par exemple, si la personne a sélectionné l'item 3 du sous-menu 2, la variable
numeroMenu vaut 203 (numéro du sous-menu * 100 + numéro de l'item */
display.setCursor(0, 0);
display.setTextColor(WHITE);
display.println("Vous avez");
display.println("choisi");
display.print("l'item ");
display.println(numeroMenu % 100);
display.print("du sous-menu ");
display.println(numeroMenu / 100);
}
display.display();
}
view raw OLED_menus.ino hosted with ❤ by GitHub

Yves Pelletier   (TwitterFacebook)

8 commentaires:

  1. Bonjour, j’ai galéré un bon moment avec le modèle SSD1306 qui grâce à votre tuto s’est avéré être un modèle SSH1106. Un grand merci pour cet excellent tuto qui me permet de bien contrôler mon afficheur. Dan

    RépondreSupprimer
  2. Enfin un tuto en Français pour le SSH1106 ! Et très complet en prime ! Merci !

    RépondreSupprimer
  3. oui bon tuto pour démarrer avec un SH1106 1.3", les 2 premiers sketchs OK du premier coup !
    maintenant je passe à mon appli (mesure ultrason)

    RépondreSupprimer
  4. Est ce Oled n'est pas influencé par les charges inductive comme les afficheur LCD et tft

    RépondreSupprimer
  5. Merci Yves pour ce très bon tuto
    ça fonctionne bien du 1er coup !

    RépondreSupprimer
  6. Oh oui merci pour ce tuto Yves. Avec loupe 8x, au dos de l'écran, il y a bien un régulateur 3.3 V, un 662K en cms. Donc je pense que c'est ok sur mon modèle 3.3 ou 5 V comme précisé.

    RépondreSupprimer
  7. Bonjour, super tuto! L'adresse I2C est elle programmable sur cet ecran?

    RépondreSupprimer
  8. Très cool ces tutos biens utiles pour démarrer, bravo

    RépondreSupprimer