Menu system in Spin with 3 buttons and minimum / maximum range.
And now on to another part of my coding.... I have a simple menu system setup I wrote using arrays to pre-define the menu item and another array that stores the value for each menu item.
Example of what I have now (Not all Code is here) :
What I have works just fine, but I don't like the navigation of the menu system since I am only using 3 buttons (Up, Down, Menu/Enter). I want to convert the entire menu to be much more accessible without having to go through each menu item till I get to the one I need to change.
Currently, I am working with the Parallax 2x16 Serial display so my space is limited on what I can put on the screen. The first initial screen is the "working" screen which shows updated variables as the program runs and reads sensors. This screen must be cleared and the cog stopped to prevent other writing on the screen while in the menu system. Once the cog is stopped, another is started for the Menu system to take over. If there is a better way to do this, please let me know.
My idea is to stay with the 3 buttons but have the menu button instantly access the menu instead of holding it down for 2 or 3 seconds. Then once the menu is loaded, each menu item will be listed on the screen 2 items at a time. When I press the down button, the menu items will shift up so I can "scroll" through the menu. The selected line will be show with an ">" and will stay on the first line of the screen. Once the menu item I want to edit is in the selected line, I can then press the Menu/Enter button to edit its value. I can more than likely get to this point with the changes but here is where I am not sure what to do to make this easier in programming terms. I am only a little knowledgeable in Spin and cannot grasp PASM at all.
Each menu item's value (the Stored[] variable) will be a numerical value stored in the EEPROM which is updated by adjusting the value in the menu. Each menu item's value will need to have a pre-defined range (Minimum and Maximum value). Some values will be 1, 2, or 3, some will be 15 through 100. This means that when a specific menu item is being changed, the value must not go higher or lower than that specific menu item's pre-defined range. What would be the best way to accomplish this in SPIN? Using Arrays seems to be easiest for me currently since I can use the Array pointer as the multiplier for where to save the value in the EEPROM.
Example of what I have now (Not all Code is here) :
VAR
LONG Menu[255]
BYTE Stored[255]
PUB Main
Menu[0] := string("Menu Item 1")
Menu[1] := string("Menu Item 2")
Menu[2] := string("Menu Item 3")
Menu[3] := string("Menu Item 4")
StartLCD
PUB StartLCD
StopLCD
cogon := (cog := cognew(LCDupdate, @LCDstack)) > 0
PUB StopLCD
if cogon~
cogstop(cog)
PUB StartMenu
StopLCD
cogon := (cog := cognew(EnterMenu, @LCDstack)) > 0
PUB EnterMenu | btnpresstime, startid, userExit
startid := 0
userExit := 0
lcd.init(24, 9600, 2)
lcd.displayOn
lcd.backLight(TRUE)
waitcnt(1_000_000 + cnt)
lcd.gotoxy(0,0)
lcd.str(string("Programming Menu"))
lcd.gotoxy(0,1)
lcd.str(string("Loading.... "))
waitcnt(100_000_000 + cnt)
repeat
DisplayMenu(startid)
UpdateMenuValue(startid, 0)
userExit := 0
repeat until userExit == 1
btnpresstime := 0
repeat while ina[downbutton] == 1 or ina[upbutton] == 1 or ina[menubutton] == 1
if(ina[downbutton] == 1)
if(btnpresstime == 0)
UpdateMenuValue(startid, -1)
if(ina[upbutton] == 1)
if(btnpresstime == 0)
UpdateMenuValue(startid, 1)
if ina[menubutton] == 1
if btnpresstime == 0
saveval(Stored[startid], startid)
userExit := 1
btnpresstime++
waitcnt(20_000_000 + cnt)
if(btnpresstime == 10)
restartMain := 1
startid++
if(startid > menuItems)
startid := 0
PUB DisplayMenu(id)
lcd.gotoxy(0,0)
lcd.str(Menu[id])
lcd.gotoxy(0, 1)
lcd.str(String("Value : "))
PUB UpdateMenuValue(id, amount)
lcd.gotoxy(8, 1)
Stored[id] := Stored[id] + amount
lcd.str(string(" "))
lcd.gotoxy(8, 1)
lcd.str(num.dec(Stored[id]))
What I have works just fine, but I don't like the navigation of the menu system since I am only using 3 buttons (Up, Down, Menu/Enter). I want to convert the entire menu to be much more accessible without having to go through each menu item till I get to the one I need to change.
Currently, I am working with the Parallax 2x16 Serial display so my space is limited on what I can put on the screen. The first initial screen is the "working" screen which shows updated variables as the program runs and reads sensors. This screen must be cleared and the cog stopped to prevent other writing on the screen while in the menu system. Once the cog is stopped, another is started for the Menu system to take over. If there is a better way to do this, please let me know.
My idea is to stay with the 3 buttons but have the menu button instantly access the menu instead of holding it down for 2 or 3 seconds. Then once the menu is loaded, each menu item will be listed on the screen 2 items at a time. When I press the down button, the menu items will shift up so I can "scroll" through the menu. The selected line will be show with an ">" and will stay on the first line of the screen. Once the menu item I want to edit is in the selected line, I can then press the Menu/Enter button to edit its value. I can more than likely get to this point with the changes but here is where I am not sure what to do to make this easier in programming terms. I am only a little knowledgeable in Spin and cannot grasp PASM at all.
Each menu item's value (the Stored[] variable) will be a numerical value stored in the EEPROM which is updated by adjusting the value in the menu. Each menu item's value will need to have a pre-defined range (Minimum and Maximum value). Some values will be 1, 2, or 3, some will be 15 through 100. This means that when a specific menu item is being changed, the value must not go higher or lower than that specific menu item's pre-defined range. What would be the best way to accomplish this in SPIN? Using Arrays seems to be easiest for me currently since I can use the Array pointer as the multiplier for where to save the value in the EEPROM.

