; lcd.asm Andy Meng ; PIC at 4MHz errorlevel -302 ; get rid of annoying bank bits notification org 0 goto Init __CONFIG _BODEN_OFF & _CP_OFF & _XT_OSC & _PWRTE_ON & _WDT_OFF & _LVP_OFF include "P16F872.inc" ; Declarations d1 equ 0x21 ; declaration for delay register D1 equ 0x22 ; for 5ms delay D2 equ 0x23 ; another for the 5ms delay long_reg equ 0x31 PORTCtemp equ 0x29 ; LCD RS equ 0 ; Instruction/Register Select E equ 1 ; Clock CharNum equ 0x24 LCDcharData equ 0x25 LCDtemp equ 0x26 Init: bsf STATUS,RP0 movlw 0xDF ; set PORTB direction movwf TRISB bcf STATUS,RP0 clrf PORTB ; clear PORTB so no lights come on clrf INTCON ; make sure INTCON is cleared call Delay15ms ; long delay for LCD to turn on bsf STATUS, RP0 ; go into bank 1 movlw 0x06 ; set ADC to all digital mode movwf ADCON1 movlw b'00011111' ; set PORTA to be all inputs movwf TRISA movlw b'11000000' ; set PORTC to let USART work correctly movwf TRISC ; PORTC all outputs also bcf STATUS, RP0 ; go back to bank 0 movlw 0x30 ; LCD initialization value movwf PORTCtemp ; move it to the LCD temp port bcf STATUS,C rrf PORTCtemp,f rrf PORTCtemp,f bcf PORTCtemp,RS ; set instruction mode bsf PORTCtemp,E ; clock the data in movf PORTCtemp,w ; move PORTCtemp to w movwf PORTC ; move it to PORTC goto $ + 1 ; delay bcf PORTC,E ; end clock signal call Delay5ms ; wait for the command to execute bsf PORTC,E ; set clock line goto $ + 1 ; short delay bcf PORTC,E ; clear clock line call Delay160us ; 160us delay bsf PORTC,E goto $ + 1 bcf PORTC,E call Delay160us movlw 0x20 ; set LCD to use 4-bit mode call LCDwrite call Delay160us movlw 0x28 ; set LCD to 4-bit, one line, 5x7 call LCDwrite ; call the LCD write routine movlw 0x10 ; don't shift display after write call LCDwrite movlw 0x01 ; clear LCD call LCDwrite call Delay5ms movlw 0x06 ; inc cursor after byte write, dont shift display call LCDwrite movlw 0x0E ; turn on display and cursor call LCDwrite clrf timeL clrf CharNum ; clear the character counter bsf PORTC,RS ; set mode to character write clrf timeH clrf EEmemnum InitialDisp: bcf INTCON,GIE movf CharNum,w ; move the val in CharNum to w call LCDtable ; call the lookup table movwf LCDcharData ; put the result in LCDcharData xorlw 0x00 ; XOR the result with 00hex btfsc STATUS,Z ; test to see if the result is 0 (end of table) goto Start movf CharNum,w ;xorlw 0x08 ;btfsc STATUS,Z ;call Ninth ; move the cursor to the ninth position movf LCDcharData,w ; put data back in w call LCDwrite ; call the LCD write routine movf LCDcharData,w ; put data back in w incf CharNum,f ; increment the value to look up goto InitialDisp ; repeat the loop LCDtable: addwf PCL,f ; add w and program counter, put in program counter dt "LCD Timer v.00 ",0x0A,0x0D,0 ; create a lookup table (same as retlw table) LCDwrite: ; writes data in w to LCD in 4-bit mode - the heart of the LCD control program movwf LCDtemp ; put w in LCDtemp for later swapping andlw 0xF0 ; only write top 4 bits to PORTC movwf PORTCtemp ; put data in w on PORTC bcf STATUS,C ; clear carry bit (make sure nothing is pulled in) rrf PORTCtemp,f ; shift bits down so they are in right spot on PORTC bcf STATUS,C ; clear carry bit again rrf PORTCtemp,f ; rotate one more spot bsf PORTCtemp,RS ; set PORTCtemp RS bit (so it can be cleared if needed) btfss PORTC,RS ; check to see if RS bit is set bcf PORTCtemp,RS ; if it is clear, clear it in PORTCtemp bsf PORTCtemp,E ; set clock bit in PORTCtemp movf PORTCtemp,w ; put PORTCtemp in w movwf PORTC ; put it in PORTC goto $ + 1 ; 2 cycle delay bcf PORTC,E ; turn it off again goto $ + 1 clrf PORTCtemp swapf LCDtemp,w ; swap first and last nibbles of PORTC, put in w andlw 0xF0 ; only write top 4 bits to PORTC movwf PORTCtemp ; put w in PORTCtemp bcf STATUS,C ; do same stuff as above for next nibble rrf PORTCtemp,f bcf STATUS,C rrf PORTCtemp,f bsf PORTCtemp,RS ; set RS (character mode) btfss PORTC,RS ; check to see if RS bit is set bcf PORTCtemp,RS ; if it is clear, clear it in PORTCtemp bsf PORTCtemp,E ; set clock in PORTCtemp movf PORTCtemp,w ; put PORTCtemp in w movwf PORTC ; put it in PORTC goto $ + 1 bcf PORTC,E ; take the clock line low call Delay160us ; wait for instruction to execute return RS232_Transmit: ; examples of RS232 routines - setup needs to be done in Init ; bsf STATUS,RP0 ; page 1 ; btfss TXSTA,TRMT ; see if the transmitter is ready for data ; goto $ - 1 ; loop until transmitter ready ; bcf STATUS,RP0 ; page 0 ; movwf TXREG ; transmit the byte (put it in the TX reg) return ;RS232_Receive: ; called in ISR ; movf RCREG,w ; put received data in w ; movwf RXdata ; put it in RXdata reg ; call LCDwrite ; write char to LCD ; movf RXdata,w ; put data in w again ; xorlw 0x0D ; see if enter was pressed ; btfsc STATUS,Z ; if it was goto next instruction ; call ClearLCD ; return ;;;;;;;; LCD Control Functions ;;;;;;;; TopLine: ; move cursor to top row bcf PORTC,RS ; instruction mode movlw 0x00 ; top line display location iorlw 0x80 ; "move cursor to" instruction call LCDwrite call Delay160us bsf PORTC,RS return BotLine: ; move cursor to bottom row (8th char for 1 line) bcf PORTC,RS ; put LCD in instruction mode movlw 0x40 ; display location iorlw 0x80 ; "move cursor to" instruction call LCDwrite ; move cursor to 0x40 (ninth position) call Delay160us ; wait for instruction to execute bsf PORTC,RS ; put LCD back in character mode return MoveCursor: ; move cursor to position in w bcf PORTC,RS ; instruction mode iorlw 0x80 ; or position with "move cursor to" instruction call LCDwrite call Delay160us bsf PORTC,RS return CursorOff: ; turn off the cursor so it doesn't blink bcf PORTC,RS movlw 0x0C call LCDwrite bsf PORTC,RS return ClearLCD: ; clear everything off of the LCD bcf PORTC,RS ; instruction mode movlw 0x01 ; clear LCD call LCDwrite ; write command to LCD call Delay5ms ; wait for cmd to execute bsf PORTC,RS ; char mode ;;;;;;;; Delay Routines ;;;;;;;; Delay500ms: ; speed based off Delay5ms routine movlw 0x64 ; put 100d in w movwf long_reg ; put it in the long delay register Loop_cont: call Delay5ms decfsz long_reg,f ; decrement long delay register, skip if 0 goto Loop_cont return ; exit the long delay function Delay160us: ; delay for 100us (speed specific for 4MHz) movlw 0x25 movwf d1 Delay_00 decfsz d1, f goto Delay_00 nop return Delay5ms: ; delay for 5ms (speed specific for 4MHz) movlw 0x30 movwf D1 delay_00 movlw 0x28 movwf D2 delay_01 decfsz D2, f goto delay_01 decfsz D1, f goto delay_00 movlw 0x0c movwf D1 delay_10 decfsz D1, f goto delay_10 goto $+1 return Delay15ms: call Delay5ms call Delay5ms call Delay5ms return end