Aide pour menu LCD

Bonjour à tous!

Ceci est mon premier message, donc merci à vous pour l'accueil, et chaude bise à qui veut.

Je débute sur Arduino et la programmation (Arduino), en faisant à peu près tout les moocs qui en traitent, et en faisant pas mal de recherche sur le net. J'ai déjà compris pas mal de chose, mais là, je bloque, et de plus il n'y a quasiment aucun tuto solide sur le menu LCD (16x2). Je viens donc vers vous.

Je me suis lancé comme défi de faire un petit programme qui donne l'heure, la date, où on peut changer ces deux paramètres et aussi synchroniser l'heure (ça je sais pas si ça marche une fois le prog lancé, je verrai c'est accessoire), et aussi mettre une alarme.

J'aimerai un menu comme tel que:

menu1 Affichage **
** menu11 Date

** menu12 Heure**
** menu13 Synchronisation**
menu2 Réglage
** menu21 Date**
** menu22 Heure**
** menu23 Alarme**
menu3 Alarme
** menu31 Non**
** menu32 Oui**
** menu33 Peut-être(ça c'est pour le fun)**

Ceci me permettra de mobiliser tout un tas de compétence, et j'aime bien ça.

Trois bouton pour choisir le menu, un pour le sous-menu, et un autre pour activer l'action correspondante.

Et je suis bloqué... Au sous menu. J'arrive à faire défiler le menu sur l'LCD, mais je ne comprend pas comment faire pour le sous-menu... C'est bloqué sur la première option pour l'instant.
Je me suis inspiré du mooc d'Openclassroom où, il est fait mention en guise d'exercice de faire un menu lcd, comme ça, sans prévenir et sans guère plus d'explication. J'ai essayé de broder avec ce que je connaissais et découvrais au fur et à mesure de mes recherches.
J'ai cherché tout un tas d'option et du coup j'ai fais un truc tout pourri qui ne fonctionne pas et que je devrai effacer sans nul doute (Des strings vers des pointeurs qui sont des tableaux, je pense que c'est un gros lol de ma part).
Mais allons-y, puisque le ridicule ne me tuera pas cette fois non plus:

const int bp1      = 8;
const int bp2      = 9;
int posMenu        = 0;
int posSousMenu    = 0;
//Nom des [3]menus de la ligne 1
String ligne1[3] = {"Afficher        ",
                    "Regler          ",
                    "Mettre l'alarme   "};
String mAfficher[2] = 
  {
    "La date         ",
    "L'heure         "
  };
String mRegler[2] =
  {
    "La date         ",
    "L'heure         "
  };
String mAlarme[2] =
  {
    "Oui             ",
    "Nope            ",
  };
String ligne2[3] = {*mAfficher,
                    *mRegler,
                    *mAlarme};
void loop()
{  
 navigation();
 affichage();
}
/*********************************************/
void navigation()
{ //Variables d'état bouton
  boolean stbp1 = !digitalRead(bp1);
  boolean stbp2 = !digitalRead(bp2);
  //Boucle de navigation
  if (stbp1 | stbp2)
    {
      if (stbp1)
      { 
        posMenu = (posMenu+1)%3;
      }
      if (stbp2)
      {
        switch(posMenu)
        {
          case 0:
          posSousMenu = (posSousMenu+1)%2;
          
          return mAfficher[posSousMenu];
          case 1:
          mRegler[posSousMenu];
          return ;
          case 2:
          mAlarme[posSousMenu];
          return ;
        }
      }     
    
      delay(200);
    }

}

//fonction de rafraîchissement de l'écran LCD

void affichage() 
{
/**********LIGNE 1*****************/

  lcd.setCursor(0, 0); // on positionne le curseur en haut à gauche
  lcd.print(ligne1[posMenu]); // on écrit le menu de la ligne 1
  
/**********LIGNE2******************/
  
  lcd.setCursor(0, 1); // on passe à la ligne suivante
  lcd.print(ligne2[posSousMenu]);

}

En gros, ce que j'aimerai que quelqu'un me dise et m'explique, c'est comment gérer un sous-menu, tout simplement, et sans utilisation de lib extérieures, j'ai envie d'apprendre et donc ne pas me reposer sur le taf de quelqu'un, pour l'instant.

D'avance merci, et espérant ne pas avoir été trop long pour vos petits yeux! :o :slight_smile:

PS:Ce code est en mode "je lache l'affaire après avoir essayé des trucs nawak", il y a donc des bout d'essais incomplets ou inutilisés, merci pour votre indulgence :wink:

Bon je me fait mon petit topic tout seul du coup :cry:

J'ai planché sur cette histoire de sous-menu, et je crois que j'ai enfin trouvé !!
Je me suis martelé les neurones à grands coup de tableaux et de if, et j'ai un menu qui a l'air de fonctionner!

Je vous transmet l'ébauche, qui est sans action, c'était pour m'entraîner. L'action est la prochaine étape!

En gros j'arrive à avoir sur l'écran les String de ligne1 et de ligne2 (si vous voulez pas lire le code)

#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
const int bp1      = 8;
const int bp2      = 9;
int posMenu        = 0;
int memMenu        = 0;
int memSousMenu    = 0;
int posSousMenu[2] = {posMenu,posSousMenu};

//Nom des [3] menus de la ligne 1
String ligne1[3] = {"Menu1          ",
                    "Menu2          ",
                    "Menu3          "};
//Nom des [3]*3 menus de la ligne 2                    
String ligne2 [3][3] = {"Option1-1         ", "Option1-2         ", "Option1-3         ",
                        "Option2-1         ", "Option2-2         ", "Option2-3         ",
                        "Option3-1         ", "Option3-2         ", "Option3-3         "};


void setup()  
{
lcd.begin(16, 2);
lcd.clear();
pinMode(bp1, INPUT_PULLUP);
pinMode(bp2, INPUT_PULLUP);  
}

void loop()
{  
 navigation();
 affichage();
}

void navigation()
{ //Variables d'état bouton
  boolean stbp1 = !digitalRead(bp1);
  boolean stbp2 = !digitalRead(bp2);
  //Boucle de navigation
  if (stbp1 | stbp2)
    {
      if (stbp1)
      { 
        posMenu = (posMenu+1)%3;
      }
      if (stbp2)
      {
        memSousMenu=(memSousMenu+1)%3;
        posSousMenu[posMenu,memSousMenu];
        ;
      }      
      delay(200);
    }
}

void affichage() 
{
/**********LIGNE 1*****************/
  lcd.setCursor(0, 0); 
  lcd.print(ligne1[posMenu]); 
  
/**********LIGNE2******************/
  
  lcd.setCursor(0, 1);
  lcd.print(ligne2[posMenu][memSousMenu]);

}

J'aimerai avoir votre avis sur la technique utilisé ==> c'est bien ou pas?

J'avais vu ça ==> int posSousMenu[2] = {0,0}; <== sur le tuto d'openclassroom, mais il n'était pas utilisé, et finalement je ne l'utilise pas non plus, bien qu'il apparaisse au début. A quoi ça sert de stocker la position dans un tableau, et comment on s'en sert ?

Voilà si quelques uns pouvaient éclairer ma LED sur mes débuts de débutants, je vous en serai reconnaissant...

Cordialement !

Bonjour

Voici un sujet bien posé, avec une réflexion préalable, qui donne en envie de filer un coup de main. :slight_smile:
Désolé de ne pas l'avoir vu plus tôt

Oui l'approche me semble très bonne.

L'idée générale est de bien séparer la gestion des entrées (= boutons) de celle des sorties (= LCD)

Donc un loop qui ressemble au tien :

void loop() {
  traiterBoutons();
  traiterAffichage();
}

traiterBoutons ne fait que regarder l'état des boutons, et mettre à jour des variables globales.
Ces variables caractérisent l'état du système à un instant t
traiterAffichage ne fait qu'actualiser le LCD en fonction uniquement du contenu des variables globales.

Ainsi, il ne doit jamais y avoir d'ordres envoyés au LCD depuis le bloc traiterBoutons.
Et inversement traiterAffichage ne doit contenir aucune lecture de l'état des boutons.

Une fois ce principe posé, avant d'écrire la moindre ligne de code, il faut commencer par structurer l'ergonomie d'utilisation des boutons et de l'affichage. C'est-à-dire imaginer comment on veut que le système fonctionne, du point de vue de l'utilisation.
"Je suis dans tel contexte, j'appuie sur tel bouton, il doit se passer ça..."

Pour les boutons, il y a plein de possibilités.
Les deux principales sont :

  1. tout gérer avec seulement deux boutons
    un bouton de défilement (toujours dans un seul sens)
    un bouton de sélection
    On peut tout faire avec deux boutons, mais ce n'est pas très pratique à l'utilisatio (comme dans les vieilles montres à quartz).
  2. utiliser 4 boutons haut/bas/droite/gauche
    Personnellement c'est ce que j'utilise toujours. Je ne vois pas de nécessité absolue d'en avoir plus.

Exemple depuis un menu affiché : haut/bas permettent de sélectionner la ligne du menu souhaitée, droite descend dans le sous-menu (ou écran terminal), gauche revient au menu précédent

L'état général du système se caractérise alors au minimum par :

  1. l'écran affiché
  2. la ligne sélectionnée à l'intérieur de l'écran affiché, quand celui-ci est un menu

La mémorisation de la ligne sélectionnée permet de savoir par la suite comment traiter un appui sur le bouton "droite".

Il convient aussi de maquetter ses affichages (= ses "écrans" logiques).
Par exemple pour l'affichage de menus, il peut être judicieux de laisser la première colonne de caractères vierge, pour ajouter un > devant la ligne sélectionnée.

A partir du maquettage, on peut identifier toutes les données qui seront nécessaires à la gestion de l'affichage.
C'est-à-dire toutes la variables globales qui seront nécessaires.

A titre d'apprentissage, pour arriver à une bonne maîtrise de ces principes, il faut programmer un menu :

  • avec au moins deux niveaux de sous-menu à un endroit : si on arrive à faire une gestion à 3 niveaux, alors on sait faire un gestion à 10 niveaux.
  • avec au moins un menu comportant plus d'options que ce qui est affichable simultanément, pour apprendre à gérer à la fois la sélection d'une option et le défilement des options.

Wow, merci beaucoup de ta réponse détaillée, qui ne me fait pas regretter de m'être inscrit parmi vous!

Je te lis et m'apprête à tester tout cela. Mais avant, quelques précisions si tu le veux bien :slight_smile:

Dans mon cas, les fonctions "traiterBouton" et "traiterAffichage" son "Navigation" et "affichage", ou est-ce que je me trompe? Je veux dire, est-ce que j'ai déjà bien fait ?
Ces seules deux fonctions suffisent dans le loop pour naviguer complètement et exécuter une action, ou dois-je aussi ajouter une fonction de type "traiterAction" pour reprendre ton exemple, incluant dedans les fonctions en questions? Si oui, dans le cas d'un menu à 3 niveaux, est-ce que cela ressemblerait à:

void traiterAction()
 if (positionMenu=[x][y][z]  && bouton3Appui)
  actionXYZ();
 if (positionMenu=[a][b][c]  && bouton3Appui)
  actionABC();

Est-ce que je peux faire ça?

pour le positionMenu, ça va marcher comme ça? En fait je ne comprend pas comment utiliser ce tableau de position du menu, vraiment.

Ou suis-je obligé de faire ainsi:

void TraiterAction()
 if (memMenu==1 && memSousMenu==2 && memSousMenu2==1 && bouton3appui)
  actionMenu121() 

etc...

Aussi, n'y a-t-il pas un truc à faire en intégrant carrément les mémoires menus dans une fonction, genre:

void traiterAction(memMenu, memSousMenu, memSousMenu2)
 //Et là je ne sais pas quoi faire en fait

Bon j'arrête les questions tant que je n'ai pas plus expérimenté, mais je subodore tout de même qu'il y a quelque chose à faire avec cette histoire de tableau de mémoire de position, et avec pourquoi pas des pointeurs. J'ai vite fait essayé et c'est l'échec pour l'instant avec mes connaissances lacunaires!

A moi les tests !!!

Encore merci de ta réponse, c'est super de se faire aider!
Et désolé si j'ai répondu un peu vite, j'ai tout lu en tout cas et je garde ton post à côté de mon IDE :wink:

En fait tu n'es pas obligé d'adopter un code factorisé à base de tableaux de chaînes pour gérer des menus, surtout si tu n'es pas à l'aise avec ça.

Cela a l'avantage de décrire tout le paramétrage des menus dans une structure fixe, mais aussi la contrainte de se mettre dans un cadre figé pour tous les menus.

Parfois on peut vouloir plus de dynamisme dans les menus : avoir certains choix affichés ou non en fonction de l'état du système, ou bien un choix dont le texte associé change au gré d'une variable.

Par exemple simplifié :

int ecran_actif;

...

void afficherMenu1()
{
...
}

void afficherMenu2()
{
...
}

void afficherMenu3()
{
...
}

void afficher()
{
  switch (ecran_actif)
  {
    case 1 : afficherMenu1();break;
    case 2 : afficherMenu2();break;
    case 3 : afficherMenu3();break;
  }
}

Le traitement des boutons va modifier la variable ecran_actif.
Il vaut mieux éviter d'avoir une grosse fonction traiterAction, car il faudra venir la modifier à chaque fois qu'on veut gérer un nouveau cas d'affichage.
Le plus simple est aussi de la structurer par contexte d'affichage :

void traiterActionMenu1(int bouton_enfonce)
{
  //coder ici les modifs de variables globales à effectuer en fonction du bouton enfonce, et dans le contexte du menu1 affiché sur le LCD
  if (bouton_enfonce == 1)
  ...
}

void traiterActionMenu2(int bouton_enfonce)
{
  ...
}

void traiterActionMenu3(int bouton_enfonce)
{
  ...
}

void traiterAction(int bouton_enfonce)
{
  switch (ecran_actif)
  {
    case 1 : traiterActionMenu1(bouton_enfonce);break;
    case 2 : traiterActionMenu2(bouton_enfonce);break;
    case 3 : traiterActionMenu3(bouton_enfonce);break;
  }
}

Comme ça, chaque contexte (caractérisé par la valeur de la variable ecran_actif) est associé à deux fonctions bien isolées (plus facile à coder, tester et maintenir) : une qui permet de coder les effets de chaque appui bouton, l'autre qui actualise l'affichage.

Avec deux fonctions principales d'aiguillage basées sur un gros switch.

Oui je commence à comprendre je crois... Merci bricoleau pour ton intervention.

Si j'ai bien compris, dans:

void traiterActionMenu1(int bouton_enfonce)
{
 if (bouton_enfonce == 1)
 ...
}

la variable "bouton_enfonce" désigne "quel bouton est appuyé" c'est bien ça?
Donc dans mon cas ça fera quelque chose comme

ecran_actif==posMem

void traiterActionMenu1(int bouton_enfonce)
{
 if (bouton_enfonce == stbp1) //état bouton1
 {
  action correspondante au menu 1
 }
}

void afficher(bouton_enfonce)
{
  switch (posMem)
  {
    case 1 : afficherMenu1();break;
    case 2 : afficherMenu2();break;
    case 3 : afficherMenu3();break;
  }
 switch (posSousMem)
  {
   case 1 : afficherSousMenu1();break;
   etc....
  }
}

Wow, j'étais en train d'écrire et je me suis perdu... Je crois que je devrai pratiquer pour voir!

Je vais essayer tout ça

oui j'ai considéré que bouton_enfoncé est une variable temporaire qui désigne quel bouton a été enfoncé.
Donc en gros le numéro de bouton (ou la pin associée)

Dans mon exemple il n'y a aucune différence entre un menu et un sous-menu. Il peuvent tous êtres codés au même niveau dans le même râteau.
Tout comme les affichages terminaux (ce qui doit être affiché au bout du bout après un choix final dans un sous-menu).

int ecran_actif;

//valeurs possibles (peu importe les valeurs du moment qu'elles sont différentes)
const int ecran_menu1 = 1;
const int ecran_menu2 = 2;
const int ecran_menu3 = 3;
const int ecran_sousmenu11 = 4;
const int ecran_sousmenu12 = 5;
const int ecran_detail121 = 6;

...

void afficher()
{
  switch(ecran_actif)
  {
    case ecran_menu1      : afficherEcranMenu1();break;
    case ecran_menu2      : afficherEcranMenu2();break;
    case ecran_menu3      : afficherEcranMenu3();break;
    case ecran_sousmenu11 : afficherEcranSousMenu11();break;
    case ecran_sousmenu12 : afficherEcranSousMenu12();break;
    case ecran_detail121  : afficherEcranDetail121();break;
  }
}

mais bon c'est juste une manière de faire, basée sur des notions de coding simples.

Aaah oui d'accord, ça c'est pour stocker plus tard la const int dans le int de l'écran actif? Pas bête.

Donc du coup pas de String fastidieux avec les noms de menu? On part sur du 0 tableau là ou je me trompe?

Si oui, c'est fou toutes les façons qu'il y a de faire la même chose... Ca me fait penser à photoshop... Mais en pire. :smiling_imp:

Effectivement pas de tableau... du moins dans une premier temps

C'est plus une démarche d'apprentissage que je te propose.

De manière générale, il faut factoriser le code. C'est-à-dire mutualiser tout ce qui peut l'être, ne pas coder la même chose à des endroits différents.

Avec l'expérience, la structuration du code dès le départ devient vite une habitude.

Mais quand on débute, vouloir apprendre les bases et tout de suite viser un code factorisé, ça fait deux marches à gravir.

Là je te propose de commencer par la première marche : écrire une fonction pour chaque cas d'affichage.
Cela te permettra d'arriver à une première version du code, simple, que tu comprends et maîtrise.

Derrière, tu vas te retrouver avec des fonctions afficherMenu1() afficherMenu2() qui sont presque identiques.

La seconde marche consistera à prendre conscience qu'à chaque fois qu'on fait un copier/coller à l'intérieur d'un même programme, c'est qu'il y a un bout de code à mettre en commun.

Et là tu pourras alors partir d'une version de programme qui marche, et ajouter une couche d'optimisation.
Les fonctions afficherMenuxxx() seront remplacées par une seule fonction afficherMenu(int lequel).
Cette fonction aura un code unique, mais aura besoin d'avoir quelque part un ou des tableaux pour isoler les différences entre les menus.
Mais ça c'est la seconde marche... :slight_smile:

Trop cool, merci pour ton aide!
Tu es le tuto que je cherchais!! Ahah :slight_smile:

J'essaie de faire quelque chose avec trois boutons, et je viens te poster le résultat!
Et oui en effet, là c'est déjà très redondant. Pour un menu composé de 4 menus, chacun contenant 4 sous menus, et l'un contenant un troisième niveau de 4 sous menu encore, j'ai donc 4x4+4 const int ecranMenux = x, et tout autant de fonction afficherMenux... Mais si ça marche je suis content :wink:

Pour éprouver le modèle, tu peux éventuellement commencer par moins de menus et sous-menus.

Il va falloir aussi regarder la gestion des boutons.
Je ne vois pas de gestion d'anti rebond dans ton premier code.
Comment sont-ils cablés ?

Comme tu as l'air de te soucier de mon code (et je t'en remercie), je te transmet l'avancée des travaux!
Ca ne fonctionne pas vraiment, mais j'ai l'impression d'avancer dans la compréhension du langage.
Je le met en plusieurs balises afin que ce soit plus lisible.

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

