Print Menu on 4x20 LCD?
Hi,
I need to store the following data in my code and call it later, does anyone know how I can?
A multidimensional array was my first idea, however this isn't supported in SPIN.
Any other ideas?
Thank you
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
"powered by Propeller" domed stickers $1.50 - Find them here
Check out my Design and Technology project for my Higher School Certificate www.ecosureblog.net
Post Edited (computer guy) : 1/15/2010 12:00:35 PM GMT
I need to store the following data in my code and call it later, does anyone know how I can?
Text Function Menu ├─Date/Time goto "Date/Time" menu │ ├─Set Date goto "Set Date" menu │ │ ├─Day goto "Set Day" menu │ │ ├─Month goto "Set Month" menu │ │ └─Year goto "Set Year" menu │ └─Set Time goto "Set Time" menu │ ├─Hour goto "Set Hour" menu │ └─Minute goto "Set Min" menu └─Timer goto "Timer" menu ├─Duration goto "Set Duration" menu └─PreHeat goto "Set PreHeat" menu
A multidimensional array was my first idea, however this isn't supported in SPIN.
Any other ideas?
Thank you

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
"powered by Propeller" domed stickers $1.50 - Find them here
Check out my Design and Technology project for my Higher School Certificate www.ecosureblog.net
Post Edited (computer guy) : 1/15/2010 12:00:35 PM GMT

