création d'un menu avec keypad 4 x 4

bonjour a tous et a toute, je poste ce nouveau sujet car je n'es rien trouver pour me débloquer.

je souhaite créé un menu et navigué dedans grâce a un keypad , avec dans chaque menu 2 option a choisir valider par 2 bouton

voila pour les grande ligne

je pense que c'est un problème de variable, ou alors j'ai rien fait de bien ce qui est fort possible !
si quelqu'un peu m'aider en m'expliquant ce qui ne va pas sa serait très gentil de votre part.
je sèche toute mes tentative on échoué , j'ai cherché un exemple de code pour m'en inspiré et débloqué mais j'ai rien trouvé !!!

merci par avance pour votre aide et bon courage avec cette pandémie

menu_soumi_forum.ino (13.9 KB)

Un bon moyen de déboguer serait premièrement d'afficher la touche appuyée sur la console.

char key = keypad.getKey();
Serial.print("KEY:"); Serial.println(key);

merci pour le conseil j'ai recommencer avec une variable mais j'arrive a rien

ou pourrai je trouver un model de menu pour voir comment c'es fait ?

menu_soumi_forum.ino (15.5 KB)

Voici un exemple avec un LCD 2004 en I2C et un clavier 4x4.

/*
    Copyright (c) 2020 J-M-L  https://forum.arduino.cc/index.php?action=profile;u=438300
    Author        :   J-M-L
    Create Time   :   May 2020
    Change Log    :

    The MIT License (MIT)
    Permission is hereby granted, free of charge, to any person obtaining a copy
    of this software and associated documentation files (the "Software"), to deal
    in the Software without restriction, including without limitation the rights
    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies of the Software, and to permit persons to whom the Software is
    furnished to do so, subject to the following conditions:
    The above copyright notice and this permission notice shall be included in
    all copies or substantial portions of the Software.
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    THE SOFTWARE.

    USING LIBRARIES (c) their own authors. See their terms and conditions
    Keypad.h                https://github.com/Chris--A/Keypad
    LiquidCrystal_I2C.h     https://github.com/fdebrabander/Arduino-LiquidCrystal-I2C-library
    
*/

/* LE CLAVIER */
#include <Keypad.h> // https://github.com/Chris--A/Keypad
const uint8_t KBD_L = 4;
const uint8_t KBD_C = 4;
uint8_t rowPins[] = { 7, 6, 5, 4 };
uint8_t colPins[] = {11, 10, 9, 8};

char keys[KBD_L][KBD_C] = {
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {'*', '0', '#', 'D'}
};

Keypad clavier = Keypad( makeKeymap(keys), rowPins, colPins, KBD_L, KBD_C);

/* LE LCD */
#include <LiquidCrystal_I2C.h>    // https://github.com/fdebrabander/Arduino-LiquidCrystal-I2C-library
const byte LCD_A = 0x3F;   // adresse du LCD en 0x3F
const byte LCD_L = 4;      // 4 Lignes
const byte LCD_C = 20;     // de 20 caractères
LiquidCrystal_I2C lcd(LCD_A , LCD_C, LCD_L);


/* GESTION SIMPLE D'UN MENU */

/* un menu est composé de plusieurs lignes de commandes */
/* chaque ligne présente un texte, à une touche d'activation et une fonction à appeler */
struct t_LigneMenu {
  const char* texte;      // le texte à afficher
  const char  touche;     // la touche du keypad à appuyer
  void (*action)(char);   // la fonction a apppeler en cas d'appui, avec en paramètre la touche de commande
};

struct t_menu {
  const uint8_t nbLignes;  // le nombre de lignes actives dans le menu
  t_LigneMenu menu[LCD_L]; // les lignes, au maximum le nombre de lignes du LCD
};

// on a la notion de menu actif, celui qui s'affiche quand
// on appele la fonction afficheMenu()
// si ce menuActif est NULL c'est qu'on n'a pas de menu à afficher.

t_menu* menuActif = NULL;

// on a deux fonctions utilitaires, une pour afficher le menu en cours
// l'autre pour gérer les interactions avec le Menu (s'il est non NULL)

// retourne true si un menu était à afficher
bool afficheMenu()
{
  if (menuActif == NULL) return false; // pas de menu

  // sinon on efface l'écran et présente le menu
  lcd.clear();
  for (uint8_t c = 0; c < menuActif->nbLignes; c++) {
    lcd.setCursor(0, c);
    lcd.print(menuActif->menu[c].texte);
  }
  return true;
}