#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

const int bp1                  = 7;
const int bp2                  = 8;
const int bp3                  = 9;

/*********VARIABLE D'ECRAN**************/
int ecranActif                 = 0;

//Nombre de menus (utile pour le retour fin de ligne)
//Chiffre = niveau de menu
int nbr1Menu                   = 4;
int nbr2Menu                   = 4;
int nbr3Menu                   = 4;

//Principaux
const int ecranMenu1           = 1;
const int ecranMenu2           = 2;
const int ecranMenu3           = 3;
const int ecranMenu4           = 4;

//Deuxième niveau
const int ecranMenu11          = 11;
const int ecranMenu12          = 12;
const int ecranMenu13          = 13;
const int ecranMenu14          = 14;

const int ecranMenu21          = 21;
const int ecranMenu22          = 22;
const int ecranMenu23          = 23;
const int ecranMenu24          = 24;

const int ecranMenu31          = 31;
const int ecranMenu32          = 32;
const int ecranMenu33          = 33;
const int ecranMenu34          = 34;

const int ecranMenu41          = 41;
const int ecranMenu42          = 42;
const int ecranMenu43          = 43;
const int ecranMenu44          = 44;

//Troisième niveau
const int ecranMenu441         = 441;
const int ecranMenu442         = 442;
const int ecranMenu443         = 443;
const int ecranMenu444         = 444;
/***************PROGRAMME***************/
void setup()
{
 //Serial.begin(9600); //Pour tester, décommenter

 lcd.begin(16, 2);
 lcd.clear();
 pinMode(bp1, INPUT_PULLUP);
 pinMode(bp2, INPUT_PULLUP);  
 pinMode(bp3, INPUT_PULLUP);  




}





