LCDMenuModule
SwordfishUser.LCDMenuModule History
Hide minor edits - Show changes to output
Changed lines 1-2 from:
%center%http://www.sfcompiler.co.uk/wiki/uploads/AndyO/menu.png
to:
%rframe width=300px%http://www.sfcompiler.co.uk/wiki/uploads/AndyO/menu.png
A module for displaying a hierarchical menu system on a character LCD.
The module handles scrolling the menus and navigating up and down the menu levels. It triggers an event in the main program when the user selects a menu item which requires an action other then opening another menu. All the menu data is stored in Const arrays so the module uses very little RAM. It works with LCD displays from 1 to many lines and has various options to control how the menus are displayed.
To accompany the module is a basic utility - Menu Builder - which allows you to design the menu structure using a tree-view and then generates all the Const array declarations for you.
A module for displaying a hierarchical menu system on a character LCD.
The module handles scrolling the menus and navigating up and down the menu levels. It triggers an event in the main program when the user selects a menu item which requires an action other then opening another menu. All the menu data is stored in Const arrays so the module uses very little RAM. It works with LCD displays from 1 to many lines and has various options to control how the menus are displayed.
To accompany the module is a basic utility - Menu Builder - which allows you to design the menu structure using a tree-view and then generates all the Const array declarations for you.
Added lines 12-14:
[[http://www.sfcompiler.co.uk/wiki/uploads/AndyO/LCDMenuModule.pdf | Download module description and instructions doc »]]
%lfloat% http://www.sfcompiler.co.uk/wiki/uploads/StevenWright/download.gif
%lfloat% http://www.sfcompiler.co.uk/wiki/uploads/StevenWright/download.gif
Deleted lines 17-19:
%lfloat% http://www.sfcompiler.co.uk/wiki/uploads/StevenWright/download.gif
Changed lines 21-22 from:
[[http://www.sfcompiler.co.uk/wiki/uploads/AndyO/RunningSampleProgram.pdf | Download instructions for running sample code »]]
to:
[[http://www.sfcompiler.co.uk/wiki/uploads/AndyO/RunningSampleProgram.pdf | Download instructions for running example code »]]
Added line 29:
Changed lines 1-2 from:
%centre%http://www.sfcompiler.co.uk/wiki/uploads/AndyO/menu.png
to:
%center%http://www.sfcompiler.co.uk/wiki/uploads/AndyO/menu.png
Added lines 1-2:
%centre%http://www.sfcompiler.co.uk/wiki/uploads/AndyO/menu.png
Changed lines 6-20 from:
to:
%lfloat% http://www.sfcompiler.co.uk/wiki/uploads/StevenWright/download.gif
[[http://www.sfcompiler.co.uk/wiki/uploads/AndyO/LCDMenuModule.pdf | Download PDF instructions »]]
%lfloat% http://www.sfcompiler.co.uk/wiki/uploads/StevenWright/download.gif
[[http://www.sfcompiler.co.uk/wiki/uploads/AndyO/MenuModuleSample.zip | Download example code »]]
%lfloat% http://www.sfcompiler.co.uk/wiki/uploads/StevenWright/download.gif
[[http://www.sfcompiler.co.uk/wiki/uploads/AndyO/RunningSampleProgram.pdf | Download instructions for running sample code »]]
%lfloat% http://www.sfcompiler.co.uk/wiki/uploads/StevenWright/download.gif
[[http://www.sfcompiler.co.uk/wiki/uploads/AndyO/MenuBuilder.zip | Download Menu Builder Utility »]]
%lfloat% http://www.sfcompiler.co.uk/wiki/uploads/StevenWright/download.gif
[[http://www.sfcompiler.co.uk/wiki/uploads/AndyO/MenuBuilderUtility.pdf | Download Menu Builder Utility instructions »]]
[[http://www.sfcompiler.co.uk/wiki/uploads/AndyO/LCDMenuModule.pdf | Download PDF instructions »]]
%lfloat% http://www.sfcompiler.co.uk/wiki/uploads/StevenWright/download.gif
[[http://www.sfcompiler.co.uk/wiki/uploads/AndyO/MenuModuleSample.zip | Download example code »]]
%lfloat% http://www.sfcompiler.co.uk/wiki/uploads/StevenWright/download.gif
[[http://www.sfcompiler.co.uk/wiki/uploads/AndyO/RunningSampleProgram.pdf | Download instructions for running sample code »]]
%lfloat% http://www.sfcompiler.co.uk/wiki/uploads/StevenWright/download.gif
[[http://www.sfcompiler.co.uk/wiki/uploads/AndyO/MenuBuilder.zip | Download Menu Builder Utility »]]
%lfloat% http://www.sfcompiler.co.uk/wiki/uploads/StevenWright/download.gif
[[http://www.sfcompiler.co.uk/wiki/uploads/AndyO/MenuBuilderUtility.pdf | Download Menu Builder Utility instructions »]]
Added lines 1-6:
!!!Downloads
%lfloat% http://www.sfcompiler.co.uk/wiki/uploads/StevenWright/download.gif
[[http://www.sfcompiler.co.uk/wiki/uploads/AndyO/Menu.zip | Download Menu module & updated LCD module »]]
%lfloat% http://www.sfcompiler.co.uk/wiki/uploads/StevenWright/download.gif
[[http://www.sfcompiler.co.uk/wiki/uploads/AndyO/Menu.zip | Download Menu module & updated LCD module »]]
Changed lines 696-697 from:
If (PointerLine >= LCDLines - 1 Or PointerPosition = LastItemNumber - FirstItemNumber) And CanScroll = True Then
to:
If (PointerLine >= LCDLines - 1 Or PointerPosition = LastItemNumber - FirstItemNumber) And
CanScroll = True Then
CanScroll = True Then
Changed lines 282-283 from:
Public Const mnuMenuName(5) As String = ("MAIN MENU", "FLASH SETTINGS", "CONFIRM RESET", "LED1 Frequency", "LED2 Frequency")
to:
Public Const mnuMenuName(5) As String = ("MAIN MENU", "FLASH SETTINGS", "CONFIRM RESET",
"LED1 Frequency", "LED2 Frequency")
"LED1 Frequency", "LED2 Frequency")
Changed lines 289-293 from:
"Stop Flashing", "Flash Settings", "Reset", "LED1 Frequency", "LED2 Frequency", "Back", "No", "Yes", "1Hz", "2Hz", "10Hz", "Back", "1Hz",
"2Hz", "10Hz", "Back")
Public Const mnuItemAction(17) As Byte = (255, 255, 1, 2, 3, 4, 0, 0, 255, 255, 255, 255, 1, 255, 255, 255, 1)
Public Const mnuItemAction(17) As Byte = (255, 255, 1, 2, 3, 4, 0, 0, 255,
to:
"Stop Flashing", "Flash Settings", "Reset", "LED1 Frequency", "LED2 Frequency", "Back", "No",
"Yes", "1Hz", "2Hz", "10Hz", "Back", "1Hz", "2Hz", "10Hz", "Back")
Public Const mnuItemAction(17) As Byte = (255, 255, 1, 2, 3, 4, 0, 0, 255,
255, 255, 255, 1, 255, 255, 255, 1)
"Yes", "1Hz", "2Hz", "10Hz", "Back", "1Hz", "2Hz", "10Hz", "Back")
Public Const mnuItemAction(17) As Byte = (255, 255, 1, 2, 3, 4, 0, 0, 255,
255, 255, 255, 1, 255, 255, 255, 1)
Changed lines 287-289 from:
Public Const mnuItemName(17) As String = ("Start Flashing", "Stop Flashing", "Flash Settings", "Reset", "LED1 Frequency", "LED2 Frequency", "Back", "No", "Yes", "1Hz", "2Hz", "10Hz", "Back", "1Hz", "2Hz", "10Hz", "Back")
to:
Public Const mnuItemName(17) As String = ("Start Flashing",
"Stop Flashing", "Flash Settings", "Reset", "LED1 Frequency", "LED2 Frequency", "Back", "No", "Yes", "1Hz", "2Hz", "10Hz", "Back", "1Hz",
"2Hz", "10Hz", "Back")
"Stop Flashing", "Flash Settings", "Reset", "LED1 Frequency", "LED2 Frequency", "Back", "No", "Yes", "1Hz", "2Hz", "10Hz", "Back", "1Hz",
"2Hz", "10Hz", "Back")
Changed lines 722-723 from:
ElseIf PointerLine < LCDLines And PointerPosition + FirstItemNumber + ScrollPosition < LastItemNumber Then
to:
ElseIf PointerLine < LCDLines And
PointerPosition + FirstItemNumber + ScrollPosition < LastItemNumber Then
PointerPosition + FirstItemNumber + ScrollPosition < LastItemNumber Then
Changed lines 729-730 from:
#If (Menu_LCDLines < 4 Or Menu_ScrollWrapping = True) And Menu_ShowScrollIndicators = True
to:
#If (Menu_LCDLines < 4 Or Menu_ScrollWrapping = True) And
Menu_ShowScrollIndicators = True
Menu_ShowScrollIndicators = True
Changed line 1 from:
!!!Sample Code
to:
!!!Menu Module Sample Code
Deleted lines 2-6:
=]
!!!Menu Module
=code [=
Changed line 5 from:
* Name : LCD Menu Module *
to:
* Name : LCD Menu Module Sample Program *
Changed line 9 from:
* Date : 13/07/2008 *
to:
* Date : 5 October 2008 *
Changed line 11 from:
* Notes : See doc "LCD Menu Module.pdf" *
to:
* Notes : See separate doc - "Running the Sample Program.pdf" *
Deleted lines 12-48:
* : module indicated by #define MenuDataModule = "filename.BAS" in *
* : main program *
* : *
* : Requires modified LCD.bas module. Following sub should be placed *
* : after sub "WriteAt": *
* *
* ------------------------------------------------------------------------- *
Public Sub WriteConstStringAt(pY, pX As Byte, ByRefConst pText As String)
SetLocationY(pY)
SetLocationX(pX)
MoveTo()
EECON1 = 0
EECON1.7 = 1
TABLEPTR = @pText
ASM
TBLRD*+
End ASM
While TABLAT <> 0
WriteItem(TABLAT)
ASM
TBLRD*+
End ASM
Wend
End Sub
* ------------------------------------------------------------------------- *
* *
* *
Deleted lines 15-24:
Include "LCD.bas"
#ifdef MenuDataModule
Include MenuDataModule
#else
#error "No MenuDataModule defined in main program"
#endif
Changed line 17 from:
'User definable options
to:
'Device, Clock and Config directives
Changed lines 20-34 from:
#option Menu_ShowMenuTitle = True 'Display Menu Name at top of screen?
#option Menu_ShowScrollIndicators = True 'Show up and down scroll indicators?
#option Menu_ScrollWrapping = False 'Scroll wraps from top to bottom?
#option Menu_PointerCharacter = 126 'Character used as pointer
#if Menu_LCDLines = 1 And Menu_ShowMenuTitle = True
#error "Cannot show menu titles on 1 line LCD"
#endif
to:
Device = 18F2520
Clock = 20
'Disable MCLR on Pin 1 (RE3)
Config MCLRE = OFF
Clock = 20
'Disable MCLR on Pin 1 (RE3)
Config MCLRE = OFF
Changed line 28 from:
'Variable and Const Declarations
to:
'Module options & Includes
Changed lines 31-76 from:
Type TEvent = Event()
'---Bring options into module
Private Const
LCDLines As Byte = Menu_LCDLines,
PointerCharacter As Byte = Menu_PointerCharacter
'---Custom Characters (only loaded if option Menu_ShowScrollIndicators = True)
#If Menu_ShowScrollIndicators = True
'Character definitions for Up Arrow and Down Arrow scroll indicators
Private Const ScrollIndicators(16) As Byte=($04,$0E,$1F,$00,$00,$00,$00,$00,
$00,$00,$00,$00,$00,$1F,$0E,$04)
Private Const UpArrow = 0
Private Const DownArrow = 1
#EndIf
'---Private Variables
Private Dim FItemActionEvent As TEvent 'Holds pointer to event code in main
'program which is run when an "action"
'menu item is selected
Private Dim PointerPosition As Byte 'Position of pointer character (0 = 1st)
Private Dim PointerLine As Byte 'Actual LCD line of pointer
Private Dim ScrollPosition As Byte 'Number of lines the menu is scrolled by
Private Dim CurrentMenu As Byte 'Index number of current menu
Private Dim ParentID As Byte 'Index number of parent of current menu
Private Dim FirstItemNumber As Byte 'First item number for current menu
Private Dim LastItemNumber As Byte 'Last item number for current menu
'---Public Variables
Public Dim SelectedMenuItem As Byte 'Index number of selected menu item
to:
'---Menu module options
#define MenuDataModule = "SampleDataModule.bas"
#option Menu_ShowMenuTitle = True
#option Menu_ShowScrollIndicators = True
#option Menu_ScrollWrapping = False
#option Menu_LCDLines = 4
'---LCD module options
#option LCD_DATA = PORTA.0
#option LCD_RS = PORTA.4
#option LCD_EN = PORTA.5
'---Includes
Include "LCD.bas"
Include "Utils.bas"
Include "Menu.bas" 'Menu Module
Include "SampleDataModule.bas" 'Menu Data Module
#define MenuDataModule = "SampleDataModule.bas"
#option Menu_ShowMenuTitle = True
#option Menu_ShowScrollIndicators = True
#option Menu_ScrollWrapping = False
#option Menu_LCDLines = 4
'---LCD module options
#option LCD_DATA = PORTA.0
#option LCD_RS = PORTA.4
#option LCD_EN = PORTA.5
'---Includes
Include "LCD.bas"
Include "Utils.bas"
Include "Menu.bas" 'Menu Module
Include "SampleDataModule.bas" 'Menu Data Module
Changed line 51 from:
'Helper Subs and Functions (Private - can't be called from main program)
to:
'Variable and Const Declarations
Added lines 54-81:
Dim UpButton As PORTB.4
Dim DownButton As PORTB.5
Dim SelectButton As PORTB.6
Dim LED1 As PORTB.0
Dim LED2 As PORTB.1
Dim UpButtonCount As Byte '}Counters used for button debounce -
Dim DownButtonCount As Byte '}Counters track how long each button has
Dim SelectButtonCount As Byte '}been pressed and
Dim NoButtonCount As Byte '}how long no button has been pressed
Const DebounceCount As Byte = 2 'Default debounce delay in units of 5ms
Dim LED1Delay As Byte '}Delay between on/off toggle of LEDs in
Dim LED2Delay As Byte '}units of 5mS
Dim LED1Count As Byte '}Counters used to track time to next on/off
Dim LED2Count As Byte '}toggle of LEDs
Dim DoFlash As Boolean 'True = flash LEDs, False = don't flash LEDs
'===============================================================================
'Interrupts and Events
'-------------------------------------------------------------------------------
Dim DownButton As PORTB.5
Dim SelectButton As PORTB.6
Dim LED1 As PORTB.0
Dim LED2 As PORTB.1
Dim UpButtonCount As Byte '}Counters used for button debounce -
Dim DownButtonCount As Byte '}Counters track how long each button has
Dim SelectButtonCount As Byte '}been pressed and
Dim NoButtonCount As Byte '}how long no button has been pressed
Const DebounceCount As Byte = 2 'Default debounce delay in units of 5ms
Dim LED1Delay As Byte '}Delay between on/off toggle of LEDs in
Dim LED2Delay As Byte '}units of 5mS
Dim LED1Count As Byte '}Counters used to track time to next on/off
Dim LED2Count As Byte '}toggle of LEDs
Dim DoFlash As Boolean 'True = flash LEDs, False = don't flash LEDs
'===============================================================================
'Interrupts and Events
'-------------------------------------------------------------------------------
Changed lines 83-85 from:
'Name: DrawMenu(pMenuNumber as byte)
'Purpose: Draws currentmenu, scrolled by ScrollPosition amount
'
'Purpose: Draws current
'
to:
'Name: Event - MenuItemSelected
'Purpose: Event called by menu module whenever 'action' menu item is selected
' Executes item action and then displays root menu
'
'Notes: Variable 'Menu.SelectedMenuItem' holds index number of menu item.
'
' Aliases to menu items used in Select...Case structure are declared
' in the Menu Data Module - "SampleDataModule.bas".
'
'Purpose: Event called by menu module whenever 'action' menu item is selected
' Executes item action and then displays root menu
'
'Notes: Variable 'Menu.SelectedMenuItem' holds index number of menu item.
'
' Aliases to menu items used in Select...Case structure are declared
' in the Menu Data Module - "SampleDataModule.bas".
'
Changed lines 94-107 from:
Dim ItemNumber As Byte
#If Menu_ScrollWrapping = True '}
'}If scroll wrapping enabled then
Dim ItemsDrawn As Byte '}also need to keep track of number
'}of menu items drawn on LCD
ItemsDrawn = 0 '}
'}
#EndIf
LCD.Cls
to:
Event MenuItemSelected()
Select Menu.SelectedMenuItem
Case mnuMainMenu_StartFlashing
DoFlash = True
Select Menu.SelectedMenuItem
Case mnuMainMenu_StartFlashing
DoFlash = True
Changed lines 102-105 from:
to:
Case mnuMainMenu_StopFlashing
DoFlash = False
DoFlash = False
Changed lines 106-109 from:
to:
Case mnuConfirmReset_Yes
LCD.Cls
LCD.WriteAt(1,1,"Resetting...")
DelayMS(500)
ASM
reset
End ASM
LCD.Cls
LCD.WriteAt(1,1,"Resetting...")
DelayMS(500)
ASM
reset
End ASM
Added lines 115-117:
Case mnuLed1Frequency_1hz
LED1Delay = 100
LED1Delay = 100
Changed lines 119-127 from:
' back to first menu item as necessary) until either the number of LCD
' lines has been reached or all menu items have been written (ItemsDrawn =
' LastItemNumber - FirstItemNumber)
'
' Scroll Wrapping Not Enabled: write items until the number of LCD lines
' has been reached or the last menu item has been written
to:
Case mnuLed1Frequency_2hz
LED1Delay = 50
LED1Delay = 50
Changed lines 123-132 from:
LCD.WriteConstStringAt(LineNumber, 2, mnuItemName(ItemNumber))
Inc(LineNumber)
Inc(ItemNumber)
#If Menu
Inc(ItemsDrawn)
to:
Case mnuLed1Frequency_10hz
Changed lines 125-129 from:
'}Scroll wrapping enabled so wrap
ItemNumber = FirstItemNumber '}from last menu item to the first
'}menu item
EndIf '}
to:
LED1Delay = 10
Changed lines 127-131 from:
Until LineNumber > LCDLines Or ItemNumber > LastItemNumber
to:
Case mnuLed2Frequency_1hz
LED2Delay = 100
LED2Delay = 100
Changed lines 131-133 from:
to:
Case mnuLed2Frequency_2hz
LED2Delay = 50
LED2Delay = 50
Added lines 135-137:
Case mnuLed2Frequency_10hz
LED2Delay = 10
LED2Delay = 10
Changed lines 139-149 from:
'depending on the following conditions -
'
' Scroll Wrapping Enabled: Show both Up and Down arrows if the number of
' menu items exceeds the number of available LCD lines
'
' Scroll Wrapping Not Enabled: Show Up arrow if menu can be scrolled up,
' Down arrow if there are more menu items to display
'
'Note: Number of available LCD lines and position of Up arrow depends on
' whether Menu_ShowMenuTitle is enabled or not
to:
EndSelect
Changed lines 141-180 from:
to:
Menu.ShowMenu 'Show root menu
End Event
'===============================================================================
'Main Program
'-------------------------------------------------------------------------------
'Turn off analogue functions
SetAllDigital
'Initialise vars
LED1Delay = 100 '}Both LEDs set to 1Hz flash
LED2Delay = 100 '}frequency (500mS between toggles)
LED1Count = 0
LED2Count = 0
UpButtonCount = 0
DownButtonCount = 0
SelectButtonCount = 0
NoButtonCount = 0
DoFlash = True
DelayMS(100) 'Let things settle
Menu.Initialise(MenuItemSelected) 'Initialise Menu module and let it
'know the name of the event handler
Menu.ShowMenu 'Show the root menu
Low(LED1) '}Make both LED pins outputs and
Low(LED2) '}turn off
While True 'Endless loop which executes every
DelayMS(5) '5mS
End Event
'===============================================================================
'Main Program
'-------------------------------------------------------------------------------
'Turn off analogue functions
SetAllDigital
'Initialise vars
LED1Delay = 100 '}Both LEDs set to 1Hz flash
LED2Delay = 100 '}frequency (500mS between toggles)
LED1Count = 0
LED2Count = 0
UpButtonCount = 0
DownButtonCount = 0
SelectButtonCount = 0
NoButtonCount = 0
DoFlash = True
DelayMS(100) 'Let things settle
Menu.Initialise(MenuItemSelected) 'Initialise Menu module and let it
'know the name of the event handler
Menu.ShowMenu 'Show the root menu
Low(LED1) '}Make both LED pins outputs and
Low(LED2) '}turn off
While True 'Endless loop which executes every
DelayMS(5) '5mS
Changed lines 182-194 from:
to:
'Flash the LEDs
If DoFlash = True Then 'If the LEDs should be flashing:
Inc(LED1Count) '}Increase both LED counters by 1
Inc(LED2Count) '}
If LED1Count >= LED1Delay Then '}If LED1 count has reached the delay
'}value:
Toggle(LED1) '}Toggle the LED and
LED1Count = 0 '}Reset counter to 0
'}
EndIf '}
Changed lines 196-341 from:
to:
If LED2Count >= LED2Delay Then '}If LED2 count has reached the delay
'}value:
Toggle(LED2) '}Toggle the LED and
LED2Count = 0 '}Reset counter to 0
'}
EndIf '}
EndIf
'Check and debounce buttons
If NoButtonCount = DebounceCount Then '}If no button has been pressed for
'}10mS:
'}
If UpButton = 1 Then '}Check each button and if a button
'}is pressed then increase that
Inc(UpButtonCount) '}button's counter by 1
'}
ElseIf DownButton = 1 Then '}
'}
Inc(DownButtonCount) '}
'}
ElseIf SelectButton = 1 Then '}
'}
Inc(SelectButtonCount) '}
'}
EndIf '}
ElseIf (PORTB And %01110000) = 0 Then '}If less than 10mS since the last
'}button push and no button is being
Inc(NoButtonCount) '}pressed then increase the
'}No-button counter by 1
EndIf '}
If UpButtonCount = DebounceCount Then '}For each button, if the counter
'}has reached 2 (i.e. the button has
UpButtonCount = 0 '}been pushed for 10mS) then:
NoButtonCount = 0 '}
Menu.MoveUp '}Reset that button's counter,
'}Reset the No-button counter, and
EndIf '}Call the appropriate Menu sub -
'}i.e. Up, Down or SelectItem
If DownButtonCount = DebounceCount Then '}
'}
DownButtonCount = 0 '}
NoButtonCount = 0 '}
Menu.MoveDown '}
'}
EndIf '}
'}
If SelectButtonCount = DebounceCount Then '}
'}
SelectButtonCount = 0 '}
NoButtonCount = 0 '}
Menu.SelectItem '}
'}
EndIf '}
Wend
=]
!!!Menu Module Sample Code Data
=code [=
{
********************************************************************************
* Name : LCD Menu Sample Data Module *
* Author : AndyO *
* Notice : Copyright (c) 2008 AndyO *
* : All Rights Reserved *
* Date : 04/09/2008 *
* Version : 1.0 *
* Notes : For use with LCD Menu Module sample program. *
* : *
* : All Const declarations generated by Menu Builder utility. *
* : *
********************************************************************************
}
Module SampleDataModule
'===============================================================================
'Menu Header & Menu Item Data
'-------------------------------------------------------------------------------
Public Const mnuMenuName(5) As String = ("MAIN MENU", "FLASH SETTINGS", "CONFIRM RESET", "LED1 Frequency", "LED2 Frequency")
Public Const mnuMenuItemStart(5) As Byte = (0, 4, 7, 9, 13)
Public Const mnuMenuItemEnd(5) As Byte = (3, 6, 8, 12, 16)
Public Const mnuParentMenuID(5) As Byte = (0, 0, 0, 1, 1)
Public Const mnuItemName(17) As String = ("Start Flashing", "Stop Flashing", "Flash Settings", "Reset", "LED1 Frequency", "LED2 Frequency", "Back", "No", "Yes", "1Hz", "2Hz", "10Hz", "Back", "1Hz", "2Hz", "10Hz", "Back")
Public Const mnuItemAction(17) As Byte = (255, 255, 1, 2, 3, 4, 0, 0, 255, 255, 255, 255, 1, 255, 255, 255, 1)
'===============================================================================
'Menu Item Aliases - used by Select Case structure in main program
'-------------------------------------------------------------------------------
Public Const mnuMainMenu_StartFlashing = 0
Public Const mnuMainMenu_StopFlashing = 1
Public Const mnuConfirmReset_Yes = 8
Public Const mnuLed1Frequency_1hz = 9
Public Const mnuLed1Frequency_2hz = 10
Public Const mnuLed1Frequency_10hz = 11
Public Const mnuLed2Frequency_1hz = 13
Public Const mnuLed2Frequency_2hz = 14
Public Const mnuLed2Frequency_10hz = 15
=]
!!!Menu Module
=code [=
{
********************************************************************************
* Name : LCD Menu Module *
* Author : AndyO *
* Notice : Copyright (c) 2008 AndyO *
* : All Rights Reserved *
* Date : 13/07/2008 *
* Version : 1.0 *
* Notes : See doc "LCD Menu Module.pdf" *
* : *
* : Menu data stored in Const arrays which are declared in seperate *
* : module indicated by #define MenuDataModule = "filename.BAS" in *
* : main program *
* : *
* : Requires modified LCD.bas module. Following sub should be placed *
* : after sub "WriteAt": *
* *
* ------------------------------------------------------------------------- *
Public Sub WriteConstStringAt(pY, pX As Byte, ByRefConst pText As String)
SetLocationY(pY)
SetLocationX(pX)
MoveTo()
EECON1 = 0
EECON1.7 = 1
TABLEPTR = @pText
ASM
TBLRD*+
End ASM
While TABLAT <> 0
'}value:
Toggle(LED2) '}Toggle the LED and
LED2Count = 0 '}Reset counter to 0
'}
EndIf '}
EndIf
'Check and debounce buttons
If NoButtonCount = DebounceCount Then '}If no button has been pressed for
'}10mS:
'}
If UpButton = 1 Then '}Check each button and if a button
'}is pressed then increase that
Inc(UpButtonCount) '}button's counter by 1
'}
ElseIf DownButton = 1 Then '}
'}
Inc(DownButtonCount) '}
'}
ElseIf SelectButton = 1 Then '}
'}
Inc(SelectButtonCount) '}
'}
EndIf '}
ElseIf (PORTB And %01110000) = 0 Then '}If less than 10mS since the last
'}button push and no button is being
Inc(NoButtonCount) '}pressed then increase the
'}No-button counter by 1
EndIf '}
If UpButtonCount = DebounceCount Then '}For each button, if the counter
'}has reached 2 (i.e. the button has
UpButtonCount = 0 '}been pushed for 10mS) then:
NoButtonCount = 0 '}
Menu.MoveUp '}Reset that button's counter,
'}Reset the No-button counter, and
EndIf '}Call the appropriate Menu sub -
'}i.e. Up, Down or SelectItem
If DownButtonCount = DebounceCount Then '}
'}
DownButtonCount = 0 '}
NoButtonCount = 0 '}
Menu.MoveDown '}
'}
EndIf '}
'}
If SelectButtonCount = DebounceCount Then '}
'}
SelectButtonCount = 0 '}
NoButtonCount = 0 '}
Menu.SelectItem '}
'}
EndIf '}
Wend
=]
!!!Menu Module Sample Code Data
=code [=
{
********************************************************************************
* Name : LCD Menu Sample Data Module *
* Author : AndyO *
* Notice : Copyright (c) 2008 AndyO *
* : All Rights Reserved *
* Date : 04/09/2008 *
* Version : 1.0 *
* Notes : For use with LCD Menu Module sample program. *
* : *
* : All Const declarations generated by Menu Builder utility. *
* : *
********************************************************************************
}
Module SampleDataModule
'===============================================================================
'Menu Header & Menu Item Data
'-------------------------------------------------------------------------------
Public Const mnuMenuName(5) As String = ("MAIN MENU", "FLASH SETTINGS", "CONFIRM RESET", "LED1 Frequency", "LED2 Frequency")
Public Const mnuMenuItemStart(5) As Byte = (0, 4, 7, 9, 13)
Public Const mnuMenuItemEnd(5) As Byte = (3, 6, 8, 12, 16)
Public Const mnuParentMenuID(5) As Byte = (0, 0, 0, 1, 1)
Public Const mnuItemName(17) As String = ("Start Flashing", "Stop Flashing", "Flash Settings", "Reset", "LED1 Frequency", "LED2 Frequency", "Back", "No", "Yes", "1Hz", "2Hz", "10Hz", "Back", "1Hz", "2Hz", "10Hz", "Back")
Public Const mnuItemAction(17) As Byte = (255, 255, 1, 2, 3, 4, 0, 0, 255, 255, 255, 255, 1, 255, 255, 255, 1)
'===============================================================================
'Menu Item Aliases - used by Select Case structure in main program
'-------------------------------------------------------------------------------
Public Const mnuMainMenu_StartFlashing = 0
Public Const mnuMainMenu_StopFlashing = 1
Public Const mnuConfirmReset_Yes = 8
Public Const mnuLed1Frequency_1hz = 9
Public Const mnuLed1Frequency_2hz = 10
Public Const mnuLed1Frequency_10hz = 11
Public Const mnuLed2Frequency_1hz = 13
Public Const mnuLed2Frequency_2hz = 14
Public Const mnuLed2Frequency_10hz = 15
=]
!!!Menu Module
=code [=
{
********************************************************************************
* Name : LCD Menu Module *
* Author : AndyO *
* Notice : Copyright (c) 2008 AndyO *
* : All Rights Reserved *
* Date : 13/07/2008 *
* Version : 1.0 *
* Notes : See doc "LCD Menu Module.pdf" *
* : *
* : Menu data stored in Const arrays which are declared in seperate *
* : module indicated by #define MenuDataModule = "filename.BAS" in *
* : main program *
* : *
* : Requires modified LCD.bas module. Following sub should be placed *
* : after sub "WriteAt": *
* *
* ------------------------------------------------------------------------- *
Public Sub WriteConstStringAt(pY, pX As Byte, ByRefConst pText As String)
SetLocationY(pY)
SetLocationX(pX)
MoveTo()
EECON1 = 0
EECON1.7 = 1
TABLEPTR = @pText
ASM
TBLRD*+
End ASM
While TABLAT <> 0
Changed lines 343-348 from:
LCD.WriteAt
LCD.WriteAt(2, 1, UpArrow)
#Else
to:
WriteItem(TABLAT)
Changed lines 345-352 from:
LCD.WriteAt(1, 1, UpArrow)
#EndIf
EndIf
to:
ASM
TBLRD*+
End ASM
TBLRD*+
End ASM
Changed line 349 from:
to:
Wend
Changed lines 351-388 from:
#EndIf
#EndIf
End Sub
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'Name: DrawPointer(pOldPosition as byte)
'Purpose: Deletes pointer at pOldPosition and draws pointer at PointerPosition
'
'Notes: When pointer is at first menu item on screen, PointerPosition = 0
'
' Pointer character determined by option
' default = 126 (right arrow)
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Private Sub DrawPointer(pOldPosition As Byte)
to:
End Sub
* ------------------------------------------------------------------------- *
* *
* *
********************************************************************************
}
Module Menu
Include "LCD.bas"
#ifdef MenuDataModule
Include MenuDataModule
#else
#error "No MenuDataModule defined in main program"
#endif
'===============================================================================
'User definable options
'-------------------------------------------------------------------------------
#option Menu_LCDLines = 4 'Number of lines on LCD display
#option Menu_ShowMenuTitle = True 'Display Menu Name at top of screen?
#option Menu_ShowScrollIndicators = True 'Show up and down scroll indicators?
#option Menu_ScrollWrapping = False 'Scroll wraps from top to bottom?
#option Menu_PointerCharacter = 126 'Character used as pointer
#if Menu_LCDLines = 1 And Menu_ShowMenuTitle = True
#error "Cannot show menu titles on 1 line LCD"
* ------------------------------------------------------------------------- *
* *
* *
********************************************************************************
}
Module Menu
Include "LCD.bas"
#ifdef MenuDataModule
Include MenuDataModule
#else
#error "No MenuDataModule defined in main program"
#endif
'===============================================================================
'User definable options
'-------------------------------------------------------------------------------
#option Menu_LCDLines = 4 'Number of lines on LCD display
#option Menu_ShowMenuTitle = True 'Display Menu Name at top of screen?
#option Menu_ShowScrollIndicators = True 'Show up and down scroll indicators?
#option Menu_ScrollWrapping = False 'Scroll wraps from top to bottom?
#option Menu_PointerCharacter = 126 'Character used as pointer
#if Menu_LCDLines = 1 And Menu_ShowMenuTitle = True
#error "Cannot show menu titles on 1 line LCD"
Changed lines 385-405 from:
'Menu_ShowMenuTitle is enabled or not
PointerLine = PointerPosition + 2
LCD.WriteAt(pOldPosition + 2, 1, " ")
LCD.WriteAt(PointerLine, 1, PointerCharacter)
#Else
PointerLine = PointerPosition + 1
LCD.WriteAt(pOldPosition + 1, 1, " ")
LCD.WriteAt(PointerLine, 1, PointerCharacter)
#EndIf
End Sub
to:
#endif
Changed line 388 from:
'Public Subs and Functions
to:
'Variable and Const Declarations
Changed lines 391-401 from:
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'Name: ShowMenu(pMenuNumber as byte = 0)
'Purpose: Display specified menu on LCD
'
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Public Sub ShowMenu(pMenuNumber As Byte = 0)
'Reset scroll and pointer positions
ScrollPosition = 0
PointerPosition = 0
'Name:
'
Public Sub ShowMenu
PointerPosition = 0
to:
'---Types
Type TEvent = Event()
'---Bring options into module
Private Const
LCDLines As Byte = Menu_LCDLines,
PointerCharacter As Byte = Menu_PointerCharacter
'---Custom Characters (only loaded if option Menu_ShowScrollIndicators = True)
#If Menu_ShowScrollIndicators = True
'Character definitions for Up Arrow and Down Arrow scroll indicators
Private Const ScrollIndicators(16) As Byte=($04,$0E,$1F,$00,$00,$00,$00,$00,
$00,$00,$00,$00,$00,$1F,$0E,$04)
Type TEvent = Event()
'---Bring options into module
Private Const
LCDLines As Byte = Menu_LCDLines,
PointerCharacter As Byte = Menu_PointerCharacter
'---Custom Characters (only loaded if option Menu_ShowScrollIndicators = True)
#If Menu_ShowScrollIndicators = True
'Character definitions for Up Arrow and Down Arrow scroll indicators
Private Const ScrollIndicators(16) As Byte=($04,$0E,$1F,$00,$00,$00,$00,$00,
$00,$00,$00,$00,$00,$1F,$0E,$04)
Changed lines 411-416 from:
CurrentMenu = pMenuNumber
ParentID = mnuParentMenuID(CurrentMenu)
FirstItemNumber = mnuMenuItemStart(CurrentMenu)
LastItemNumber = mnuMenuItemEnd(CurrentMenu)
to:
Private Const UpArrow = 0
Private Const DownArrow = 1
#EndIf
'---Private Variables
Private Const DownArrow = 1
#EndIf
'---Private Variables
Changed lines 419-424 from:
End Sub
to:
Private Dim FItemActionEvent As TEvent 'Holds pointer to event code in main
'program which is run when an "action"
'menu item is selected
Private Dim PointerPosition As Byte 'Position of pointer character (0 = 1st)
Private Dim PointerLine As Byte 'Actual LCD line of pointer
Private Dim ScrollPosition As Byte 'Number of lines the menu is scrolled by
Private Dim CurrentMenu As Byte 'Index number of current menu
Private Dim ParentID As Byte 'Index number of parent of current menu
Private Dim FirstItemNumber As Byte 'First item number for current menu
Private Dim LastItemNumber As Byte 'Last item number for current menu
'---Public Variables
Public Dim SelectedMenuItem As Byte 'Index number of selected menu item
'===============================================================================
'Helper Subs and Functions (Private - can't be called from main program)
'-------------------------------------------------------------------------------
'program which is run when an "action"
'menu item is selected
Private Dim PointerPosition As Byte 'Position of pointer character (0 = 1st)
Private Dim PointerLine As Byte 'Actual LCD line of pointer
Private Dim ScrollPosition As Byte 'Number of lines the menu is scrolled by
Private Dim CurrentMenu As Byte 'Index number of current menu
Private Dim ParentID As Byte 'Index number of parent of current menu
Private Dim FirstItemNumber As Byte 'First item number for current menu
Private Dim LastItemNumber As Byte 'Last item number for current menu
'---Public Variables
Public Dim SelectedMenuItem As Byte 'Index number of selected menu item
'===============================================================================
'Helper Subs and Functions (Private - can't be called from main program)
'-------------------------------------------------------------------------------
Changed lines 442-444 from:
'Name: MoveDown()
'Purpose: Move pointer to next menu item, scrolling the menu if necessary
'
'
to:
'Name: DrawMenu(pMenuNumber as byte)
'Purpose: Draws current menu, scrolled by ScrollPosition amount
'
'Purpose: Draws current menu, scrolled by ScrollPosition amount
'
Changed lines 447-451 from:
Dim CanScroll As Boolean
'First, determine if the menu can be scrolled down and set CanScroll -
to:
Private Sub DrawMenu()
Dim LineNumber As Byte 'Line number of LCD to write at
Dim ItemNumber As Byte 'Index of menu item number to write
#If Menu_ScrollWrapping = True '}
'}If scroll wrapping enabled then
Dim ItemsDrawn As Byte '}also need to keep track of number
'}of menu items drawn on LCD
ItemsDrawn = 0 '}
'}
#EndIf
LCD.Cls
LineNumber = 1
ItemNumber = FirstItemNumber + ScrollPosition
#If Menu_ShowMenuTitle = True 'If option enabled, show Menu Title
LCD.WriteConstStringAt(1, 1, mnuMenuName(CurrentMenu))
LineNumber = 2
#Endif
'Loop which keeps writing menu items until the following conditions exist -
Dim LineNumber As Byte 'Line number of LCD to write at
Dim ItemNumber As Byte 'Index of menu item number to write
#If Menu_ScrollWrapping = True '}
'}If scroll wrapping enabled then
Dim ItemsDrawn As Byte '}also need to keep track of number
'}of menu items drawn on LCD
ItemsDrawn = 0 '}
'}
#EndIf
LCD.Cls
LineNumber = 1
ItemNumber = FirstItemNumber + ScrollPosition
#If Menu_ShowMenuTitle = True 'If option enabled, show Menu Title
LCD.WriteConstStringAt(1, 1, mnuMenuName(CurrentMenu))
LineNumber = 2
#Endif
'Loop which keeps writing menu items until the following conditions exist -
Changed lines 475-477 from:
' If Scroll Wrapping Not Enabled: Menu may only be scrolled down if the
' number of menu items left to display won't fit on the number of
' available LCD lines
to:
' Scroll Wrapping Enabled: write menu items (wrapping from last menu item
' back to first menu item as necessary) until either the number of LCD
' lines has been reached or all menu items have been written (ItemsDrawn =
' LastItemNumber - FirstItemNumber)
' back to first menu item as necessary) until either the number of LCD
' lines has been reached or all menu items have been written (ItemsDrawn =
' LastItemNumber - FirstItemNumber)
Changed lines 480-487 from:
' Note: Number of available lines depends on whether Menu_ShowMenuTitle is
' enabled or not
'
' If Scroll Wrapping Enabled: Can always scroll down
#If Menu_ScrollWrapping = False
CanScroll = False
'
' If Scroll Wrapping Enabled: Can always scroll down
#If Menu_ScrollWrapping = False
CanScroll = False
to:
' Scroll Wrapping Not Enabled: write items until the number of LCD lines
' has been reached or the last menu item has been written
' has been reached or the last menu item has been written
Changed lines 483-485 from:
to:
Repeat
LCD.WriteConstStringAt(LineNumber, 2, mnuItemName(ItemNumber))
LCD.WriteConstStringAt(LineNumber, 2, mnuItemName(ItemNumber))
Changed lines 487-493 from:
CanScroll = True
EndIf
#Else
to:
Inc(LineNumber)
Inc(ItemNumber)
Inc(ItemNumber)
Changed lines 490-496 from:
CanScroll = True
EndIf
#EndIf
to:
#If Menu_ScrollWrapping = True
Changed line 492 from:
to:
Inc(ItemsDrawn)
Changed lines 494-502 from:
to:
If ItemNumber > LastItemNumber Then '}
'}Scroll wrapping enabled so wrap
ItemNumber = FirstItemNumber '}from last menu item to the first
'}menu item
EndIf '}
Until LineNumber > LCDLines Or ItemsDrawn > LastItemNumber - FirstItemNumber
#Else
'}Scroll wrapping enabled so wrap
ItemNumber = FirstItemNumber '}from last menu item to the first
'}menu item
EndIf '}
Until LineNumber > LCDLines Or ItemsDrawn > LastItemNumber - FirstItemNumber
#Else
Added lines 504-505:
Until LineNumber > LCDLines Or ItemNumber > LastItemNumber
Changed lines 507-509 from:
to:
'If Menu_ShowScrollIndicators option enabled then show scroll indicators
'depending on the following conditions -
Changed lines 512-518 from:
' Menu can be scrolled down and pointer is on or below the second last
' line of the display
' OR
' Menu can be scrolled down and pointer is on the last menu item - this
' allows scroll wrapping
If (PointerLine >= LCDLines - 1 Or PointerPosition = LastItemNumber - FirstItemNumber) And CanScroll = True Then
'
If (PointerLine >= LCDLines - 1 Or PointerPosition = LastItemNumber - FirstItemNumber) And CanScroll = True Then
to:
' Scroll Wrapping Enabled: Show both Up and Down arrows if the number of
' menu items exceeds the number of available LCD lines
'
' Scroll Wrapping Not Enabled: Show Up arrow if menu can be scrolled up,
' Down arrow if there are more menu items to display
'
'Note: Number of available LCD lines and position of Up arrow depends on
' whether Menu_ShowMenuTitle is enabled or not
' menu items exceeds the number of available LCD lines
'
' Scroll Wrapping Not Enabled: Show Up arrow if menu can be scrolled up,
' Down arrow if there are more menu items to display
'
'Note: Number of available LCD lines and position of Up arrow depends on
' whether Menu_ShowMenuTitle is enabled or not
Changed lines 521-523 from:
to:
#If Menu_ShowScrollIndicators = True
#If Menu_ScrollWrapping = True
#If Menu_ScrollWrapping = True
Changed lines 525-530 from:
'If scroll wrapping and we've scrolled to the bottom then start again at
'the top
If ScrollPosition > (LastItemNumber - FirstItemNumber) Then
to:
#If Menu_ShowMenuTitle = True
Changed line 527 from:
to:
If LastItemNumber - FirstItemNumber > LCDLines - 1 Then
Changed lines 529-532 from:
to:
LCD.WriteAt(LCDLines, 1, DownArrow)
LCD.WriteAt(2, 1, UpArrow)
#Else
LCD.WriteAt(2, 1, UpArrow)
#Else
Changed lines 534-541 from:
#EndIf
to:
If LastItemNumber - FirstItemNumber > LCDLines Then
LCD.WriteAt(LCDLines, 1, DownArrow)
LCD.WriteAt(1, 1, UpArrow)
#EndIf
EndIf
LCD.WriteAt(LCDLines, 1, DownArrow)
LCD.WriteAt(1, 1, UpArrow)
#EndIf
EndIf
Changed lines 543-545 from:
DrawPointer(PointerPosition)
to:
#Else
Changed lines 545-561 from:
'conditions exist -
'
' Pointer is not on the last line of the display
' AND
' Pointer isn't on the last menu item
ElseIf PointerLine < LCDLines And PointerPosition + FirstItemNumber + ScrollPosition < LastItemNumber Then
Inc(PointerPosition)
'Fix to ensure Up Arrow scroll indicator is shown on smaller displays
'when pointer moves down from top line
#If (Menu_LCDLines < 4 Or Menu_ScrollWrapping = True) And Menu_ShowScrollIndicators = True
DrawMenu()
DrawPointer(PointerPosition)
to:
If ItemNumber - 1 < LastItemNumber Then
Changed lines 547-549 from:
DrawPointer(PointerPosition - 1
to:
LCD.WriteAt(LCDLines, 1, DownArrow)
Added lines 549-565:
EndIf
If ScrollPosition > 0 Then
#If Menu_ShowMenuTitle = True
LCD.WriteAt(2, 1, UpArrow)
#Else
LCD.WriteAt(1, 1, UpArrow)
#EndIf
EndIf
If ScrollPosition > 0 Then
#If Menu_ShowMenuTitle = True
LCD.WriteAt(2, 1, UpArrow)
#Else
LCD.WriteAt(1, 1, UpArrow)
#EndIf
EndIf
Changed lines 567-569 from:
to:
#EndIf
Changed lines 573-574 from:
'Name: MoveUp()
'Purpose: Move pointer to previous menu item, scrolling menu if necessary
to:
'Name: DrawPointer(pOldPosition as byte)
'Purpose: Deletes pointer at pOldPosition and draws pointer at PointerPosition
'Purpose: Deletes pointer at pOldPosition and draws pointer at PointerPosition
Added lines 576-579:
'Notes: When pointer is at first menu item on screen, PointerPosition = 0
'
' Pointer character determined by option "Menu_PointerCharacter",
' default = 126 (right arrow)
'
' Pointer character determined by option "Menu_PointerCharacter",
' default = 126 (right arrow)
Changed lines 582-596 from:
'depending on the current state:
'
'If there is a free LCD line above the pointer (i.e. one that doesn't have
'the menu title or a scroll indicator in it then move the pointer up;
'
'Otherwise, if the menu can be scrolled (either because scroll wrapping is
'on or because the current scroll position > 0) then scroll the menu up;
'
'If the menu can't be scrolled then move the pointer up, overwriting any
'scroll-up indicator. (If necessary, re-draw the scroll-down indicator).
#If Menu_ShowMenuTitle = True
to:
Private Sub DrawPointer(pOldPosition As Byte)
'Actual LCD line which pointer is drawn on depends on whether
'Menu_ShowMenuTitle is enabled or not
'Actual LCD line which pointer is drawn on depends on whether
'Menu_ShowMenuTitle is enabled or not
Changed lines 587-592 from:
to:
#If Menu_ShowMenuTitle Then
PointerLine = PointerPosition + 2
LCD.WriteAt(pOldPosition + 2, 1, " ")
LCD.WriteAt(PointerLine, 1, PointerCharacter)
PointerLine = PointerPosition + 2
LCD.WriteAt(pOldPosition + 2, 1, " ")
LCD.WriteAt(PointerLine, 1, PointerCharacter)
Changed lines 594-596 from:
#Else
to:
#Else
PointerLine = PointerPosition + 1
PointerLine = PointerPosition + 1
Changed lines 598-599 from:
to:
LCD.WriteAt(pOldPosition + 1, 1, " ")
LCD.WriteAt(PointerLine, 1, PointerCharacter)
LCD.WriteAt(PointerLine, 1, PointerCharacter)
Changed lines 601-661 from:
to:
#EndIf
End Sub
'===============================================================================
'Public Subs and Functions
'-------------------------------------------------------------------------------
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'Name: ShowMenu(pMenuNumber as byte = 0)
'Purpose: Display specified menu on LCD
'
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Public Sub ShowMenu(pMenuNumber As Byte = 0)
'Reset scroll and pointer positions
ScrollPosition = 0
PointerPosition = 0
'Set values for first item number, last item number & parentID for current
'menu
CurrentMenu = pMenuNumber
ParentID = mnuParentMenuID(CurrentMenu)
FirstItemNumber = mnuMenuItemStart(CurrentMenu)
LastItemNumber = mnuMenuItemEnd(CurrentMenu)
'Display menu & pointer
DrawMenu
DrawPointer(0)
End Sub
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'Name: MoveDown()
'Purpose: Move pointer to next menu item, scrolling the menu if necessary
'
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Public Sub MoveDown()
Dim CanScroll As Boolean
'First, determine if the menu can be scrolled down and set CanScroll -
'
' If Scroll Wrapping Not Enabled: Menu may only be scrolled down if the
' number of menu items left to display won't fit on the number of
' available LCD lines
'
' Note: Number of available lines depends on whether Menu_ShowMenuTitle is
' enabled or not
'
' If Scroll Wrapping Enabled: Can always scroll down
#If Menu_ScrollWrapping = False
CanScroll = False
#If Menu_ShowMenuTitle = True Then
If FirstItemNumber + ScrollPosition + LCDLines - 2 < LastItemNumber Then
End Sub
'===============================================================================
'Public Subs and Functions
'-------------------------------------------------------------------------------
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'Name: ShowMenu(pMenuNumber as byte = 0)
'Purpose: Display specified menu on LCD
'
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Public Sub ShowMenu(pMenuNumber As Byte = 0)
'Reset scroll and pointer positions
ScrollPosition = 0
PointerPosition = 0
'Set values for first item number, last item number & parentID for current
'menu
CurrentMenu = pMenuNumber
ParentID = mnuParentMenuID(CurrentMenu)
FirstItemNumber = mnuMenuItemStart(CurrentMenu)
LastItemNumber = mnuMenuItemEnd(CurrentMenu)
'Display menu & pointer
DrawMenu
DrawPointer(0)
End Sub
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'Name: MoveDown()
'Purpose: Move pointer to next menu item, scrolling the menu if necessary
'
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Public Sub MoveDown()
Dim CanScroll As Boolean
'First, determine if the menu can be scrolled down and set CanScroll -
'
' If Scroll Wrapping Not Enabled: Menu may only be scrolled down if the
' number of menu items left to display won't fit on the number of
' available LCD lines
'
' Note: Number of available lines depends on whether Menu_ShowMenuTitle is
' enabled or not
'
' If Scroll Wrapping Enabled: Can always scroll down
#If Menu_ScrollWrapping = False
CanScroll = False
#If Menu_ShowMenuTitle = True Then
If FirstItemNumber + ScrollPosition + LCDLines - 2 < LastItemNumber Then
Changed lines 663-664 from:
to:
CanScroll = True
Changed lines 665-667 from:
to:
EndIf
#Else
#Else
Changed lines 669-675 from:
Else
ScrollPosition = LastItemNumber - FirstItemNumber
EndIf
to:
If FirstItemNumber + ScrollPosition + LCDLines - 1 < LastItemNumber Then
CanScroll = True
CanScroll = True
Deleted lines 672-674:
DrawPointer(PointerPosition)
Changed lines 675-688 from:
#Else
ElseIf ScrollPosition > 0 Then
Dec(ScrollPosition)
DrawMenu()
DrawPointer(PointerPosition)
ElseIf PointerLine > 2 Then
Dec(PointerPosition)
#If Menu_LCDLines < 4 And Menu_ShowScrollIndicators = True
ElseIf ScrollPosition > 0 Then
Dec(ScrollPosition)
DrawMenu()
DrawPointer(PointerPosition)
ElseIf PointerLine > 2 Then
Dec(PointerPosition)
#If Menu_LCDLines < 4 And Menu_ShowScrollIndicators = True
to:
#EndIf
Deleted lines 676-688:
DrawPointer(PointerPosition)
#Else
DrawPointer(PointerPosition + 1)
#EndIf
EndIf
#EndIf
Changed lines 678-679 from:
to:
CanScroll = True
Changed lines 681-683 from:
to:
#EndIf
Changed lines 683-694 from:
to:
'Scroll the menu if the following conditions exist -
'
' Menu can be scrolled down and pointer is on or below the second last
' line of the display
' OR
' Menu can be scrolled down and pointer is on the last menu item - this
' allows scroll wrapping
If (PointerLine >= LCDLines - 1 Or PointerPosition = LastItemNumber - FirstItemNumber) And CanScroll = True Then
Inc(ScrollPosition)
Changed lines 696-699 from:
#EndIf
Dec(PointerPosition)
DrawPointer(PointerPosition + 1)
Dec(PointerPosition)
DrawPointer(PointerPosition + 1)
to:
#If Menu_ScrollWrapping = True
Added lines 698-699:
'If scroll wrapping and we've scrolled to the bottom then start again at
'the top
'the top
Changed lines 701-707 from:
to:
If ScrollPosition > (LastItemNumber - FirstItemNumber) Then
ScrollPosition = 0
EndIf
#EndIf
ScrollPosition = 0
EndIf
#EndIf
Changed lines 709-735 from:
If ScrollPosition > 0 Then
Dec(ScrollPosition)
Else
ScrollPosition = LastItemNumber - FirstItemNumber
EndIf
DrawMenu()
DrawPointer(PointerPosition)
EndIf
#Else
ElseIf ScrollPosition > 0 Then
Dec(ScrollPosition)
DrawMenu()
DrawPointer(PointerPosition)
ElseIf PointerLine > 1 Then
Dec(PointerPosition)
#If Menu_LCDLines < 4 And Menu_ShowScrollIndicators = True
to:
DrawMenu()
DrawPointer(PointerPosition)
DrawPointer(PointerPosition)
Changed lines 712-723 from:
#EndIf
EndIf
#EndIf
to:
'If not scrolling the menu then move the pointer down if the following
'conditions exist -
'
' Pointer is not on the last line of the display
' AND
' Pointer isn't on the last menu item
ElseIf PointerLine < LCDLines And PointerPosition + FirstItemNumber + ScrollPosition < LastItemNumber Then
Inc(PointerPosition)
Changed lines 724-725 from:
#EndIf
to:
'Fix to ensure Up Arrow scroll indicator is shown on smaller displays
'when pointer moves down from top line
#If (Menu_LCDLines < 4 Or Menu_ScrollWrapping = True) And Menu_ShowScrollIndicators = True
DrawMenu()
DrawPointer(PointerPosition)
#Else
DrawPointer(PointerPosition - 1)
#EndIf
End If
'when pointer moves down from top line
#If (Menu_LCDLines < 4 Or Menu_ScrollWrapping = True) And Menu_ShowScrollIndicators = True
DrawMenu()
DrawPointer(PointerPosition)
#Else
DrawPointer(PointerPosition - 1)
#EndIf
End If
Changed lines 742-743 from:
'Name: Back()
'Purpose:Show parent of current menu
'Purpose:
to:
'Name: MoveUp()
'Purpose: Move pointer to previous menu item, scrolling menu if necessary
'Purpose: Move pointer to previous menu item, scrolling menu if necessary
Changed lines 747-770 from:
Public Sub Back()
ShowMenu(ParentID)
End Sub
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'Name: SelectItem()
'Purpose: Carries out action of selected menu item. If menu item opens
' another menu then that menu is drawn. If menu item is an 'action'
' item then the event in the main program which handles the action is
' called
'
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Public Sub SelectItem()
Dim ItemAction As Byte
SelectedMenuItem = FirstItemNumber + ScrollPosition + PointerPosition
#If Menu_ScrollWrapping = True
If SelectedMenuItem > LastItemNumber Then
End Sub
'Name:
'
'
'
Public Sub SelectItem()
Dim ItemAction As Byte
SelectedMenuItem = FirstItemNumber + ScrollPosition + PointerPosition
to:
Public Sub MoveUp()
'Routine decides whether to scroll the menu up or just move the pointer up
'depending on the current state:
'
'If there is a free LCD line above the pointer (i.e. one that doesn't have
'the menu title or a scroll indicator in it then move the pointer up;
'
'Otherwise, if the menu can be scrolled (either because scroll wrapping is
'on or because the current scroll position > 0) then scroll the menu up;
'
'If the menu can't be scrolled then move the pointer up, overwriting any
'scroll-up indicator. (If necessary, re-draw the scroll-down indicator).
#If Menu_ShowMenuTitle = True
#If Menu_ShowScrollIndicators = True
If PointerLine > 3 Then
'Routine decides whether to scroll the menu up or just move the pointer up
'depending on the current state:
'
'If there is a free LCD line above the pointer (i.e. one that doesn't have
'the menu title or a scroll indicator in it then move the pointer up;
'
'Otherwise, if the menu can be scrolled (either because scroll wrapping is
'on or because the current scroll position > 0) then scroll the menu up;
'
'If the menu can't be scrolled then move the pointer up, overwriting any
'scroll-up indicator. (If necessary, re-draw the scroll-down indicator).
#If Menu_ShowMenuTitle = True
#If Menu_ShowScrollIndicators = True
If PointerLine > 3 Then
Changed lines 767-771 from:
to:
#Else
If PointerLine > 2 Then
#EndIf
If PointerLine > 2 Then
#EndIf
Changed lines 773-783 from:
to:
Dec(PointerPosition)
DrawPointer(PointerPosition + 1)
#If Menu_ScrollWrapping = True
DrawPointer(PointerPosition + 1)
#If Menu_ScrollWrapping = True
Changed lines 778-780 from:
ShowMenu(ItemAction)
to:
Else
If ScrollPosition > 0 Then
Dec(ScrollPosition)
Else
ScrollPosition = LastItemNumber - FirstItemNumber
EndIf
DrawMenu()
DrawPointer(PointerPosition)
EndIf
#Else
ElseIf ScrollPosition > 0 Then
Dec(ScrollPosition)
DrawMenu()
DrawPointer(PointerPosition)
ElseIf PointerLine > 2 Then
Dec(PointerPosition)
#If Menu_LCDLines < 4 And Menu_ShowScrollIndicators = True
If ScrollPosition > 0 Then
Dec(ScrollPosition)
Else
ScrollPosition = LastItemNumber - FirstItemNumber
EndIf
DrawMenu()
DrawPointer(PointerPosition)
EndIf
#Else
ElseIf ScrollPosition > 0 Then
Dec(ScrollPosition)
DrawMenu()
DrawPointer(PointerPosition)
ElseIf PointerLine > 2 Then
Dec(PointerPosition)
#If Menu_LCDLines < 4 And Menu_ShowScrollIndicators = True
Changed lines 806-807 from:
to:
DrawMenu()
DrawPointer(PointerPosition)
#Else
DrawPointer(PointerPosition + 1)
#EndIf
EndIf
#EndIf
#Else
#If Menu_ShowScrollIndicators = True
If PointerLine > 2 Then
#Else
If PointerLine > 1 Then
#EndIf
Dec(PointerPosition)
DrawPointer(PointerPosition + 1)
#If Menu_ScrollWrapping = True
Else
If ScrollPosition > 0 Then
Dec(ScrollPosition)
Else
ScrollPosition = LastItemNumber - FirstItemNumber
EndIf
DrawMenu()
DrawPointer(PointerPosition)
EndIf
#Else
ElseIf ScrollPosition > 0 Then
Dec(ScrollPosition)
DrawMenu()
DrawPointer(PointerPosition)
ElseIf PointerLine > 1 Then
Dec(PointerPosition)
#If Menu_LCDLines < 4 And Menu_ShowScrollIndicators = True
DrawMenu()
DrawPointer(PointerPosition)
#Else
DrawPointer(PointerPosition + 1)
#EndIf
EndIf
#EndIf
#EndIf
DrawPointer(PointerPosition)
#Else
DrawPointer(PointerPosition + 1)
#EndIf
EndIf
#EndIf
#Else
#If Menu_ShowScrollIndicators = True
If PointerLine > 2 Then
#Else
If PointerLine > 1 Then
#EndIf
Dec(PointerPosition)
DrawPointer(PointerPosition + 1)
#If Menu_ScrollWrapping = True
Else
If ScrollPosition > 0 Then
Dec(ScrollPosition)
Else
ScrollPosition = LastItemNumber - FirstItemNumber
EndIf
DrawMenu()
DrawPointer(PointerPosition)
EndIf
#Else
ElseIf ScrollPosition > 0 Then
Dec(ScrollPosition)
DrawMenu()
DrawPointer(PointerPosition)
ElseIf PointerLine > 1 Then
Dec(PointerPosition)
#If Menu_LCDLines < 4 And Menu_ShowScrollIndicators = True
DrawMenu()
DrawPointer(PointerPosition)
#Else
DrawPointer(PointerPosition + 1)
#EndIf
EndIf
#EndIf
#EndIf
Changed lines 883-885 from:
'Name: Initialise(pItemActionEvent as TEvent)
'Purpose: Sets name of main program event handler and loads custom scroll
' characters into LCD
' characters into LCD
to:
'Name: Back()
'Purpose: Show parent of current menu
'Purpose: Show parent of current menu
Changed lines 888-897 from:
Public Sub Initialise(pItemActionEvent As TEvent)
FItemActionEvent = pItemActionEvent
#If Menu_ShowScrollIndicators = True Then
LCD.Write(ScrollIndicators)
#EndIf
#If Menu_ShowScrollIndicators = True Then
LCD.Write
#EndIf
to:
Public Sub Back()
ShowMenu(ParentID)
ShowMenu(ParentID)
Added lines 894-953:
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'Name: SelectItem()
'Purpose: Carries out action of selected menu item. If menu item opens
' another menu then that menu is drawn. If menu item is an 'action'
' item then the event in the main program which handles the action is
' called
'
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Public Sub SelectItem()
Dim ItemAction As Byte
SelectedMenuItem = FirstItemNumber + ScrollPosition + PointerPosition
#If Menu_ScrollWrapping = True
If SelectedMenuItem > LastItemNumber Then
SelectedMenuItem = SelectedMenuItem - (LastItemNumber - FirstItemNumber) - 1
EndIf
#EndIf
ItemAction = mnuItemAction(SelectedMenuItem)
If ItemAction = 255 Then
ParentID = CurrentMenu 'Means 'back' command will return to correct menu
FItemActionEvent() 'Call event handler in main program
Else
ShowMenu(ItemAction)
EndIf
End Sub
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'Name: Initialise(pItemActionEvent as TEvent)
'Purpose: Sets name of main program event handler and loads custom scroll
' characters into LCD
'
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Public Sub Initialise(pItemActionEvent As TEvent)
FItemActionEvent = pItemActionEvent
#If Menu_ShowScrollIndicators = True Then
LCD.Write(ScrollIndicators)
#EndIf
End Sub
'Name: SelectItem()
'Purpose: Carries out action of selected menu item. If menu item opens
' another menu then that menu is drawn. If menu item is an 'action'
' item then the event in the main program which handles the action is
' called
'
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Public Sub SelectItem()
Dim ItemAction As Byte
SelectedMenuItem = FirstItemNumber + ScrollPosition + PointerPosition
#If Menu_ScrollWrapping = True
If SelectedMenuItem > LastItemNumber Then
SelectedMenuItem = SelectedMenuItem - (LastItemNumber - FirstItemNumber) - 1
EndIf
#EndIf
ItemAction = mnuItemAction(SelectedMenuItem)
If ItemAction = 255 Then
ParentID = CurrentMenu 'Means 'back' command will return to correct menu
FItemActionEvent() 'Call event handler in main program
Else
ShowMenu(ItemAction)
EndIf
End Sub
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'Name: Initialise(pItemActionEvent as TEvent)
'Purpose: Sets name of main program event handler and loads custom scroll
' characters into LCD
'
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Public Sub Initialise(pItemActionEvent As TEvent)
FItemActionEvent = pItemActionEvent
#If Menu_ShowScrollIndicators = True Then
LCD.Write(ScrollIndicators)
#EndIf
End Sub
Changed line 6 from:
!!!Module
to:
!!!Menu Module
Added lines 658-1193:
!!!Updated LCD Module
=code [=
{
****************************************************************
* Name : LCD.BAS - Modified *
* Author : David John Barker - modified by AndyO *
* Notice : Copyright (c) 2006 Mecanique *
* : All Rights Reserved *
* Date : 17/07/2008 *
* Version : 1.2 - Added "WriteConstStringAt" function for *
* sending String Const Array to LCD without using *
* RAM - uses ByRefConst method of parameter passing *
* : 1.1 - Implements optional RW pin for testing the *
* device busy flag, rather than using fixed delays *
* : 1.0 - Release *
* Notes : Supports Hitachi HD44780 LCD controller *
****************************************************************
}
Module LCD
Include "system.bas"
Include "utils.bas"
// by default, the module assumes RW is not used and tied to ground - if the
// user specifies a RW pin, then data read code is linked in...
#if IsOption(LCD_RW)
#define _RW_USED
#if Not IsValidPortPin(LCD_RW)
#error LCD_RW, "Invalid option. RW must be a valid port pin."
#endif
#endif
// user has specified a data port, check to see if it is 8
// bit or 4 bit interface...
#if IsOption(LCD_DATA)
#ifndef LCD_DATA@
#define _LCD_INTERFACE_08
#endif
#endif
// default module option - user options can override these values...
#option LCD_DATA = PORTB.4
#option LCD_RS = PORTB.3
#option LCD_EN = PORTB.2
#option LCD_COMMAND_US = 2000
#option LCD_DATA_US = 50
#option LCD_INIT_DELAY = 100
// validate data port...
#if IsOption(LCD_DATA)
#if Not IsValidPort(LCD_DATA)
#error LCD_DATA, "Invalid option. DATA must be a valid port name."
#endif
// has the user specified a DATA port bit? If so, then
// we need to validate and set for 4 bit interface...
#ifdef LCD_DATA@ Then
#if Not (LCD_DATA@ in (0,4))
#error LCD_DATA@, "Invalid option. DATA pin must be 0 or 4."
#endif
#if LCD_DATA@ = 4
#define _LCD_UPPER
#endif
#endif
#endif
// create TRIS, based on the DATA port option...
#option _LCD_DATA_TRIS = GetTRIS(LCD_DATA)
// validate RS pin...
#if IsOption(LCD_RS) And Not IsValidPortPin(LCD_RS)
#error LCD_RS, "Invalid option. RS must be a valid port pin."
#endif
// validate EN pin...
#if IsOption(LCD_EN) And Not IsValidPortPin(LCD_EN)
#error LCD_EN, "Invalid option. EN must be a valid port pin."
#endif
// validate command delay...
#if IsOption(LCD_COMMAND_US) And Not (LCD_COMMAND_US in (1 to 65535))
#error LCD_COMMAND_US, "Invalid option. Command delay must be between 1 and 65535 us."
#endif
// validate data delay...
#if IsOption(LCD_DATA_US) And Not (LCD_DATA_US in (1 to 255))
#error LCD_DATA_US, "Invalid option. Data delay must be between 1 and 255 us."
#endif
// validate initialisation delay...
#if IsOption(LCD_INIT_DELAY)
#if Not (LCD_INIT_DELAY in (0 to 1000))
#error LCD_INIT_DELAY, "Invalid option. LCD initialize delay must be between 0 and 1000 (ms)."
#endif
#endif
// public command constants...
Public Const
cmdCGRAM = %01000000,
cmdDDRAM = %10000000,
cmdClear = %00000001,
cmdHome = %00000010,
cmdCursorOff = %00001100,
cmdCursorOn = %00001110,
cmdBlinkOn = %00001101,
cmdBlinkOff = %00001100,
cmdMoveLeft = %00010000,
cmdMoveRight = %00010100
// bring delay options into the module...
Const
DataUS = LCD_DATA_US,
CommandUS = LCD_COMMAND_US,
LCDDelay = LCD_INIT_DELAY
// bring port and pin options into the module...
Dim
Data As LCD_DATA, // DATA port
TRISData As _LCD_DATA_TRIS, // DATA port TRIS
RS As LCD_RS.LCD_RS@, // register select
EN As LCD_EN.LCD_EN@, // enable read
FPosX, FPosY As Byte // local x, y coordinates
// RW specified...
#ifdef _RW_USED
Dim RW As LCD_RW.LCD_RW@
#endif
{
****************************************************************************
* Name : StrobeEN (PRIVATE) *
* Purpose : Strobe read enable *
****************************************************************************
}
Inline Sub StrobeEN()
EN = 1
ASM-
Nop
End ASM
EN = 0
End Sub
{
****************************************************************************
* Name : MakeOutput (PRIVATE) *
* Purpose : Make data pins output *
****************************************************************************
}
#ifdef _RW_USED
Sub MakeOutput()
#ifdef _LCD_INTERFACE_08
TRISData = $00
#else
#ifdef _LCD_UPPER
TRISData = TRISData And $0F
#else
TRISData = TRISData And $F0
#endif
#endif
End Sub
{
****************************************************************************
* Name : MakeInput (PRIVATE) *
* Purpose : Make data pins input *
****************************************************************************
}
Sub MakeInput()
#ifdef _LCD_INTERFACE_08
TRISData = $FF
#else
#ifdef _LCD_UPPER
TRISData = TRISData Or $F0
#else
TRISData = TRISData Or $0F
#endif
#endif
End Sub
{
****************************************************************************
* Name : GetData (PRIVATE) *
* Purpose : Read Data port value. For 4 bit interface, value is returned *
* : in LSNibble *
****************************************************************************
}
Function GetData() As Byte
EN = 1
ASM-
bra $ + 2
bra $ + 2
End ASM
result = Data
#ifndef _LCD_INTERFACE_08
#ifdef _LCD_UPPER
result = result >> 4
#else
result = result And $0F
#endif
#endif
EN = 0
End Function
{
****************************************************************************
* Name : ReadByte (PRIVATE) *
* Purpose : Read a data byte from the device *
****************************************************************************
}
Function ReadByte() As Byte
MakeInput
RS = 0
RW = 1
#ifdef _LCD_INTERFACE_08
result = GetData
#else
result = GetData << 4 // high nibble
result = result Or (GetData And $0F) // low nibble
#endif
RW = 0
MakeOutput
End Function
{
****************************************************************************
* Name : WaitFor (PRIVATE) *
* Purpose : Wait for device busy flag to clear *
****************************************************************************
}
Sub WaitFor()
Repeat
Until (ReadByte And $80) = 0
End Sub
#endif // _RW_USED
{
****************************************************************************
* Name : SetData (PRIVATE) *
* Purpose : Sets DATA port value *
****************************************************************************
}
Sub SetData(pData As Byte)
#ifdef _LCD_INTERFACE_08
Data = pData
#else
#ifdef _LCD_UPPER
Data = Data And $0F
Data = Data Or (pData And $F0)
#else
Data = Data And $F0
Data = Data Or (pData And $0F)
#endif
#endif
StrobeEN
ClrWDT
End Sub
{
****************************************************************************
* Name : SetDDRAM (PRIVATE) *
* Purpose : Set DDRAM address *
****************************************************************************
}
Sub SetDDRAM(pAddr As Byte)
#ifdef _RW_USED
WaitFor
#endif
RS = 0
#ifdef _LCD_INTERFACE_08
SetData(pAddr Or %10000000)
#else
#ifdef _LCD_UPPER
SetData(pAddr Or %10000000)
SetData(pAddr << 4)
#else
SetData((pAddr Or %10000000) >> 4)
SetData(pAddr)
#endif
#endif
#ifndef _RW_USED
DelayUS(DataUS)
#endif
ClrWDT
End Sub
{
****************************************************************************
* Name : Command *
* Purpose : Write command to LCD *
****************************************************************************
}
Public Sub Command(pCommand As Byte)
#ifdef _RW_USED
WaitFor
#endif
RS = 0
#ifdef _LCD_INTERFACE_08
SetData(pCommand)
#else
#ifdef _LCD_UPPER
SetData(pCommand)
SetData(pCommand << 4)
#else
SetData(pCommand >> 4)
SetData(pCommand)
#endif
#endif
#ifndef _RW_USED
DelayUS(CommandUS)
#endif
ClrWDT
End Sub
{
****************************************************************************
* Name : MoveCursor *
* Purpose : Move the cursor to line and column *
****************************************************************************
}
Public Sub MoveCursor(pLine, pCol As Byte)
Dec(pCol)
Select pLine
Case 1 : SetDDRAM(pCol)
Case 2 : SetDDRAM($40 + pCol)
Case 3 : SetDDRAM($14 + pCol)
Case 4 : SetDDRAM($54 + pCol)
End Select
End Sub
{
****************************************************************************
* Name : WriteItem (OVERLOAD) *
* Purpose : Write a single byte to the LCD *
****************************************************************************
}
Sub WriteItem(pData As Byte)
#ifdef _RW_USED
WaitFor
#endif
RS = 1
#ifdef _LCD_INTERFACE_08
SetData(pData)
#else
#ifdef _LCD_UPPER
SetData(pData)
SetData(pData << 4)
#else
SetData(pData >> 4)
SetData(pData)
#endif
#endif
#ifndef _RW_USED
DelayUS(DataUS)
#endif
ClrWDT
End Sub
{
****************************************************************************
* Name : WriteItem (OVERLOAD) *
* Purpose : Write a string to the LCD *
****************************************************************************
}
Sub WriteItem(pText As String)
Dim TextPtr As POSTINC0
Dim Text As INDF0
FSR0 = AddressOf(pText)
While Text <> 0
WriteItem(TextPtr)
Wend
End Sub
{
****************************************************************************
* Name : WriteItem (OVERLOAD) *
* Purpose : Initialise the CGRAM with constant data array. Eight *
* : programmable characters are available (0..7). *
****************************************************************************
}
Sub WriteItem(ByRefConst pBitmap() As Byte)
Dim Index As Byte
Command(cmdCGRAM)
For Index = 0 To Bound(pBitmap)
WriteItem(pBitmap(Index))
Next
Command(cmdDDRAM)
End Sub
{
****************************************************************************
* Name : Write (COMPOUND) *
* Purpose : Calls one or more WriteItem() subroutines *
****************************************************************************
}
Public Compound Sub Write(WriteItem)
{
****************************************************************************
* Name : MoveTo (PRIVATE) *
* Purpose : Moves cursor to module private x, y location *
****************************************************************************
}
Sub MoveTo()
MoveCursor(FPosY, FPosX)
End Sub
{
****************************************************************************
* Name : SetLocationX (PRIVATE) *
* Purpose : Set cursor x *
****************************************************************************
}
Sub SetLocationX(pX As Byte)
FPosX = pX
End Sub
{
****************************************************************************
* Name : SetLocationY (PRIVATE) *
* Purpose : Set cursor y *
****************************************************************************
}
Sub SetLocationY(pY As Byte)
FPosY = pY
End Sub
{
****************************************************************************
* Name : WriteAt (COMPOUND) *
* Purpose : Calls one or more WriteItem() subroutines at location x, y *
****************************************************************************
}
Public Compound Sub WriteAt(SetLocationY, SetLocationX, MoveTo, WriteItem)
{
****************************************************************************
* Name : WriteConstStringAt(pY, pX As Byte,ByRefConst pText As String) *
* Purpose : Writes a string stored in a Const Array *
****************************************************************************
}
Public Sub WriteConstStringAt(pY, pX As Byte, ByRefConst pText As String)
SetLocationY(pY)
SetLocationX(pX)
MoveTo()
EECON1 = 0
EECON1.7 = 1
TABLEPTR = @pText
ASM
TBLRD*+
End ASM
While TABLAT <> 0
WriteItem(TABLAT)
ASM
TBLRD*+
End ASM
Wend
End Sub
{
****************************************************************************
* Name : Cls *
* Purpose : Clear the LCD screen *
****************************************************************************
}
Public Sub Cls()
Command(cmdClear)
DelayMS(30)
End Sub
{
****************************************************************************
* Name : DoInitSequence (PRIVATE) *
* Purpose : Performs a initialization sequence *
****************************************************************************
}
Sub DoInitSequence(pValue As Byte)
SetData(pValue)
DelayMS(5)
SetData(pValue)
DelayUS(160)
SetData(pValue)
DelayUS(160)
End Sub
{
****************************************************************************
* Name : Initialize (PRIVATE) *
* Purpose : Initialize the LCD *
****************************************************************************
}
Sub Initialize()
// wait for LCD to stabilise...
SetAllDigital
DelayMS(LCDDelay)
// read write...
#ifdef _RW_USED
Low(RW)
#endif
// set RS and EN to low output...
Low(RS)
Low(EN)
DelayMS(15)
// initialise for 8 bit interface...
#ifdef _LCD_INTERFACE_08
Data = $00
TRISData = $00
DoInitSequence($30)
Command(%00111000) // DL = 1, N = 1, F = 0
// initialise for 4 bit interface...
#else
#ifdef _LCD_UPPER
Data = Data And $0F
TRISData = TRISData And $0F
DoInitSequence($30)
SetData($20)
DelayUS(160)
#else
Data = Data And $F0
TRISData = TRISData And $F0
DoInitSequence($03)
SetData($02)
DelayUS(160)
#endif
Command(%00101000) // DL = 0, N = 1, F = 0
#endif
Command(%00001000) // D = 0, C = 0, B = 0
Command(%00000001) // Clear
Command(%00000110) // ID = 1, S = 0
Command(%00001100) // D = 1, C = 0, B = 0
End Sub
// initialise the module...
Initialize
=]
Added lines 1-657:
!!!Sample Code
=code [=
=]
!!!Module
=code [=
{
********************************************************************************
* Name : LCD Menu Module *
* Author : AndyO *
* Notice : Copyright (c) 2008 AndyO *
* : All Rights Reserved *
* Date : 13/07/2008 *
* Version : 1.0 *
* Notes : See doc "LCD Menu Module.pdf" *
* : *
* : Menu data stored in Const arrays which are declared in seperate *
* : module indicated by #define MenuDataModule = "filename.BAS" in *
* : main program *
* : *
* : Requires modified LCD.bas module. Following sub should be placed *
* : after sub "WriteAt": *
* *
* ------------------------------------------------------------------------- *
Public Sub WriteConstStringAt(pY, pX As Byte, ByRefConst pText As String)
SetLocationY(pY)
SetLocationX(pX)
MoveTo()
EECON1 = 0
EECON1.7 = 1
TABLEPTR = @pText
ASM
TBLRD*+
End ASM
While TABLAT <> 0
WriteItem(TABLAT)
ASM
TBLRD*+
End ASM
Wend
End Sub
* ------------------------------------------------------------------------- *
* *
* *
********************************************************************************
}
Module Menu
Include "LCD.bas"
#ifdef MenuDataModule
Include MenuDataModule
#else
#error "No MenuDataModule defined in main program"
#endif
'===============================================================================
'User definable options
'-------------------------------------------------------------------------------
#option Menu_LCDLines = 4 'Number of lines on LCD display
#option Menu_ShowMenuTitle = True 'Display Menu Name at top of screen?
#option Menu_ShowScrollIndicators = True 'Show up and down scroll indicators?
#option Menu_ScrollWrapping = False 'Scroll wraps from top to bottom?
#option Menu_PointerCharacter = 126 'Character used as pointer
#if Menu_LCDLines = 1 And Menu_ShowMenuTitle = True
#error "Cannot show menu titles on 1 line LCD"
#endif
'===============================================================================
'Variable and Const Declarations
'-------------------------------------------------------------------------------
'---Types
Type TEvent = Event()
'---Bring options into module
Private Const
LCDLines As Byte = Menu_LCDLines,
PointerCharacter As Byte = Menu_PointerCharacter
'---Custom Characters (only loaded if option Menu_ShowScrollIndicators = True)
#If Menu_ShowScrollIndicators = True
'Character definitions for Up Arrow and Down Arrow scroll indicators
Private Const ScrollIndicators(16) As Byte=($04,$0E,$1F,$00,$00,$00,$00,$00,
$00,$00,$00,$00,$00,$1F,$0E,$04)
Private Const UpArrow = 0
Private Const DownArrow = 1
#EndIf
'---Private Variables
Private Dim FItemActionEvent As TEvent 'Holds pointer to event code in main
'program which is run when an "action"
'menu item is selected
Private Dim PointerPosition As Byte 'Position of pointer character (0 = 1st)
Private Dim PointerLine As Byte 'Actual LCD line of pointer
Private Dim ScrollPosition As Byte 'Number of lines the menu is scrolled by
Private Dim CurrentMenu As Byte 'Index number of current menu
Private Dim ParentID As Byte 'Index number of parent of current menu
Private Dim FirstItemNumber As Byte 'First item number for current menu
Private Dim LastItemNumber As Byte 'Last item number for current menu
'---Public Variables
Public Dim SelectedMenuItem As Byte 'Index number of selected menu item
'===============================================================================
'Helper Subs and Functions (Private - can't be called from main program)
'-------------------------------------------------------------------------------
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'Name: DrawMenu(pMenuNumber as byte)
'Purpose: Draws current menu, scrolled by ScrollPosition amount
'
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Private Sub DrawMenu()
Dim LineNumber As Byte 'Line number of LCD to write at
Dim ItemNumber As Byte 'Index of menu item number to write
#If Menu_ScrollWrapping = True '}
'}If scroll wrapping enabled then
Dim ItemsDrawn As Byte '}also need to keep track of number
'}of menu items drawn on LCD
ItemsDrawn = 0 '}
'}
#EndIf
LCD.Cls
LineNumber = 1
ItemNumber = FirstItemNumber + ScrollPosition
#If Menu_ShowMenuTitle = True 'If option enabled, show Menu Title
LCD.WriteConstStringAt(1, 1, mnuMenuName(CurrentMenu))
LineNumber = 2
#Endif
'Loop which keeps writing menu items until the following conditions exist -
'
' Scroll Wrapping Enabled: write menu items (wrapping from last menu item
' back to first menu item as necessary) until either the number of LCD
' lines has been reached or all menu items have been written (ItemsDrawn =
' LastItemNumber - FirstItemNumber)
'
' Scroll Wrapping Not Enabled: write items until the number of LCD lines
' has been reached or the last menu item has been written
Repeat
LCD.WriteConstStringAt(LineNumber, 2, mnuItemName(ItemNumber))
Inc(LineNumber)
Inc(ItemNumber)
#If Menu_ScrollWrapping = True
Inc(ItemsDrawn)
If ItemNumber > LastItemNumber Then '}
'}Scroll wrapping enabled so wrap
ItemNumber = FirstItemNumber '}from last menu item to the first
'}menu item
EndIf '}
Until LineNumber > LCDLines Or ItemsDrawn > LastItemNumber - FirstItemNumber
#Else
Until LineNumber > LCDLines Or ItemNumber > LastItemNumber
#EndIf
'If Menu_ShowScrollIndicators option enabled then show scroll indicators
'depending on the following conditions -
'
' Scroll Wrapping Enabled: Show both Up and Down arrows if the number of
' menu items exceeds the number of available LCD lines
'
' Scroll Wrapping Not Enabled: Show Up arrow if menu can be scrolled up,
' Down arrow if there are more menu items to display
'
'Note: Number of available LCD lines and position of Up arrow depends on
' whether Menu_ShowMenuTitle is enabled or not
#If Menu_ShowScrollIndicators = True
#If Menu_ScrollWrapping = True
#If Menu_ShowMenuTitle = True
If LastItemNumber - FirstItemNumber > LCDLines - 1 Then
LCD.WriteAt(LCDLines, 1, DownArrow)
LCD.WriteAt(2, 1, UpArrow)
#Else
If LastItemNumber - FirstItemNumber > LCDLines Then
LCD.WriteAt(LCDLines, 1, DownArrow)
LCD.WriteAt(1, 1, UpArrow)
#EndIf
EndIf
#Else
If ItemNumber - 1 < LastItemNumber Then
LCD.WriteAt(LCDLines, 1, DownArrow)
EndIf
If ScrollPosition > 0 Then
#If Menu_ShowMenuTitle = True
LCD.WriteAt(2, 1, UpArrow)
#Else
LCD.WriteAt(1, 1, UpArrow)
#EndIf
EndIf
#EndIf
#EndIf
End Sub
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'Name: DrawPointer(pOldPosition as byte)
'Purpose: Deletes pointer at pOldPosition and draws pointer at PointerPosition
'
'Notes: When pointer is at first menu item on screen, PointerPosition = 0
'
' Pointer character determined by option "Menu_PointerCharacter",
' default = 126 (right arrow)
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Private Sub DrawPointer(pOldPosition As Byte)
'Actual LCD line which pointer is drawn on depends on whether
'Menu_ShowMenuTitle is enabled or not
#If Menu_ShowMenuTitle Then
PointerLine = PointerPosition + 2
LCD.WriteAt(pOldPosition + 2, 1, " ")
LCD.WriteAt(PointerLine, 1, PointerCharacter)
#Else
PointerLine = PointerPosition + 1
LCD.WriteAt(pOldPosition + 1, 1, " ")
LCD.WriteAt(PointerLine, 1, PointerCharacter)
#EndIf
End Sub
'===============================================================================
'Public Subs and Functions
'-------------------------------------------------------------------------------
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'Name: ShowMenu(pMenuNumber as byte = 0)
'Purpose: Display specified menu on LCD
'
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Public Sub ShowMenu(pMenuNumber As Byte = 0)
'Reset scroll and pointer positions
ScrollPosition = 0
PointerPosition = 0
'Set values for first item number, last item number & parentID for current
'menu
CurrentMenu = pMenuNumber
ParentID = mnuParentMenuID(CurrentMenu)
FirstItemNumber = mnuMenuItemStart(CurrentMenu)
LastItemNumber = mnuMenuItemEnd(CurrentMenu)
'Display menu & pointer
DrawMenu
DrawPointer(0)
End Sub
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'Name: MoveDown()
'Purpose: Move pointer to next menu item, scrolling the menu if necessary
'
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Public Sub MoveDown()
Dim CanScroll As Boolean
'First, determine if the menu can be scrolled down and set CanScroll -
'
' If Scroll Wrapping Not Enabled: Menu may only be scrolled down if the
' number of menu items left to display won't fit on the number of
' available LCD lines
'
' Note: Number of available lines depends on whether Menu_ShowMenuTitle is
' enabled or not
'
' If Scroll Wrapping Enabled: Can always scroll down
#If Menu_ScrollWrapping = False
CanScroll = False
#If Menu_ShowMenuTitle = True Then
If FirstItemNumber + ScrollPosition + LCDLines - 2 < LastItemNumber Then
CanScroll = True
EndIf
#Else
If FirstItemNumber + ScrollPosition + LCDLines - 1 < LastItemNumber Then
CanScroll = True
EndIf
#EndIf
#Else
CanScroll = True
#EndIf
'Scroll the menu if the following conditions exist -
'
' Menu can be scrolled down and pointer is on or below the second last
' line of the display
' OR
' Menu can be scrolled down and pointer is on the last menu item - this
' allows scroll wrapping
If (PointerLine >= LCDLines - 1 Or PointerPosition = LastItemNumber - FirstItemNumber) And CanScroll = True Then
Inc(ScrollPosition)
#If Menu_ScrollWrapping = True
'If scroll wrapping and we've scrolled to the bottom then start again at
'the top
If ScrollPosition > (LastItemNumber - FirstItemNumber) Then
ScrollPosition = 0
EndIf
#EndIf
DrawMenu()
DrawPointer(PointerPosition)
'If not scrolling the menu then move the pointer down if the following
'conditions exist -
'
' Pointer is not on the last line of the display
' AND
' Pointer isn't on the last menu item
ElseIf PointerLine < LCDLines And PointerPosition + FirstItemNumber + ScrollPosition < LastItemNumber Then
Inc(PointerPosition)
'Fix to ensure Up Arrow scroll indicator is shown on smaller displays
'when pointer moves down from top line
#If (Menu_LCDLines < 4 Or Menu_ScrollWrapping = True) And Menu_ShowScrollIndicators = True
DrawMenu()
DrawPointer(PointerPosition)
#Else
DrawPointer(PointerPosition - 1)
#EndIf
End If
End Sub
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'Name: MoveUp()
'Purpose: Move pointer to previous menu item, scrolling menu if necessary
'
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Public Sub MoveUp()
'Routine decides whether to scroll the menu up or just move the pointer up
'depending on the current state:
'
'If there is a free LCD line above the pointer (i.e. one that doesn't have
'the menu title or a scroll indicator in it then move the pointer up;
'
'Otherwise, if the menu can be scrolled (either because scroll wrapping is
'on or because the current scroll position > 0) then scroll the menu up;
'
'If the menu can't be scrolled then move the pointer up, overwriting any
'scroll-up indicator. (If necessary, re-draw the scroll-down indicator).
#If Menu_ShowMenuTitle = True
#If Menu_ShowScrollIndicators = True
If PointerLine > 3 Then
#Else
If PointerLine > 2 Then
#EndIf
Dec(PointerPosition)
DrawPointer(PointerPosition + 1)
#If Menu_ScrollWrapping = True
Else
If ScrollPosition > 0 Then
Dec(ScrollPosition)
Else
ScrollPosition = LastItemNumber - FirstItemNumber
EndIf
DrawMenu()
DrawPointer(PointerPosition)
EndIf
#Else
ElseIf ScrollPosition > 0 Then
Dec(ScrollPosition)
DrawMenu()
DrawPointer(PointerPosition)
ElseIf PointerLine > 2 Then
Dec(PointerPosition)
#If Menu_LCDLines < 4 And Menu_ShowScrollIndicators = True
DrawMenu()
DrawPointer(PointerPosition)
#Else
DrawPointer(PointerPosition + 1)
#EndIf
EndIf
#EndIf
#Else
#If Menu_ShowScrollIndicators = True
If PointerLine > 2 Then
#Else
If PointerLine > 1 Then
#EndIf
Dec(PointerPosition)
DrawPointer(PointerPosition + 1)
#If Menu_ScrollWrapping = True
Else
If ScrollPosition > 0 Then
Dec(ScrollPosition)
Else
ScrollPosition = LastItemNumber - FirstItemNumber
EndIf
DrawMenu()
DrawPointer(PointerPosition)
EndIf
#Else
ElseIf ScrollPosition > 0 Then
Dec(ScrollPosition)
DrawMenu()
DrawPointer(PointerPosition)
ElseIf PointerLine > 1 Then
Dec(PointerPosition)
#If Menu_LCDLines < 4 And Menu_ShowScrollIndicators = True
DrawMenu()
DrawPointer(PointerPosition)
#Else
DrawPointer(PointerPosition + 1)
#EndIf
EndIf
#EndIf
#EndIf
End Sub
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'Name: Back()
'Purpose: Show parent of current menu
'
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Public Sub Back()
ShowMenu(ParentID)
End Sub
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'Name: SelectItem()
'Purpose: Carries out action of selected menu item. If menu item opens
' another menu then that menu is drawn. If menu item is an 'action'
' item then the event in the main program which handles the action is
' called
'
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Public Sub SelectItem()
Dim ItemAction As Byte
SelectedMenuItem = FirstItemNumber + ScrollPosition + PointerPosition
#If Menu_ScrollWrapping = True
If SelectedMenuItem > LastItemNumber Then
SelectedMenuItem = SelectedMenuItem - (LastItemNumber - FirstItemNumber) - 1
EndIf
#EndIf
ItemAction = mnuItemAction(SelectedMenuItem)
If ItemAction = 255 Then
ParentID = CurrentMenu 'Means 'back' command will return to correct menu
FItemActionEvent() 'Call event handler in main program
Else
ShowMenu(ItemAction)
EndIf
End Sub
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'Name: Initialise(pItemActionEvent as TEvent)
'Purpose: Sets name of main program event handler and loads custom scroll
' characters into LCD
'
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Public Sub Initialise(pItemActionEvent As TEvent)
FItemActionEvent = pItemActionEvent
#If Menu_ShowScrollIndicators = True Then
LCD.Write(ScrollIndicators)
#EndIf
End Sub
'===============================================================================
'Module Initialisation
'-------------------------------------------------------------------------------
=]
=code [=
=]
!!!Module
=code [=
{
********************************************************************************
* Name : LCD Menu Module *
* Author : AndyO *
* Notice : Copyright (c) 2008 AndyO *
* : All Rights Reserved *
* Date : 13/07/2008 *
* Version : 1.0 *
* Notes : See doc "LCD Menu Module.pdf" *
* : *
* : Menu data stored in Const arrays which are declared in seperate *
* : module indicated by #define MenuDataModule = "filename.BAS" in *
* : main program *
* : *
* : Requires modified LCD.bas module. Following sub should be placed *
* : after sub "WriteAt": *
* *
* ------------------------------------------------------------------------- *
Public Sub WriteConstStringAt(pY, pX As Byte, ByRefConst pText As String)
SetLocationY(pY)
SetLocationX(pX)
MoveTo()
EECON1 = 0
EECON1.7 = 1
TABLEPTR = @pText
ASM
TBLRD*+
End ASM
While TABLAT <> 0
WriteItem(TABLAT)
ASM
TBLRD*+
End ASM
Wend
End Sub
* ------------------------------------------------------------------------- *
* *
* *
********************************************************************************
}
Module Menu
Include "LCD.bas"
#ifdef MenuDataModule
Include MenuDataModule
#else
#error "No MenuDataModule defined in main program"
#endif
'===============================================================================
'User definable options
'-------------------------------------------------------------------------------
#option Menu_LCDLines = 4 'Number of lines on LCD display
#option Menu_ShowMenuTitle = True 'Display Menu Name at top of screen?
#option Menu_ShowScrollIndicators = True 'Show up and down scroll indicators?
#option Menu_ScrollWrapping = False 'Scroll wraps from top to bottom?
#option Menu_PointerCharacter = 126 'Character used as pointer
#if Menu_LCDLines = 1 And Menu_ShowMenuTitle = True
#error "Cannot show menu titles on 1 line LCD"
#endif
'===============================================================================
'Variable and Const Declarations
'-------------------------------------------------------------------------------
'---Types
Type TEvent = Event()
'---Bring options into module
Private Const
LCDLines As Byte = Menu_LCDLines,
PointerCharacter As Byte = Menu_PointerCharacter
'---Custom Characters (only loaded if option Menu_ShowScrollIndicators = True)
#If Menu_ShowScrollIndicators = True
'Character definitions for Up Arrow and Down Arrow scroll indicators
Private Const ScrollIndicators(16) As Byte=($04,$0E,$1F,$00,$00,$00,$00,$00,
$00,$00,$00,$00,$00,$1F,$0E,$04)
Private Const UpArrow = 0
Private Const DownArrow = 1
#EndIf
'---Private Variables
Private Dim FItemActionEvent As TEvent 'Holds pointer to event code in main
'program which is run when an "action"
'menu item is selected
Private Dim PointerPosition As Byte 'Position of pointer character (0 = 1st)
Private Dim PointerLine As Byte 'Actual LCD line of pointer
Private Dim ScrollPosition As Byte 'Number of lines the menu is scrolled by
Private Dim CurrentMenu As Byte 'Index number of current menu
Private Dim ParentID As Byte 'Index number of parent of current menu
Private Dim FirstItemNumber As Byte 'First item number for current menu
Private Dim LastItemNumber As Byte 'Last item number for current menu
'---Public Variables
Public Dim SelectedMenuItem As Byte 'Index number of selected menu item
'===============================================================================
'Helper Subs and Functions (Private - can't be called from main program)
'-------------------------------------------------------------------------------
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'Name: DrawMenu(pMenuNumber as byte)
'Purpose: Draws current menu, scrolled by ScrollPosition amount
'
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Private Sub DrawMenu()
Dim LineNumber As Byte 'Line number of LCD to write at
Dim ItemNumber As Byte 'Index of menu item number to write
#If Menu_ScrollWrapping = True '}
'}If scroll wrapping enabled then
Dim ItemsDrawn As Byte '}also need to keep track of number
'}of menu items drawn on LCD
ItemsDrawn = 0 '}
'}
#EndIf
LCD.Cls
LineNumber = 1
ItemNumber = FirstItemNumber + ScrollPosition
#If Menu_ShowMenuTitle = True 'If option enabled, show Menu Title
LCD.WriteConstStringAt(1, 1, mnuMenuName(CurrentMenu))
LineNumber = 2
#Endif
'Loop which keeps writing menu items until the following conditions exist -
'
' Scroll Wrapping Enabled: write menu items (wrapping from last menu item
' back to first menu item as necessary) until either the number of LCD
' lines has been reached or all menu items have been written (ItemsDrawn =
' LastItemNumber - FirstItemNumber)
'
' Scroll Wrapping Not Enabled: write items until the number of LCD lines
' has been reached or the last menu item has been written
Repeat
LCD.WriteConstStringAt(LineNumber, 2, mnuItemName(ItemNumber))
Inc(LineNumber)
Inc(ItemNumber)
#If Menu_ScrollWrapping = True
Inc(ItemsDrawn)
If ItemNumber > LastItemNumber Then '}
'}Scroll wrapping enabled so wrap
ItemNumber = FirstItemNumber '}from last menu item to the first
'}menu item
EndIf '}
Until LineNumber > LCDLines Or ItemsDrawn > LastItemNumber - FirstItemNumber
#Else
Until LineNumber > LCDLines Or ItemNumber > LastItemNumber
#EndIf
'If Menu_ShowScrollIndicators option enabled then show scroll indicators
'depending on the following conditions -
'
' Scroll Wrapping Enabled: Show both Up and Down arrows if the number of
' menu items exceeds the number of available LCD lines
'
' Scroll Wrapping Not Enabled: Show Up arrow if menu can be scrolled up,
' Down arrow if there are more menu items to display
'
'Note: Number of available LCD lines and position of Up arrow depends on
' whether Menu_ShowMenuTitle is enabled or not
#If Menu_ShowScrollIndicators = True
#If Menu_ScrollWrapping = True
#If Menu_ShowMenuTitle = True
If LastItemNumber - FirstItemNumber > LCDLines - 1 Then
LCD.WriteAt(LCDLines, 1, DownArrow)
LCD.WriteAt(2, 1, UpArrow)
#Else
If LastItemNumber - FirstItemNumber > LCDLines Then
LCD.WriteAt(LCDLines, 1, DownArrow)
LCD.WriteAt(1, 1, UpArrow)
#EndIf
EndIf
#Else
If ItemNumber - 1 < LastItemNumber Then
LCD.WriteAt(LCDLines, 1, DownArrow)
EndIf
If ScrollPosition > 0 Then
#If Menu_ShowMenuTitle = True
LCD.WriteAt(2, 1, UpArrow)
#Else
LCD.WriteAt(1, 1, UpArrow)
#EndIf
EndIf
#EndIf
#EndIf
End Sub
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'Name: DrawPointer(pOldPosition as byte)
'Purpose: Deletes pointer at pOldPosition and draws pointer at PointerPosition
'
'Notes: When pointer is at first menu item on screen, PointerPosition = 0
'
' Pointer character determined by option "Menu_PointerCharacter",
' default = 126 (right arrow)
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Private Sub DrawPointer(pOldPosition As Byte)
'Actual LCD line which pointer is drawn on depends on whether
'Menu_ShowMenuTitle is enabled or not
#If Menu_ShowMenuTitle Then
PointerLine = PointerPosition + 2
LCD.WriteAt(pOldPosition + 2, 1, " ")
LCD.WriteAt(PointerLine, 1, PointerCharacter)
#Else
PointerLine = PointerPosition + 1
LCD.WriteAt(pOldPosition + 1, 1, " ")
LCD.WriteAt(PointerLine, 1, PointerCharacter)
#EndIf
End Sub
'===============================================================================
'Public Subs and Functions
'-------------------------------------------------------------------------------
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'Name: ShowMenu(pMenuNumber as byte = 0)
'Purpose: Display specified menu on LCD
'
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Public Sub ShowMenu(pMenuNumber As Byte = 0)
'Reset scroll and pointer positions
ScrollPosition = 0
PointerPosition = 0
'Set values for first item number, last item number & parentID for current
'menu
CurrentMenu = pMenuNumber
ParentID = mnuParentMenuID(CurrentMenu)
FirstItemNumber = mnuMenuItemStart(CurrentMenu)
LastItemNumber = mnuMenuItemEnd(CurrentMenu)
'Display menu & pointer
DrawMenu
DrawPointer(0)
End Sub
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'Name: MoveDown()
'Purpose: Move pointer to next menu item, scrolling the menu if necessary
'
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Public Sub MoveDown()
Dim CanScroll As Boolean
'First, determine if the menu can be scrolled down and set CanScroll -
'
' If Scroll Wrapping Not Enabled: Menu may only be scrolled down if the
' number of menu items left to display won't fit on the number of
' available LCD lines
'
' Note: Number of available lines depends on whether Menu_ShowMenuTitle is
' enabled or not
'
' If Scroll Wrapping Enabled: Can always scroll down
#If Menu_ScrollWrapping = False
CanScroll = False
#If Menu_ShowMenuTitle = True Then
If FirstItemNumber + ScrollPosition + LCDLines - 2 < LastItemNumber Then
CanScroll = True
EndIf
#Else
If FirstItemNumber + ScrollPosition + LCDLines - 1 < LastItemNumber Then
CanScroll = True
EndIf
#EndIf
#Else
CanScroll = True
#EndIf
'Scroll the menu if the following conditions exist -
'
' Menu can be scrolled down and pointer is on or below the second last
' line of the display
' OR
' Menu can be scrolled down and pointer is on the last menu item - this
' allows scroll wrapping
If (PointerLine >= LCDLines - 1 Or PointerPosition = LastItemNumber - FirstItemNumber) And CanScroll = True Then
Inc(ScrollPosition)
#If Menu_ScrollWrapping = True
'If scroll wrapping and we've scrolled to the bottom then start again at
'the top
If ScrollPosition > (LastItemNumber - FirstItemNumber) Then
ScrollPosition = 0
EndIf
#EndIf
DrawMenu()
DrawPointer(PointerPosition)
'If not scrolling the menu then move the pointer down if the following
'conditions exist -
'
' Pointer is not on the last line of the display
' AND
' Pointer isn't on the last menu item
ElseIf PointerLine < LCDLines And PointerPosition + FirstItemNumber + ScrollPosition < LastItemNumber Then
Inc(PointerPosition)
'Fix to ensure Up Arrow scroll indicator is shown on smaller displays
'when pointer moves down from top line
#If (Menu_LCDLines < 4 Or Menu_ScrollWrapping = True) And Menu_ShowScrollIndicators = True
DrawMenu()
DrawPointer(PointerPosition)
#Else
DrawPointer(PointerPosition - 1)
#EndIf
End If
End Sub
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'Name: MoveUp()
'Purpose: Move pointer to previous menu item, scrolling menu if necessary
'
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Public Sub MoveUp()
'Routine decides whether to scroll the menu up or just move the pointer up
'depending on the current state:
'
'If there is a free LCD line above the pointer (i.e. one that doesn't have
'the menu title or a scroll indicator in it then move the pointer up;
'
'Otherwise, if the menu can be scrolled (either because scroll wrapping is
'on or because the current scroll position > 0) then scroll the menu up;
'
'If the menu can't be scrolled then move the pointer up, overwriting any
'scroll-up indicator. (If necessary, re-draw the scroll-down indicator).
#If Menu_ShowMenuTitle = True
#If Menu_ShowScrollIndicators = True
If PointerLine > 3 Then
#Else
If PointerLine > 2 Then
#EndIf
Dec(PointerPosition)
DrawPointer(PointerPosition + 1)
#If Menu_ScrollWrapping = True
Else
If ScrollPosition > 0 Then
Dec(ScrollPosition)
Else
ScrollPosition = LastItemNumber - FirstItemNumber
EndIf
DrawMenu()
DrawPointer(PointerPosition)
EndIf
#Else
ElseIf ScrollPosition > 0 Then
Dec(ScrollPosition)
DrawMenu()
DrawPointer(PointerPosition)
ElseIf PointerLine > 2 Then
Dec(PointerPosition)
#If Menu_LCDLines < 4 And Menu_ShowScrollIndicators = True
DrawMenu()
DrawPointer(PointerPosition)
#Else
DrawPointer(PointerPosition + 1)
#EndIf
EndIf
#EndIf
#Else
#If Menu_ShowScrollIndicators = True
If PointerLine > 2 Then
#Else
If PointerLine > 1 Then
#EndIf
Dec(PointerPosition)
DrawPointer(PointerPosition + 1)
#If Menu_ScrollWrapping = True
Else
If ScrollPosition > 0 Then
Dec(ScrollPosition)
Else
ScrollPosition = LastItemNumber - FirstItemNumber
EndIf
DrawMenu()
DrawPointer(PointerPosition)
EndIf
#Else
ElseIf ScrollPosition > 0 Then
Dec(ScrollPosition)
DrawMenu()
DrawPointer(PointerPosition)
ElseIf PointerLine > 1 Then
Dec(PointerPosition)
#If Menu_LCDLines < 4 And Menu_ShowScrollIndicators = True
DrawMenu()
DrawPointer(PointerPosition)
#Else
DrawPointer(PointerPosition + 1)
#EndIf
EndIf
#EndIf
#EndIf
End Sub
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'Name: Back()
'Purpose: Show parent of current menu
'
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Public Sub Back()
ShowMenu(ParentID)
End Sub
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'Name: SelectItem()
'Purpose: Carries out action of selected menu item. If menu item opens
' another menu then that menu is drawn. If menu item is an 'action'
' item then the event in the main program which handles the action is
' called
'
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Public Sub SelectItem()
Dim ItemAction As Byte
SelectedMenuItem = FirstItemNumber + ScrollPosition + PointerPosition
#If Menu_ScrollWrapping = True
If SelectedMenuItem > LastItemNumber Then
SelectedMenuItem = SelectedMenuItem - (LastItemNumber - FirstItemNumber) - 1
EndIf
#EndIf
ItemAction = mnuItemAction(SelectedMenuItem)
If ItemAction = 255 Then
ParentID = CurrentMenu 'Means 'back' command will return to correct menu
FItemActionEvent() 'Call event handler in main program
Else
ShowMenu(ItemAction)
EndIf
End Sub
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'Name: Initialise(pItemActionEvent as TEvent)
'Purpose: Sets name of main program event handler and loads custom scroll
' characters into LCD
'
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Public Sub Initialise(pItemActionEvent As TEvent)
FItemActionEvent = pItemActionEvent
#If Menu_ShowScrollIndicators = True Then
LCD.Write(ScrollIndicators)
#EndIf
End Sub
'===============================================================================
'Module Initialisation
'-------------------------------------------------------------------------------
=]