;*************************************************************************** ; ; File Name :'lcd4.asm" ; Title :HD44xx kompatibilis LCD Driver (I/O Port) ; Date :2003.10.28. ; Version :1.0.0 ; Support telephone :+36-70-333-4034, old: +36-30-9541-658 VFX ; Support fax : ; Support Email :info@vfx.hu ; Target MCU :ATmega128, M48/88 ; ;*************************************************************************** ; D E S C R I P T I O N ; ; http://home.iae.nl/users/pouweha/lcd/lcd.shtml ; ; Support 2x16 char LCD ; ; - LCD_Init ; - LCD_Clear ; - LCD_SendCmd ; - LCD_SendChar ; - LCD_Goto ; - LCD_PrnFLASHStr ; - LCD_ScrollUp ; - LCD_PrintStr ; ;*************************************************************************** ; M O D I F I C A T I O N H I S T O R Y ; ; ; rev. date who why ; ---- ---------- --- ------------------------------------ ; 0.01 2003.10.28 VFX Creation ; ;*************************************************************************** ;Hardware ;*************************************************************************** ;* ;* SYSCLK: f=16.000 MHz (T= 62.5 ns) ;* ;*************************************************************************** ; ; ;************************************************************************** ;* Hardware Def. ; ;*************************************************************************** .equ LCDRS_PORT=PORTD ;LCD Register Select .equ LCDRS_DIR=DDRD ;Register Select 1=data 0=command .equ LCDRS=7 .equ LCDRW_PORT=PORTD ;LCD Read/Write .equ LCDRW_DIR=DDRD ;0=write to display, 1= read from display .equ LCDRW=6 .equ LCDEN_PORT=PORTB ;LCD Enable .equ LCDEN_DIR=DDRB ;Enable - data clocked on falling edge .equ LCDEN=6 .equ LCDDAT_PORT=PORTC+0x20 ;LCD Data PortC[3..0] .equ LCDDAT_DIR=DDRC+0x20 ;M128 F port = DDRF, PORTF; M48/88 -> DDRC+0x20, PORTC+0x20 .equ LCDDAT_PIN=PINC ; .equ LCDDAT_Mask=0b00001111 .equ LCDLine0 = 0x00 ;0 Line in LCD .equ LCDLine1 = 0x40 ;1 Line in LCD .equ LCDLine2 = 0x14 ;2 Line in LCD .equ LCDLine3 = 0x54 ;3 Line in LCD .equ LCDRow = 2 .equ LCDVis = 16 ;*************************************************************************** ;**** VARIABLES .DSEG LCdDisp: .byte LCDROW * LCDVis LCDPOS: .byte 1 ;*************************************************************************** .ESEG ;*************************************************************************** ;**** CODE SEG ;*************************************************************************** .CSEG ;***************************************************** ;** LCD_pulseE ;** ;** In: - ;** ;** Out: R0 - Data on LCDDat pin ;** ;** ;** Alt ;** ;** Description: Generate ENABLE signal to LCD ;* LCD_pulseE: sbi LCDEN_PORT,LCDEN ;Enable high nop ;Wait 500ns @16MHz nop nop nop nop nop nop nop in R0,LCDDAT_PIN cbi LCDEN_PORT,LCDEN ;Enable low, latch data ret ;***************************************************** ;** LCD_Init ;** ;** In: - ;** ;** Out: - ;** ;** ;** Alt: ;** ;** Description: Initialize LCD in 4 bit mode ;* LCD_Init: sbi LCDEN_DIR,LCDEN ;LCD I/O Disabled cbi LCDEN_PORT,LCDEN sbi LCDRS_DIR,LCDRS ;Sel. LCD Command Register cbi LCDRS_PORT,LCDRS sbi LCDRW_DIR,LCDRW ;LCD Write mode cbi LCDRW_PORT,LCDRW ldi R16,LCDDAT_Mask ;LCD Data lines outputs lds R0,LCDDAT_DIR or R0,R16 sts LCDDAT_DIR,R0 lds R0,LCDDAT_PORT com R16 and R0,R16 ;All data bits zeros sts LCDDAT_PORT,R0 ldi R16,15 ;Wait at least 15msec after rcall Wait1ms ;powerup before writing to display ; Put the LCD in 8-bit mode. Even though we want the display to ; operate in 4-bit mode, the only way to guarantee that our commands ; are aligned properly is to initialize in 8-bit. (The user might have ; hit reset between nibbles of a dual 4-bit cycle.) lds R16,LCDDAT_PORT andi R16,255-LCDDAT_Mask ori R16,0b00000011 ;3x probalkozunk 8 bit mode-ba rakni sts LCDDAT_PORT,R16 nop nop cbi LCDRS_PORT,LCDRS ;Set to Command Reg. cbi LCDRW_PORT,LCDRW ;read rcall LCD_pulseE ;1 ldi R16,15 rcall Wait1ms ;wait 5ms cbi LCDRS_PORT,LCDRS ;Set to Command Reg. cbi LCDRW_PORT,LCDRW ;read rcall LCD_pulseE ;2 ldi R16,5 rcall Wait1ms ;wait 5ms cbi LCDRS_PORT,LCDRS ;Set to Command Reg. cbi LCDRW_PORT,LCDRW ;read rcall LCD_pulseE ;3 ldi R16,5 rcall Wait1ms ;wait 5ms ; Now it's safe to go into 4-bit mode. lds R16,LCDDAT_PORT andi R16,255-LCDDAT_Mask ori R16,0b00000010 ;4bit bus mode sts LCDDAT_PORT,R16 rcall LCD_pulseE ldi R16,5 rcall Wait1ms ;wait 5ms ; *** Send the 'FUNCTION SET' command ; +------ Data: 0 = 4-bit; 1 = 8-bit ; |+----- Lines: 0 = 1; 1 = 2 ; ||+---- Font: 0 = 5x8; 1 = 5x11 ldi R16,0b00101000 rcall LCD_SendCmd ; *** Send the 'CURSOR/DISPLAY SHIFT' command ; +----- S/C: 0 = cursor; 1 = display ; |+---- R/L: 0 = left; 1 = right ldi R16,0b00010100 rcall LCD_SendCmd ; *** Send the 'ENTRY MODE' command ; +--- Direction: 0 = left; 1 = right ; |+-- Shift Dislay: 0 = off; 1 = on ldi R16,0b00000110 rcall LCD_SendCmd ; *** Send the 'DISPLAY ON/OFF' command ; +---- Display: 0 = off; 1 = on ; |+--- Cursor: 0 = off; 1 = on ; ||+-- Blink: 0 = off; 1 = on ldi R16,0b00001100 rcall LCD_SendCmd rcall LCD_Clear ret ;***************************************************** ;** LCD_Clear ;** ;** In: - ;** ;** Out: - ;** ;** ;** Alt: ;** ;** Description: ;** Clears the display and sends the cursor home. ; LCD_Clear: ldi R16,0b00000001 ;Clear LCD rcall LCD_SendCmd ldi R16,0b00000010 ;Send the cursor home rcall LCD_SendCmd ClearLCDSpace: ldi R16,LCDROW * LCDVis ldi R17,32 ldi ZL,low(LCdDisp) ldi ZH,High(LCdDisp) FillLCD: st Z+,R17 dec R16 brne FillLCD sts LCDPOS,R16 ret ;***************************************************** ;** LCD_WaitBusy ;** ;** In: - ;** ;** Out: T flag =1 LCD Error, Not response or damaged ;** =0 LCD Works ;** ;** Alt: R0 ;** ;** Description: ;** Waits for the busy flag to go low. Since we're in 4-bit mode, ;** the register has to be read twice (for a total of 8 bits). ;* LCD_WaitBusy: push R16 push ZL push ZH ;wating for bysy flag . Max waiting time is 100us (64us most longer statements in HD744x) ;100us @16MHz => 1600 cycles ;real waiting time is more more more...than 1600 cycles ldi ZL,low(1600) ldi ZH,high(1600) lds R16,LCDDAT_DIR andi R16,255-LCDDAT_Mask ;LCD data bits going to input sts LCDDAT_DIR,R16 lds R16,LCDDAT_PORT ori R16,LCDDAT_Mask ;pull-up sts LCDDAT_PORT,R16 rjmp LCDWait1 LCDWait0: sbiw ZL,1 brne LCDWait001 set ;T = 1 LCD Error rjmp LCDWait2 ;Jump out if LCD not present or damaged LCDWait001: ldi R16,2 ;Wait min. ~1us LCDWait01: nop dec R16 brne LCDWait01 LCDWait1: cbi LCDRS_PORT,LCDRS ;Set to Command Reg. sbi LCDRW_PORT,LCDRW ;read rcall LCD_pulseE ;Busy Flag read bit 7. mov R16,R0 rcall LCD_pulseE ;lower nibble must read sbrc R16,3 ;Check busy flag rjmp LCDWait0 clt ;T =0 LCD Done LCDWait2: lds R16,LCDDAT_DIR ;LCD Data lines outputs ori R16,LCDDAT_Mask sts LCDDAT_DIR,R16 lds R16,LCDDAT_PORT andi R16,255-LCDDAT_Mask ;All zero sts LCDDAT_PORT,R16 pop ZH pop ZL pop R16 ret ;***************************************************** ;** LCD_SendCmd ;** ;** In: R16 - Command byte ;** ;** Out: - ;** ;** ;** Alt: R0, R1, R16 ;** ;** Description: ;** Routine to write a command to the instruction register. ; LCD_SendCmd: push R17 rcall LCD_WaitBusy mov R1,R16 swap R16 andi R16,LCDDAT_Mask ;send upper nibble first lds R17,LCDDAT_PORT andi R17,255-LCDDAT_Mask or R17,R16 sts LCDDAT_PORT,R17 cbi LCDRS_PORT,LCDRS ;Set to Command Reg. cbi LCDRW_PORT,LCDRW ;Write rcall LCD_PulseE ;Latch upper nibble mov R16,R1 andi R16,LCDDAT_Mask ;send lower nibble lds R17,LCDDAT_PORT andi R17,255-LCDDAT_Mask or R17,R16 sts LCDDAT_PORT,R17 cbi LCDRS_PORT,LCDRS ;Set to Command Reg. cbi LCDRW_PORT,LCDRW ;Write rcall LCD_PulseE ;Latch lower nibble pop R17 ret ;***************************************************** ;** LCD_SendChar ;** ;** In: R16 - character code ;** ;** Out: - ;** ;** ;** Alt: R0,R1, R16 ;** ;** Description: ;** Routine to write a character to the data register. ; LCD_SendChar: push ZL push ZH push R17 cpi R16,CR ;CR -> Line feed and scroll brne LCD_SC00 lds R17,LCDPos ldi R18,LCDLine1 cpi R17,LCDLine0+LCDVis brcc LCD_SC001 rjmp LCD_SC02 LCD_SC001: ldi R18,LCDLine3 cpi R17,LCDLine2+LCDVis brcc LCD_SC002 rjmp LCD_SC02 LCD_SC002: ldi R18,LCDLine2 cpi R17,LCDLine1+LCDVis brcc LCD_SC003 rjmp LCD_SC02 LCD_SC003: rcall LCD_ScrollUp ldi R18,LCDLine3 rjmp LCD_SC02 LCD_SC00: ;standard print ldi ZL,low(LCDDisp) ldi ZH,High(LCDDisp) lds R17,LCDPos cpi R17,LCDLine3+LCDVis ;utolso sor utolso karakter? brcs LCD_SC01 push R16 rcall LCD_ScrollUp pop R16 ldi R17,LCDLine3 LCD_SC01: ldi R18,0 cpi R17,LCDLine0+LCDVis brcs LCDCharOk ;0. sor ldi R18,2*LCDVis-LCDLine2 cpi R17,LCDLine2+LCDVis brcs LCDCharOk ;2. sor ldi R18,3*LCDVis-LCDLine3 cpi R17,LCDLine3 brcc LCDCharOk ;3. sor ldi R18,1*LCDVis-LCDLine1 cpi R17,LCDLine1 brcc LCDCharOk ;1. sor push R16 ldi R16,LCDLine3 rcall LCD_Goto pop R16 ldi R17,LCDLine3 ldi R18,3*LCDVis-LCDLine3 LCDCharOk: clr R0 sub R17,R18 add ZL,R17 adc ZH,R0 st Z,R16 LCDCharWr: rcall LCD_WaitBusy mov R1,R16 swap R16 andi R16,LCDDAT_Mask ;send upper nibble first lds R17,LCDDAT_PORT andi R17,255-LCDDAT_Mask or R17,R16 sts LCDDAT_PORT,R17 sbi LCDRS_PORT,LCDRS ;Set to data Reg. cbi LCDRW_PORT,LCDRW ;Write rcall LCD_PulseE ;Latch upper nibble mov R16,R1 andi R16,LCDDAT_Mask ;send lower nibble lds R17,LCDDAT_PORT andi R17,255-LCDDAT_Mask or R17,R16 sts LCDDAT_PORT,R17 sbi LCDRS_PORT,LCDRS ;Set to Data Reg. cbi LCDRW_PORT,LCDRW ;Write rcall LCD_PulseE ;Latch lower nibble lds R16,LCDPos inc R16 sts LCDPos,R16 ldi R18,LCDLine1 cpi R16,LCDLine0+LCDVis breq LCD_SC02 ldi R18,LCDLine2 cpi R16,LCDLine1+LCDVis breq LCD_SC02 ldi R18,LCDLine3 cpi R16,LCDLine2+LCDVis brne LCD_SC03 LCD_SC02: mov R16,R18 rcall LCD_Goto LCD_SC03: pop R17 pop ZH pop ZL ret ;***************************************************** ;** LCD_Goto ;** ;** In: R16 - position ;** 0x00 - 1.row, 1.col ;** 0x40 - 2.row, 1.col ;** ;** Out: - ;** ;** ;** Alt: R0, R1, R16 ;** ;** Description: ;** ; LCD_Goto: sts LCDPOS,R16 ori R16,0b10000000 ;Set address Command rcall LCD_SendCmd ret ;***************************************************** ;** LCD_PrnFLASHStr ;** ;** In: Z+RAMP - start address of string ;** ;** Out: - ;** ;** ;** Alt: R0, R1, R16, R17 ;** ;** Description: ;** Print a null terminated string to LCD ; LCD_PrnFLASHStr: lpm R16,Z+ ;elpm for M128 tst R16 breq LCD_PrnFLSH0 rcall LCD_SendChar rjmp LCD_PrnFLASHStr LCD_PrnFLSH0: ret ;***************************************************** ;** LCD_ScrollUp ;** ;** In: - ;** ;** Out: - ;** ;** ;** Alt: ?? ,R18 ;** ;** Description: ;** Scroll up 1 line no LCD ; LCD_ScrollUp: ldi R16,0 rcall LCD_Goto push ZL push ZH ldi ZL,low(LCDDisp+1*LCDVis) ldi ZH,High(LCDDisp+1*LCDVis) ldi R17,(LCDRow*LCDVis)-LCDVis LCD_Scrl1: push R17 ld R16,Z+ rcall LCD_SendChar pop R17 dec R17 brne LCD_Scrl1 pop ZH pop ZL ldi R16,LCDLine3 rcall LCD_Goto ldi R17,LCDVis LCD_Scrl2: push R17 ldi R16,32 rcall LCD_SendChar pop R17 dec R17 brne LCD_Scrl2 ldi R16,LCDLine3 ;Line 3 rcall LCD_Goto ret ;***************************************************** ;** LCD_PrintStr ;** ;** In: Y - Str pointer ;** R16 - lenght of string ;** ;** Out: - ;** ;** ;** Alt: ?? ,R18 ;** ;** Description: ; LCD_PrintStr: tst R16 brne LCD_PrintStr000 ret LCD_PrintStr000: push R16 ld R16,Y+ rcall LCD_SendChar pop R16 dec R16 rjmp LCD_PrintStr