where : ibrtses embedded
having a menu on an LCD
A menu is the visual part of the user interface. The software parts behind do not have to be
that complicated. I found a rather efficient way.
the state machine
behind the menu is a state machine with as many states as the menu has :
state0 : ; sign on
Mycompany ; line1
Device ; line2
Version ; line3
timed -> state1
state1 : ; screen1
Function1 ; line1
Function2 ; line2
Function3 ; line3
cursor(1,?)
key1 :proc1 :state?
key2 :proc2 :state?
key3 :proc3 :state?
..
state2 : ; screen2
..
the states have to be designed on paper. Each state displays something, and upon
a key (or another event) something happens (denoted as proc?) and a new state
(denoted as state?) is entered.
the main
the main shall be :
Repeat
getevent (key)
execute action
display state
Unitl false
implementation of execute action
the following state table has 10+ states with 4 keys (up, down,esc,enter)
there is always the new state, followed by the action to be executed :
eg. upon ret, state0 changes to state1 after proc0 is executed, or
upon ret, state7 changes to state19 after proc3 was executed.
statetable:
;vertical : entry state
;horizontal key up, down, esc, ret
state0: .db 0 ,0 ,0 ,0 ,0 ,0 ,1 ,0
state1: .db 1 ,0 ,2 ,0 ,0 ,0 ,4 ,0
state2: .db 1 ,0 ,3 ,0 ,0 ,0 ,12 ,0
state3: .db 2 ,0 ,3 ,0 ,0 ,0 ,15 ,0
state4: .db 4 ,0 ,5 ,0 ,1 ,0 ,17 ,1
state5: .db 4 ,0 ,6 ,0 ,1 ,0 ,18 ,2
state6: .db 5 ,0 ,7 ,0 ,1 ,0 ,6 ,0
state7: .db 6 ,0 ,8 ,0 ,1 ,0 ,19 ,3
state8: .db 7 ,0 ,9 ,0 ,1 ,0 ,8 ,0
state9: .db 8 ,0 ,10 ,0 ,1 ,0 ,20 ,4
state10: .db 9 ,0 ,11 ,0 ,1 ,0 ,10 ,0
now the procedures are listed as array for indirect access
proctable:
; list of the following procedures
; contains the adress of the proc's
; the indices above correspond to the procs
pr0: .dw proc0
pr1: .dw proc4r
pr2: .dw proc5r
pr3: .dw proc7r
pr4: .dw proc9r
pr5: .dw proc11r
pr6: .dw proc12r
pr7: .dw proc17r
..
proc0: ret
proc4r:
SetZptr PumpEnable
ld U1,Z
SetZPtr LCD_Copy
st Z,U1
ret
proc5r:
SetZptr PumpSetCurrent
ld U1,Z
SetZPtr LCD_Copy
st Z,U1
ret
..
now the code :
; menu state machine
; entry state in mstate
; exit state in mstate
; key in keybd
; proc to be executed in Z<>0
execute:
pushX
pushY
push U1
push U2
mov U1,mstate ;8 entries per state
lsl U1
lsl U1
lsl U1
cpi keybd,0x0
breq mexecend
cpi keybd,0x01 ; sort out which key - as it is the offset into the line
brne mexec1
ldi U2,0 ; key1 -> offset:=0
rjmp mexec2
mexec1: cpi keybd,0x02
brne mexec3
ldi U2,2 ; key2 -> offset:=2
rjmp mexec2
mexec3: cpi keybd,0x04
brne mexec4
ldi U2,4 ; key3 -> offset:=4
rjmp mexec2
mexec4: cpi keybd,0x08
brne mexecend
ldi U2,6 ; key4 -> offset:=6
mexec2: SetZPtr (Statetable*2)
clr temp
add ZL,U1
adc ZH,temp
add ZL,U2
adc ZH,temp
lpm
mov mstate,R0 ; new state
adiw ZL,1
lpm
mov U2,R0 ; proc
lsl U2 ; 2 entries per index
SetZPtr (Proctable*2)
add ZL,U2
adc ZH,temp
lpm
mov YL,R0
adiw ZL,1
lpm
mov YH,R0
swapYZ
icall
mexecend:
pop U2
pop U1
popY
popX
ret
implementation of display state
; screen being displayed as set in mstate
;
displaystate:
pushX
pushY
pushZ
push U1
push U2
push U3
SetXPtr (ScreenTable*2)
mov U1,mstate ;5*mstate
lsl U1
lsl U1
add U1,mstate
add U1,mstate
clr temp
add XL,U1
adc XH,temp
ldi U3,1
; 1st line
mdd1: copyXtoZ
lpm
mov U1,R0
SetZPtr ABuf
rcall mline ; get the line(# in U1) to be displayed (Z^)
rcall fill_eol
mov U2,U3
rcall LCD_StringY ; display string(Z^) at line U2
inc U3
adiw XL,1
cpi U3,4
breq mdd2
rjmp mdd1
; cursor
mdd2:
copyXtoZ
lpm
mov U2,R0 ; the y cursor
adiw XL,1
copyXtoZ
lpm
mov U1,R0 ; the x cursor
rcall LCD_CursorXY
pop U3
pop U2
pop U1
popZ
popY
popX
ret
the screen had 3 lines for the menu, the first 3 entries are the lines,
the next 2 entries are the cursor position
ScreenTable:
; which screens contains which lines
; 1.&2.&3. :linenumber 4,5: cursor on line (y,x)
; linenumber
scr0: .db 0,17,17,1,3
scr1: .db 1,2,3,1,3
scr2: .db 1,2,3,2,8
scr3: .db 1,2,3,3,4
scr4: .db 1,4,5,2,6
scr5: .db 1,4,5,3,11
scr6: .db 1,5,6,3,11
scr7: .db 1,6,7,3,11
scr8: .db 1,7,8,3,11
scr9: .db 1,8,9,3,11
scr10: .db 1,9,10,3,8
implementation of getting an indexed string
Sometimes many lines of a menu are the same or similar.
Then indexing a line becomes efficient.
; takes static line and appends data
;
;line numbered in U1
;returns complete line in Z^
;
mline:
pushX
pushY
pushZ
copyZtoY
push U2
push U3
push U4
mov U4,U1
lsl U4 ;2 entries per index
SetZPtr (LineTable*2)
add ZL,U4
clr temp
adc ZH,temp
lpm
mov XL,R0 ; jump adr to X
adiw ZL,1
lpm
mov XH,R0
CopyXtoZ
icall ;string is Y^, index:U1
pop U4
pop U3
pop U2
popZ
popY
popX
ret
LineTable:
li0: .dw line0 ; menu
li1: .dw line1 ; ??
li2: .dw line2 ; ??
li3: .dw line3 ; ??
li4: .dw line4 ; ??
li5: .dw line5 ; ??
li6: .dw line6 ; ??
li7: .dw line7 ; ??
li8: .dw line8 ; ??
li9: .dw line9 ; ??
li10: .dw line10 ; ??
..
line0: ;makes line0, whatever it is
..
ret
line1: ;do
..
ret
disclaimer
AVR index
embedded software pages
home
last updated: 2.sept.99
Questions ?
Suggestions?
Feedback ?
sponsored links
Copyright (99,2001) Ing.Büro R.Tschaggelar