void loop()
{  
 lesBoutons(); 
mainAffichage();


}
/**************FONCTIONS*****************/
void lesBoutons()
{
 boolean stbp1 = !digitalRead(7);
 boolean stbp2 = !digitalRead(8);
 boolean stbp3 = !digitalRead(9);

 if (stbp1 | stbp2)
 {
  if (stbp1)
   {
    ecranActif = ecranActif-1;
//Correction pour retourner à droite du menu une fois arrivé au bout à gauche
     if (ecranActif == (nbr1Menu-nbr1Menu)-1) 
       {
         ecranActif = nbr1Menu;
       }
   }

   if (stbp2)
   {
    ecranActif = (ecranActif+1)%nbr1Menu;

   }
 }


   

 if (stbp3)
 {
  if (ecranActif<=nbr2Menu)
    {
    switch (ecranActif) 
    {
        case 0 :
        ecranActif==(ecranActif+10);
        break;

        case 1 :
        ecranActif==(ecranActif+20);
        break;

        case 2 :
        ecranActif==(ecranActif+30);
        break;

        case 3 :
        ecranActif==(ecranActif+40);
        break;
    }
  }
 }
 delay(120);
}
void affichage()
{
  if (ecranActif<11)
  {
   switch(ecranActif)
   {
    case 0:
    afficherMenu1();
    break;
    case 1:
    afficherMenu2();
    break;
    case 2:
    afficherMenu3();
    break;
    case 3:
    afficherMenu4();
    break;

   }
 }
 if (ecranActif>10 && ecranActif<21)
  {
   switch(ecranActif)
   {
    case 0:
    afficherSousMenu11();
    break;
    case 1:
    afficherSousMenu12();
    break;
    case 2:
    afficherSousMenu13();
    break;
    case 3:
    afficherSousMenu14();
    break;

   }
 }
 if (ecranActif>20 && ecranActif<31)
  {
   switch(ecranActif)
   {
    case 0:
    afficherSousMenu21();
    break;
    case 1:
    afficherSousMenu22();
    break;
    case 2:
    afficherSousMenu23();
    break;
    case 3:
    afficherSousMenu24();
    break;

   }
 }
 if (ecranActif>30 && ecranActif<41)
  {
   switch(ecranActif)
   {
    case 0:
    afficherSousMenu31();
    break;
    case 1:
    afficherSousMenu32();
    break;
    case 2:
    afficherSousMenu33();
    break;
    case 3:
    afficherSousMenu34();
    break;

   }
 }
 if (ecranActif>40 && ecranActif<51)
  {
   switch(ecranActif)
   {
    case 0:
    afficherSousMenu41();
    break;
    case 1:
    afficherSousMenu42();
    break;
    case 2:
    afficherSousMenu43();
    break;
    case 3:
    afficherSousMenu44();
    break;

   }
 }
}


