Créer un menu déroulant avec des choix multiples sur Arduino

Bonjour tous le monde,

J'essayer de me mettre à l'arduino depuis quelques temps.
J'utilise un Arduino UNO

Je cherche à faire un menu déroulant avec plusieurs choix, ces plusieurs choix ouvrant la possibilité de choisir plusieurs autres choix,... avec un Arduino UNO, 4 boutons poussoirs, un LCD. Le but de ces menus successifs serait de faire de la consultation d'états et de valeurs ou de la modification d'états et de valeurs.

Je sais gérer l'écran lcd, enclencher une lecture de l'état du bouton.

J'ai fait un essai avec des while() des if() et des temporisations, mais ma solution marche trés mal et je n'arrive pas à gérer plus d'un étage de choix.

Quelqu'un parmi vous aurait-il déja fait ce genre de menu? si, oui, sur quelle solution me conseiller vous de partir?

D'avance merci
Cordialement,
Florian

Mets déjà ce que tu as fais.

#include <LiquidCrystal.h>

const int NOIR = 4; //ORANGE
const int VERT = 5; //JAUNE
const int ROUGE = 6; //VERT
LiquidCrystal lcd(8, 13, 9, 10, 11, 12); //RS E 4 5 6 7

int R = 0;
int N = 0;
int V = 0;
void setup(){
  pinMode(NOIR, INPUT);
  pinMode(VERT, INPUT);
  pinMode(ROUGE, INPUT);
  lcd.begin(20, 4);
  // Print a message to the LCD.
 //////////// lcd.print("hello, world!");
}
void loop() {
while(1){
  N = digitalRead(NOIR);
  lcd.setCursor(0, 0);
  lcd.clear();
  lcd.print("MENU 0 ");
  delay(500);
  N = digitalRead(NOIR);
  V = digitalRead(VERT);
  R = digitalRead(ROUGE);
  
  if (N == HIGH){
    delay(500);
    N = digitalRead(NOIR);  
    while (N == LOW){ 
      lcd.clear();
      lcd.print("MENU 1");
      delay(500);
      N = digitalRead(NOIR);
      V = digitalRead(VERT);
      R = digitalRead(ROUGE);
      delay(3000);
  
      N = digitalRead(NOIR);
      V = digitalRead(VERT);
      R = digitalRead(ROUGE);
     if(V==HIGH){
       lcd.clear();
       lcd.print("MENU 2");
       delay(3000); }
     if(R==HIGH) {
       lcd.clear();
       lcd.print("MENU 2 BIS");
       delay(3000);}
       N = digitalRead(NOIR);
       V = digitalRead(VERT);
       R = digitalRead(ROUGE);
 }}}}

 
 
//  lcd.setCursor(0, 1);
  // print the number of seconds since reset:
//  lcd.print(millis()/1000);

Voila! :slight_smile:
Je sais mon niveau n'est pas élevé!!

En faite, je cherche à faire en quelque sorte le même genre qu'un menu que l'on ferrai en informatique, avec par exemple
le programme qui defile puis qui fait une pause lors d'un scanf(), que au lieu de choisir avec les touches d'un clavier que ça se fasse avec les 3-4 boutons, puis qu'au bout d'un momment on ressorte de la partie menu du programme afin qu'il reprenne sont cycle normal. Je ne sais pas si c'est réalisable sur un Arduino.

D'avance merci pour votre aide,
Cordialement,
Flca

Tu peux t'inspirer de cela une version modifié de "photoduino" pour un "lcd keypad shield" il y une bonne utilisation de menus

http://forum.snootlab.com/viewtopic.php?f=18&t=581&start=80
téléchargement ici
http://forum.snootlab.com/download/file.php?id=359

Merci Pa44 pour ta réponse, le lcd keypad shield est ce que je cherchais en gros à réaliser, par contre les programmes du photoduino, c'est pour l'instant trop compliqué pour moi :frowning:

Flca

Bonsoir,
Pour voir plus clair tu devrais faire un petit organigramme de ce que tu veux faire avec ton logiciel, ce qui a l'avantage de clarifier le problème donc la solution.
Pour cela, il existe un outil formidable le papier, le crayon et une gomme (sic je ne sais plus qui - désolé) :smiley:
@+

Oui, c'est ce que je m'etais fait, en faite, je veux relier ensuite l'Arduino à différents composants comme par exemple un DS1307, un contact, un DS75,... et le menu me servirait à configurer l'heure de mon DS1307, remettre à 0 mon compteur comptabilisant le nombre d'actionnement du contact, l'heure de début de comptage des actionnements, une limite de température,...

