(Dans un autre article, ce sketch a été adapté pour un écran OLED SH1106 I2C).
Le menu principal comporte un certain nombre de sous-menus. Chaque sous-menu donne accès à une deuxième page comportant une liste d'items pouvant être sélectionnés par l'utilisateur.
Le bouton "flèche vers le bas" permet de sélectionner l'item se situant une ligne plus bas dans la liste. Le bouton "flèche vers le haut" permet de sélectionner l'item se situant une ligne plus haut dans la liste. Le bouton "flèche vers la droite" permet d'exécuter l'item de la liste qui est sélectionné. Le bouton "flèche vers la gauche" permet de revenir à la page précédente.
Le nombre de sous-menus dans le menu principal ainsi que le nombre d'items dans chaque sous-menu peu facilement être modifié à l'intérieur du sketch.
Je vous présente immédiatement une courte vidéo montrant le résultat:
Le circuit
L'écran Nokia est branché à l'Arduino de la même façon que dans mes 3 billets précédents: un circuit intégré 4050 a été utilisé afin d'abaisser à 3,3 V les tension de sortie de l'Arduino Uno (voir ce précédent billet pour plus de détails concernant les branchements du 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
- bouton "flèche vers le haut": broche 6 de l'Arduino
- bouton "flèche vers le bas": broche 7 de l'Arduino
- bouton "flèche vers la gauche": broche 8 de l'Arduino
- bouton "flèche vers la droite": broche 9 de l'Arduino
Le sketch
Pour utiliser ce sketch, il faut d'abord avoir installé les bibliothèques Adafruit-PCD8544-Nokia-5110-LCD-library et Adafruit-GFX-Library dans votre IDE Arduino.
La fonction loop() consiste essentiellement à surveiller l'état des boutons et, lorsque l'un d'eux a été enfoncé, modifier l'état des variables appropriées (un délai de 50 millisecondes a été prévu pour éviter les rebonds).
La fonction miseAJour() est responsable de dessiner le contenu de l'écran en fonction de l'état des variables ayant été modifiées au moyen des boutons. Par exemple, la variable NumeroMenu prend la valeur "0" lorsqu'il faut afficher le menu principal, mais devient "1" lorsque le sous-menu numéro 1 a été sélectionné. La variable NumeroItem contient le numéro de l'élément de la liste qui est sélectionné (donc écriture blanche sur fond noir). Puisque l'écran ne peut montrer que 4 éléments de la liste à la fois, mais que la liste peut contenir plus de 4 éléments. la variable numeroTeteDeListe contient le numéro du premier élément à afficher dans le haut de l'écran.
Bien entendu, le texte de chaque liste peut être modifié à volonté de façon à produire un programme qui répond à vos besoins (dans son état actuel, chaque titre doit comporter un maximum de 14 caractères, ce qui est sensiblement la taille maximale pouvant être affichée sur une ligne de l'écran).
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/***************************************************** | |
Système de menus de navigation contrôlé par 4 boutons | |
poussoirs sur écran Nokia 5110 et Arduino. | |
Pour plus d'informations: | |
https://electroniqueamateur.blogspot.com/2018/12/menus-de-navigation-sur-ecran-nokia.html | |
*****************************************************/ | |
// bibliothèques pour l'utilisation de l'écran | |
#include <SPI.h> | |
#include <Adafruit_GFX.h> | |
#include <Adafruit_PCD8544.h> | |
// broches utilisées par l'écran Nokia | |
Adafruit_PCD8544 display = Adafruit_PCD8544(5, 4, 3); | |
// 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.setContrast(60); // généralement entre 40 et 60: ça dépend de votre écran | |
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 > 4) { | |
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 <= 4) { | |
numeroTeteDeListe = 1; | |
} | |
else { | |
numeroTeteDeListe = numeroItem - 3; | |
} | |
} | |
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] ; | |
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(BLACK); | |
// é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 noir à la position de l'item sélectionné | |
display.fillRect(0, 10 * (numeroItem - numeroTeteDeListe + 1) - 1, 84, 10, BLACK); | |
// é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(WHITE); | |
} | |
else { | |
display.setTextColor(BLACK); | |
} | |
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(WHITE); | |
} | |
else { | |
display.setTextColor(BLACK); | |
} | |
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(WHITE); | |
} | |
else { | |
display.setTextColor(BLACK); | |
} | |
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(WHITE); | |
} | |
else { | |
display.setTextColor(BLACK); | |
} | |
display.setCursor(5, 40); | |
display.println(itemDStr); | |
} | |
} | |
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(BLACK); | |
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(); | |
} |
Yves Pelletier (Twitter, Facebook)
Aucun commentaire:
Enregistrer un commentaire