; Demonstracao do uso do emulador de display LCD com o HAPSIM ; usa um LCD de 4x20 e escreve nas 4 linhas .nolist .include "m88def.inc" .list .listmac .equ LCDDATA=PORTB ; port wired to the LCD data pins .equ LCDCTL=PORTC ; port with 3 bits wired to the LCD control pins .equ ENABLE=0 ; bit in LCDCTL wired to the enable LCD pin .equ RS=1 ; bit in LCDCTL wired to the RS LCD pin .equ RW=2 ; bit in LCDCTL wired to the RW LCD pin .def LCDtempr=r19 ; temporary reg used by the LCD routines - must be >= 16 ; for the 3 equ's below, note that on AVR's, DDRx=PORTx-1 & PINx=PORTx-2 .equ LCDDATADDR=LCDDATA-1 ; DDR reg of the port wired to the LCD data pins .equ LCDDATAPIN=LCDDATA-2 ; PIN reg of the port wired to the LCD data pins .equ LCDCTLDDR=LCDCTL-1 ; DDR reg of the port wired to the LCD control pins rjmp RESET ;LCD handling routines - notice that all symbols start with LCD ;************************************************************************************* lcd_busy: ; tests the busy state repeatedly until LCD is ready ; in HAPSIM, the LCD is always ready, so for the simulation ; to go faster, this routine can return immediately ret ; ATTENTION: remove when using the real hardware sbi LCDCTL,RW ; RW high to read cbi LCDCTL,RS ; RS low for command mode ldi LCDtempr,0 ; set dat port for input out LCDDATADDR,LCDtempr lcd_testagain: sbi LCDCTL,ENABLE ; enable the LCD in LCDtempr,LCDDATAPIN ; read it cbi LCDCTL,ENABLE ; disable the LCD sbrc LCDtempr,7 ; skip if busy bit is clear, ie: the LCD is ready rjmp lcd_testagain ; the LCD is still busy - repeat test ldi LCDtempr,$ff ; LCD is ready - make port output before returning out LCDDATADDR,LCDtempr cbi LCDCTL,RW ; RW low to write mode ret ;**************************************************************************************** lcd_cmd: ; sends the value in register LCDtempr to the LCD, as a command cbi LCDCTL,RS ; RS low for command mode cbi LCDCTL,RW ; RW low to write sbi LCDCTL,ENABLE ; Enable HIGH out LCDDATA,LCDtempr ; place the command on the LCD data pins cbi LCDCTL,ENABLE ; Enable LOW to execute ret ;***************************************************************************************************** lcd_write: ; sends the value in register LCDtempr to the LCD, as data sbi LCDCTL,RS ; RS high for data mode cbi LCDCTL,RW ; RW low to write sbi LCDCTL,ENABLE ; Enable HIGH out LCDDATA,LCDtempr ; ; place the data on the LCD data pins cbi LCDCTL,ENABLE ; Enable LOW to execute ret ;***************************************************************** writemsg: ; writes the char vector (terminated by a binary zero) pointed to by Z on the LCD, ; starting @ the current LCD data memory location lpm LCDtempr,z+ ; load the next char to display & increment the string pointer cpi LCDtempr, 0 ; is this the end marker? breq writedone ; yes - done rcall lcd_write ; write the char on the LCD data memory rcall lcd_busy ; wait until LCD ready rjmp writemsg ; & go get the next char writedone: ret ;***************************************************************************************************** lcdinit: ;initialize LCD - LCD memory pointer is left pointing to the 1st byte in the data memory ldi LCDtempr,0xff out LCDDATADDR,LCDtempr ; set the LCD data port for output sbi LCDCTLDDR,ENABLE ; set the ENABLE bit in the LCD control port for output sbi LCDCTLDDR,RS ; set the RS bit in the LCD control port for output sbi LCDCTLDDR,RW ; set the RW bit in the LCD control port for output ldi LCDtempr,$38 ; init the LCD: 8 bit mode, 2 lines (also used for 4 lines) rcall lcd_cmd ; send command to the LCD rcall lcd_busy ; wait until LCD is ready ldi LCDtempr,1 ; clear screen rcall lcd_cmd ; send command to the LCD rcall lcd_busy ; wait until LCD is ready ; the following command is 00001DCB where D=1 turns display ON, C=1 shows cursor & B=1 blinks cursor position ; if we want D=C=B=1, there is no need to send the command, since this is the default ldi LCDtempr,$0c ; display ON, hide cursor, no blink rcall lcd_cmd ; send command to the LCD rcall lcd_busy ; wait until LCD is ready ldi LCDtempr,2 ; cursor home command rcall lcd_cmd ; send command to the LCD rcall lcd_busy ; wait until LCD is ready ret ;***************************************************************************************************** ;end of LCD handling routines msg: .db "Benvindos ao HAPSIM!",0 msg2: .db "MC404 1",$df," Sem 2010",0 msg3: .db "FEM-UNICAMP",0 msg4: .db "Eng de Autom & Contr",0 RESET: ; no need to initialize the stack pointer on the ATMEGA88 rcall lcdinit ; initialize LCD - LCD now pointing to the data memory @ the beginning of 1st line ldi zl,low(msg*2) ; point to message for 1st line ldi zh,high(msg*2) rcall writemsg ; display it ldi LCDtempr, $c0 ; command to point to the LCD data memory @ the beginning of 2nd line rcall lcd_cmd ; send the command to the LCD rcall lcd_busy ; wait until LCD is ready ldi zl,low(msg2*2) ; point to message for 2nd line ldi zh,high(msg2*2) rcall writemsg ; display it ldi LCDtempr, $94 ; command to point to the LCD data memory @ the beginning of 4rd line rcall lcd_cmd ; send the command to the LCD rcall lcd_busy ; wait until LCD is ready ldi zl,low(msg3*2) ; point to message for 3rd line ldi zh,high(msg3*2) rcall writemsg ; display it ldi LCDtempr, $d4 ; command to point to the LCD data memory @ the beginning of 4th line rcall lcd_cmd ; send the command to the LCD rcall lcd_busy ; wait until LCD is ready ldi zl,low(msg4*2) ; point to message for 4th line ldi zh,high(msg4*2) rcall writemsg ; display it done: rjmp PC