// retourne true si un menu a été déclenché, la fonction aura été appelée
bool gestionMenu()
{
  if (menuActif == NULL) return false; // pas de menu

  // sinon on regarde si un touche correspondant au menu est appuyée
  char t = clavier.getKey();

  if (t == NO_KEY) return false; // pas de touche appuyée

  // sinon on regarde si elle correspond à une touche autorisée
  bool executionMenu = false;
  for (uint8_t c = 0; c < menuActif->nbLignes; c++) {
    if (t == menuActif->menu[c].touche) { // on a trouvé la bonne touche
      menuActif->menu[c].action(t); // on appelle la fonction associée
      executionMenu = true; // on dit qu'on a effectué une action
      break; // pas la peine d'aller voir plus loin, on sort du for
    }
  }
  return executionMenu;
}

// ***********************************************************
// le menu appelle des fonctions qui sont de signature 'void f(char) {...}'
// on pré-définit ces fonctions pour pouvoir déclarer les menus

void actionsSousMenu(char c);
void actionsA(char c);
void actionsB(char c);

// maintenant on définit les menus
t_menu menuPrincipal = {
  2, // 2 entrées actives
  {
    {"[A]   fonction A", 'A', actionsSousMenu},
    {"[B]   fonction B", 'B', actionsSousMenu},
    {NULL, '\0', NULL},
    {NULL, '\0', NULL}
  }
};

t_menu sousMenuA = {
  3,  // 3 entrées actives
  {
    {"[1]   fonction A1", '1', actionsA},
    {"[2]   fonction A2", '2', actionsA},
    {"[3]   fonction A3", '3', actionsA},
    {NULL, '\0', NULL}
  }
};

t_menu sousMenuB = {
  4,  // 4 entrées actives
  {
    {"[1]   fonction B1", '1', actionsB},
    {"[2]   fonction B2", '2', actionsB},
    {"[3]   fonction B3", '3', actionsB},
    {"[4]   fonction B4", '4', actionsB}
  }
};

// On définit ce que doivent faire les fonctions.
// ici le menu principal (A/B) affiche un sous menu associé
// qui appelleront soit la fonction actionsA ou actionsB
// avec en paramètre la touche de déclenchement ce qui permet de savoir quoi faire

void actionsSousMenu(char c)
{
  Serial.print(F("Appel sous menu, touche ["));
  Serial.write(c);
  Serial.println(F("]"));
  switch (c) {

    case 'A':
      menuActif = &sousMenuA; // on choisit le prochain menu
      break;

    case 'B':
      menuActif = &sousMenuB; // on choisit le prochain menu
      break;

    default: // ne devrait pas arriver on conserve le même menu
      break;
  }
}

void actionsA(char c)
{
  Serial.print(F("Actions A — choix ["));
  Serial.write(c);
  Serial.println(F("]"));
  menuActif = &menuPrincipal; // on revient au menu principal
}

void actionsB(char c)
{
  Serial.print(F("Actions B — choix ["));
  Serial.write(c);
  Serial.println(F("]"));
  menuActif = &menuPrincipal; // on revient au menu principal
}

// ----------------------

void setup()
{
  Serial.begin(115200);
  lcd.begin();
  lcd.backlight();
  lcd.clear();

  menuActif = &menuPrincipal;   // on dit quel est le menu actif
  afficheMenu();                // et on l'affiche
}

void loop()
{
  if (gestionMenu()) afficheMenu();// si un déclenchement a été fait, il y a peut-être un nouveau menu  

  // ici on peut faire autre chose 
  // ne pas toucher l'affichage si un menu est actif bien sûr (sinon le menu disparait)
}

Vous définissez vos menus dans une structure t_menu et il y a deux fonctions afficheMenu() et gestionMenu() qui font le job pour vous ensuite de superviser ce qui est appuyé sur le clavier et d'appeler la bonne fonction associée.

Il faut initialiser un menu en définissant le menu actif et en l'affichant

  menuActif = &menuPrincipal;   // on dit quel est le menu actif
  afficheMenu();                // et on l'affiche

Lancez le code et regardez ce que dit le LCD et ce qui dit le moniteur Série ouvert à 115200 bauds. Vous verrez vos commandesle moniteur série () 115200 bauds) affichera

[color=purple][nobbc]
Appel sous menu, touche [A]
Actions A — choix [1]
Appel sous menu, touche [A]
Actions A — choix [2]
Appel sous menu, touche [A]
Actions A — choix [3]
Appel sous menu, touche [B]
Actions B — choix [1]
Appel sous menu, touche [B]
Actions B — choix [2]
Appel sous menu, touche [B]
Actions B — choix [3]
Appel sous menu, touche [B]
Actions B — choix [4][/nobbc]
[/color]

bonjour un grand merci pour cette exemple, je vais étudier sa et tenter de comprendre tout sa .
donc mon code ne va pas du tout en faite .

Votre code est juste un peu compliqué, vous mélangez la logique des menus et les actions spécifiques à votre projet. Autant essayer de garder les choses séparées, ça évite les codes spaghettis :slight_smile:

avec l'approche ci dessus c'est simple de définir plein de menus et de les rendre actifs et vous avez des fonctions spécifiques qui sont appelées pour vous quand l'utilisateur fait un choix.