Comments
http://forums.parallax.com/showthread.php?141846-Menus-on-the-Parallax-4X20-Serial-LCD-Screen.&p=1118421&viewfull=1#post1118421
I am sure I can do the scrolling menu which is the easier part of my question
CON _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 MAX_MOVIE_MENU_ITMES = 5 VAR DAT miSel byte $FF mi1 byte "Star Wars",0 mi2 byte "The Hangover",0 mi3 byte "Christmas Vacation",0 mi4 byte "One Flew Over the Cuckoo's Nest",0 mi5 byte "The Good, the Bad and the Ugly",0 mis long @mi1, @mi2, @mi3, @mi4, @mi5 null long $00 OBJ pst : "Parallax Serial Terminal" PUB Main | i, ptr pst.Start(115_200) pause(500) repeat i from 0 to MAX_MOVIE_MENU_ITMES-1 pst.str(SelectMenuByIndex(i)) pst.str(string(" | Selected Index = ")) pst.dec(GetMenuItemSelected) pst.char(13) 'Detect index out of bounds ptr := SelectMenuByIndex(10) if(ptr == @null) pst.str(string(13, "Index is out of bounds", 13)) 'Last slected index pst.str(string("Last Selected Index = ")) pst.dec(GetMenuItemSelected) pst.char(13) PUB SelectMenuByIndex(idx) if(idx > MAX_MOVIE_MENU_ITMES-1) return @null miSel := idx return @@mis[idx] PUB GetMenuItemSelected return miSel PRI pause(Duration) waitcnt(((clkfreq / 1_000 * Duration - 3932) #> 381) + cnt) returnBTW, this is not good design due to scope.
PUB Main Menu[0] := string("Menu Item 1") Menu[1] := string("Menu Item 2") Menu[2] := string("Menu Item 3") Menu[3] := string("Menu Item 4")http://obex.parallax.com/objects/696/
I have an (unpublished) 3-button version I can post if it would help...though extending the 1-button method to 3 is pretty straightforward.
You already have an array for storing the values I guess. So, what you need is simply add 2 more arrays one named maxval and one called minval.
This does not look like an array, but you can use it in the same way. In the code where you increment or decrement the value you's simply write:
' increment
value[ actual_selection ] := ++value[ actual_selection ] <# maxval[ actual_selection ]
' decrement
value[ actual_selection ] := --value[ actual_selection ] #> minval[ actual_selection ]
I have no idea what scope means and can't figure out how it is different from this :
It would be as easy as
con #0,MODE_SCREEN1, MODE_SCREEN2 var long mode pub userIO mode:=MODE_SCREEN1 repeat check_buttons case mode MODE_SCREEN1: update_screen1 MODE_SCREEN2: update_screen2check_buttons, update_screen1 and update_screen2 being functions.
check_buttons reads the buttons and according to the mode it is doing different things:
if mode == MODE_SCREEN1 it switches into the other mode if the right button is pushed (switch to menu).
if mode == MODE_SCREEN2 it switches into the other mode if the right button is pushed (going back to main screen).
and it updates values if increase decrease buttons are pushed
and it updates print_from variable if buttons for scrolling in the menu are pushed.
update_screen1 simply print values that are updated by other code running in n other COGs
update_screen2 prints the actual part of the menu (print_from variable) and the editable values