void mainAffichage()
{
  lcd.print("Menu principal");

  lcd.setCursor(0,1);               
  afficherMenu1();          

  lcd.setCursor(9,1);
  afficherMenu2();

  /*lcd.setCursor(0,1);               
  afficherMenu3();

  lcd.setCursor(9,1);
  afficherMenu4();*/

}
/******************************/
void afficherMenu1()
{
 lcd.print(" Menu 1          ");
}
void afficherMenu2()
{
 lcd.print(" Menu 2          ");
}
void afficherMenu3()
{
 lcd.print(" Menu 3          ");
}
void afficherMenu4()
{
 lcd.print(" Menu 4          ");
}
/******************************/
void afficherSousMenu11()
{
 lcd.home();
 lcd.print(" Menu 11        ");
}
void afficherSousMenu12()
{
 lcd.home();
 lcd.print(" Menu 12        ");
}
void afficherSousMenu13()
{
 lcd.home();
 lcd.print(" Menu 13        ");
}
void afficherSousMenu14()
{
 lcd.home();
 lcd.print(" Menu 14        ");
}
 /******************************/
void afficherSousMenu21()
{
 lcd.home();
 lcd.print(" Menu 21        ");
}
void afficherSousMenu22()
{
 lcd.home();
 lcd.print(" Menu 22        ");
}
void afficherSousMenu23()
{
 lcd.home();
 lcd.print(" Menu 23        ");
}
void afficherSousMenu24()
{
 lcd.home();
 lcd.print(" Menu 24        ");
}
/******************************/
void afficherSousMenu31()
{
 lcd.home();
 lcd.print(" Menu 31        ");
}
void afficherSousMenu32()
{
 lcd.home();
 lcd.print(" Menu 32        ");
}
void afficherSousMenu33()
{
 lcd.home();
 lcd.print(" Menu 33        ");
}
void afficherSousMenu34()
{
 lcd.home();
 lcd.print(" Menu 34        ");
}
 /******************************/
