A Real
Time Operating System for the PIC – Part 3
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 (DS) |
Next |
Toggle |
Toggle |
Main Set
Clock |
Sub Set Hours |
Enter/Next |
Dec
Hours |
Inc Hour |
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 back to a
default display and 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.
Interfacing
to the Menu 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, 2, has 1
sub menu, 3 and 4 have 2 submenus and 5 has no 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.
When the menu button is pressed from the Default
Display mode the Menu code will call 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 call ProcMainMenu in
the application code. (MenuAct will hold the value $10 indicating the first
Main menu item).
ProcMainMenu
is a jump table to application code for each menu indexed by ActPtr. (ActPtr is simply the MS nibble of MenuAct -
1 so that the jump can be 0 based).
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.
See the code snippets below.
ProcMainMenu:
On ActPtr GoToL Menu_Clock,
Menu_Next, etc...
GoSub ActionFail [10]
Return
ProcMainSet:
On ActPtr GoToL Set_Clock, Set_Next, etc...
GoSub ActionFail [20]
Return
ProcMainIncDec:
On ActPtr GoToL IncDec_Clock,
IncDec_Next, etc...
GoSub ActionFail [30]
Return
Once in Menu mode, 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 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.
I usually use Set to cycle around alternative default displays. In the case of the demo program I have used
Inc and Dec 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.
Underneath
the Covers
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.
I will discuss the details of this part of the code
further in the article covering Interrupts and Serial Communications
interfacing.
Attached
Code:
MainCTest.Bas The main application code
Menu_P+.inc The Menu code.