|
|
View previous topic :: View next topic |
Author |
Message |
mvaraujo
Joined: 20 Feb 2004 Posts: 59 Location: Brazil
|
Creating Menus and Submenus |
Posted: Tue May 18, 2004 10:01 am |
|
|
Hi everyone,
I would like to put in discussion an issue that always makes me confused: which is the best way to implement menus and submenus for display in a PIC application?
I usually use a structure of state machines based in some variables like state and substate, whatever, I use the keyboard to create actions of incrementing or decrementing these state variables and then jump from one state to another. These states can be screens with information, a menus with a selection cursor that points to the options, etc.
What do you guys think about this? Does anyone point to other direction that could bring better results? When I talk about better results, I always think about faster code and smaller code.
Thanks in advance!
Marcus |
|
|
Haplo
Joined: 06 Sep 2003 Posts: 659 Location: Sydney, Australia
|
|
Posted: Tue May 18, 2004 5:31 pm |
|
|
Once we had to do a big menu system for a dot-matrix display, under 68HC16. After careful delibration we decided the state machine was the best way to go. It is fast but the code tends to get big. |
|
|
Neutone
Joined: 08 Sep 2003 Posts: 839 Location: Houston
|
|
Posted: Tue May 18, 2004 7:45 pm |
|
|
I would suggest using a state machine with a state for each menu item. Prior to running the current state read and debounce the inputs and set a flag for each input that is active. After running the current state clear all input flags. This keeps the code required for reading inputs at a minimum and keeps the code easy to read. The bigger problem though is going to be displaying text. If you setup a couple buffers that are pushed to your display after running the state you only need those functions once. That also gets you some versitility. Maybe have a flag that when set will cause a temp integer printed to one of the buffers. Then copy your working variable to the temp integer within the state and set the flag. I don't think I have every seen a good example of a menu system posted. |
|
|
mvaraujo
Joined: 20 Feb 2004 Posts: 59 Location: Brazil
|
|
Posted: Wed May 19, 2004 7:28 am |
|
|
I understand what you guys say...
That's the point, the state machine is simple to understand into the code but the code itself gets big.
One issue that is always complicated to handle is that you need substates to each screen if you want to setup variables of your system. For example, I have a menu chain like this in one of the options:
Main screen >> Config >> Clock/Calendar >> Clock Setup Screen
In this clock setup screen (my state #4), the screen should start with hour blinking, so you can set it up (substate #0), then when you accept, it should blink minutes (substate #1), and so on for day of month, month, year. For each substate the keys don't have similiar actions. My keyboard is only four keys (arrows: up, down, left and right). So I have to write code for each substate and it gets amazingly big. It's easy to follow up and understand but it's large.
I'll post the code to show how it's going until now:
Code: | void maq_estados_disp(void)
// maquina de estados provisoria
{
int temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8; // registradores temporarios reservados
switch (estado_display)
{
case 0: // tela padrao
subestado_display = 0; // subestado em 0
temp1 = temperat / 10;
temp2 = temperat - (temp1*10);
printf(disp_store,"SIPIG-A-v2 %03d.%01u",temp1,temp2); // monta o display padrao
if (v_rms < 85 || v_rms > 260 || freq < 45 || freq > 65)
printf(disp_store,"CA fora de faixa");
else
printf(disp_store,"%03lu.%01uV %02u.%01uHz",v_rms,v_rms_dec,freq,freq_dec);
rep_tcl = 0x00; // tcl em modo nao repetitivo para todas teclas
if (buf_tcl.RT == TRUE) // se RT pressionado, avanca estado
estado_display++;
break;
case 1: // selecao de opcao geral
switch (subestado_display)
{
case 0:
case 1:
printf(disp_store,CONFIG_DISP); // constroi o display de selecao
if (subestado_display == 0)
printf(disp_store,CURSOR);
else
printf(disp_store," ");
printf(disp_store,TESTE_DISP);
if (subestado_display == 0)
printf(disp_store," ");
else
printf(disp_store,CURSOR);
if (buf_tcl.LT == TRUE)
{
estado_display--; // se LT pressionado, volta estado
return;
}
if (buf_tcl.DN == TRUE)
{
if (subestado_display < 1) // se subestado dentro dos limites
subestado_display++; // se DN pressionado, avanca subestado
return;
}
if (buf_tcl.UP == TRUE)
{
if (subestado_display > 0) // se subestado dentro dos limites
subestado_display--; // se UP pressionado, avanca subestado
return;
}
if (buf_tcl.RT == TRUE) // se RT pressionado, avanca estado
{
if (subestado_display == 0) // vai para config
{
estado_display=2;
subestado_display=0;
}
else
{
//estado_display=3; // vai para auto-teste
subestado_display=0;
}
return;
}
break;
}
break;
case 2: // selecao de config
switch (subestado_display)
{
case 0:
case 1:
printf(disp_store,LIMIAR); // constroi o display de selecao
if (subestado_display == 0)
printf(disp_store,CURSOR);
else
printf(disp_store," ");
printf(disp_store,RELOGIO);
if (subestado_display == 0)
printf(disp_store," ");
else
printf(disp_store,CURSOR);
break;
case 2:
case 3:
printf(disp_store,COMUNIC); // constroi o display de selecao
if (subestado_display == 2)
printf(disp_store,CURSOR);
else
printf(disp_store," ");
printf(disp_store,MEMORIA);
if (subestado_display == 2)
printf(disp_store," ");
else
printf(disp_store,CURSOR);
break;
}
if (buf_tcl.LT == TRUE)
{
estado_display=1; // se LT pressionado, volta estado
subestado_display=0;
return;
}
if (buf_tcl.DN == TRUE)
{
if (subestado_display < 3) // se subestado dentro dos limites
subestado_display++; // se DN pressionado, avanca subestado
return;
}
if (buf_tcl.UP == TRUE)
{
if (subestado_display > 0) // se subestado dentro dos limites
subestado_display--; // se UP pressionado, avanca subestado
return;
}
if (buf_tcl.RT == TRUE) // se RT pressionado, avanca estado
{
estado_display = subestado + 3; // aponta para o estado correto
subestado_display=0;
return;
}
break;
case 3:
estado_display=0;
break;
case 4: // config do relogio
break;
case default:
estado_display=0;
break;
}
} |
The display messages are these by now:
Code: | // Display principal (estado 0)
// 1o Display de escolha (config / autoteste)
#DEFINE CONFIG_DISP "Config " // 15 caracteres
#DEFINE TESTE_DISP "Auto-teste " // 15 caracteres
#DEFINE CURSOR "<" // 1 caracter
// Selecao no menu de config
#DEFINE LIMIAR "Limiares " // 15 caracteres
#DEFINE RELOGIO "Relogio " // 15 caracteres
#DEFINE COMUNIC "Comunicacao " // 15 caracteres
#DEFINE MEMORIA "Memoria " // 15 caracteres
//#DEFINE CURSOR "<" // 1 caracter
// Selecao no menu de limiares
#DEFINE DESCONE "Desconexao " // 15 caracteres
#DEFINE ALARME "Alarme " // 15 caracteres
//#DEFINE CURSOR "<" // 1 caracter
// Selecao no menu de comunicacao
#DEFINE BAUDRATE "Baud Rate " // 15 caracteres
#DEFINE ENDERECO "Endereco " // 15 caracteres
//#DEFINE CURSOR "<" // 1 caracter |
As you see, for a pretty simple structure of menus, submenus and key actions, long code. And consider that I didn't include all the setup screen for my variables, only the menus and submenus. At least the posted code can be a simple reference of how implementing a menu, I didn't seen anything like these posted.
Give me your comments of the code, perhaps I can optimize stuff in there from your ideas.
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
|