*******
Short intro English
Here you can find a method to implement a menu on an LCD display driven by a microcontroller (Arduino board, PIC microcontroller etc).
Idea is simple: you have the top menus, under a top menu you have sub-menus (parent menu with children menus), sub-menus can have sub-sub-menus and so on. I advise to put you menu structure on a paper to understand the exact structure of the menus, sub-menus, sub-sub-menus. It will look like an oriented graph.
I put the menu structure on a matrix, here is an example:
**1, 8, 11, 1, 0, 0
-this is element 1
-is a parent menu
-this one has sub-menus starting from element 8 ending at element 11
**14, 100, 100, 2, 0, 0
-this is element 14
-is a sub-menu
-has no sub-menus
On the bottom of this post you can find the source code commented on English, the variable names are still in Romanian.
*******
O parte dintre aplicatiile cu microcontroler au nevoie de o metoda de interactiune cu utilizatorul, aici ma refer la ceea ce vrea sa ne spuna echipamentul: fie simple LEDuri, fie ecrane cu cristale lichide (LCD). Aceste LCD-uri sunt fie LCDuri grafice (o matrice de puncte) ori sunt LCDuri cu rinduri de caractere.
LCDurile cu rinduri cu caractere pot fi de 2 rinduri x 16 caractere (2 x 16), 2 x 20, 4 x 16, 4 x 20 etc. Toate aceste LCDuri functioneaza dupa acelasi principiu: au 8 linii de date (D0..D7), au linii de control (RS, RW, E). Pe aceste linii se dau datele care sunt ulterior interpretate de un chipset (de obicei compatibil Hitachi HD4470).
Ecran cu cristale lichide (Liquid Crystals Display - LCD)
cu 2 rinduri de cate 16 caractere si lumina de fundal albastra
Datele trimise catre LCD sunt traduse in caractere pe ecran (un caracter este format din puncte: 5 puncte x 8 puncte). Se pot crea si caractere speciale definite de utilizator.
Asadar pentru afisare trebuie sa specificam rindul, numarul caracterului din rind si ce vrem sa afisam. Este o solutie convenabila de afisare, dar fiindca se utilizeaza un microcotroler, uneori un LCD da bataie de cap.
Problema mea a fost sa realizez o aplicatie cu microcontroler, butoane si LCD 2x16 si care sa ofere un meniu de selectie al optiunilor. Am inceput sa sap pe Internet in ideea ca altii inaintea mea au avut aceeasi problema si deci solutia e simpla si rafinata deja, nu are sens sa inventez roata. Totusi nu este chiar asa, caci la microcontrolere solutiile sunt oarecum specifice aplicatiei date. Am gasit o prezentare facuta de un domn care a realizat un meniu foarte complex, avea vreo 70 de elemente, elemente care se activau daca in prealabil activai un meniu sau daca erai in modul de service, avea meniu in mai multe limbi straine - prea complex pentru mine si pentru aplicatia mea. In fine, am ajuns sa creez un mic Frankenstein, dar functioneaza bine :)
Placa de dezvoltare cu LCD si PIC18F4550
Schema electrica - cu mentiunea ca push button-anele sunt
legateastfel: RB0, RB1, RB4 si RB5
legateastfel: RB0, RB1, RB4 si RB5
Asadar pentru simplitate sa consideram ca avem 5 meniuri principale: Meniu1 .. Meniu5, iar primele 3 meniuri (Meniu 1 .. Meniu 3) au sub-meniuri:
Structura meniului
Pentru a defini aceste elemente de meniu am ales sa utilizez o matrice, fiecare linie defineste un element de meniu astfel:
Descrierea unui element din meniu
In aceasta matrice, primele 5 linii sunt pentru elementele de meniu, apoi urmatoarele linii reprezinta sub-meniurile. In cazul nostru avem 5 elemente de meniu si 11 elemente de sub-meniu, deci avem 5+11 = 16 linii in matrice ori 16 elemente de meniu.
Explicatii:
**nr element meniu: in cazul nostru nr element meniu este intre 0 si 15 (caci avem 16 elemente de meniu)
**primul sub-element: daca elementul are sub-elemente, indica numarul primului element; daca valoarea este 100, atunci nu are sub-elemente
**ultimul sub-element: daca elementul are sub-elemente, indica numarul ultimului element; daca valoarea este 100, atunci nu are sub-elemente
**nivel: nivelul din care provine elementul; aici este 1 pt nivelul meniu si 2 pentru nivelul sub-meniu
**folosinta ulterioara: ultimile pozitii sunt pentru aplicatii ulterioara (meniu activ, meniu activ doar in mod service etc)
Exemplu:
**1, 8, 11, 1, 0, 0
este elementul 1 de meniu si are sub-meniuri care incep de la elementul 8 si pana la elementul 11
**14, 100, 100, 2, 0, 0
este elementul 14, este sub-meniu, nu mai are sub-elemente
Acum urmeaza sa vedem cum parcurgem aceste elemente de meniu: fie folosim 3 butoane (sus, jos, intra meniu) si un element de meniu care sa ne intoarca de unde am pornit, fie folosim 4 butoane (sus, jos, intra meniu, iesire meniu). Din generozitate am folosit 4 butoane :)
Partea cu butoanele: 3 pe placa si unul la rotary encoder (se apasa axul)
Acum problema se rezuma la a parcurge matricea din imagine si de a afisa textul corespunzator pe cele 2 linii ale ecranului. Mai e un amanunt: avem si un cursor care poate fi ori pe linia 1 ori pe linia 2 a ecranului LCD.
Din start folosim ceea ce stim: avem meniuri de la elementele 0 la 4 (5 meniuri), avem sub-meniuri de la elementele 5 la 15. Daca alegem sa intram intr-un meniu, trebuie sa salvam undeva contextul: meniul din care am venit, starea ecranului LCD (ce era pe rindul 1 si 2 si unde era cursorul). Acest lucruri fac metoda scalabila la un numar mare de meniuri si sub-meniuri, inclusiv sub-sub-meniuri. Totul depinde de capacitatile microcontrolerului, memoria este limitata.
Iata ce a iesit (cod mikroC pentru PIC18F4550):
1: /*LCD menu on LCD 2 rows by 16 characters
2: buttons are on: RD7, RD4, RD3 si RD2, when press, logical 1 on pin
3: rotary encoder on: RD5, RD6
4: LCD lines: RB2..RB7
5: LED: RC0, RD0, RD1, to turn on a LED, set logical 0
6: modified on 2013.02.10
7: */
8:
9: int nr_element, temp_int, rindLCD, MsgLCD1, MsgLCD2;
10: int start_element, stop_element, element_activ, meniu_parinte;
11:
12: // define LCD lines
13: sbit LCD_RS at RB2_bit;
14: sbit LCD_EN at RB3_bit;
15: sbit LCD_D4 at RB4_bit;
16: sbit LCD_D5 at RB5_bit;
17: sbit LCD_D6 at RB6_bit;
18: sbit LCD_D7 at RB7_bit;
19:
20: sbit LCD_RS_Direction at TRISB2_bit;
21: sbit LCD_EN_Direction at TRISB3_bit;
22: sbit LCD_D4_Direction at TRISB4_bit;
23: sbit LCD_D5_Direction at TRISB5_bit;
24: sbit LCD_D6_Direction at TRISB6_bit;
25: sbit LCD_D7_Direction at TRISB7_bit;
26: // end LCD lines definitions
27:
28: int m_Meniu[16][6] = {{0,5,7,1,0,0}, //menu element Men1, this one has 3 sub-menus (3 children)
29: {1,8,11,1,0,0}, //element meniu Men2 are 4 copii sub meniu
30: {2,12,15,1,0,0}, //element meniu Men3 are 4 copii sub meniu
31: {3,100,100,1,0,0}, //element meniu Men4 nu are copii sub meniu
32: {4,100,100,1,0,0}, //element meniu Men5 nu are copii sub meniu
33: {5,100,100,2,0,0}, //sub menu 1 from Men1
34: {6,100,100,2,0,0}, //sub meniu 2 de la Men1
35: {7,100,100,2,0,0}, //sub meniu 3 de la Men1 ***
36: {8,100,100,2,0,0}, //sub meniu 1 de la Men2
37: {9,100,100,2,0,0}, //sub meniu 2 de la Men2
38: {10,100,100,2,0,0}, //sub meniu 3 de la Men2
39: {11,100,100,2,0}, //sub meniu 4 de la Men2 ***
40: {12,100,100,2,0,0}, //sub meniu 1 de la Men3
41: {13,100,100,2,0,0}, //sub meniu 2 de la Men3
42: {14,100,100,2,0,0}, //sub meniu 3 de la Men4
43: {15,100,100,2,0,0}}; //sub meniu 4 de la Men5
44:
45: // {nr element meniu} {start }
46:
47: //sub-menus have no sub-sub menus
48: //100, 100 menas that there are no sub-sub menus
49:
50: int m_Nivel[8] = {0, 0, 0, 0, 0, 0, 0, 0}; //this is to save the context before going down on the menu
51:
52: char *Mesaj_LCD[16] = {"Men1 ",
53: "Men2 ",
54: "Men3 ",
55: "Men4 ",
56: "Men5 ", //element 4
57: "SubMen1_1 ",
58: "SubMen1_2 ",
59: "SubMen1_3 ", //el 7
60: "SubMen2_1 ",
61: "SubMen2_2 ",
62: "SubMen2_3 ",
63: "SubMen2_4 ", //11
64: "SubMen3_1 ",
65: "SubMen3_2 ",
66: "SubMen3_3 ",
67: "SubMen3_4 "}; //el 15 Mesaj_LCD[0][15]
68:
69:
70: void main() {
71:
72: ADCON1 |= 0x0F; // Configure AN pins as digital
73: CMCON |= 7; // Disable comparators
74:
75: TRISD0_bit = 0; // set direction to be output for LED RD0
76: RD0_bit = 1; // Turn OFF LED on PORTD0
77:
78: TRISD2_bit = 1; // set direction to be input button RD2
79: TRISD3_bit = 1; // set direction to be input button RD3
80: TRISD4_bit = 1; // set direction to be input button RD4
81: TRISD7_bit = 1; // set direction to be input button RD7
82:
83:
84: nr_element=0; //row index
85: element_activ = 0;
86: //*******************************************
87: //here it was pressed the MENU button
88: //I press the button for the menu, I go down on that menu and I have on LCD on the first row menu number 1 (default [0][5])
89: //now I wait to press up, down, menu in, menu out
90: rindLCD = 1; // this is to know the exact row we are, we can be on row 1 or row 2
91: //this will be used to know where to set the LCD display cursor (which menu / message on the LCD display is selected)
92: //by default, the LCD cursor is on row 1, on menu 1
93: start_element = m_Meniu[nr_element][0];
94: stop_element = m_Meniu[4][0];
95:
96: MsgLCD1 = m_Meniu[nr_element][0]; //message on row 1 on LCD, default is menu 1 - this is telling me what to display on row 1 on the LCD display
97: MsgLCD2 = m_Meniu[nr_element + 1][0]; //message on row 2 on LCD, default is menu 2 (next under menu is showing me what to display on row 2 on the LCD display
98:
99: Lcd_Init(); // Initialize LCD
100: Lcd_Cmd(_LCD_CLEAR); // Clear display
101: Lcd_Cmd(_LCD_CURSOR_OFF); // Cursor off
102:
103: //here starts the menu sequence; I poll which button was pressed and I took a certain action
104: do{
105:
106: ///*************************************
107: if(Button(&PORTD, 2, 50, 1)){ //if <down> button was pressed, I have to go to the next menu
108:
109: if(rindLCD<2){ //I check which row is the cursor on the LCD display - can be 1 or 2
110: rindLCD++; //if I am not on row 2, I go on row (got to row 2)
111: element_activ++;
112: //I check where is the position on the sub-menu / menu
113: if(element_activ > stop_element){element_activ = start_element;}
114: nr_element++;
115: if(nr_element > stop_element){nr_element = start_element;}
116: }
117: else{
118: rindLCD = 2; //if cursor is on LCD row number 2, then stay there
119: element_activ++;
120: nr_element++;
121:
122: if(nr_element>stop_element){
123: element_activ = m_Meniu[start_element][0];
124: nr_element = m_Meniu[start_element][0];
125: MsgLCD1 = MsgLCD2;
126: MsgLCD2 = nr_element;
127: }
128: else{
129: MsgLCD1 = MsgLCD2;
130: MsgLCD2 = nr_element;
131: }
132: }
133: }
134:
135: //******************************************
136: if(Button(&PORTD, 4, 50, 1)){ //if button <up> is pressed, then go to the previous menu
137: if(rindLCD>1){ //check which row is the cursor on the LCD display
138: rindLCD--;
139: element_activ--;
140: if(element_activ < start_element){element_activ = stop_element;}
141: nr_element--;
142: if(nr_element < start_element){nr_element = stop_element;}
143: }
144:
145: else{
146: rindLCD = 1;
147: element_activ--;
148: nr_element--;
149:
150: if(nr_element<start_element){
151: element_activ = m_Meniu[stop_element][0];
152: nr_element = m_Meniu[stop_element][0];
153: MsgLCD2 = MsgLCD1;
154: MsgLCD1 = m_Meniu[nr_element][0];}
155: else{
156: MsgLCD2 = MsgLCD1;
157: MsgLCD1 = m_Meniu[nr_element][0];}
158: }
159: }
160:
161:
162: //*****************************************************
163: if(Button(&PORTD, 7, 50, 1)){ //if button <enter> RD7 was pressed
164: if(m_Meniu[nr_element][1]!=100){ //check if the menu has sub-menus
165: //if yes, I have to save the context
166: m_Nivel[0] = nr_element; //this is the parent menu for the sub-menu
167: m_Nivel[1] = rindLCD; //row on LCD for the parent menu
168:
169: m_Nivel[2] = MsgLCD1; //message on row 1 on LCD display parent menu
170: m_Nivel[3] = MsgLCD2; //message on row 2 on LCD display parent menu
171:
172: m_Nivel[4] = m_Meniu[nr_element][3]; //level of parent element from menu element matrix (1 means menu)
173: m_Nivel[5] = m_Meniu[0][0]; //here is the start element of parent menu
174: //end of context saving
175:
176: rindLCD = 1;
177:
178: //here I load the sub-menu (child menu) of the parent menu
179: start_element = m_Meniu[nr_element][1];
180: stop_element = m_Meniu[nr_element][2];
181:
182: temp_int = m_Meniu[start_element][3];//here is the current child level (2 means sub-menu)
183: m_Nivel[6] = temp_int;
184:
185: nr_element = start_element;
186:
187: MsgLCD1 = m_Meniu[start_element][0];
188: MsgLCD2 = m_Meniu[start_element+1][0];}
189: }
190:
191: // *****************************
192: //here we pressed the exit menu
193: if(Button(&PORTD, 3, 50, 1)){ // if button <out> RD3 was pressed
194:
195: if(m_Nivel[4]==0){ //check if parent menu is a menu
196: //if it is a menu, then I write on LCD that there are no other upper menus
197: Lcd_Out(1, 1, "There are no");
198: Lcd_Out(2, 1, "other menus !");
199: Delay_ms(1500);
200: Lcd_Cmd(_LCD_CLEAR);}
201:
202: else{ //if we are on a sub-menu and need to go up one level,
203: //I have to load the context I was before entering that menu
204: nr_element = m_Nivel[0];
205: m_Nivel[0] = 0;
206:
207: rindLCD = m_Nivel[1];
208: m_Nivel[1] = 0;
209:
210: MsgLCD1 = m_Nivel[2];
211: m_Nivel[2] = 0;
212:
213: MsgLCD2 = m_Nivel[3];
214: m_Nivel[3] = 0;
215:
216: meniu_parinte = m_Nivel[4];
217: m_Nivel[4] = 0;
218: start_element = m_Nivel[5]; //here is the start level of the parent menu
219: stop_element = 4; //here is the stop level of the parent menu
220: }
221: }
222: //*****************************************************************
223:
224: //here is where the elements are displayed on the LCD display and the active element (cursor)
225: if(rindLCD == 1){Lcd_Out(2, 1, " ");
226: Lcd_Out(1, 1, ">");} //if active row is 1, then display character ">" on row 1
227: if(rindLCD == 2){Lcd_Out(1, 1, " ");
228: Lcd_Out(2, 1, ">");} //if active row is 2, then display character ">" on row 2
229:
230: Lcd_Out(1, 2, Mesaj_LCD[MsgLCD1]); //write correct message on row 1
231: Delay_ms(50);
232: Lcd_Out(2, 2, Mesaj_LCD[MsgLCD2]); //write correct message on row 2
233: Delay_ms(50);
234:
235:
236: switch(element_activ){
237: case 0: {; break;} //perform action X
238: case 1: break; //perform action Y
239: case 2: break; //perform action Z
240: case 3: break; //perform action aX
241: case 4: break;
242: case 5: break;
243: case 6: break;
244: case 7: break;
245: case 8: break;
246: case 9: break;
247: case 10: break;
248: case 11: break;
249: case 12: break;
250: case 13: break;
251: case 14: break;
252: case 15: break;}
253:
254: }while(1);
255: }
Aici este un scurt clip video despre acest meniu in actiune:
PS: in programare primul element este considerat cel cu numarul 0, spre exemplu numarul maxim de locatii pe 8 biti este de 256 de locatii, insa prima locatie este locatia 0, iar ultima locatie este locatia 255, deci nu este de la 1 la 256, ci de la 0 la 255.
Alt exemplu: 8 biti inseamna bitii 0, 1, 2, 3, 4, 5, 6, 7. Asadar mare atentie la acest amanunt caci poate da mari batai de cap, codul sa fie perfect, dar sa nu de-a rezultatul asteptat.
*******************
Source code (mikroC) with comments on English
/*LCD menu on LCD 2 rows by 16 characters
buttons are on: RD7, RD4, RD3 si RD2, when press, logical 1 on pin
rotary encoder on: RD5, RD6
LCD lines: RB2..RB7
LED: RC0, RD0, RD1, to turn on a LED, set logical 0
modified on 2013.02.10
*/
int nr_element, temp_int, rindLCD, MsgLCD1, MsgLCD2;
int start_element, stop_element, element_activ, meniu_parinte;
// define LCD lines
sbit LCD_RS at RB2_bit;
sbit LCD_EN at RB3_bit;
sbit LCD_D4 at RB4_bit;
sbit LCD_D5 at RB5_bit;
sbit LCD_D6 at RB6_bit;
sbit LCD_D7 at RB7_bit;
sbit LCD_RS_Direction at TRISB2_bit;
sbit LCD_EN_Direction at TRISB3_bit;
sbit LCD_D4_Direction at TRISB4_bit;
sbit LCD_D5_Direction at TRISB5_bit;
sbit LCD_D6_Direction at TRISB6_bit;
sbit LCD_D7_Direction at TRISB7_bit;
// end LCD lines definitions
int m_Meniu[16][6] = {{0,5,7,1,0,0}, //menu element Men1, this one has 3 sub-menus (3 children)
{1,8,11,1,0,0}, //element meniu Men2 are 4 copii sub meniu
{2,12,15,1,0,0}, //element meniu Men3 are 4 copii sub meniu
{3,100,100,1,0,0}, //element meniu Men4 nu are copii sub meniu
{4,100,100,1,0,0}, //element meniu Men5 nu are copii sub meniu
{5,100,100,2,0,0}, //sub menu 1 from Men1
{6,100,100,2,0,0}, //sub meniu 2 de la Men1
{7,100,100,2,0,0}, //sub meniu 3 de la Men1 ***
{8,100,100,2,0,0}, //sub meniu 1 de la Men2
{9,100,100,2,0,0}, //sub meniu 2 de la Men2
{10,100,100,2,0,0}, //sub meniu 3 de la Men2
{11,100,100,2,0}, //sub meniu 4 de la Men2 ***
{12,100,100,2,0,0}, //sub meniu 1 de la Men3
{13,100,100,2,0,0}, //sub meniu 2 de la Men3
{14,100,100,2,0,0}, //sub meniu 3 de la Men4
{15,100,100,2,0,0}}; //sub meniu 4 de la Men5
// {nr element meniu} {start }
//sub-menus have no sub-sub menus
//100, 100 menas that there are no sub-sub menus
int m_Nivel[8] = {0, 0, 0, 0, 0, 0, 0, 0}; //this is to save the context before going down on the menu
char *Mesaj_LCD[16] = {"Men1 ",
"Men2 ",
"Men3 ",
"Men4 ",
"Men5 ", //element 4
"SubMen1_1 ",
"SubMen1_2 ",
"SubMen1_3 ", //el 7
"SubMen2_1 ",
"SubMen2_2 ",
"SubMen2_3 ",
"SubMen2_4 ", //11
"SubMen3_1 ",
"SubMen3_2 ",
"SubMen3_3 ",
"SubMen3_4 "}; //el 15 Mesaj_LCD[0][15]
void main() {
ADCON1 |= 0x0F; // Configure AN pins as digital
CMCON |= 7; // Disable comparators
TRISD0_bit = 0; // set direction to be output for LED RD0
RD0_bit = 1; // Turn OFF LED on PORTD0
TRISD2_bit = 1; // set direction to be input button RD2
TRISD3_bit = 1; // set direction to be input button RD3
TRISD4_bit = 1; // set direction to be input button RD4
TRISD7_bit = 1; // set direction to be input button RD7
nr_element=0; //row index
element_activ = 0;
//*******************************************
//here it was pressed the MENU button
//I press the button for the menu, I go down on that menu and I have on LCD on the first row menu number 1 (default [0][5])
//now I wait to press up, down, menu in, menu out
rindLCD = 1; // this is to know the exact row we are, we can be on row 1 or row 2
//this will be used to know where to set the LCD display cursor (which menu / message on the LCD display is selected)
//by default, the LCD cursor is on row 1, on menu 1
start_element = m_Meniu[nr_element][0];
stop_element = m_Meniu[4][0];
MsgLCD1 = m_Meniu[nr_element][0]; //message on row 1 on LCD, default is menu 1 - this is telling me what to display on row 1 on the LCD display
MsgLCD2 = m_Meniu[nr_element + 1][0]; //message on row 2 on LCD, default is menu 2 (next under menu is showing me what to display on row 2 on the LCD display
Lcd_Init(); // Initialize LCD
Lcd_Cmd(_LCD_CLEAR); // Clear display
Lcd_Cmd(_LCD_CURSOR_OFF); // Cursor off
//here starts the menu sequence; I poll which button was pressed and I took a certain action
do{
///*************************************
if(Button(&PORTD, 2, 50, 1)){ //if
if(rindLCD<2 -="" 1="" 2="" be="" br="" can="" check="" cursor="" display="" is="" lcd="" nbsp="" on="" or="" row="" the="" which=""> rindLCD++; //if I am not on row 2, I go on row (got to row 2)
element_activ++;
//I check where is the position on the sub-menu / menu
if(element_activ > stop_element){element_activ = start_element;}
nr_element++;
if(nr_element > stop_element){nr_element = start_element;}
}
else{
rindLCD = 2; //if cursor is on LCD row number 2, then stay there
element_activ++;
nr_element++;
if(nr_element>stop_element){
element_activ = m_Meniu[start_element][0];
nr_element = m_Meniu[start_element][0];
MsgLCD1 = MsgLCD2;
MsgLCD2 = nr_element;
}
else{
MsgLCD1 = MsgLCD2;
MsgLCD2 = nr_element;
}
}
}
//******************************************
if(Button(&PORTD, 4, 50, 1)){ //if button
if(rindLCD>1){ //check which row is the cursor on the LCD display
rindLCD--;
element_activ--;
if(element_activ < start_element){element_activ = stop_element;}
nr_element--;
if(nr_element < start_element){nr_element = stop_element;}
}
else{
rindLCD = 1;
element_activ--;
nr_element--;
if(nr_element
nr_element = m_Meniu[stop_element][0];
MsgLCD2 = MsgLCD1;
MsgLCD1 = m_Meniu[nr_element][0];}
else{
MsgLCD2 = MsgLCD1;
MsgLCD1 = m_Meniu[nr_element][0];}
}
}
//*****************************************************
if(Button(&PORTD, 7, 50, 1)){ //if button
if(m_Meniu[nr_element][1]!=100){ //check if the menu has sub-menus
//if yes, I have to save the context
m_Nivel[0] = nr_element; //this is the parent menu for the sub-menu
m_Nivel[1] = rindLCD; //row on LCD for the parent menu
m_Nivel[2] = MsgLCD1; //message on row 1 on LCD display parent menu
m_Nivel[3] = MsgLCD2; //message on row 2 on LCD display parent menu
m_Nivel[4] = m_Meniu[nr_element][3]; //level of parent element from menu element matrix (1 means menu)
m_Nivel[5] = m_Meniu[0][0]; //here is the start element of parent menu
//end of context saving
rindLCD = 1;
//here I load the sub-menu (child menu) of the parent menu
start_element = m_Meniu[nr_element][1];
stop_element = m_Meniu[nr_element][2];
temp_int = m_Meniu[start_element][3];//here is the current child level (2 means sub-menu)
m_Nivel[6] = temp_int;
nr_element = start_element;
MsgLCD1 = m_Meniu[start_element][0];
MsgLCD2 = m_Meniu[start_element+1][0];}
}
// *****************************
//here we pressed the exit menu
if(Button(&PORTD, 3, 50, 1)){ // if button
if(m_Nivel[4]==0){ //check if parent menu is a menu
//if it is a menu, then I write on LCD that there are no other upper menus
Lcd_Out(1, 1, "There are no");
Lcd_Out(2, 1, "other menus !");
Delay_ms(1500);
Lcd_Cmd(_LCD_CLEAR);}
else{ //if we are on a sub-menu and need to go up one level,
//I have to load the context I was before entering that menu
nr_element = m_Nivel[0];
m_Nivel[0] = 0;
rindLCD = m_Nivel[1];
m_Nivel[1] = 0;
MsgLCD1 = m_Nivel[2];
m_Nivel[2] = 0;
MsgLCD2 = m_Nivel[3];
m_Nivel[3] = 0;
meniu_parinte = m_Nivel[4];
m_Nivel[4] = 0;
start_element = m_Nivel[5]; //here is the start level of the parent menu
stop_element = 4; //here is the stop level of the parent menu
}
}
//*****************************************************************
//here is where the elements are displayed on the LCD display and the active element (cursor)
if(rindLCD == 1){Lcd_Out(2, 1, " ");
Lcd_Out(1, 1, ">");} //if active row is 1, then display character ">" on row 1
if(rindLCD == 2){Lcd_Out(1, 1, " ");
Lcd_Out(2, 1, ">");} //if active row is 2, then display character ">" on row 2
Lcd_Out(1, 2, Mesaj_LCD[MsgLCD1]); //write correct message on row 1
Delay_ms(50);
Lcd_Out(2, 2, Mesaj_LCD[MsgLCD2]); //write correct message on row 2
Delay_ms(50);
switch(element_activ){
case 0: {; break;} //perform action X
case 1: break; //perform action Y
case 2: break; //perform action Z
case 3: break; //perform action aX
case 4: break;
case 5: break;
case 6: break;
case 7: break;
case 8: break;
case 9: break;
case 10: break;
case 11: break;
case 12: break;
case 13: break;
case 14: break;
case 15: break;}
}while(1);
}
Multumesc. Excelenta metoda pentru tratarea meniurilor.
RăspundețiȘtergeresalut, ai cam facut risipa de "biscuite" :)
RăspundețiȘtergereif(nr_element element_activ = m_Meniu[stop_element][0]; <--error?
RăspundețiȘtergereFixed, thanks! (strange that copy paste was not working as expected)
Ștergereif(Button(&PORTB, 4, 50, 1)){ //daca am apasat butonul "in sus", trebuie sa //merg la meniul anterior
RăspundețiȘtergere...
...
..
if(nr_element>stop_element){ <---------------------aceasta ar trebui să repara eroarea
element_activ = m_Meniu[start_element][0];
You can ask in English as well, it will be more helpful to understand your advice, thanks!
ȘtergereThere seems to be an error with the UP button.
Ștergereif(Button(&PORTB, 4, 50, 1)){ //daca am apasat butonul "in sus", trebuie sa //merg la meniul anterior
if(rindLCD>1){ //verificam rindul pe ecran
rindLCD--;
element_activ--;
if(element_activ < start_element){element_activ = stop_element;}
nr_element--;
if(nr_element < start_element){nr_element = stop_element;}
}
else{
rindLCD = 1;
element_activ--;
nr_element--;
something wrong here? ----------> if(nr_element element_activ = m_Meniu[stop_element][0]{
nr_element = m_Meniu[stop_element][0];
MsgLCD2 = MsgLCD1;
MsgLCD1 = m_Meniu[nr_element][0];}
else{
MsgLCD2 = MsgLCD1;
MsgLCD1 = m_Meniu[nr_element][0];}
}
}
also:
{11,100,100,2,0}, //sub meniu 4 de la Men2 *** <---- missing an extra '0' ?
It can be, I will look for it, thanks for pointing it out! On the other hand I think that I must change the formatting for the source code to something much more readable. This source code was copy paste from microC IDE, but there are missing things and I don;t know why, compilation of the original was giving a good result and the menu was operational.
ȘtergereCatalin, is there a way to contact you by email without using this comments section?
ȘtergereSure, try this one: simion dot catalin at gmail dot com
Ștergereodată ce este selectat un sub_menu , cum se spune pentru a rula un program ? ( Am traducerea această întrebare din engleză în română )
RăspundețiȘtergereYou can ask in English as well, it will be more helpful to understand your question, thanks!
ȘtergereCould you please provide the code for reading the encoder?
RăspundețiȘtergereDid you think at using the encoder instead of push button when jumping between menus?
I didn't implement yet a rotary encoder, in my application I don't use the encoder, I mean not the rotary part of it. I use only the push button from the rotary encoder. But you can find implementations on the WWW, use Google..
Ștergere