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