another way to program without using goto, please help

I understand that the "goto" is an incorrect way to use, I am using it for 3 things, the first is to clear screen, the second to avoid that you out of a menu at the end of the execution of a function, the third is when user push a button to return to the previous menu.

Example 1: clear screen

Here the goto use when the user wants to delete screen

delete:
lcd.clear();
lcd.setCursor(1,0);lcd.print("Password");     
                                   
for( i=0; i < sizeof(Ingresar_Contrasena); i++){ 

 kp = Teclado (); function keyboard
 Ingresar_Contrasena[i]=kp;   
                                            
  f(Ingresar_Contrasena[i]=='*'){     
                                                
             goto delete; //Pressing deletes asterisk screen
                                            
    }
                                      
  lcd.setCursor(3+i,3); lcd.print(Ingresar_Contrasena[i]); 

}

Example 2: prevent it getting out of the program with the use of the "break"

At the time of completion of the execution of a function that ends in "break" the program returns to the menu.

void main(){
 
Home: 
lcd.clear();
lcd.setCursor(1,0);lcd.print("Menu 1"); 
lcd.setCursor(1,0);lcd.print("Menu 2");
kp = Teclado ();//function keyboard

switch(kp){  

case 1:
lcd.clear();
lcd.setCursor(1,0);lcd.print("Menu 1");

//*------------------------


function



 //*------------------------
goto Home; 

break;







case 2:
lcd.clear();
lcd.setCursor(1,0);lcd.print("Menu 2");

//*------------------------


function



 //*------------------------

goto Home; 
break;

 
}

Example 3: Move to the previous menu.

This is for when the user wants to return to the previous menu press asterisk

void main(){

home:
lcd.clear();
lcd.setCursor(0,0); lcd.print("Menu 1"); //Imprime en la lcd 
lcd.setCursor(0,1); lcd.print("Menu 2"); //Imprime en la lcd 


kp=Teclado ();

 switch (kp){
  
  case 1:
  lcd.setCursor(0,1); lcd.print("Menu 1"); //Imprime en la lcd 
 
 //-------------------------------------------
      function

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

   if(kp=*){
    goto home;  //if the user presses * moves to the previous menu
   }

  break;



 case 2:
  lcd.setCursor(0,1); lcd.print("Menu 2"); 
  
//-------------------------------------------
      function

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

   if(kp=*){
    goto home;  //if the user presses * moves to the previous menu
   }

  break;

}


}

Can someone tell me how to do this yourself without using the "goto" thank you very much.

I'm new and I'm learning

(by google translate)

From what I can tell, it looks like you can just make home a function.

Have a look at Planning and Implementing a Program - not a GOTO in sight.

...R

Robin2:
Have a look at Planning and Implementing a Program - not a GOTO in sight.

...R

Hello, I liked its publication, with respect to goto, I saw that replaced it by a boolean variable, to be honest can give me an example as I can apply my programming, if not too much trouble. I'm new and I'm learning to program.

Sincerely;

Regards

(By translate google)

carloszuniga:
can give me an example as I can apply my programming,

I feel I have already provided sufficient examples in the link I gave you. Have you actually tried the program? have you tried modifying it to see if you understand it?

I have not replaced GOTO with a boolean variable. I think you need to forget completely that GOTO exists and just design your program differently.

When you call a function it does stuff and returns to the line immediately after the line that callled it. That is automatic - it does not need a GOTO.

If you want to be able to interrupt things (for example press a button to stop flashing lights) then a single iteration of loop() needs to be short and the code to detect the button press needs to be checked in every iteration of loop().

...R

It might be better to add some additional information as how your application works. Sorry for not getting back to you in your other thread - page2; bookmarked it with the intention to help further.

Did Jurassic Park just clone some old teachers from the dawn of the computer age? What is your teacher's name who told you about goto? They should not be allowed near a school any more.

Yes, goto is part of the language, but it is so dangerous that you should not be told its name until you have learned all the other parts of the language. If you had actually been shown correctly, then you would not have been able to write a program that uses goto.

One of the better ways for menus is making use of C structs and function pointers. It can also be done with classes and I thinbk that there is even a library for it.

Below a (non-perfect) approach using structs. structs define a group of variables that belong together.

The first step is to define a structure for a menu item.

struct MENU_ITEM
{
  // key that activates menu item
  char key;
  // display title
  char *title;
  // function to execute
  void (*menufunction)(void);
  // associated sub menu
  MENU *subMenu;
};

void (*menufunction)(void); says that menufunction is a pointer to a function (that takes no arguments and returns nothing). You can now e.g. write a function to switch a led on (e.g. ledOn()) and assign that function to menu function.

The MENU_ITEM also contains a pointer to a sub menu for an associated sub menu; this will be set to NULL if there is no sub menu for the menu item or to a MENU if there is a sub menu. It can also be 'abused' to go to e.g. the main menu so menu would have been a more appropriate name (too late now :wink: )

We also need a MENU structure

struct MENU
{
  // items in a menu
  MENU_ITEM *items;
  // number of items
  byte numItems;
};
[code]
A menu consists of one or more items, This structure allows you to define the items and the number of items (the latter is required because we use a pointer to MENU_ITEMS and hence have no idea how many items are in there,

When we place this in the beginning of the sketch and try to compile, the compiler will complain about the MENU in MENU_ITEM ('MENU' does not name a type) because MENU is defined after MENU_ITEM. Swapping MENU_ITEM and MENU around will not help as in that case the compiler will complain about MENU_ITEM in a similar way.

A little bit of a chicken and egg problem, that can be solved with a forward declaration.

[code]
/*
  forward declarations
*/
struct MENU;
/*
  end of forward declarations
*/

/*
  menu structures
*/
struct MENU_ITEM
{
  // key that activates menu item
  char key;
  // display title
  char *title;
  // function to execute
  void (*menufunction)(void);
  // associated sub menu
  MENU *subMenu;
};

struct MENU
{
  // items in a menu
  MENU_ITEM *items;
  // number of items
  byte numItems;
};
/*
  end of menu structures
*/

void setup()
{
}

void loop()
{
}

Now we can define the menus using the MENU and MENU_ITEM. We again will need some forward declarations to prevent compiler errors.

/*
  forward declarations
*/
struct MENU;

// menu functions
void showMenu();
void ledOn();
void ledOff();

// all defined menus although we might not need all
extern MENU mainMenu;
extern MENU ledMenu;
extern MENU subMenu2;
extern MENU subMenu21;
/*
  end of forward declarations
*/

/*
  menu structures
*/
struct MENU_ITEM
{
  // key that activates menu item
  char key;
  // display title
  char *title;
  // function to execute
  void (*menufunction)(void);
  // associated sub menu
  MENU *subMenu;
};

struct MENU
{
  // items in a menu
  MENU_ITEM *items;
  // number of items
  byte numItems;
};
/*
  end of menu structures
*/

/*
  menus
*/

// main menu
MENU_ITEM mainMenu_Items[] =
{
  {'1', "Led", showMenu, &ledMenu},       // activate Led sub menu by pressing '1', execute function showMenu and set current menu to ledMenu
  {'2', "sub 2", showMenu, &subMenu2}
};
MENU mainMenu = {mainMenu_Items, sizeof(mainMenu_Items) / sizeof(MENU_ITEM)};

// led menu
MENU_ITEM ledMenu_Items[] =
{
  {'1', "Led on", ledOn, NULL},           // switch led on by pressing '1', execute function ledOn and no menu associated with this menu item
  {'2', "Led off", ledOff, NULL},
  {'*', "Back", showMenu, &mainMenu},
  {'0', "Home", showMenu, &mainMenu}
};
MENU ledMenu = {ledMenu_Items, sizeof(ledMenu_Items) / sizeof(MENU_ITEM)};

// another sub menu
MENU_ITEM subMenu2_Items[] =
{
  {'1', "sub 2_1", showMenu, &subMenu21},
  {'2', "sub 2_2", NULL, NULL},
  {'*', "Back", showMenu, &mainMenu}
};
MENU subMenu2 = {subMenu2_Items, sizeof(subMenu2_Items) / sizeof(MENU_ITEM)};

// sub menu of sub menu
MENU_ITEM subMenu21_Items[] =
{
  {'1', "sub 2_1_1", NULL, NULL},
  {'2', "sub 2_2_1", NULL, NULL},
  {'*', "Back", showMenu, &subMenu2},
  {'0', "Home", showMenu, &mainMenu}
};
MENU subMenu21 = {subMenu21_Items, sizeof(subMenu21_Items) / sizeof(MENU_ITEM)};
/*
  end of menus
*/

// current menu
MENU *currMenu = &mainMenu;

void setup()
{
}

void loop()
{
}

The above will compile but not link because the function names in the MENU_ITEMS (showMenu, ledOff and ledOn are unknown). We will writebthem a little later.

// main menu
MENU_ITEM mainMenu_Items[] =
{
  {'1', "Led", showMenu, &ledMenu},       // activate Led sub menu by pressing '1', execute function showMenu and set current menu to ledMenu
  {'2', "sub 2", showMenu, &subMenu2}
};
MENU mainMenu = {mainMenu_Items, sizeof(mainMenu_Items) / sizeof(MENU_ITEM)};

The main menu contains two menu items ("Led" and "sub 2"); they are activated by sending '1' and '2' respectively from the serial monitor (or in your case it will be the keypad). When activated, both will use showMenu to display the specified menu (ledMenu and subMenu2 respectively).

If you have a look at subMenu21, it has two entries to 'go back' to the parent menu (subMenu2) and to go back to the main menu. Both again use the function showMenu() and have a pointer to (different) menus specified.
subMenu21 is basically only there to show you how to go back to the parent menu or to go back to the main menu. Therefore the other two MENU_ITEMS don't have a function not a subMenu specified.

We now have to implement the functions that are used in the menus. ledOn() and ledOff() are straight forward.

/*
  switch led on pin 13 on
*/
void ledOn()
{
  digitalWrite(13, HIGH);
}

/*
  switch led on pin 13 off
*/
void ledOff()
{
  digitalWrite(13, LOW);
}

showMenu() is slightly more complicated.

/*
  show the current menu
*/
void showMenu()
{
  // safety net to prevent crashes in case something was incorrectly set up
  if(currMenu->items == NULL || currMenu->numItems)
  {
    return;
  }
  
  for (int cnt = 0; cnt < currMenu->numItems; cnt++)
  {
    Serial.print(currMenu->items[cnt].key);
    Serial.print('\t');
    Serial.println(currMenu->items[cnt].title);
  }
}

It basically loops through the menu items of the current menu and prints the 'key' and the 'title'.

In the next post we will tie it all together.

/*
  forward declarations
*/
struct MENU;

// menu functions
void showMenu();
void ledOn();
void ledOff();

// all defined menus although we might not need all
extern MENU mainMenu;
extern MENU ledMenu;
extern MENU subMenu2;
extern MENU subMenu21;
/*
  end of forward declarations
*/

/*
  menu structures
*/
struct MENU_ITEM
{
  // key that activates menu item
  char key;
  // display title
  char *title;
  // function to execute
  void (*menufunction)(void);
  // associated sub menu
  MENU *subMenu;
};

struct MENU
{
  // items in a menu
  MENU_ITEM *items;
  // number of items
  byte numItems;
};
/*
  end of menu structures
*/

/*
  menus
*/

// main menu
MENU_ITEM mainMenu_Items[] =
{
  {'1', "Led", showMenu, &ledMenu},       // activate Led sub menu by pressing '1', execute function showMenu and set current menu to ledMenu
  {'2', "sub 2", showMenu, &subMenu2}
};
MENU mainMenu = {mainMenu_Items, sizeof(mainMenu_Items) / sizeof(MENU_ITEM)};

// led menu
MENU_ITEM ledMenu_Items[] =
{
  {'1', "Led on", ledOn, NULL},           // switch led on by pressing '1', execute function ledOn and no menu associated with this menu item
  {'2', "Led off", ledOff, NULL},
  {'*', "Back", showMenu, &mainMenu},
  {'0', "Home", showMenu, &mainMenu}
};
MENU ledMenu = {ledMenu_Items, sizeof(ledMenu_Items) / sizeof(MENU_ITEM)};

// another sub menu
MENU_ITEM subMenu2_Items[] =
{
  {'1', "sub 2_1", showMenu, &subMenu21},
  {'2', "sub 2_2", NULL, NULL},
  {'*', "Back", showMenu, &mainMenu}
};
MENU subMenu2 = {subMenu2_Items, sizeof(subMenu2_Items) / sizeof(MENU_ITEM)};

// sub menu of sub menu
MENU_ITEM subMenu21_Items[] =
{
  {'1', "sub 2_1_1", NULL, NULL},
  {'2', "sub 2_2_1", NULL, NULL},
  {'*', "Back", showMenu, &subMenu2},
  {'0', "Home", showMenu, &mainMenu}
};
MENU subMenu21 = {subMenu21_Items, sizeof(subMenu21_Items) / sizeof(MENU_ITEM)};
/*
  end of menus
*/

// current menu
MENU *currMenu = &mainMenu;

/*
  show the current menu
*/
void showMenu()
{
  // safety net to prevent crashes in case something was incorrectly set up
  if(currMenu->items == NULL || currMenu->numItems)
  {
    return;
  }
  
  Serial.println(currMenu->numItems);
  for (int cnt = 0; cnt < currMenu->numItems; cnt++)
  {
    Serial.print(currMenu->items[cnt].key);
    Serial.print('\t');
    Serial.println(currMenu->items[cnt].title);
  }
}

/*
  switch led on pin 13 on
*/
void ledOn()
{
  digitalWrite(13, HIGH);
}

/*
  switch led on pin 13 off
*/
void ledOff()
{
  digitalWrite(13, LOW);
}

void setup()
{
  Serial.begin(9600);

  // led pin initialisation
  pinMode(13, OUTPUT);
  digitalWrite(13, LOW);

  // show current menu
  showMenu();
}

void loop()
{
  char ch = 0;
  if (Serial.available() > 0)
  {
    ch = Serial.read();
  }

  for (int cnt = 0; cnt < currMenu->numItems; cnt++)
  {
    // check if character is known in current menu
    if (currMenu->items[cnt].key == ch)
    {
      // get the function to execute
      void (*func)() = currMenu->items[cnt].menufunction;
      // if there is a sub menu specified, change the current menu
      if (currMenu->items[cnt].subMenu != NULL)
      {
        currMenu = currMenu->items[cnt].subMenu;
      }
      // if a function was specified, execute it
      if (func != NULL)
      {
        func();
      }
    }
  }
}

setup() is basically straight forward. I used serial monitor for testing, so the Serial port is configured, the led pin is configured and next the code displays the current menu (that was set to mainMenu).

loop() handles the rest. If a character is received from the serial monitor (in your case from the keypad), loop() uses a for loop to iterate through items of the the current menu and checks if 'key' in the MENU_ITEM matches the received character. If so, it saves the function pointer (in func) and checks if a menu was specified and if so changes the current menu to the specified menu. Lastly it checks if a function was specified and executes that function.

Be aware that you should only specify a subMenu in MENU_ITEM if you specify showMenu for the function !!

sterretje:

/*

forward declarations
*/
struct MENU;

// menu functions
void showMenu();
void ledOn();
void ledOff();

// all defined menus although we might not need all
extern MENU mainMenu;
extern MENU ledMenu;
extern MENU subMenu2;
extern MENU subMenu21;
/*
  end of forward declarations
*/

/*
  menu structures
*/
struct MENU_ITEM
{
  // key that activates menu item
  char key;
  // display title
  char *title;
  // function to execute
  void (*menufunction)(void);
  // associated sub menu
  MENU *subMenu;
};

struct MENU
{
  // items in a menu
  MENU_ITEM items;
  // number of items
  byte numItems;
};
/

  end of menu structures
*/

/*
  menus
*/

// main menu
MENU_ITEM mainMenu_Items[] =
{
  {'1', "Led", showMenu, &ledMenu},      // activate Led sub menu by pressing '1', execute function showMenu and set current menu to ledMenu
  {'2', "sub 2", showMenu, &subMenu2}
};
MENU mainMenu = {mainMenu_Items, sizeof(mainMenu_Items) / sizeof(MENU_ITEM)};

// led menu
MENU_ITEM ledMenu_Items[] =
{
  {'1', "Led on", ledOn, NULL},          // switch led on by pressing '1', execute function ledOn and no menu associated with this menu item
  {'2', "Led off", ledOff, NULL},
  {'*', "Back", showMenu, &mainMenu},
  {'0', "Home", showMenu, &mainMenu}
};
MENU ledMenu = {ledMenu_Items, sizeof(ledMenu_Items) / sizeof(MENU_ITEM)};

// another sub menu
MENU_ITEM subMenu2_Items[] =
{
  {'1', "sub 2_1", showMenu, &subMenu21},
  {'2', "sub 2_2", NULL, NULL},
  {'*', "Back", showMenu, &mainMenu}
};
MENU subMenu2 = {subMenu2_Items, sizeof(subMenu2_Items) / sizeof(MENU_ITEM)};

// sub menu of sub menu
MENU_ITEM subMenu21_Items[] =
{
  {'1', "sub 2_1_1", NULL, NULL},
  {'2', "sub 2_2_1", NULL, NULL},
  {'', "Back", showMenu, &subMenu2},
  {'0', "Home", showMenu, &mainMenu}
};
MENU subMenu21 = {subMenu21_Items, sizeof(subMenu21_Items) / sizeof(MENU_ITEM)};
/

  end of menus
*/

// current menu
MENU *currMenu = &mainMenu;

/*
  show the current menu
*/
void showMenu()
{
  // safety net to prevent crashes in case something was incorrectly set up
  if(currMenu->items == NULL || currMenu->numItems)
  {
    return;
  }
 
  Serial.println(currMenu->numItems);
  for (int cnt = 0; cnt < currMenu->numItems; cnt++)
  {
    Serial.print(currMenu->items[cnt].key);
    Serial.print('\t');
    Serial.println(currMenu->items[cnt].title);
  }
}

/*
  switch led on pin 13 on
*/
void ledOn()
{
  digitalWrite(13, HIGH);
}

/*
  switch led on pin 13 off
*/
void ledOff()
{
  digitalWrite(13, LOW);
}

void setup()
{
  Serial.begin(9600);

// led pin initialisation
  pinMode(13, OUTPUT);
  digitalWrite(13, LOW);

// show current menu
  showMenu();
}

void loop()
{
  char ch = 0;
  if (Serial.available() > 0)
  {
    ch = Serial.read();
  }

for (int cnt = 0; cnt < currMenu->numItems; cnt++)
  {
    // check if character is known in current menu
    if (currMenu->items[cnt].key == ch)
    {
      // get the function to execute
      void (*func)() = currMenu->items[cnt].menufunction;
      // if there is a sub menu specified, change the current menu
      if (currMenu->items[cnt].subMenu != NULL)
      {
        currMenu = currMenu->items[cnt].subMenu;
      }
      // if a function was specified, execute it
      if (func != NULL)
      {
        func();
      }
    }
  }
}



setup() is basically straight forward. I used serial monitor for testing, so the Serial port is configured, the led pin is configured and next the code displays the current menu (that was set to mainMenu).

loop() handles the rest. If a character is received from the serial monitor (in your case from the keypad), loop() uses a for loop to iterate through items of the the current menu and checks if 'key' in the MENU_ITEM matches the received character. If so, it saves the function pointer (in func) and checks if a menu was specified and if so changes the current menu to the specified menu. Lastly it checks if a function was specified and executes that function.

Be aware that you should only specify a subMenu in MENU_ITEM if you specify showMenu for the function !!

I will study in detail, thank you very much for your help.

Sincerely.

sterretje:

/*

forward declarations
*/
struct MENU;

// menu functions
void showMenu();
void ledOn();
void ledOff();

// all defined menus although we might not need all
extern MENU mainMenu;
extern MENU ledMenu;
extern MENU subMenu2;
extern MENU subMenu21;
/*
  end of forward declarations
*/

/*
  menu structures
*/
struct MENU_ITEM
{
  // key that activates menu item
  char key;
  // display title
  char *title;
  // function to execute
  void (*menufunction)(void);
  // associated sub menu
  MENU *subMenu;
};

struct MENU
{
  // items in a menu
  MENU_ITEM items;
  // number of items
  byte numItems;
};
/

  end of menu structures
*/

/*
  menus
*/

// main menu
MENU_ITEM mainMenu_Items[] =
{
  {'1', "Led", showMenu, &ledMenu},      // activate Led sub menu by pressing '1', execute function showMenu and set current menu to ledMenu
  {'2', "sub 2", showMenu, &subMenu2}
};
MENU mainMenu = {mainMenu_Items, sizeof(mainMenu_Items) / sizeof(MENU_ITEM)};

// led menu
MENU_ITEM ledMenu_Items[] =
{
  {'1', "Led on", ledOn, NULL},          // switch led on by pressing '1', execute function ledOn and no menu associated with this menu item
  {'2', "Led off", ledOff, NULL},
  {'*', "Back", showMenu, &mainMenu},
  {'0', "Home", showMenu, &mainMenu}
};
MENU ledMenu = {ledMenu_Items, sizeof(ledMenu_Items) / sizeof(MENU_ITEM)};

// another sub menu
MENU_ITEM subMenu2_Items[] =
{
  {'1', "sub 2_1", showMenu, &subMenu21},
  {'2', "sub 2_2", NULL, NULL},
  {'*', "Back", showMenu, &mainMenu}
};
MENU subMenu2 = {subMenu2_Items, sizeof(subMenu2_Items) / sizeof(MENU_ITEM)};

// sub menu of sub menu
MENU_ITEM subMenu21_Items[] =
{
  {'1', "sub 2_1_1", NULL, NULL},
  {'2', "sub 2_2_1", NULL, NULL},
  {'', "Back", showMenu, &subMenu2},
  {'0', "Home", showMenu, &mainMenu}
};
MENU subMenu21 = {subMenu21_Items, sizeof(subMenu21_Items) / sizeof(MENU_ITEM)};
/

  end of menus
*/

// current menu
MENU *currMenu = &mainMenu;

/*
  show the current menu
*/
void showMenu()
{
  // safety net to prevent crashes in case something was incorrectly set up
  if(currMenu->items == NULL || currMenu->numItems)
  {
    return;
  }
 
  Serial.println(currMenu->numItems);
  for (int cnt = 0; cnt < currMenu->numItems; cnt++)
  {
    Serial.print(currMenu->items[cnt].key);
    Serial.print('\t');
    Serial.println(currMenu->items[cnt].title);
  }
}

/*
  switch led on pin 13 on
*/
void ledOn()
{
  digitalWrite(13, HIGH);
}

/*
  switch led on pin 13 off
*/
void ledOff()
{
  digitalWrite(13, LOW);
}

void setup()
{
  Serial.begin(9600);

// led pin initialisation
  pinMode(13, OUTPUT);
  digitalWrite(13, LOW);

// show current menu
  showMenu();
}

void loop()
{
  char ch = 0;
  if (Serial.available() > 0)
  {
    ch = Serial.read();
  }

for (int cnt = 0; cnt < currMenu->numItems; cnt++)
  {
    // check if character is known in current menu
    if (currMenu->items[cnt].key == ch)
    {
      // get the function to execute
      void (*func)() = currMenu->items[cnt].menufunction;
      // if there is a sub menu specified, change the current menu
      if (currMenu->items[cnt].subMenu != NULL)
      {
        currMenu = currMenu->items[cnt].subMenu;
      }
      // if a function was specified, execute it
      if (func != NULL)
      {
        func();
      }
    }
  }
}



setup() is basically straight forward. I used serial monitor for testing, so the Serial port is configured, the led pin is configured and next the code displays the current menu (that was set to mainMenu).

loop() handles the rest. If a character is received from the serial monitor (in your case from the keypad), loop() uses a for loop to iterate through items of the the current menu and checks if 'key' in the MENU_ITEM matches the received character. If so, it saves the function pointer (in func) and checks if a menu was specified and if so changes the current menu to the specified menu. Lastly it checks if a function was specified and executes that function.

Be aware that you should only specify a subMenu in MENU_ITEM if you specify showMenu for the function !!

I understand, but I have some doubts about the syntax of programming.

  1. How do I view the menu on the LCD?

struct MENU
{
  // items in a menu
  MENU_ITEM *items;
  // number of items
  byte numItems;
};
  1. What is the use struct Menu and how it works?
  2. What Makes menu_item * items and byte numItems?

struct MENU_ITEM
{
  // key that activates menu item
  char key;
  // display title
  char *title;
  // function to execute
  void (*menufunction)(void);
  // associated sub menu
  MENU *subMenu;
};
  1. Because MENU_ITEM items have pointers (* title, * menufunction, MENU * subMenu)?

  2. That function makes "MENU * subMenu"?


showMenu does not run anything.

void showMenu()
{
  // safety net to prevent crashes in case something was incorrectly set up
  if(currMenu->items == NULL || currMenu->numItems)
  {
    return;
  }
  
  Serial.println(currMenu->numItems);
  for (int cnt = 0; cnt < currMenu->numItems; cnt++)
  {
    Serial.print(currMenu->items[cnt].key);
    Serial.print('\t');
    Serial.println(currMenu->items[cnt].title);
  }
}
  1. Do not understood the symbol "->"?
  2. What does currMenu?

Serial.print(currMenu->items[cnt].key);
Serial.println(currMenu->items[cnt].title);
struct MENU
{
  // items in a menu
  MENU_ITEM *items;
  // number of items
  byte numItems;
};
  1. ¿Items [ctrl].key refers to MENUITEM * items?

MENU_ITEM mainMenu_Items[] =
{
  {'1', "Led", showMenu, &ledMenu},       // activate Led sub menu by pressing '1', execute function showMenu and set current menu to ledMenu
  {'2', "sub 2", showMenu, &subMenu2}
};
MENU mainMenu = {mainMenu_Items, sizeof(mainMenu_Items) / sizeof(MENU_ITEM)};
  1. Why "& ledMenu" has pointer and showMenu not?

I say this because * title; void (* menu function) (void); MENU * subMenu; They have pointers.


MENU mainMenu = {mainMenu_Items, sizeof(mainMenu_Items) / sizeof(MENU_ITEM)};

10.What Does "MENU mainMenu" and because it uses "sizeof (mainMenu Items) / sizeof (menu_item)"?

  for (int cnt = 0; cnt < currMenu->numItems; cnt++)
  {
    // check if character is known in current menu
    if (currMenu->items[cnt].key == ch)
    {
      // get the function to execute
      void (*func)() = currMenu->items[cnt].menufunction;
      // if there is a sub menu specified, change the current menu
      if (currMenu->items[cnt].subMenu != NULL)
      {
        currMenu = currMenu->items[cnt].subMenu;
      }
      // if a function was specified, execute it
      if (func != NULL)
      {
        func();
      }

In void loop is a bit difficult to understand because of the symbol "->", the whole function is Chinese lol

Excuse me for many questions, maybe some questions are repeated, it is that I want to understand programming syntax in detail, for my something new is this type of menu, since only wise to do so with "switch" and "case".

I would like to adapt it to my programming

The logic of my programming is this

void loop(){

/*
RFID reading mode
  It is the function where the user shows the tag, and the system is responsible for verifying the existence of this, if
  exist tag opens the door, but rather displays an error message.
 
  I still have not done the function.	
*/

kp = Teclado ();
if(kp == '*'){
   lcd.clear();//Limpia Pantalla
   lcd.setCursor(0,1);lcd.print("1. Administrator");     //Admn
   lcd.setCursor(0,2);lcd.print("2. User");     //user
   
    switch(kp){

	case '1': //Admn
		 
		/*
		   1. The Administrator enter the password
                   2. After the system verifies if the password is correct
                   3. If there is access to the menu

		*/

		
		//Menu
		 lcd.clear();  
                 lcd.setCursor(1,0);lcd.print("1. Enter");      //Imprime en la LCD
                 lcd.setCursor(1,1);lcd.print("2. Tags");          //Imprime en la LCD
                 lcd.setCursor(1,2);lcd.print("3. User");      //Imprime en la LCD
                 lcd.setCursor(1,3);lcd.print("4. change Pass");   //Imprime en la LCD

		 kp = Teclado ();
                 if(kp == '*'){
                               case '1': 
				/*
				Function where the administrator presses a key to enter 
				*/
				break;

				 case '2':

                                /*
				Function to add tag
                                I still have not done
				*/

				 break;

                                 case '3':

					lcd.clear();  
                                        lcd.setCursor(0,0);lcd.print("1 New User");  
                                        lcd.setCursor(0,1);lcd.print("2 delete User");  
                                        lcd.setCursor(0,2);lcd.print("3 change Pass");  
                                        kp = Teclado ();
                                                                     
                                        switch(kp){
						 case '1': 
						/*
						Function to add user
						*/
						 break;

 						case '2':
 						/*
						Function to delete user					
                                                */
						 break;

 						case '3': 
						/*
						Function to change user pass
						*/
						 break;

					}
				break;

                                 case '4':
				  /*
				  pass function change manager
				  */	
				 break;
                 }



		

	break;

	case '2': //User

	/*
	The user enters the password, the system checks whether there
        if it exists access to the menu	
	*/

	//Menu

	lcd.clear();  
        lcd.setCursor(0,0); lcd.print("1. Ingresar"); //Imprime en la lcd
        lcd.setCursor(0,1); lcd.print("2. change Pas"); //Imprime en la lcd
        kp = Teclado ();

        switch(kp){
		case '1':
			/*
			Function where the user presses a key to enter
			*/
		break;

		case '2':
			/*
			Function where the user change their password
			*/

		break;
	}


	break;

   }
 }	
}

I do not put all programming because it is very long.

But let me know if I can adapt programming to their menu to my programming.

regards

My code contained this in showMenu()

  for (int cnt = 0; cnt < currMenu->numItems; cnt++)
  {
    Serial.print(currMenu->items[cnt].key);
    Serial.print('\t');
    Serial.println(currMenu->items[cnt].title);
  }

Replace the Serial.print by something for the lcd; replace the tab ('\t') by a space.

struct menu simply groups a number of items; it's like the file menu, theedit menu, the sketch menu etc in the IDE.

There is an array of MENU_ITEMS; in MENU, items is a pointer to that array. In e.g. mainMenu, items is a pointer to the mainMenu_Items. numbytes is an indication how many the items are in there (on can't count the number of elements for a pointer).

4 and 5)
Unclear what you're asking.

currMenu is a pointer to a menu; the elements of the struct that it points to are accessed using the '->' notation.

currMenu is the current menu; it's initialised with mainMenu and if you go to a submenu it's changed to that subMenu. That way the code can keep track which menu is currently displayed and knows which keystrokes are valid.

8)

See 6?

ledMenu is a 'normal' variable; MENU_ITEM expects a pointer (address), so you give it the address of ledMenu.
showMenu is a function and the compiler will fill in it's address

"sizeof (mainMenu Items) / sizeof (menu_item)" calculates the number of elements in the array at compile time; you can google for the sizeof() operator.

Hope that this helps a bit

Thank you very much, you are programming god, I'm studying pointers is something we did not know. Know where I can find information about these types of menu structure is to study better.

you are programming god

I'm not :wink: Just like you I have taught myself. But it is over 20 years of experience that counts in this case. And I can not even describe in 'official' terms what it all does.

20 years, I'm just going to meet 4 months in August since I learned to program reading books, videos from youtube, and codes on the web, (start programming in Mikroc).

Regarding the menu I have not able to display the menu in the virtual terminal, or the LCD. (see image)

The safety net feature was something that was added as an afterthought and was (more than likely) not tested

if(currMenu->items == NULL || currMenu->numItems)

I picked up a bug in showMenu this morning; you can modify it to below

  // safety net to prevent crashes in case something was incorrectly set up
  if (currMenu->items == NULL || currMenu->numItems == 0)
  {
    return;
  }

or

  // safety net to prevent crashes in case something was incorrectly set up
  if (currMenu->items == NULL)
  {
    return;
  }

For the second version, the for-loop will handle the case where numItems is zero.

A new problem, virtual terminal appears works well, only it appears at the beginning a "2".

And to modify it is displayed on the LCD only the last item and not all shown, and by default shown in the virtual terminal 2, 1, 2.

You have to understand the code that I gave you. Go through the showMenu() function in this case.

What do you think that the below line does?

Serial.println(currMenu->numItems);

Hello, as you would to return to the "erase" line without using "goto".

Sorry for asking so many questions really.

Regards

#include <Keypad.h>
#include <LiquidCrystal.h>

///////////////////////LCD///////////////////////////////////////

//Incializa la libreria con los numeros de pines a interactuar el LCD
LiquidCrystal lcd(13, 12, 11, 10, 9, 8);

///////////////////////////////////////////////////////////////////


//////////////Teclado/////////////////////////////////////////////

//Definición de filas y columnas
const byte Filas = 4; //Cuatro filas
const byte Cols = 4; //Cuatro columnas

//Definición de los pines
byte Pins_Filas[] = {3, 2, 1, 0}; //Pines Arduino para las filas
byte Pins_Cols[] =  {4, 5, 6, 7}; // Pines Arduino para las columnas


//Definición de las teclas
char Teclas [ Filas ][ Cols ] =
{
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};

//Se crea una instancia llamada Teclado1 y el cual asignara las teclas que tenemos en el arreglo "Teclas" y le decimos
//que se han conectados los pines de las filas y columnas


Keypad kpd = Keypad(makeKeymap(Teclas), Pins_Filas, Pins_Cols, Filas, Cols);



char Teclado ()
{
  do{
    
    char Tecla = kpd.getKey();         // lee el teclado por si hay alguna tecla pulsada
    
    if(Tecla != NO_KEY)          
    {
      return Tecla;
    }   
  } while (1);
}

int i = 0;
static int cnt = 0;
char kp;
char Estado; 
char Menu;
char Ingresar_Contrasena[10];
char Contrasena1[] = {"123456"};
char Ingresar_Contrasena_Adm[10];
int short Peligro = A1;

void setup() {
 lcd.begin(16, 4); //Configura el LCD con el numero de columas y filas. Para un LCD 16x4: 16 columnas y 4 filas.
  lcd.display(); //Enciende el display
}

void loop() {
  // put your main code here, to run repeatedly:
erase:                                                      //------------------------------------Goto erase
lcd.clear();//Limpia Pantalla
lcd.setCursor(1,0);lcd.print("Administrador");     //Imprime en la LCD
lcd.setCursor(1,1);lcd.print("enter Pass");     //Imprime en la LCD
                                   


for( i=0; i < sizeof(Ingresar_Contrasena); i++){ 

     kp = Teclado (); 
     Ingresar_Contrasena[i]=kp;      
                                            
    if(Ingresar_Contrasena[i]=='#'){ 
              Ingresar_Contrasena[i] = '\0';  
              break; 
    }
                                        
     else{ //Si presiona * borra pantalla 
           if(Ingresar_Contrasena[i]=='*'){
                  goto erase;                                             //------------------------------------Goto
           }
    }
                                        

     if(i == (sizeof(Ingresar_Contrasena)- 1)){
           i--;
     }

     lcd.setCursor(3+i,3); lcd.print('*'); 
 }

//Si en las teclas 5, 6, 7, 8, 9 presiono numeral compara si la contraseña es correcta o no, de ser correcta accede al menu, de lo contrario no.

if ((Ingresar_Contrasena[0] == '\0') || (Ingresar_Contrasena[1] == '\0') || (Ingresar_Contrasena[2] == '\0') || (Ingresar_Contrasena[3] == '\0') || (Ingresar_Contrasena[4] == '\0') || (Ingresar_Contrasena[5] == '\0') || (Ingresar_Contrasena[6] == '\0') || (Ingresar_Contrasena[7] == '\0') || (Ingresar_Contrasena[8] == '\0') || (Ingresar_Contrasena[9] == '\0')){
                                        

//Si estado es cero y las teclas pulsadas coinciden con la contraseña por default accede al menu
        if((cnt<3) && (strcmp (Contrasena1, Ingresar_Contrasena)==0) && (Estado == 0)){ 
                Menu=1;
        }
 
//Si estado es 1 y las teclas pulsadas coinciden con la contraseña guardada en la memoria eeprom     accede al menu

         else if ((cnt<3) && (strcmp (Ingresar_Contrasena_Adm, Ingresar_Contrasena)==0) && (Estado == 1)){
                    Menu=1;
         }

          //Si ninguna de las contraseña es correcta muestra el mensaje incorrecto
          else{ 
                cnt++;
                lcd.clear(); 
                lcd.setCursor(2,1);lcd.print("WRONG");     
                delay(100);
                goto erase;                                                 //------------------------------------Goto
                
           }
                                        
            //Si el usuario ingreso mal 3 veces la contraseña muestra el mensaje
             
            if(cnt==3){ 
                cnt=0; 
                lcd.clear(); //Limpia pantalla
                lcd.setCursor(4,2);lcd.print("PELIGRO");     //Imprime en la LCD
                digitalWrite(Peligro, HIGH);
                delay(1000);
                digitalWrite(Peligro, LOW); 
             }

             //---------------------------Menu del admnistrador-----------------------------
                                         
              if(Menu==1){
                    lcd.clear();  //Limpia pantalla
                    lcd.setCursor(1,0);lcd.print("1. Ingresar");      //Imprime en la LCD
                    lcd.setCursor(1,2);lcd.print("2. Usuarios");      //Imprime en la LCD
                    lcd.setCursor(1,3);lcd.print("3. Cambiar Pass");   //Imprime en la LCD
                    delay(100);

            }

  }


}

use two cats, the first to clear the display

erase:                                                      //------------------------------------Goto erase
lcd.clear();//Limpia Pantalla
lcd.setCursor(1,0);lcd.print("Administrador");     //Imprime en la LCD
lcd.setCursor(1,1);lcd.print("enter Pass");     //Imprime en la LCD
                                   


for( i=0; i < sizeof(Ingresar_Contrasena); i++){ 

     kp = Teclado (); 
     Ingresar_Contrasena[i]=kp;      
                                            
    if(Ingresar_Contrasena[i]=='#'){ 
              Ingresar_Contrasena[i] = '\0';  
              break; 
    }
                                        
     else{ //Si presiona * borra pantalla 
           if(Ingresar_Contrasena[i]=='*'){
                  goto erase;                                             //------------------------------------Goto
           }
    }
                                        

     if(i == (sizeof(Ingresar_Contrasena)- 1)){
           i--;
     }

     lcd.setCursor(3+i,3); lcd.print('*'); 
 }

The second is for when you show the word "wrong" on the LCD, return to enter the password

 else{ 
       cnt++;
      lcd.clear(); 
      lcd.setCursor(2,1);lcd.print("WRONG");     
      delay(100);
      goto erase;                                                 //------------------------------------Goto
                
}

Thank you very much, greetings