Mais le probléme c'est que tant que je ne saurais pas faire un simple menu je ne pourrais pas faire ce systéme.

Cordialement,
Flca

En faite, je pense que pour moi ce qui est le plus dure c'est de faire une pause dans le déroulement du programme jusqu'à un changement d'état (que l'on prend en même temps en compte) comme le ferait le scanf() en informatique.
Cordialement,
Flca

C'est quoi qui change d'état ?

Un changement d'etat par un appui sur le bouton 1, 2, 3, 4, que en même temps on enregistre quel bouton est actionné et qu'avec un if() en fonction du bouton appuyé on reparte dans un menu ou un autre

regarde ce post :

http://forum.arduino.cc/index.php?topic=143810.0

voici un menu qui marche, avec des sous-menus. inspire-toi, il va falloir que tu arrives à décoder, mais c'est je crois dans l'esprit de ce que tu cherches...

void loop(){
  byte key;
  word vit_perso;
  
  key = keypad_getKey();
  if (key != NO_KEY) {
    switch (key){
      case key_set:                           // touche menu
        setting = HIGH;
        lcd_busy = HIGH;
        lcd.clear();
        vit_perso = vitesses[tmp_vitesse];
        lcd.print ("Vit. perso =");
        lcd.setCursor (0,1);
        lcd.print (opmn);
        lcd.setCursor (11, 0);
        lcd.print (vit_perso);
        set_encours = HIGH;
        while (set_encours) {
          key_dumy = keypad_getKey();
          if (key_dumy != NO_KEY) {
            switch (key_dumy){
              case key_valid:               // Valider, on met à jour le régulateur.
                vitesses[9] = vit_perso;
                cmpt_imp[9] = word(FACT_V_M * vitesses[9]);   // initialisation des valeurs d'impulsons
                servo1_base[9] = servo_get_moy(vitesses[9]); 
                servo_write(1, servo1_base[9]);
                cour_vitesse = 9;
                tmp_vitesse = 9;
                set_encours = LOW;
                break;
              case key_plus:               // +
                vit_perso++;
                break;
              case key_moins:               // -
                vit_perso--;
                break;
              case key_annul:               // Annuler
                set_encours = LOW;
                break;
              case key_set:                                                     // fonction 2 : modif param accélération
                lcd.clear();
                lcd.print ("F ACCel : ");
                lcd.setCursor (0,1);
                lcd.print (opmn);
                lcd.setCursor (10, 0);
                lcd.print (Ka);
                set_encours_1 = HIGH;
                var_save = Ka;         // sauvegarde de v_stab_Ka
                while (set_encours_1) {
                  key_dumy = keypad_getKey();
                  if (key_dumy != NO_KEY) {
                    switch (key_dumy){
                      case key_valid:               // Valider, on enregistre la valeur.
                        EEPROM_write (adr_Ka, Ka);
                        set_encours_1 = LOW;
                        set_encours   = LOW;
                        break;
                      case key_plus:               // +
                        Ka++;
                        break;
                      case key_moins:               // -
                        Ka--;
                        break;
                      case key_annul:               // Annuler
                        Ka = var_save;         // rappel de v_stab_Ka
                        set_encours_1 = LOW;
                        set_encours   = LOW;
                        break;
                      case key_set:                                                 // fonction 3 : modif param décélération
                       if (Ka == var_save) {               // accessible que si l'on n'a pas changé la valeur précédente
                        lcd.clear();
                        lcd.print ("F DECel : ");
                        lcd.setCursor (0,1);
                        lcd.print (opmn);
                        lcd.setCursor (10, 0);
                        lcd.print (Kd);
                        set_encours_2 = HIGH;
                        var_save = Kd;         // sauvegarde de v_stab_Kd
                        while (set_encours_2) {
                          key_dumy = keypad_getKey();
                          if (key_dumy != NO_KEY) {
                            switch (key_dumy){
                              case key_valid:               // Valider, on enregistre la valeur.
                                EEPROM_write (adr_Kd, Kd);
                                set_encours_2 = LOW;
                                set_encours_1 = LOW;
                                set_encours   = LOW;
                                break;
                              case key_plus:               // +
                                Kd++;
                                break;
                              case key_moins:               // -
                                Kd--;
                                break;
                              case key_annul:               // Annuler
                                Kd = var_save;         // rappel de v_stab_Kd
                                set_encours_2 = LOW;
                                set_encours_1 = LOW;
                                set_encours   = LOW;
                                break;
                              case key_set:                                               // fonction 4 : fenêtre d'intégration. v_stab_max
                                if (Kd == var_save) {               // accessible que si l'on n'a pas changé la valeur précédente
                                  lcd.clear();
                                  lcd.print ("Fen Int : ");
                                  lcd.setCursor (0,1);
                                  lcd.print (opmn);
                                  lcd.setCursor (10, 0);
                                  lcd.print (v_stab_max);
                                  set_encours_3 = HIGH;
                                  var_save = v_stab_max;         // sauvegarde de v_stab_max
                                  while (set_encours_3) {
                                    key_dumy = keypad_getKey();
                                    if (key_dumy != NO_KEY) {
                                      switch (key_dumy){
                                        case key_valid:               // Valider, on enregistre la valeur.
                                          EEPROM_write (adr_v_stab_max, v_stab_max);
                                          set_encours_3 = LOW;
                                          set_encours_2 = LOW;
                                          set_encours_1 = LOW;
                                          set_encours   = LOW;
                                          break;
                                        case key_plus:               // +
                                          v_stab_max++;
                                          break;
                                        case key_moins:               // -
                                          v_stab_max--;
                                          break;
                                        case key_annul:               // Annuler
                                          v_stab_max = var_save;         // rappel de v_stab_max
                                          set_encours_3 = LOW;
                                          set_encours_2 = LOW;
                                          set_encours_1 = LOW;
                                          set_encours   = LOW;
                                          break;
                                        case key_set:                           // fonction 5 : pas de fonction, sortir du menu.
                                          if (v_stab_max == var_save) {            // accessible que si l'on n'a pas changé la valeur précédente
                                            set_encours_3 = LOW;
                                            set_encours_2 = LOW;
                                            set_encours_1 = LOW;
                                            set_encours   = LOW;
                                          }
                                          break;
                                      }
                                      if (v_stab_max < 1) v_stab_max = 1;
                                      lcd.setCursor (10, 0);
                                      lcd.print (v_stab_max);
                                      lcd.print ("  ");
                                    }
                                  }
                                }
                                break;
                            }
                            if (Kd < 1) Kd = 1;
                              lcd.setCursor (10, 0);
                              lcd.print (Kd);
                              lcd.print ("  ");
                          }
                        }
                       }
                       break;
                    }
                    if (Ka < 1) Ka = 1;
                      lcd.setCursor (10, 0);
                      lcd.print (Ka);
                      lcd.print ("  ");
                  }
                }
                break;  
            }
            lcd.setCursor (11, 0);
            lcd.print (vit_perso);
            lcd.print("  ");
          }
        }
        t_ligne2 = t_space16;
        setting = LOW; 
        lcd_busy = LOW;       
        break;
    }
  } 
}