void afficherSousMenu41()
{
 lcd.home();
 lcd.print(" Menu 41        ");
}
void afficherSousMenu42()
{
 lcd.home();
 lcd.print(" Menu 42        ");
}
void afficherSousMenu43()
{
 lcd.home();
 lcd.print(" Menu 43        ");
}
void afficherSousMenu44()
{
 lcd.home();
 lcd.print(" Menu 44        ");
}

Je me suis grave embrouillé avec la gestion du troisième bouton (action), je pense qu'il faut que je recommence mon projet avec une autre approche, car ça ne va pas du tout...
De plus, je suis tombé sur => cet article <=, et cela m'amène à penser que je me prend la tête pour pas grand chose! Je pense me pencher sérieusement dessus, je me sens capable de comprendre ce code si je m'y penche bien.

C'est la deuxième tentative de réponse, je ne sais pas pourquoi ça n'a pas marché la première fois... J'espère que je n'ai rien oublié.

Ah si, le debounce. Oui je n'en ai pas mis car je ne sais pas comment on fait :slight_smile:
A venir !

Oh et pour compléter, tu remarqueras sans peine que j'ai fait n'importe quoi... Je pense que l'idée de gérer les menus par leur numéro (const int xxx = 41 pour le sous menu 1 du menu 4 ) est une erreur, je m'y suis perdu totalement... Je pense que je vais carrément tout recommencer pour y voir plus clair.

