|
|
View previous topic :: View next topic |
Author |
Message |
mesuty Guest
|
menu system for LCD |
Posted: Wed Jul 20, 2005 8:13 am |
|
|
Hi friends;
I inspected the existing codes in the forum. My problem is to implement a menu system on a 2 line LCD. I have 4 buttons on circuit. By pressing two predefined buttons , the menu must appear. Menu has nearly 50 sub items in 4 sub groups. Most of the sub items deals with entering an float number through those 4 keys.
any kind of idea / help is appreciated.
Note : I inspected the function pointer based LCD algorithm , though could not apply to the problem. |
|
|
Neutone
Joined: 08 Sep 2003 Posts: 839 Location: Houston
|
|
Posted: Wed Jul 20, 2005 8:31 am |
|
|
I like the simple method. Use the up down keys to select menu items. and the left right keys to increment or decrement. The trick is to inc/dec on a fixed time interval as the key is held down and increase the amount of the inc/dec while the key is pressed. Use one line to display the paramater name and the other paramater value. While this does mean scrolling through all the menu items you dont need to adjust its very simple and eazy to understand. It's also simple to explane to a new user where sub-menus are more dificult. |
|
|
Salenko
Joined: 08 Sep 2008 Posts: 84
|
|
Posted: Sun Nov 02, 2008 12:07 pm |
|
|
Neutone wrote: | I like the simple method. Use the up down keys to select menu items. and the left right keys to increment or decrement. The trick is to inc/dec on a fixed time interval as the key is held down and increase the amount of the inc/dec while the key is pressed. Use one line to display the paramater name and the other paramater value. While this does mean scrolling through all the menu items you dont need to adjust its very simple and eazy to understand. It's also simple to explane to a new user where sub-menus are more dificult. |
hi Neutone,
I´m nearly in the same situation, I have to display 4 lines in my Menu ,I have a 2 lines LCD, and when I use my code (below), the lines are over written .
Code: |
lcd_putc("1-CHANGE A");
lcd_gotoxy(1,2);
lcd_putc("2-CHANGE B");
lcd_gotoxy(1,3);
lcd_putc("3-CHANGE C");
lcd_gotoxy(1,4);
lcd_putc("4-QUIT"); |
I changed
with
but the result is the same, what should I do to display the 4 lines in my 2-lines LCD ,(I mean the LCD will be as a window to my Menu, then I would be able to scroll it)
thanks for any help. |
|
|
Ttelmah Guest
|
|
Posted: Mon Nov 03, 2008 5:26 am |
|
|
Code: |
int8 menu(int8 max) {
//Routine to toggle between two displayed prompts, and allow one to be
//selected. Returns selected number.
int1 flag;
int8 selected;
int8 display_from;
int1 toggle;
//Start at the top of the list
selected=display_from=0;
toggle=true;
flag=true;
//Use zero relative for maximum
max--;
sys_tick=0;
LCD_PUTC('\f');
//Wait for key to be released
while (ENTER==0) ;
while (flag) {
while (sys_tick) ;
sys_tick=1;
if (toggle) {
LCD_GOTOXY(1,1);
printf(LCD_PUTC,"%s",&prompt[display_from][0]);
LCD_GOTOXY(1,2);
printf(LCD_PUTC,"%s",&prompt[display_from+1][0]);
toggle=false;
}
else {
if (selected==display_from) {
LCD_GOTOXY(1,1);
LCD_PUTC(" ");
LCD_GOTOXY(1,2);
printf(LCD_PUTC,"%s",&prompt[display_from+1][0]);
}
else {
LCD_GOTOXY(1,1);
printf(LCD_PUTC,"%s",&prompt[display_from][0]);
LCD_GOTOXY(1,2);
LCD_PUTC(" ");
}
toggle=true;
}
if (UP==0) {
if (selected>0) --selected;
if (selected<display_from) --display_from;
}
if (DOWN==0) {
if (selected<max) ++selected;
if (selected>(display_from+1)) ++display_from;
}
if (ENTER==0) flag=false;
}
return selected;
}
|
This is cut directly out of a project of mine, and requires several things.
First, there has to be an interrupt driven 'clock' running, which clears 'sys_tick' at intervals. On my code, it is about 2/3rd second.
Second three keys, called 'UP', 'DOWN', and 'ENTER', which pull their inputs low, when pushed. The bit defines for these need to be present. If you are using 'standard_io', then you will need to change the tests for these, to use 'input_bit', rather than just reading them.
An array of text 'labels' for the lines, called 'prompt'. In my case defined as:
char prompt[6][17];
You load this with the menu lines you want, so:
Code: |
strcpy(&prompt[0][0],"FIRST MENU ");
strcpy(&prompt[1][0],"SECOND MENU ");
strcpy(&prompt[2][0],"THIRD MENU");
switch(menu(3)) {
|
and call the 'menu' function, with the number of entries to use (as shown in the switch above - three for the example shown). The function returns the line selected. Remember 16 characters per entry max, and 6 entries max with the array as shown.
The display starts showing the top two entries, with the upper one flashing as the speed determined by the interrupt already mentioned. 'down', flashes the second line'. Hit down again, and the next two lines are displayed, with the bottom one flashing. Whichever line is flashing when the 'enter' key is pushed, is the number returned.
Hopefully it gives you some ideas.
Best Wishes |
|
|
Salenko
Joined: 08 Sep 2008 Posts: 84
|
|
Posted: Mon Nov 03, 2008 2:21 pm |
|
|
hi,
thanks would be light to express my gratitude Mr Ttelmah, in two words : great person you are.
Quote: |
Second three keys, called 'UP', 'DOWN', and 'ENTER', which pull their inputs low, when pushed. The bit defines for these need to be present. If you are using 'standard_io', then you will need to change the tests for these, to use 'input_bit', rather than just reading them. |
I assume that you are using FAST_IO(),
I made a small program to test the code (below), I got this error
Quote: |
Not enough RAM for all variables
|
so I reduced prompt[6][17] to prompt[6][16] and the program was compiled without errors (but with warnings of conditions always false).
Code: | #include <16F876.h>
#fuses XT, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock = 20000000)
#use rs232 (baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,ERRORS,bits=8)
#include "flex_lcd.c"
#byte PortB = 6
#use FAST_IO(B)
//=====pins configuration==========
#define UP PIN_B5
#define DOWN PIN_B7
#define ENTER PIN_B6
//========Variables=======
int1 sys_tick; //bit
char prompt[6][16];
//=======TIMER==========
#int_timer0
void timer0_isr ( )
{
set_timer1(69);
sys_tick=0;
}
//=============Procedures==============
void initialisation()
{
lcd_init();
lcd_putc("READY...\@");
}
int8 menu(int8 max) {
//Routine to toggle between two displayed prompts, and allow one to be
//selected. Returns selected number.
int1 flag;
int8 selected;
int8 display_from;
int1 toggle;
//Start at the top of the list
selected=display_from=0;
toggle=true;
flag=true;
//Use zero relative for maximum
max--;
sys_tick=0;
LCD_PUTC('\f');
//Wait for key to be released
while (ENTER==0) ;
while (flag) {
while (sys_tick) ;
sys_tick=1;
if (toggle) {
LCD_GOTOXY(1,1);
printf(LCD_PUTC,"%s",&prompt[display_from][0]);
LCD_GOTOXY(1,2);
printf(LCD_PUTC,"%s",&prompt[display_from+1][0]);
toggle=false;
}
else {
if (selected==display_from) {
LCD_GOTOXY(1,1);
LCD_PUTC(" ");
LCD_GOTOXY(1,2);
printf(LCD_PUTC,"%s",&prompt[display_from+1][0]);
}
else {
LCD_GOTOXY(1,1);
printf(LCD_PUTC,"%s",&prompt[display_from][0]);
LCD_GOTOXY(1,2);
LCD_PUTC(" ");
}
toggle=true;
}
if (UP==0) {
if (selected>0) --selected;
if (selected<display_from) --display_from;
}
if (DOWN==0) {
if (selected<max) ++selected;
if (selected>(display_from+1)) ++display_from;
}
if (ENTER==0) flag=false;
}
return selected;
}
|
the main:
Code: |
//=========PROGRAM============
void main()
{
//char cb;
set_tris_b(0xE0);
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_OFF);
setup_spi(FALSE);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_16);
enable_interrupts(INT_TIMER1);
disable_interrupts(INT_EXT);
disable_interrupts(INT_RB);
initialisation();
strcpy(&prompt[0][0],"FIRST MENU");
strcpy(&prompt[1][0],"SECOND MENU");
strcpy(&prompt[2][0],"THIRD MENU");
while(1)
{
int a;
a=menu(3);
}
}
|
in simulation, I did not get flashing lines and scrolling menu, I just got those fixed two lines.
Last edited by Salenko on Mon Nov 03, 2008 11:52 pm; edited 1 time in total |
|
|
Ttelmah Guest
|
|
Posted: Mon Nov 03, 2008 4:07 pm |
|
|
You are missing the point about the note about the pins.
If you are using the standard pin defines, you need to use the CCS input instructions, not just defines for the pin numbers.
You could (for instance), do this:
Code: |
#define UP input_bit(PIN_B5)
#define DOWN input_bit(PIN_B7)
#define ENTER input_bit(PIN_B6)
|
Otherwise, the defines need to be _bit_ defines like:
Code: |
#ifdef __PCH__
#byte PORTB=0xF81
#else
#byte PORTB=0x6
#endif
#bit UP=PORTB.5
#bit DOWN=PORTB.7
#bit ENTER=PORTB.6
|
The pin numbers themselves will never equal zero, which is why the warnings...
With the bit defines, you need to either just set the TRIS before calling the function, or use FAST_IO.
Beware of going down to 16 characters per row in the array. remember that a 16 character string needs 17 characters. Reduce the number of rows, unless you need this many in the menu.
You are interrupting on timer1, but programming up timer0?.
I'd suggest:
Code: |
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_8);
enable_interrupts(INT_TIMER0);
//Will give just over half second for the tick.
#int_timer0
void timer0_isr ( ) {
sys_tick=0;
}
|
I actually use a number for sys_tick, in my own code, since I can program timeout's for lots of other code using it. However as shown should be fine.
Best Wishes |
|
|
Salenko
Joined: 08 Sep 2008 Posts: 84
|
|
Posted: Tue Nov 04, 2008 8:16 am |
|
|
hi Ttelmah, thank you for answering me again,
I've made the following changements/corrections:
Code: |
#define UP input_state(PIN_B5) //*
#define DOWN input_state(PIN_B7)
#define ENTER input_state(PIN_B6)
main()
{
set_tris_b(0xE0);
}
|
*:I did not use the input_bit() function cause it is not defined in my compiler (PCM 4.057).
Quote: |
Beware of going down to 16 characters per row in the array. remember that a 16 character string needs 17 characters. Reduce the number of rows, unless you need this many in the menu.
|
I did so:
Code: | char prompt[5][17]; |
should I make a changement in your code if I have to add another Menu line, (for instance,FOURTH MENU) in addition to adding :
Code: | strcpy(&prompt[3][0],"FOURTH MENU"); |
setting timer1 insted of timer0 was a careless mistake, this will give 600ms for the tick, here is the correct timer isr:
Code: |
#int_timer0
void timer0_isr ( )
{
set_timer0(69);
sys_tick=0;
}
|
Code: |
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_8);
enable_interrupts(INT_TIMER0);
//Will give just over half second for the tick.
#int_timer0
void timer0_isr ( ) {
sys_tick=0;
}
|
by the way, I'd like to know, how the interruption time is set in your code without the set_timer0() in the routine ?
when simulating, every line below the flashing line has a curser moving through it (for instance, FIRST MENU and SECOND MENU in the beginning), I don't know from where this came ? , did you get this ?
last question:
how should I deal with this code if I like to have a sub menu when I select one of the lines (and get an QUIT on it to return to the main Menu).
just an idea ...
and thank you a lot in advance. |
|
|
crystal_lattice
Joined: 13 Jun 2006 Posts: 164
|
LCD MENU SYTEM |
Posted: Wed Nov 05, 2008 7:17 am |
|
|
i've just presented my project yesterday (after completing a 3hour examination... and more than a month's worth of agonising documentation...) and was thinking to post my version of a LCD menu system in the code section in the near future.
I used the 16F886 as the touch key pad interface and this communicates with a 18LF4620 which is running the LCD menu. The keypad only had 4 buttons, UP,DOWN, ENTER and ESCAPE.
I did not have to enter any values but it enabled me to execute various functions like a calibration sequence and it also enables the user to adjust the date/time of the RTC using the UP/DOWN arrows. The whole menu was designed around a switch statement "state machine" and contained several sub menus.
During the next few days/week(s) i will try and strip it down and include a useful demo which i will post in the code section. It is not the most elegant menu system, but i gets the job done and is very simple to maintain. |
|
|
Salenko
Joined: 08 Sep 2008 Posts: 84
|
Re: LCD MENU SYTEM |
Posted: Thu Nov 06, 2008 1:08 am |
|
|
crystal_lattice wrote: | i've just presented my project yesterday (after completing a 3hour examination... and more than a month's worth of agonising documentation...) and was thinking to post my version of a LCD menu system in the code section in the near future.
I used the 16F886 as the touch key pad interface and this communicates with a 18LF4620 which is running the LCD menu. The keypad only had 4 buttons, UP,DOWN, ENTER and ESCAPE.
I did not have to enter any values but it enabled me to execute various functions like a calibration sequence and it also enables the user to adjust the date/time of the RTC using the UP/DOWN arrows. The whole menu was designed around a switch statement "state machine" and contained several sub menus.
During the next few days/week(s) i will try and strip it down and include a useful demo which i will post in the code section. It is not the most elegant menu system, but i gets the job done and is very simple to maintain. |
thanks
you're welcome. |
|
|
Ttelmah Guest
|
|
Posted: Thu Nov 06, 2008 3:50 am |
|
|
As a comment 'back' to the question about interrupt time, I'm just letting the timer 'free run'.
Timers interrupt whenever they 'wrap' at the end of their count, back to zero. You can set a timer 'to' a value, to accelerate this, but unless you 'need' an exact time interval, you can just use the ntural wrap.
So, in the example, the timer is a 16bit timer (wraps every 65536 counts), fed off the prescaler of /8, which counts in Fosc/4 intervals. So the timer will interrupt every:
(4000000)/(4*8*65536)times per second
1.907times per second. Just over half a second intervals.
In fact, setting timers 'to' values, is always dangerous. The problem is that if the timer is being fed from a clock faster than perhaps a few dozen instruction times, there is always the potential for the clock to have already counted some cycles, before you reach the interrupt routine. Hence timings _will_ be inaccurate. Alternative is to read the timer, and add an offset to the value. Better, but still loses any counts that happen between the read, and the write. Also, on most timers, the prescaler is reset, when it's value is written, leading to another error...
Generally then, I'll always let timers free run, or use the timer2, which on the bigger PICs, has a hardware reset.
Best Wishes |
|
|
soulraven
Joined: 08 Feb 2009 Posts: 72 Location: campulung muscel
|
|
Posted: Mon Apr 06, 2009 10:04 am |
|
|
i have a problem with the code.....
Code: | *** Error 28 "main.c" Line 27(28,29): Expecting an identifier
*** Error 43 "main.c" Line 27(39,40): Expecting a declaration
*** Error 43 "main.c" Line 27(39,40): Expecting a declaration
*** Error 43 "main.c" Line 27(40,41): Expecting a declaration
*** Error 28 "main.c" Line 28(29,30): Expecting an identifier
*** Error 43 "main.c" Line 28(30,31): Expecting a declaration
6 Errors, 0 Warnings.
Halting build on first failure as requested.
BUILD FAILED: Mon Apr 06 18:50:32 2009
|
http://s4.transfer.ro/storage/Calculator-4a91f.zip |
|
|
colesha
Joined: 09 Jan 2012 Posts: 45
|
|
Posted: Mon Feb 10, 2020 1:53 pm |
|
|
Ttelmah wrote: | You are missing the point about the note about the pins.
If you are using the standard pin defines, you need to use the CCS input instructions, not just defines for the pin numbers.
You could (for instance), do this:
Code: |
#define UP input_bit(PIN_B5)
#define DOWN input_bit(PIN_B7)
#define ENTER input_bit(PIN_B6)
|
Otherwise, the defines need to be _bit_ defines like:
Code: |
#ifdef __PCH__
#byte PORTB=0xF81
#else
#byte PORTB=0x6
#endif
#bit UP=PORTB.5
#bit DOWN=PORTB.7
#bit ENTER=PORTB.6
|
The pin numbers themselves will never equal zero, which is why the warnings...
With the bit defines, you need to either just set the TRIS before calling the function, or use FAST_IO.
Beware of going down to 16 characters per row in the array. remember that a 16 character string needs 17 characters. Reduce the number of rows, unless you need this many in the menu.
You are interrupting on timer1, but programming up timer0?.
I'd suggest:
Code: |
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_8);
enable_interrupts(INT_TIMER0);
//Will give just over half second for the tick.
#int_timer0
void timer0_isr ( ) {
sys_tick=0;
}
|
I actually use a number for sys_tick, in my own code, since I can program timeout's for lots of other code using it. However as shown should be fine.
Best Wishes |
Hello, kindly help me with working code for a menu with up/down, enter and esc push buttons .
Thanks |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|