; Control 2-line LCD with AT90S2313 AVR RISC Processor ; Using 4-wire interface ; ; Simulate one of those 8 Ball things ; ; Charles R. Ott ; May 28, 1998 .nolist ;Suppress listing of include file .include "2313def.inc" ;Define chip particulars .list ;***** Global register variables .def wreg =R16 ;General use working register .def timeout =R17 ;Timeout value passed to subroutine .def lcdstat =R18 ;LCD busy/wait status .def longtime=R19 ;Long timer for powerup ;***** Other equates .equ lcdrs =PD6 ;LCD rs pin connected to PD6 .equ lcdrw =PD5 ;LCD r/w pin connected to PD5 .equ lcde =PD4 ;LCD e pin connected to PD4 ; Timer/Counter prescaler values .equ TSTOP =0 ;Stop Timer/Counter .equ TCK1 =1 ;Timer/Counter runs from CK .equ TCK8 =2 ;Timer/Counter runs from CK / 8 .equ TCK64 =3 ;Timer/Counter runs from CK / 64 .equ TCK256 =4 ;Timer/Counter runs from CK / 256 .equ TCK1024 =5 ;Timer/Counter runs from CK / 1024 .equ TEXF =6 ;Timer/Counter runs from external falling edge .equ TEXR =7 ;Timer/Counter runs from external rising edge .equ NL =0x0A ;New line character .cseg ; Interrupt vectors .org 0 rjmp reset ;Reset Vector .org OVF0addr ;Overflow0 Interrupt Vector rjmp t0int ; Main program entry point on reset reset: ldi wreg,RAMEND ;Init Stack Pointer out SPL,wreg ldi wreg,TSTOP ;Timer 0 off (just in case) out TCCR0,wreg ;Stop timer ldi wreg,0b00000010 ;Enable Timer 0 interrupt out TIMSK,wreg sei ;Enable interrupts out PORTB,wreg ldi wreg,0x00 ;Make port B all inputs out DDRB,wreg rcall pause rcall lcdinit ;Initialize LCD module rcall lcdclr ;Clear LCD screen ldi wreg,TCK1 ;Run timer max speed out TCCR1B,wreg ; Main program loop main: ldi ZH,high(mess0*2);Print sign on message ldi ZL,low(mess0*2) ;Init Z-pointer rcall puts ;Show on LCD rcall pause pbwait: sbic PINB,7 ;Wait for button press rjmp pbwait debounce: sbis PINB,7 ;Wait for button release rjmp debounce rcall lcdclr ;Clear LCD screen in wreg,TCNT1L ;Read timer 1 low byte in wreg,TCNT1H ;Read timer 1 high byte andi wreg,7 ;Look at 3 lower bits chk1: cpi wreg,0 ;See which message to print brne chk2 ;Not message 1, see if 2 ldi ZH,high(mess1*2);Print message 1 ldi ZL,low(mess1*2) ;Init Z-pointer rjmp showit ;Show on LCD chk2: cpi wreg,1 ;See which message to print brne chk3 ;Not message 2, see if 3 ldi ZH,high(mess2*2);Print message 2 ldi ZL,low(mess2*2) ;Init Z-pointer rjmp showit ;Show on LCD chk3: cpi wreg,2 ;See which message to print brne chk4 ;Not message 3, see if 4 ldi ZH,high(mess3*2);Print message 3 ldi ZL,low(mess3*2) ;Init Z-pointer rjmp showit ;Show on LCD chk4: cpi wreg,3 ;See which message to print brne chk5 ;Not message 4, see if 5 ldi ZH,high(mess4*2);Print message 4 ldi ZL,low(mess4*2) ;Init Z-pointer rjmp showit ;Show on LCD chk5: cpi wreg,4 ;See which message to print brne chk6 ;Not message 5, see if 6 ldi ZH,high(mess5*2);Print message 5 ldi ZL,low(mess5*2) ;Init Z-pointer rjmp showit ;Show on LCD chk6: cpi wreg,5 ;See which message to print brne chk7 ;Not message 6, see if 7 ldi ZH,high(mess6*2);Print message 6 ldi ZL,low(mess6*2) ;Init Z-pointer rjmp showit ;Show on LCD chk7: cpi wreg,6 ;See which message to print brne chk8 ;Not message 7, see if 8 ldi ZH,high(mess7*2);Print message 7 ldi ZL,low(mess7*2) ;Init Z-pointer rjmp showit ;Show on LCD chk8: cpi wreg,7 ;See which message to print brne chk9 ;Not message 1, see if 2 ldi ZH,high(mess8*2);Print message 1 ldi ZL,low(mess8*2) ;Init Z-pointer rjmp showit ;Show on LCD chk9: ldi ZH,high(mess9*2);Print message 1 ldi ZL,low(mess9*2) ;Init Z-pointer showit: rcall puts ;Show on LCD rjmp pbwait ;Do it forever..... ; Clear entire LCD and delay for a bit lcdclr: ldi wreg,1 ;Clear LCD command rcall lcdcmd ; ldi timeout,256 ;Delay 15 mS for clear command ; rcall delay rcall spause ret ; Put string pointed to by Z puts: lpm ;Get next character from ROM tst R0 ;See if at end of message breq putx ;If so, quit mov wreg,R0 ;Get character cpi wreg,NL ;Check for new line brne putit ;Print if not new line ldi wreg,0xC0 ;Position cursor to line 2 rcall lcdcmd rjmp putnext putit: mov wreg,R0 ;Send it rcall lcdput putnext: adiw ZL,1 ;Increment Z-pointer rjmp puts ;Loop for more putx: ret ; Pause 1.5 seconds spause: ldi longtime,50 rjmp pwait pause: ldi longtime,100 ;Wait 1.5 second for LCD power up pwait: ldi timeout,256 ;Delay 15 mS rcall delay dec longtime brne pwait ret ; Initialize LCD module lcdinit: ldi wreg,0 ;Setup port pins out PORTD,wreg ;Pull all pins low ldi wreg,0xff ;All pins are outputs out DDRD,wreg ldi timeout,256 ;Wait at least 15 mS at power up rcall delay ldi wreg,3 ;Function set out PORTD,wreg sbi PORTD,lcde ;Toggle enable line cbi PORTD,lcde ldi timeout,65 ;Wait at least 4.1 mS rcall delay ldi wreg,3 ;Function set out PORTD,wreg sbi PORTD,lcde ;Toggle enable line cbi PORTD,lcde ldi timeout,2 ;Wait at least 100 uS rcall delay ldi wreg,3 ;Function set out PORTD,wreg sbi PORTD,lcde ;Toggle enable line cbi PORTD,lcde ldi wreg,2 ;Function set, 4 line interface out PORTD,wreg sbi PORTD,lcde ;Toggle enable line cbi PORTD,lcde ldi wreg,0b11110000 ;Make 4 data lines inputs out DDRD,wreg ; At this point, the normal 4 wire command routine can be used ldi wreg,0b00101000 ;Function set, 4 wire, 2 line, 5x7 font rcall lcdcmd ldi wreg,0b00001100 ;Display on, no cursor, no blink rcall lcdcmd ldi wreg,0b00000110 ;Address increment, without scrolling rcall lcdcmd ret ; Wait for LCD to go unbusy lcdwait: ldi wreg,0xF0 ;Make 4 data lines inputs out DDRD,wreg sbi PORTD,lcdrw ;Set r/w pin to read cbi PORTD,lcdrs ;Set register select to command waitloop: sbi PORTD,lcde ;Toggle enable line cbi PORTD,lcde in lcdstat,PIND ;Read busy flag sbi PORTD,lcde ;Toggle enable line cbi PORTD,lcde sbrc lcdstat,3 ;Loop until done rjmp waitloop ret ; Send command in wreg to LCD lcdcmd: push wreg ;Save character rcall lcdwait ;Wait for LCD to be ready ldi wreg,0xFF ;Make all port D pins outputs out DDRD,wreg pop wreg ;Get character back push wreg ;Save another copy swap wreg ;Get upper nibble andi wreg,0x0F ;Strip off upper bits out PORTD,wreg ;Put on port sbi PORTD,lcde ;Toggle enable line cbi PORTD,lcde pop wreg ;Rercall character andi wreg,0x0F ;Strip off upper bits out PORTD,wreg ;Put on port sbi PORTD,lcde ;Toggle enable line cbi PORTD,lcde ldi wreg,0xF0 ;Make 4 data lines inputs out DDRD,wreg ret ; Send character data in wreg to LCD lcdput: push wreg ;Save character rcall lcdwait ;Wait for LCD to be ready ldi wreg,0xFF ;Make all port D pins outputs out DDRD,wreg pop wreg ;Get character back push wreg ;Save another copy swap wreg ;Get upper nibble andi wreg,0x0F ;Strip off upper bits out PORTD,wreg ;Put on port sbi PORTD,lcdrs ;Register select set for data sbi PORTD,lcde ;Toggle enable line cbi PORTD,lcde pop wreg ;Rercall character andi wreg,0x0F ;Strip off upper bits out PORTD,wreg ;Put on port sbi PORTD,lcdrs ;Register select set for data sbi PORTD,lcde ;Toggle enable line cbi PORTD,lcde ldi wreg,0xF0 ;Make 4 data lines inputs out DDRD,wreg ret ;***** Timer 0 overflow interrupt handler t0int: set ;Set T flag ldi wreg,TSTOP ;Timer 0 off out TCCR0,wreg ;Stop timer reti ;Done, return ;***** Delay n*64 microseconds using timer 0, delay time passed in timeout delay: in wreg,SREG ;Save status register push wreg out TCNT0,timeout clt ;Clear T ldi wreg,TCK256 ;Timer 0 prescaler, CK / 256 out TCCR0,wreg ;Run timer dwait: brtc dwait ;Wait for timer 0 interrupt to set T pop wreg ;Restore status register out SREG,wreg ret nop mess0: .db " Magic 8 Ball",NL," Press Switch 7",0 mess1: .db " Signs point",NL," to yes",0 mess2: .db " The outlook",NL," is doubtful",0 mess3: .db "Ask again later",0 mess4: .db " Yes",0 mess5: .db " No",0 mess6: .db " Rethink your",NL," question",0 mess7: .db " How the hell",NL," should I know?",0 mess8: .db " Of course",0 mess9: .db " Bogus!",0