;AT90S8515 version created by Rafael Alcocer, ralcocer@imedicalpr.com .nolist .include "8515def.inc" .list .def charcount =r1 ;Number of characters displayed on line being written .def delay2 =r16 ;Temporary register. .def temp =r17 ;Temporary register. .def temp1 =r18 .def outchar =r19 ;Char to send by UART. .def inchar =r20 ;Char received by UART .def flagreg =r21 ;Flags .def charbuf =r22 ;Char read from circular buffer ; YL ;UART circular buffer write pointer. .def gpcount =r23 ;General purpose counter ; ZL ;UART circular buffer read pointer ; XL ;16 char line buffer pointer .equ lbufsiz =$10 .equ circbufsiz =$0F .equ OE =8 ;Bit 3 port B display enable (also directly addressed). .equ RS =4 ;Bit 2 in port B display register select (also directly ;adressed) .equ cbufbot =$60 ;Bottom of circular UART receive buffer. .equ cbuftop =$67 ;Top of circular UART receive buffer. .equ lbufbot =$70 ;Bottom of display line buffer. .equ lbuftop =$7F ;Top of display line buffer. ;Baudrate Calculation .equ clock = 4000000 ;clock frequency .equ baudrate = 9600 ;choose a baud rate .equ baudconstant = (clock/(16*baudrate))-1 ;Flagreg bit assignments ; bit 0 Pending linefeed if high. ; bit 1 ; bit 2 ; bit 3 ; bit 4 ; bit 5 ; bit 6 ; bit 7 ;Memory usage: ;Ring buffer from $60 through $67 ;Line buffer from $70 to $7F ;****************************** .cseg .org $00 rjmp start ; Reset rjmp start rjmp start rjmp start rjmp start rjmp start rjmp start rjmp start rjmp UartRecInt ;UART interrupt rjmp UartRecInt ;interrupt ;rjmp UartRecInt ;UART interrupt HelloString: ;TEXT TO BE TYPED ON FIRST LINE WHEN POWER IS APPLIED .db "8515 LCD 1002031B" .db 00,00 crlf: .db $0A,$0D .db 00,00 message1: .db "Press any key",0 message2: .db "please (1-16)",0 message3: .db "You pressed",0 message4: .db "key:",0 start: clr XH clr YH clr ZH ldi temp,low(RAMEND) ;Init Stack Pointer out SPL,temp ldi temp,high(RAMEND) out SPH,temp ldi temp,0b00000011 ;Weak pullups on inputs out PORTB,temp ldi temp,0b11111100 out DDRB,temp ;PORTB = all outputs except bits 0,1 ldi temp,0b11111111 ;Weak pullups on inputs out PORTD,temp ldi temp,0b00000000 ;PORTD - all inputs ldi flagreg,$00 ;Set all flags to zero. ldi temp,$00 mov charcount,temp rcall ClearLineBuffer ;Initialize line buffer. rcall DisplayInit ldi temp,baudconstant out ubrr,temp ;load baudrate sbi ucr,txen ;Enable the UART transmitter sbi ucr,rxen ;Enable the receiver.. rcall sendhello ;write line 1 power-up information rcall Hometwo ;Position cursor for input on line two. ldi YL,cbufbot ;Set Y and Z circ buff pointers to bottom. ldi ZL,cbufbot sbi UCR,7 ;Emable UART Interrupt. sei ;Global interrupt flag set (enabled). forever: ;Waiting for new data from circular buffer ;Get waiting char from circular buffer if there is one. cp YL,ZL ;Is circular buffer read pointer already pointing to latest entry? breq Buffempty ;If so, there is no new data in the buffer. ld charbuf,Z+ ;If pointers are not equal, then read next char in buffer. cpi ZL,cbuftop + 1 ;Advance circular buffer read pointer to next value. brne NoZeroZL ;If end of buffer, wrap around to start of buffer. ldi ZL,cbufbot NoZeroZL: ;Handle the new character as either a control char or a displayable char. ;If bufchar is a control char,test for CR and LF cpi charbuf,$1F ;If not a control char branch to displayable char routine.. brpl ItsDisplayable cpi charbuf,$0D ;If this is a carriage return character, brne noCR ;Set cursor to start of bottom line. ldi XL,lbufbot ;Its a CR so set ponters back to start of line. ldi temp,$00 mov charcount,temp rcall hometwo ;Put cursor back in first column of line two. noCR: cpi charbuf,$0A ;If its a linfeed char then brne NotALineFeed ;set linfeed pending flag. ori flagreg,0b00000001 NotALineFeed: rjmp Buffdone ItsDisplayable: ;If not a control char then do line feed if pending then ;write to display and to line buffer. sbrc flagreg,0 ;If linefeed i spending, then do it rcall linefeed cpi XL,lbuftop+1 ;Don't store if buffer at limit. breq Xfull st X+,charbuf mov temp,charbuf rcall DATA_DISPLAY Xfull: Buffdone: Buffempty: rjmp forever SendHello: ;Send HelloString rcall Homeone ldi ZH,high(2*HelloString) ; Load high part of byte address into ZH ldi ZL,low(2*HelloString) ; Load low part of byte address into ZL moretosend: lpm ; Load byte from program memory into r0 tst r0 ; Check if we've reached the end of the message breq finishsendstering ; If so, return mov temp,r0 rcall DATA_DISPLAY adiw ZL,1 ; Increment Z registers rjmp moretosend finishsendstering: ret linefeed: ;Handle a linefeed char ;Clear line 1 (top line), copy line two to line one, clear ;line two, the position the cursor in first column of line two. push gpcount ;***** push YL ;****** push ZL ;******* rcall hometwo ;Put cursor at start of line 2 so it can be cleared. ldi gpcount,$10 ;Number of chars in line.**** clearmore: ldi temp,$20 ;Fill line with spaces (erase). rcall DATA_DISPLAY dec gpcount brne clearmore rcall homeone ;Copy line buffer to line 1, reset XL to bottom. ldi XL,lbufbot ldi temp,$00 mov charcount,temp MoreToCopy: ld temp,X+ rcall DATA_DISPLAY cpi XL,lbuftop + 1 brne MoreToCopy rcall ClearLineBuffer ldi flagreg,$0b11111100 ;Clear linefeed pending and enable flagsb. ;************************************************* ;Added to reset the buffers ,counter and flag ;************************************************* rcall hometwo ldi gpcount,$00 ;******** pop ZL ;***** POP YL ;***** pop gpcount ;**** ldi flagreg,$00 ;******Set all flags to zero. ldi temp,$00 ;****** mov charcount,temp ret ;Done ;************************************************* ClearLineBuffer: ;Fill line buffer with spaces, set XL to bottom. ldi XL,lbufbot ldi temp,$00 mov charcount,temp ldi temp,$20 MoreToSpace: st X+,temp cpi XL,lbuftop + 1 brne MoreToSpace ldi XL,lbufbot ret recchar: ;sbi ucr,rxen ; set receiver bit sbis usr,rxc ;Wait for a char. rjmp recchar in inchar,udr ;Read the char. rjmp emitchar ;cbi ucr,rxen ;clear register ret emitchar: mov outchar,inchar sbis usr,udre ;wait until the register is cleared rjmp emitchar out udr,outchar ;send the byte ret ;go back HomeOne: ;Home cursor to start of first top line of display. ldi temp,$80 rcall COMMAND_DISPLAY ret HomeTwo: ;Home cursor to start of bottom line of display ldi temp,$C0 rcall COMMAND_DISPLAY ret ;************************************************ ; ; Write command to display ; command word in temp ; built in 50 usec delay; by Richard Hosking ;************************************************ COMMAND_DISPLAY: mov temp1,temp ;Copy data to temp1 andi temp,0b11110000 ;mask off lower 4 bits, make OE and RS low sbr temp,OE ;OE bit high out PORTB,temp ;write upper 4 bits to display nop ;wait 1 usec total command nop ; Stabilize line nop ;Added by DC to bring up to 1 us for 4 mHz clock nop ;Added by DC to bring up to 1 us for 4 mHz clock cbi PORTB,3 ;OE low to clock in data swap temp1 ;get lower 4 bits andi temp1,0b11110000 ; mask off lower 4 bits, make OE and RS low sbr temp1,OE ;OE high out PORTB,temp1 ;write lower 4 bits to LCD ; nop ; nop nop ;Added by DC to bring up to 1 us for 4 mHz clock nop ;Added by DC to bring up to 1 us for 4 mHz clock ; cbi PORTB,3 ;OE low to clock in data ldi temp,100 ;Wait about 50 usec D4: dec temp brne D4 ret ; return ;****************************************************** ; ; Writes data to display; incorporates 50 usec delay; data in temp ; by Richard Hosking ;******************************************************** DATA_DISPLAY: mov temp1,temp ; Copy data to temp1 andi temp,0b11110000 ; mask off lower 4 bits sbr temp,OE ; OE bit high sbr temp,RS ; data/command bit high out PORTB,temp ; write upper 4 bits to display nop ; wait 1 usec total command nop ; Stabilize line cbi PORTB,3 ; OE low to clock in data; swap temp1 ; get lower 4 bits andi temp1,0b11110000 ; mask off lower 4 bits sbr temp1,OE ; OE high sbr temp1,RS out PORTB,temp1 ; write lower 4 bits to LCD nop ; nop cbi PORTB,3 ; OE low to clock in data; ldi temp,100 ; Wait about 50 usec ; ldi temp,200 ; Wait about 50 usec D5: dec temp brne D5 ret ; return ;********************************************************************* ; Delay 2 msec with a 4MHz clock ;********************************************************************* WAIT_2msec: ldi temp1,$0B D24002: ldi Delay2,$FF D24001: dec Delay2 brne D24001 dec temp1 brne D24002 ret ;************************************************************************* ; Display setup ; Port B bit 3 OE Enable - clocks on neg transition ; 2 RS Register Select ; command=0, data=1 ; bits 4-7 data 4 bits, high nibble first ; ASCII format ; RW grounded (write) ; Note that some commands take up to 1.6 msec for display to implement ; at a nominal display clock rate of 250 KHz; Display initialize routine after power up ; by Richard ;************************************************************************ DisplayInit: ;Initialize Display ldi temp,50 ;Wait at least 15msec after D1: ;powerup before writing rcall WAIT_2msec ;to display dec temp brne D1 ldi temp,0b00111000 ;System set out PORTB,temp nop nop ;Data write cycle must be >1000usec cbi PORTB,3 ;OE low to clock in data; rcall WAIT_2msec ;Wait 4 msec rcall WAIT_2msec ; ldi temp,0b00111000 ;System set out PORTB,temp nop nop ; Data write cycle must be >1000usec cbi PORTB,3 ; OE low to clock in data; rcall WAIT_2msec ; wait at least 100usec ldi temp,0b00111000 ;System set out PORTB,temp nop ; nop ; cbi PORTB,3 ; OE low to clock in data rcall WAIT_2msec ; Wait at least 40usec (2 msec) ldi temp,0b00101000 ; Function set 4 bit mode, 2 lines 5X7 pixels rcall COMMAND_DISPLAY ; write to display -first write sets 4 bit ; Second function set added by DC ldi temp,0b00101000 ; Function set 4 bit mode, 2 lines 5X7 pixels rcall COMMAND_DISPLAY ; write to display -second write to set N and F ldi temp,0b00001000 ;Display off, cursor off ; blink off rcall COMMAND_DISPLAY ; ldi temp,0b00000001 ; Display clear rcall COMMAND_DISPLAY rcall WAIT_2msec ; Need to wait 1.6 msec after clear; ldi temp,0b00000110 ; Entry mode set ; Increment RAM, dont shift display rcall COMMAND_DISPLAY ; ldi temp,0b00001110 ; Display on, cursor on ,blink off rcall COMMAND_DISPLAY; rcall WAIT_2msec ; Need to wait 1.6 msec after clear ret UartRecInt: ;Uart interrupt service -Write received char into a circular buffer push temp rcall recchar ;Get the char from the UART. st Y+,inchar cpi YL,cbuftop + 1 brne NoZeroYL ldi YL,cbufbot NoZeroYL: pop temp reti