This section describes interfacing to a general purpose menu system which can be operated with a 2 line LCD and 4 key, keypad.
First, an explanation of the menu basics – when no buttons have been pressed the display will be showing its default display (in the case of the demo application the time and date on the top row of the display). Four buttons beneath the display have the following Functions:
Menu – this invokes the interacting menus, successive presses of the menu button will cycle round all the menus.
Inc/Dec – these 2 buttons can be used to either move between items within a menu or adjust the value of items.
Set – this button is used to accept the change. It might be used to take the user on to another item in the data entry sequence or may return to the top menu item for that sequence.
In all cases, if buttons have not been pressed within a set period, the display will revert to its default mode. Holding a button down for a default period will invoke key repeat.
Menus can have Sub Menus and the top level menu is called the Main Menu. Pressing the Menu button moves between Main Menus, depending on context the Inc/Dec or Set buttons can be used to move between sub menus.
In the default mode the Set, Inc and Dec buttons have no direct function. The system however lets you assign specific functions to these buttons if you wish. The Menu button will always have to retain the fixed Menu function.
The system supports more than one default display. How the default display is selected is up to the application. I generally use the default Set button to move around the default display options.
Operation of the Demo program - In the demo program the Inc and Dec buttons have been used to adjust the LCD contrast when in Default Display mode. The menu button will invoke the Set Clock menu item. (As it is only a clock there are no other menus in the demo). The table below shows how the menu works for the Demo program.
Mode |
Set |
Dec |
Inc |
Menu |
Default Display |
|
Contrast |
Contrast |
Main Set Clock |
Main Set Clock |
Next |
Toggle |
Toggle |
Main Set Clock |
Sub Set Hours |
Enter/Next |
Dec Hours |
Inc Hours |
Main Set Clock |
Sub Set Mins |
Enter/Next |
Dec Minutes |
Inc Minutes |
Main Set Clock |
Sub Set Day |
Enter/Next |
Dec Day |
Inc Day |
Main Set Clock |
Sub Set Month |
Enter/Next |
Dec Month |
Inc Month |
Main Set Clock |
Sub Set Year |
Update
Clock |
Dec Year |
Inc Year |
Main Set Clock |
If there were additional menu items, pressing the menu button would take the user to the next main menu item. As there is only one menu in the demo it returns to that menu.
The system supports an additional Config Mode of operation which can force the system into a different set of menus. In this mode there is no timeout and automatic return to a default display instead there has to be a specific menu action to leave this mode. This facility would normally be used in setting up specific parameters in the system.
Having explained the basic operation of the system lets see how the application can hook into the code to tailor the menus to the requirements of the application.
This module probably has the most interaction of all the modules with the application program as it is essentially the user interface. It has no function on its own without the application code; however what it does provide is a standardised method of calling functions which move between menus and for controlling the display.
The menu system is essentially a state machine with the current state of the menu held in a byte variable called MenuAct. This variable holds the MainMenu number in its high nibble and the SubMenu number in its lower nibble. Thus in theory it would be possible to support at maximum of 15 Main menus each with 15 sub menus. When no menu is active (i.e. Default Display mode) the MenuAct value is zero. The table below shows this diagrammatically:
|
In this example there are 5 Main menu items. Main menu 1 has 4 sub menus |
The number of Menu items is defined by the constants MnuMTNum and MnuMCNum for the Main Menu and the Config menu respectively. Submenu sizes are set in code as they can vary from menu to menu.
ProcMainMenu is a jump table to application code for each menu indexed by ActPtr. (ActPtr is simply the MS nibble of MenuAct). Successive pressings of Menu will increment MenuAct (and hence ActPtr) up to the maximum number of menus set in the application code. Similarly, when in the Menu mode, pressing any of the other buttons will call a similar jump table for that button.
The default Display is in practice the first menu item - i.e. Menu 0. When the menu button is pressed from the Default Display mode the Menu code will call the CancelMainMenu routine. Since the MenuAct is 0 CancelMainMenu will branch to a routine in the application code called RemoveDefaultDisp. This routine allows the application to clear up any tasks before entering the Menu mode. The Menu code will then increment MenuAct and call ProcMainMenu in the application code. (MenuAct will hold the value $10 indicating the first Main menu item).
See the code snippets below.
ProcMainMenu:
On ActPtr GoToL RestoreDefaultDisp, Menu_Clock, Menu_Next, etc...
GoSub ActionFail [10]
Return
ProcMainSet:
On ActPtr GoToL DefltSet, Set_Clock, Set_Next, etc...
GoSub ActionFail [20]
Return
ProcMainIncDec:
On ActPtr GoToL DefltIncDec, IncDec_Clock, IncDec_Next, etc...
GoSub ActionFail [30]
Return
Before calling ProcMainMenu to move to the next Main menu item the Menu code will call CancelMainMenu. This is another jump table which allows code to be added to clear up any of the existing menu before moving out of the current menu an onto the next menu item. See code snippet below:
CancelMainMenu:
On ActPtr GoToL RemoveDefaultDisp, Can_Menu_Clock, Can_Menu_Next, etc...
Can_Menu_Def:
Return
(Where action is not required in any of the above jump tables Can_Menu_Def should be placed in place of the expected jump label).
Three calls allow the Main Application code to move between submenus within the defined range for the current menu.
IncDecSubMenu – will move the submenu number up or down depending on whether Inc or Dec button pressed.
DecSubMenu will decrement the Submenu number
IncSubMenu will increment the Submenu number
These routines have to be called specifically from the relevant code in the application.
When no key has been depressed for the set menu timeout period, the Menu code will call Cancel_Main_Menu for the current menu, clear MenuAct to zero and call RestoreDefaultDisp which will set up the display to return to the current Default.
The application can, where appropriate, disable specific buttons when in a specific menu. Setting any of the three variables MenuHold, SetHold, IncDecHold will cause the Menu code to ignore the respective button.
Look at the Demo program in MainTest to see how the clock application uses the menu functions.
Default Display Mode – When the system is in Default Display mode, the menu will call DefltSet, DefltInc and DefltDec routines whenever the Set, Inc and Dec buttons are pressed. These can be used to provide certain fixed functions outside the menu. E.g. Set could be used to cycle around alternative default displays. In the case of the demo program Inc and Dec are used to adjust the contrast of the LCD display.
As mentioned earlier, there is a ConfigMode which can be invoked from the keypad which will force the system to use a different set of menus. The ConfigMode is reached by depressing more than one of the keys at the same time. The ConfigMode key combination is defined in the constant ForceConfig.
ConfigMode – In ConfigMode the menu will call an alternative set of routines which you can use for setting up the application etc. Before entering ConfigMode the screen prompts the user to confirm. The first item in the Config Menu is used for this purpose. In the demo only “No” is permitted when ask to confirm entry into ConfigMode The code snippets below show the config code used in the demo – as there are no configuration menus each routine returns simply calls Can_Menu_Def.
ProcCfgMenu:
On ActPtr GoToL Menu_Cfg_Chk, Can_Menu_Def
Cls : GoSub ActionFail [11]
Return
ProcCfgSet:
On ActPtr GoToL Set_Cfg_Chk, Can_Menu_Def
Cls : GoSub ActionFail [21]
Return
ProcCfgIncDec:
On ActPtr GoToL IncDec_Cfg_Chk, Can_Menu_Def
Cls : GoSub ActionFail [31]
Return
In configuration mode there is no menu timeout function. You must explicitly add code under one of your menus to return to normal mode. The simplest route here is to execute a software RESET once all the configuration changes have been saved.
The menu code supports interrupt driven or polled scanning of the keys. The interrupt driven approach consumes much less processor resource although it does require a little more code. It also uses TMR1 set to 50Hz (20mS) in the PIC to manage de-bounce and repeat delays. However, as it runs continuously it could also be used for other timing activities with a little modification.
For further details on this part of the code see the sections covering Interrupts and Serial Communications.