J'ai l'impression qu'il faut que j'arrête et que je potasse du C avant de continuer sérieusement avec l'Arduino, je vois trop les limites en tant que débutant total en programmation pour continuer plus loin.
Après, je pourrai aussi éventuellement faire le feignant et pomper des bibliothèques, mais ce n'est pas mon but.
Ce but n'est pas bien défini, mais je sais que j'ai envie d'apprendre le C, cela me semble un bon point de départ, assez compliqué pour être très utile avec les autres langages (à moins que je ne me trompe), et à la fois plus simple à manier que l'asm :stuck_out_tongue:

J'aurai quand même bien aimé réussir à me faire ce petit menu, j'ai quelques projets arduinesques en plus qui pourrait être bien sympa avec un menu (enfin c'est surtout que j'aime apprendre et bidouiller au fond de moi) :wink:

Allez, go pointeurs !

En fait pour illustrer, par exemple pour afficher un menu général constitué de 3 sous-menus, l'idée serait d'afficher :

  • sur la première ligne : le titre du menu général
  • sur la seconde ligne : faire défiler menu1 / menu2 / menu3

Le coding associé pourrait ressembler à :

int selection = 1;

void afficherMenuGeneral()
{
  //premiere ligne
  lcd.setCursor(0,0);
  lcd.print("Menu ");

  //seconde ligne selon valeur de la variable selection
  lcd.setCursor(0,1);
  switch (selection)
  {
    case 1 : lcd.print("Menu1 ");break;
    case 2 : lcd.print("Menu2 ");break;
    case 3 : lcd.print("Menu3 ");break;
  }
}

