; Control a 16 char x 1-line LCD with AT90S4414 AVR Processor ; Using 4-wire bus interface (plus 3 control lines) ; ; Charles R. Ott ; May 22, 1998 ;----------------------------------- ; Modified by Bruce Land for EE476 at Cornell ; Jan 1999 ; ; Port D controls the LCD ; Port A, pin 7, supplies power to the LCD ; Port B is used for diagnostic LED displays ; ; The program sets up the display, displays an EE 476 message. ; then endlessly loops, writing out characters. ; The LCD is sensitive to power up. ;----------------------------------- .nolist ;Suppress listing of include file .include "4414def.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 .def charcnt =r20 ;Char position on the display .def chr =r21 ;a variable character to print ;***** 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 enable 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 .cseg ; Interrupt vectors .org $0000 rjmp RESET ;reset entry vector reti reti reti reti reti reti rjmp t0int reti reti reti reti reti ; Main program entry point on reset reset: ldi wreg, LOW(RAMEND) ;setup stack pointer out SPL, wreg ldi wreg, HIGH(RAMEND) out SPH, 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 ;ldi wreg,0x0F ;Turn on four LEDs ;out PORTB,wreg ldi wreg,0xFF ;Make port B pin all outputs out DDRB,wreg ;power down the LCD ldi wreg, 0xff ;LCD power connection out DDRA, wreg ;power it down after reset ldi wreg, 0x00 out PORTA,wreg ldi longtime,100 ; then Wait 1.5 second with LCD power off ldi timeout,0 ;Delay 15 mS offwait:rcall delay dec longtime brne offwait ;now power up LCD ldi wreg, 0xff out PORTA, wreg ldi longtime,100 ;Wait 1.5 second for LCD power up ldi timeout,0 ;Delay 15 mS puwait: rcall delay dec longtime brne puwait ldi wreg,0xFF ;Turn off all LEDs out PORTB,wreg ;hopefully by now the LCD has rebooted main: rcall lcdinit ;Initialize LCD module rcall lcdclr ;Clear LCD screen clr charcnt ;zero the character count ldi chr, 0x20 ;load var char with first printable ldi ZH,high(message*2);first message addr to Z-ptr ldi ZL,low(message*2);Init Z-pointer nextc: lpm ;Get next character from ROM tst R0 ;See if at end of message breq end1 ;If so, next message cpi charcnt,8 ;addressing changes at char #8! brne wrtit ;at char 8, fix it ldi wreg,0xC0 ;Set address to last 8 chars rcall lcdcmd wrtit: mov wreg,R0 ;Send it to the LCD rcall lcdput adiw ZL,1 ;Increment Z-pointer inc charcnt ;keep track of chars on display rjmp nextc ;Loop for more end1: ldi longtime,100 ;Wait 1.5 second for human to read it ldi timeout,0 ;Delay 15 ms wait1 :rcall delay dec longtime brne wait1 ;now the second message mloop: rcall lcdclr ;Clear LCD screen clr charcnt ;zero the character count ldi ZH,high(mess2*2);get the second message ldi ZL,low(mess2*2);Init Z-pointer nextc2: lpm ;Get next character from ROM tst R0 ;See if at end of message breq end2 ;If so, next message cpi charcnt,8 ;addressing changes at char #8 brne wrtit2 ;fix it ldi wreg,0xC0 ;Set address to last 8 chars rcall lcdcmd wrtit2: mov wreg,R0 ;Send it rcall lcdput adiw ZL,1 ;Increment Z-pointer inc charcnt ;keep track of chars rjmp nextc2 ;Loop for more end2: mov wreg, chr ;print one more char rcall lcdput inc chr ;the next printable char ldi longtime,15 ;Wait .3 second ldi timeout,0 ;Delay 15 mS wait3: rcall delay dec longtime brne wait3 rjmp mloop ;print 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 ret ================================================ ; Initialize LCD module lcdinit: cbi PORTB,0 ;Turn on LED 0 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 ; LCD specs call for 3 repetitions as follows ldi wreg,3 ;Function set out PORTD,wreg ;to 8-bit mode nop ;nop is data setup time sbi PORTD,lcde ;Toggle enable line cbi PORTD,lcde ldi timeout,256 ;Wait at least 15 mS rcall delay ldi wreg,3 ;Function set out PORTD,wreg nop sbi PORTD,lcde ;Toggle enable line cbi PORTD,lcde ldi timeout,256 ;Wait at least 15 ms rcall delay ldi wreg,3 ;Function set out PORTD,wreg nop sbi PORTD,lcde ;Toggle enable line cbi PORTD,lcde ldi timeout,256 ;Wait at least 15 ms rcall delay ldi wreg,2 ;Function set, 4 line interface out PORTD,wreg nop ; rcall strobe ;Toggle enable line sbi PORTD,lcde ;Toggle enable line cbi PORTD,lcde ldi wreg,0b11110000 ;Make 4 data lines inputs out DDRD,wreg ; Finally, ; At this point, the normal 4 wire command routine can be used ldi wreg,0b00100000 ;Function set, 4 wire, 1 line, 5x7 font rcall lcdcmd ldi wreg,0b00001100 ;Display on, no cursor, no blink rcall lcdcmd ldi wreg,0b00000110 ;Address increment, no scrolling rcall lcdcmd sbi PORTB,0 ;Turn off LED 0 ret ============================================ ; Wait for LCD to go unbusy lcdwait: cbi PORTB,1 ;Turn on LED 1 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 ;Read, and ignore lower nibble sbi PORTD,lcde ;Toggle enable line cbi PORTD,lcde sbrc lcdstat,3 ;Loop until done rjmp waitloop sbi PORTB,1 ;Turn off LED 1 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 nop ;wait for data setup time sbi PORTD,lcde ;Toggle enable line cbi PORTD,lcde pop wreg ;Recall character andi wreg,0x0F ;Strip off upper bits out PORTD,wreg ;Put on port nop 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 nop sbi PORTD,lcde ;Toggle enable line cbi PORTD,lcde pop wreg ;Recall character andi wreg,0x0F ;Strip off upper bits out PORTD,wreg ;Put on port sbi PORTD,lcdrs ;Register select set for data nop sbi PORTD,lcde ;Toggle enable line cbi PORTD,lcde ;cbi PORTD,lcdrs ;-- ldi wreg,0xF0 ;Make 4 data lines inputs out DDRD,wreg ret ============================================= ;***** Timer 0 overflow interrupt handler t0int: set ;Set T flag ldi wreg,0xFF ;Turn off all LEDs out PORTB,wreg 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 ; weird construction, interrupt is called like a subroutine 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 ============================================= ; text data message: .db "Testing EE476", 0x00 mess2: .db "Printable chrs=", 0x00