Oui, merci, c'est ce que je cherche, mais je me rends bien compte que mon C n'est pas encore sufisament bon pour m'attaquer à un programme comme ça :(, en tous cas merci pour votre aide et votre bonne réactivité :slight_smile:
Cordialement,
Flca

mon menu permet de voir une valeur, la modifier avec +/-, valider (enregistre la valeur), annuler (remet la valeur d'origine) ou menu suivant (touche "set"). le plus dur pour toi, c'est de nettoyer mon code en virant ce qui est propre à mon prog et ce qui est utile au menu. je ne le fais pas, car je ne me souviens plus trop de comment ça tourne, mais l'idée est là : du switch en pagaille. niveau prog, tu rentres dans un switch, et selon la touche, il faut soit modifier la valeur, soit passer au menu suivant, etc etc. J'ai essayé de naviguer avec +/- dans le menu, mais ça devenait trop hard, donc on ne peut qu'avancer... C'est plus facile avec un écran graphique, car on peut afficher l'arborescence. en LCD classique, on ne peut pas, il faut donc réussir à organiser le tout...

bonjour,
tu peux aussi t'inspirer de mon menu que je iens de mettre en ligne
http://forum.arduino.cc/index.php?topic=195588.msg1471980#msg1471980

Bonjour,

J'ai regardé vos exemples avec attention, mais n'ayant pas encore le niveau pour tout comprendre, je me suis dit que j'allais reessayer d'en faire un, voila mon programme (par paresse pour ne pas avoir à brancher le lcd, j'ai affiché via mon port serie):

"

#include <LiquidCrystal.h>
#include <SoftwareSerial.h>

SoftwareSerial mySerial(10, 11); // RX, TX

const int NOIR = 4; //ORANGE
const int VERT = 5; //JAUNE
const int ROUGE = 6; //VERT
LiquidCrystal lcd(8, 13, 9, 10, 11, 12); //RS E 4 5 6 7

int cmpt = 0 ;
int cm=0;
int R = 0;
int N = 0;
int V = 0;
int l=1;
void setup(){
// Open serial communications and wait for port to open:
Serial.begin(9600);

Serial.println("Hoodnight moon!");

// set the data rate for the SoftwareSerial port
Serial.println("Hello, world?");
pinMode(NOIR, INPUT);
pinMode(VERT, INPUT);
pinMode(ROUGE, INPUT);
lcd.begin(20, 4);
Serial.println("H");

// Print a message to the LCD.
//////////// lcd.print("hello, world!");
}
void loop() {

Serial.println("A");

while(1){
Serial.println("Accueil");
delay(1000);
N = digitalRead(NOIR);
V = digitalRead(VERT);
R = digitalRead(ROUGE);
if (N==HIGH){
while(N==HIGH){
N = digitalRead(NOIR);
}
Serial.println("vous etes dans le premier menu");
while(N==LOW){
N=digitalRead(NOIR);
delay(100);
V=digitalRead(VERT);
R=digitalRead(ROUGE);
if(l==1){
Serial.println(cmpt);}
if(V==HIGH){
cmpt=cmpt+1;
l=0;
if(cm!=cmpt){
Serial.println(cmpt);}
cm=cmpt;

while (V==HIGH){
V=digitalRead(VERT);
}}
if(R==HIGH){
cmpt=cmpt-1;
l=0;
if(cm!=cmpt){
Serial.println(cmpt);}
cm=cmpt;
while (R==HIGH){
R=digitalRead(ROUGE);

}

}}
}
if (R==HIGH){
while(R==HIGH){
R = digitalRead(ROUGE);
}
Serial.println("vous etes dans 2e menu");
while(R==LOW){
R=digitalRead(ROUGE);
delay(100);
V=digitalRead(VERT);
N=digitalRead(NOIR);
if(l==1){
Serial.println(cmpt);}
if(V==HIGH){
cmpt=cmpt+1;
l=0;
if(cm!=cmpt){
Serial.println(cmpt);}
cm=cmpt;

while (V==HIGH){
V=digitalRead(VERT);
}}
if(N==HIGH){
cmpt=cmpt-1;
l=0;
if(cm!=cmpt){
Serial.println(cmpt);}
cm=cmpt;
while (N==HIGH){
N=digitalRead(NOIR);

}

}}
}
}}

"

ça marche, mais à mon avis il y a plus simple et plus court, il fait déja 6ko et j'ai seulement 2 choix dans mon menu

Voila

Cordialement
FLCA

A mon avis, tu fais fausse route totale en faisant de cette manière.
les commandes via serial ne sont pas les même avec un lcd.
déjà tu n'as pas a gérer les lignes et colonnes et tu ne t'appuie pas sur la lib du lcd.

je ne dis pas que ton boulot est mauvais en soit, mais ne sera pas applicable avec le lcd.
pars des exemples de la lib lcd, comprends, fais des modifs et tu verras que ca roulera tout seul (enfin, pas au début).

icare:
Bonsoir,
Pour voir plus clair tu devrais faire un petit organigramme de ce que tu veux faire avec ton logiciel, ce qui a l'avantage de clarifier le problème donc la solution.
Pour cela, il existe un outil formidable le papier, le crayon et une gomme (sic je ne sais plus qui - désolé) :smiley:
@+

J'ai répété cette phrase je ne sais pas combien de fois sur le forum.

Avant de coder, il faut décrire ce que l'on veut. Cela permet de clarifier le besoin. De supprimer l'inutile.
Ensuite on décrit comment on veut le faire, les actions à enchaîner (des mots que des mots pas encore du code). On appuie sur tel bouton, cela entraîne tel action, si j'appuie sur tel autre ça fait tel autre action, ....;
Ensuite on traduit les descriptions ci-dessus en blocs fonctionnels. Une fonction pour une action. Quels sont les entrées du bloc quels sont les sorties.
il faut toujours se mettre à la place du processeur. Si je le faisait à la main je ferais comme ci et comme ça.
Une fois là on peut commencer à coder les fonctions de plus bas niveau. Celles qui gèrent les entrées et les sorties. On vérifie qu'elles fonctionnent comme attendu. Ensuite on code le niveau supérieur. Et ainsi de suite.

Expliqué comme ça, cela peut sembler lourd mais en fait, cette démarche on l'applique intuitivement pour tout un tas de chose que l'on réalise quotidiennement.