void traiterBoutonMenuGeneral(int bouton)
{
  if (bouton == bouton_haut)
  {
    if (selection > 1) selection--;
  }
  else if (bouton == bouton_bas)
  {
    if (selection < 3) selection++;
  }
  else if (bouton == bouton_droite)
  {
    if (selection == 2) //seul cas géré dans cet exemple
    {
      ecran_actif = ecran_menu2;
      selection = 1;
    }
  }
}

//puis exemple avec menu2 à 4 choix

void afficherMenu2()
{
  //premiere ligne
  lcd.setCursor(0,0);
  lcd.print("Menu2");

  //seconde ligne
  lcd.setCursor(0,1);
  switch (selection)
  {
    case 1 : lcd.print("Choix1");break;
    case 2 : lcd.print("Choix2");break;
    case 3 : lcd.print("Choix3");break;
    case 4 : lcd.print("Choix4");break;
  }
}

void traiterBoutonMenu2(int bouton)
{
  //autre exemple de coding avec un switch au lieu de  if else if else if
  switch (bouton)
  {
    case bouton_haut :
    {
      if (selection > 1) selection--;
      break;
    }
    case bouton_bas :
    {
      if (selection < 4) selection++;
      break;
    }
    case bouton_gauche :
    {
      //retour au menu general
      ecran_actif = ecran_menu_general;
      selection = 2;
    }
  }
}

Hey hey Bricoleau, je reviens pour donner des nouvelles, après ce mois de quête intensive de programmation :stuck_out_tongue:

Du coup j'ai potassé bien comme il faut du C... Puis du C++ quand j'ai découvert comment c'était mieux... Puis du Ruby quand j'ai découvert comment c'était encore plusse mieux. Ahah, ma nature curieuse... Du coup entre temps j'ai eu le temps d'oublier le C, normal! Je me sens néanmoins carrément apte à reprendre ce que j'ai appris au début, je ne devrai pas en avoir pour très longtemps (en gros j'ai un niveau débutant équivalent dans les trois domaines, j'ai fais tout les tutos d'openclassroom sur ces trois sujets plus quelques autres (avec les exos of course), mais du coup je me demande:

Y'a-t-il moyen d'écrire en Ruby pour l'Arduino ?? Ce serait juste magique...

En tout cas je reviens grandit de mes petits apprentissage, et désormais le menu LCD ne me fait plus peur!

Merci à qui me lira, à qui me répondra !

Bonjour

Il me semble que Ruby est un langage interprété, et non compilé.

Sous cette hypothèse : non pas possible sur arduino