Comments
1 2
3 4
Where the numbers are the element in the 1D array.
You then write a simple function getelement(row, column) which will convert the specified row and column into a 1D index of the 1D array. You can also do the same for 3D matrices.
Graham
Could you please explain this in more detail. I kind of see what you are saying but not entirely and to be honest I think I am just getting more confused every time I try and make sense of it.
Thank you
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
"powered by Propeller" domed stickers $1.50 - Find them here
Check out my Design and Technology project for my Higher School Certificate www.ecosureblog.net
r1c1 r1c2 r1c3 r2c1 r2c2 r2c3 r3c1 r3c2 r3c3
So the first element is row 1 column 1, the second is row 1 column 2. It is a 1D array representing the following 3X3 array:
r1c1 r1c2 r1c3
r2c1 r2c2 r2c3
r3c1 r3c2 r3c3
Your function would be designed to get a particular element from the 1D array given the specified row and column. In this case which is not very accurate because the first element is 1 not 0 like in spin then you would have
1D_index = (row*3) - 3 + (column - 1)
(row*3)-3 gives you the address of the first element of a particular row to which you add the column to get the particular element
How you use this for your particular application I am not sure but it was you that suggested multidimensional arrays [noparse]:)[/noparse]
Graham
Thank you
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
"powered by Propeller" domed stickers $1.50 - Find them here
Check out my Design and Technology project for my Higher School Certificate www.ecosureblog.net
Graham
If I understand correctly, you want to store pointers to three routines in the MenuFunc array so that later you can invoke one dynamically based on an index into the array. Unfortunately, Spin does not allow this.
But you could store a label that you fed into a case statement, each case being a different function.
Graham
Thats what I was planning to do.
Can you have an array of strings and if so, what datatype would I use?
e.g.
Thank you
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
"powered by Propeller" domed stickers $1.50 - Find them here
Check out my Design and Technology project for my Higher School Certificate www.ecosureblog.net
Post Edited (computer guy) : 1/12/2010 10:13:20 PM GMT
but lets say it is C which I can understand but not write.
Don'y you have to define the structure yourself?
I think the way people have been suggesting is to figure out what the structure looks like in memory and then
make arithmetic that converts your indexes into a single index. That requires memory allocated for all possible
array values fields.
The alternative is to have variable length strings which can be null and require 1 or less bytes if they are empty,
like a lot of classic (1980s) BASICs do. In SPIN you would have to manage all elements of all arrays within one
string, and I guess each element would have pointers to other elements to create a tree structure, or whatever
structure works well for you. This method may or may not require "garbage collection" (if the array gets full and
elements are often changing size or being removed)... Perhaps there are newer ways of doing this. I still think like
it's 1980 and need to conserve RAM, which is appropriate for Propeller. If you use an SD card for storage,
different rules apply that I don't yet know well enough to explain, but may be better for your data structure,
because they have gigabytes.
Post Edited (VIRAND) : 1/13/2010 1:44:44 AM GMT
Thank you all for your help though.
I will explain what I am wanting to do.
I have an lcd display (4x20) and 4 buttons (Up, Down, Ok, Back) and I want to build a menu structure and make it possible to go into sub menus.
This entire concept is new to me.
Thank you
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
"powered by Propeller" domed stickers $1.50 - Find them here
Check out my Design and Technology project for my Higher School Certificate www.ecosureblog.net
Post Edited (computer guy) : 1/13/2010 12:18:06 AM GMT
This would be a data structure for your problem.
Then you need a function that can print the menu on the LCD display, like
printMenu( menu_address )
and maybe
scrollMenu( start_with_entry )
Next is a input loop, which will react on the user input and a big case statement that is calling the right functions.
pub main printMenu( @mainmenu ) menu_entry_focus := 0 menu_level_iterator := 1 menu_level_mask := $f repeat key := keyboard.getKey if key==level_up_key menu_level_iterator >>= 4 menu_entry_mask >>= 4 menu_entry_focus &= menu_entry_mask ' delete the part of the previous level key:=ok ' this will then reprint the menu case key up: menu_entry_focus:=menu_entry_focus - menu_level_iterator ' check that it's not negative ' if focus is outside of the lines currently displayed, call scrollMenu down: menu_entry_focus:=menu_entry_focus + menu_level_iterator ' check that it's not bigger than the number of entries in the active menu ' if focus is outside of the lines currently displayed, call scrollMenu ok: case menu_entry_focus $0: printMenu( @submenu1 ) menu_level_iterator <<= 4 menu_entry_mask := menu_entry_mask << 4 | $f $1: printMenu( @submenu2 ) menu_level_iterator <<= 4 menu_entry_mask := menu_entry_mask << 4 | $f $2: ' this is not a submenu, so you simply call the function behind this entry callWhatever ....With the menu_level_iterator you keep track of the route you used to go to the actual submenu. The main-menu currently can have 16 entries (because I used <<= 4, 4 bits = value 0-15·). So, the first digit of the hexadecimal menu_entry_focus will tell you which entry in the main menu has been selected. The entry selected in the next menu-level will be shown in the second digit of the hexadecimal. For example
$21 means that first submenu 2 has been selected in the main menu and then entry 3 has been selected.
As we have longs in SPIN you can have a menu structure with 8 levels and each submenu can have 16 entries. Should be enough.
So, in the case statement you would add a value for every possible menu and sub-menu entry. And on this level you can decide whether the selected entry directly calls functions or would lead to a deeper level submenu.
Hope that helped more than it confused ;o)
PS: This is not tested code, I just hacked it for this post. I bet there are some minor bugs, but it should show the principle. (For example $0 is a bug. $0 should rather print the main menu and the first submenu can be selected with $1 ;o) So, in fact you only have 15 entries per menu-level, as the $0 of each level is needed for redisplay the submenu·when going up and down in the menu levels.
Post Edited (MagIO2) : 1/13/2010 7:54:02 AM GMT
Thank you
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
"powered by Propeller" domed stickers $1.50 - Find them here
Check out my Design and Technology project for my Higher School Certificate www.ecosureblog.net
Tried a few things, with interesting results but not what it should output.
Thank you
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
"powered by Propeller" domed stickers $1.50 - Find them here
Check out my Design and Technology project for my Higher School Certificate www.ecosureblog.net
output the string contained in mm_entry1?
Thank you
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
"powered by Propeller" domed stickers $1.50 - Find them here
Check out my Design and Technology project for my Higher School Certificate www.ecosureblog.net
For example:
tv.dec( @table )
tv.dec( table_adr )
dat
table_adr word @table
table byte 0[noparse][[/noparse]10]
shows tow different results. Maybe it even get's worse when you use several dat section and that one with the menu is somewhere at the end.
For me it worked to add 16 to the value - possibly the 16 bytes that contain the clock-settings and some SPIN pointers.
It also works to do a
dat
org 16
PS: It's clear where the 16 comes from. It's the·propeller-tool 'internal' dat-section which is used to store the clock-settings and some SPIN pointers.
Post Edited (MagIO2) : 1/16/2010 12:11:32 AM GMT
here's my example of a menu driven 4 button 4X20 LCD code. It's for a hand held diagnostic tool for car. Disregard the PUB PROCESS_ECU , that's not finished in this version of my scantool, but gives an example how the LCD and push buttons work. This was actually ported from the SX forum from a post with me and JonnyMac talking about this same thing but with the SX.
'' Scantool ver.1 '' File: Scantool1.spin '' '' PUB MAIN could have repeat functions '' '' CON _clkmode = xtal1 + pll16x 'Sets the clock speed to 80 MHz using a times 16 multiplier _xinfreq = 5_000_000 'Crystal speed: 5 MHz LCD_Pin = 10 LCD_Baud = 19_200 LCD_Lines = 4 Btn_Up =11 'Left_Button Btn_Down =12 'Middle_Button Btn_Select =13 'Right_Button Btn_Escape =14 'bottom button Enable_K_line =15 K_Line_Rcv =16 K_Line_Xmtr =17 L_Line =18 Off = 0 On = 1 VAR LONG Stack0[noparse][[/noparse]150] 'FOR UPDATES_LCD LONG Stack1[noparse][[/noparse]150] 'FOR PROCESS_ECU LONG Stack2[noparse][[/noparse]150] 'FOR BUTTON_PUSH '==========UPDATE LCD BYTE MENU BYTE SUBMENU BYTE FUNCTION BYTE CURRENTMENU BYTE CURRENTPROMPT BYTE txByte ' transmit byte BYTE rxByte ' recv byte '==========PROCESS ECU BYTE NumOfBytes BYTE Counter BYTE Command BYTE Index BYTE Text[noparse][[/noparse]20] '==========BUTTON PUSH BYTE Button_Push_Flag OBJ LCD : "Serial_Lcd" HANDSHAKE : "Simple_Serial" ' intialize COMMS : "Simple_Serial" ' comunication PUB Start DIRA[noparse][[/noparse]15]~~ OUTA[noparse][[/noparse]15]~~ 'Enable transciever high DIRA[noparse][[/noparse]18]~~ OUTA[noparse][[/noparse]18]~ 'Enable L_line low HANDSHAKE.start(1, L_Line, 5) 'setup L_Line parameters 'COMMS.init(K_Line_Rcv, K_Line_Xmtr, 9800) CogNew(UPDATES_LCD, @Stack0) CogNew(PROCESS_ECU, @Stack1) CogNew(BUTTON_PUSH, @Stack2) PUB UPDATES_LCD | mnuStr, offset, TEMP If LCD.init(LCD_Pin, LCD_Baud, LCD_Lines) 'Initialize LCD LCD.Cursor(Off) LCD.Backlight(On) LCD.Cls PAUSE(100) '100ms Repeat LCD.Line_1 offset:= BYTE[noparse][[/noparse]@LineOffset + MENU] 'need to initialize menu LCD.str(@Prompt + offset) LCD.Line_2 case MENU 0: mnuStr := @Menu0 1: mnuStr := @Menu1 offset:= BYTE[noparse][[/noparse]@LineOffset + CURRENTPROMPT] LCD.str(mnuStr + offset) LCD.Line_3 TEMP := lookupz( MENU : 6, 3, 3 ) IF CURRENTPROMPT == TEMP offset := 0 ELSE offset := offset + 21 IF MENU == 0 mnuStr := @Menu0 IF MENU == 1 mnuStr := @Menu1 IF MENU == 2 mnuStr := @Menu2 LCD.str(mnuStr + offset) LCD.Line_4 offset := offset + 21 TEMP := lookupz( MENU : 6, 3, 3 ) IF CURRENTPROMPT == TEMP offset := 21 ELSE TEMP := lookupz( MENU : 5, 2, 2 ) IF CURRENTPROMPT == TEMP offset := 0 IF MENU == 0 mnuStr := @Menu0 IF MENU == 1 mnuStr := @Menu1 IF MENU == 2 mnuStr := @Menu2 LCD.str(mnuStr + offset) PUB PROCESS_ECU NumOfBytes := comms.rx 'recv number of bytes comms.tx(!NumOfBytes) 'send complement Counter := comms.rx 'recv counter comms.tx(!Counter) 'send complement Command := comms.rx 'recv Command comms.tx(!Command) 'send complement use value of Command to direct flow IF Command == $F7 'ACK Block comms.tx($09) 'send ACK Block IF Command == $F6 'text to follow Text := 0 Repeat Index from 0 to (NumOfBytes-3) ' recv the correct number of bytes Text[noparse][[/noparse]Index] := rxByte comms.tx(!rxByte) IF Command == $FB 'ADC read IF Command == $FC 'Error memory read IF Command == $F5 'actuator activate - response to a selection 'master 'start with Menu and Submenu 'use CASE to branch to correct process if menu ==1 and submenu ==2 then ...... comms.tx($03) PUB BUTTON_PUSH | newstate, oldstate, xstate, TEMP ' Btn_Up =11 'Left_Button ' Btn_Down =12 'Middle_Button ' Btn_Select =13 'Right_Button ' Btn_Escape =14 'bottom button ' have all the possible commands for selection, with a command flag. PROCESS_ECU will then use this to make a case selection. oldstate := inA[noparse][[/noparse]14..11] ' initial state of input pins REPEAT newstate := inA[noparse][[/noparse]14..11] ' current state of input pins xstate := newstate ^ oldstate & newstate ' detect change of 1 to 4 bits, 0->1 oldstate := newstate ' push state down IF xstate & |<0 'the bits 14..11 are shifted to 3..0 in xstate PAUSE(40) ' call method for Pin11 up REPEAT until inA[noparse][[/noparse]11] -- CURRENTPROMPT TEMP := lookupz( MENU : 6, 4, 3 ) IF CURRENTPROMPT == $FF CURRENTPROMPT := TEMP IF xstate & |<1 PAUSE(40) ' call method for Pin12 down REPEAT until inA[noparse][[/noparse]12] ++CURRENTPROMPT TEMP := lookupz( MENU : 6, 4, 3 ) IF CURRENTPROMPT > TEMP CURRENTPROMPT := 0 IF xstate & |<2 AND Button_Push_Flag := Off 'can't select if currently processing a command PAUSE(40) ' call method for Pin13 select REPEAT until inA[noparse][[/noparse]13] ++ Menu SUBMENU := CURRENTPROMPT CURRENTPROMPT := 0 Button_Push_Flag := On 'selection has been made, not processed IF xstate & |<3 PAUSE(40) ' call method for Pin14 escape REPEAT until inA[noparse][[/noparse]14] -- MENU CURRENTPROMPT := 0 PAUSE(40) PUB PAUSE(millisecs) 'As set up here it is .25 millisceconds waitcnt(((((clkfreq)/1000))*millisecs) +cnt) 'Osc speed is 40 MHz PUB L_LINE_HANDSHAKE (ADDRESS) HANDSHAKE.tx (ADDRESS) DAT Prompt BYTE "Select System ", 0 'MENU = 0 BYTE "Select Function ", 0 'MENU = 1 MENU0 ' use with "Select Device:" and "Up Down Select" BYTE " Motronic ", 0 'CURRENTPROMPT = 0 BYTE " Climate Control ", 0 'CURRENTPROMPT = 1 BYTE " ABS ", 0 'CURRENTPROMPT = 2 BYTE " Airbag ", 0 'CURRENTPROMPT = 3 BYTE " Tiptronic ", 0 'CURRENTPROMPT = 4 BYTE " Alarm ", 0 'CURRENTPROMPT = 5 BYTE " PDAS ", 0 'CURRENTPROMPT = 6 MENU1 BYTE " Error codes ", 0 BYTE " Clear codes ", 0 BYTE " Actual values ", 0 BYTE " Activate outputs ", 0 MENU2 LineOffset BYTE 0, 21, 42, 63, 84, 105, 126, 148, 169 ' line width + 1 (for 0)▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Bad spellers of the world untie!
Edit:
I have this so far and it's printing the menu to the LCD (it only has two items at the moment)
repeat i from 0 to strsize(mainmenu) LCD.str(mainmenu[noparse][[/noparse] i] + 16) LCD.putc($0D)▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
"powered by Propeller" domed stickers $1.50 - Find them here
Check out my Design and Technology project for my Higher School Certificate www.ecosureblog.net
Post Edited (computer guy) : 1/16/2010 1:31:15 AM GMT
LCD.str( mainmenu[noparse][[/noparse]0] )
is correct. mainmenu[noparse][[/noparse]0] only does not contain what we expected ... see my post above.
If you say
LCD.str( mainmenu[noparse][[/noparse]0]+16 )
the calculation is done at runtime, wasting speed and RAM for additional code.
Thank you
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
"powered by Propeller" domed stickers $1.50 - Find them here
Check out my Design and Technology project for my Higher School Certificate www.ecosureblog.net
Could you please explain "ORG" to me. I tried putting "ORG 16" at the start of the DAT section and removing the + 16, however this didn't work.
Thank you
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
"powered by Propeller" domed stickers $1.50 - Find them here
Check out my Design and Technology project for my Higher School Certificate www.ecosureblog.net
From the DAT structure that MagIO2 provided.
Please...?
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
"powered by Propeller" domed stickers $1.50 - Find them here
Check out my Design and Technology project for my Higher School Certificate www.ecosureblog.net
Thank you
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
"powered by Propeller" domed stickers $1.50 - Find them here
Check out my Design and Technology project for my Higher School Certificate www.ecosureblog.net
LCD.str( mainmenu[noparse][[/noparse]0]+16 )
try
LCD.str( @@mainmenu[noparse][[/noparse]0] )
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
"powered by Propeller" domed stickers $1.50 - Find them here
Check out my Design and Technology project for my Higher School Certificate www.ecosureblog.net
PRI printmenu(menuptr) | i LCD.cls LCD.backlight(true) i := 0 repeat if i == 0 LCD.str(string(">")) else LCD.str(string(" ")) LCD.str(@@mainmenu[noparse][[/noparse] i++]) LCD.putc($0D) while mainmenu[noparse][[/noparse] i] > 0and it's working great.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
"powered by Propeller" domed stickers $1.50 - Find them here
Check out my Design and Technology project for my Higher School Certificate www.ecosureblog.net