Beste mensen, ik probeer een HD44780 display in 8 bits modus aan de praat te krijgen. Nu begin ik met het display leeg te maken.

Wat ik probeer: E-pin hoog, data op portD, E-pin laag. Dit is de manier waarop data verzonden moet worden, nietwaar?

Het clear display commando is 00000001 als data met RS en R/W op 0. Zie http://home.iae.nl/users/pouweha/lcd/lcd0.shtml#pin_assignment

De code heb ik zo simpel mogelijk gelaten:


.include "m32def.inc"

ser  r16
out  DDRC,r16		; COM ddr is output
out  DDRD,r16		; DATA ddr is output

sbi  PORTC,0		; E pin on
cbi  PORTC,1		; R/W pin off
cbi  PORTC,2		; RS pin off
ldi  r16, 0b00000001; Data
out  PORTD,r16   	; Data out
nop
cbi  PORTC,0		; E pin off

LOOP:				; Wait
	nop
	rjmp LOOP

Maar het display wordt niet leeg! Er blijft ############# op de eerste en derde regel staan.

Help, wie weet wat ik fout doe?

Owja, ik meet wel 5V op pin 7, dat is dus DB0 van de LCD.

Alvast heel erg bedankt,
Simon

Ik doe niet zo veel met LCD's, maar hoe zit het met de timing? Ik kan me voorstellen dat bijv de E-pin een poosje hoog moet zijn voordat het display echt actief is. Zelfde met de R/W en de RS pin.

Er zijn trouwens plenty codes voor HD44780 LCD's op het net te vinden. Je hoeft het wiel niet opnieuw uit te vinden.mag wel natuurlijk

zo'n display moet toch worden geinitialiseert.

in de datasheet staat hoe dit moet gebeuren.

Jongens bedankt.

In de datasheet staat dat het initialiseren voor 8 bits automatisch gebeurt als er spanning op komt te staan, als ik het goed heb.

Ik zal eens kijken naar die codes op het net. Het probleem van die ASM codes is dat ik door de bomen het bos niet meer zie. Ik heb er al 1 geprobeerd maar die werkte ook niet.

Misschien eens gaan verdiepen in C.. Dat zal wat makkelijker zijn.

Bedankt ik kijk weer wat verder.

het is al lang geleden dat ik het nog heb gedaan, maar hier heb ik me op gebaseert

klik
kijk vooral op P26

mvg jan

Bedankt Jan, dit had ik inderdaad ook gevonden.

Ik gebruik nu zo'n voorgebakken code en ik heb in ieder geval iets werkend...

Het scherm zou tekst moeten geven maar doet nu:

################
################
################
################

ipv:
################

################

Vreemd....

is de RS pin correct aangesloten?

normaal als de initialisatie correct is verlopen is de display leeg denk ik.

ik neem aan det je met # een volledig gekleurt vakje bedoelt.

Ja dat bedoel ik.

De pinnen zijn wel goed aangesloten volgens mij. Dat heb ik ook al meermalen gecontroleerd.

De code die ik gebruik is de volgende:


; LCD subroutine test

; include files
.include	"m32def.inc"		; include file for ATmega8515 AVR

; equates
.equ LCDRS 	= 5					; LCD reg select pin, command/data
.equ LCDWR 	= 6					; LCD read/write pin
.equ LCDCLK	= 7					; lcd clock input pin (neg clk edge)

reset:	
	ldi		r16,high(RAMEND)	; stack setup
	out		SPH, r16			;
	ldi		r16,low(RAMEND)		;
	out 	SPL, r16			;
	ser		r16					;
	out		DDRC, r16			; setup PORTC for data out
	ldi 	r16, 0xF0			; PORTD pin 5,6,7 for data out, pin4 for +5V
	out 	DDRD, r16			;									to LCD
	rcall 	lcd_init			; initialize lcd display

;*********
; main:	this program simply uses lcd_cmd and lcd_prt to print "testuppr" and 
;		"testlowr" on a 2-line character LCD display.

main:
	ldi 	r16, 0x00|0x80		; place cursor in 1st row, 1st char
	rcall 	lcd_cmd				; 
	ldi 	r16, 't'	
	rcall 	lcd_prt	
	ldi 	r16, 'e'	
	rcall 	lcd_prt	
	ldi 	r16, 's'	
	rcall 	lcd_prt	
	ldi 	r16, 't'	
	rcall 	lcd_prt	
	ldi 	r16, 'u'	
	rcall 	lcd_prt	
	ldi 	r16, 'p'	
	rcall 	lcd_prt	
	ldi 	r16, 'p'	
	rcall 	lcd_prt	
	ldi 	r16, 'r'	
	rcall 	lcd_prt	
		
	ldi 	r16, 0x40|0x80		; place cursor in 2nd row, 1st char
	rcall 	lcd_cmd				; 
	ldi 	r16, 't'	
	rcall 	lcd_prt	
	ldi 	r16, 'e'	
	rcall 	lcd_prt	
	ldi 	r16, 's'	
	rcall 	lcd_prt	
	ldi 	r16, 't'	
	rcall 	lcd_prt	
	ldi 	r16, 'l'	
	rcall 	lcd_prt	
	ldi 	r16, 'o'	
	rcall 	lcd_prt	
	ldi 	r16, 'w'	
	rcall 	lcd_prt	
	ldi 	r16, 'r'	
	rcall 	lcd_prt	

end:
	rjmp	end


;*********************************************************************************
;                             	   lcd sub-routines

; OVERALL DESCRIPTION: This collection of routines writes commands and data
; to the Hitachi HD44780 LCD controller. Please refer to it's instruction set 
; for a description. 
; PORTD is the 8 DATA lines to the LCD and PORTC pins 0,3 are the control.
; For this controller it is possible to use 4-line DATA mode, saving 4 AVR pins.

;*********
lcd_init:					; lcd initialization routine 
	ldi 	r16, 0x38		; lcd function set reg:	8 bit data lines, 5x7 font
	rcall 	lcd_cmd			;						2 line display
	ldi 	r16, 0x0C		; lcd display on/off reg: on, show cursor, blink
	rcall 	lcd_cmd			;
	ldi 	r16, 0x01		; lcd reg: clear display, cursor home
	rcall	lcd_cmd			;
	ldi 	r16, 0x06		; lcd entry mode register: auto-increment cursor
	rcall	lcd_cmd			;
	ret	

;*********
; lcd_prt:	this subroutine prints to the LCD an ascii character in r16.
;			note that r16 data sent to this subroutine is lost during execution.
;			This can be fixed by using stack operations on r16 before and after 
;			calling lcd_cmd.

lcd_prt:					; lcd write data routine (data is in r16)
	sbi 	PORTD, LCDCLK	; set lcd enable pin (simulate pos clk edge)
	sbi 	PORTD, LCDRS	; set RS to enable lcd data register 
	out 	PORTC, r16		; put data on bus
	cbi 	PORTD, LCDCLK	; clear lcd enable (simulate neg clk edge)
	rjmp	lcd_wait		; go to check lcd busy flag routine
	ret

;*********
; lcd_cmd:	this subroutine sends instructions to the LCD from r16. These include
;			everything from character placement to custom characters.
;			Note r16 data sent to this subroutine is lost during execution.
;			This can be fixed by using stack operations on r16 before and after 
;			calling lcd_cmd.

lcd_cmd:					; write command to LCD routine (command is in r16)
	sbi 	PORTD, LCDCLK	; set lcd enable pin (simulate pos clk edge)
	cbi 	PORTD, LCDRS	; clear RS to enable lcd command register 
	out 	PORTC, r16		; put data on bus
	cbi 	PORTD, LCDCLK	; clear lcd enable (simulate neg clk edge)
	rjmp	lcd_wait		; go to check lcd busy flag routine
	ret	

;*********
; lcd_wait:	because the LCD has a much slower clock than the AVR, this subroutine
;			checks the LCD's busy-flag to make sure the last instruction was 
;			completed before continuing.
;			Stack operations are used within this subroutine therefore saving 
;			the need for use of a second register.

lcd_wait:					; wait for lcd busy flag routine
	cbi 	PORTD, LCDRS	; clear RS to enable lcd command register 
	sbi 	PORTD, LCDWR	; set RW for lcd read data enable
	sbi 	PORTD, LCDCLK	; set lcd enable pin
	clr 	r16				; 
	out 	DDRC, r16		; configure data port as input
	out 	PINC, r16		; clear data on input pins
	in  	r16, PINC		; get the address and busy flag
	cbi 	PORTD, LCDCLK	; clear lcd enable (simulate neg clk edge)
	push	r16
	ser 	r16				;
	out		DDRC, r16		; PORTC as output again
	cbi 	PORTD, LCDWR	; clear RW again
	pop		r16
	sbrc 	r16, 7			; if busy flag cleared, return  
	rjmp 	lcd_wait		; else repeat read/check
	ret						; return when busy flag cleared

Ziet er wel ok uit dacht ik. Met een 2 rij LCD gaat de ########## op de eerste rij weg, maar komt er geen tekst te staan?

Vreemd gedoe.. ik heb nu

################

################

Veranderd naar:
################
================
################
================

Dus nu zijn op regel 2 en 3 halve vakjes gekleurd.

Best frustrerend dat het niet normaal wil werken :[
Ik zal wel iets heel belangrijks over het hoofd zien.

Kheb het gevonden hoor!!!

Je raad het nooit.. Een pin van de header die ik gebruikte sluitte niet goed aan. Alle pinnen daaromheen wel..

Gelukkig niet voor niets lang opgebleven.

Morgen fijn weer mee verder en zelf een mooie code schrijven om dat ding aan te sturen.

Jongens bedankt voor het meedenken!

Wat mij verder nog opviel is dat je de data en adres lijnen (d0-d7 en DI en RW) instelt nadat je E hoog gooit.

Dat moet je niet doen :) Eerst data en adres instellen, dan pas E hoog gooien. E is namelijk de trigger waarop het LCD klokt. Ook de datapoort richting (in/out) instellen voor je E hoog gooit. Bij het lezen van het status bit zul je een aantal NOPs moeten tussenvoegen voor dat je de datapoort gaat lezen. Het duurt even voordat het LCD de data gaat uitsturen.

Volgens mij doe ik het gene met E wel goed, want de dalende flank van E zorgt voor de trigger.

Zie:
http://home.iae.nl/users/pouweha/lcd/images/lcd/8bit-interface.gif

Dat lezen van de status bit was ik nog niet aan toe gekomen. Ik stuurde nu om de halve seconde nieuwe data als test, dat werkte ook wel ok.

Ik neem je suggesties mee als ik mooiere code hiervoor ga schrijven. Bedankt!

De reden is om databus stress te vermijden :) Als je in het plaatje kijkt, zie je dat R/W wordt gewijzigd wanneer E laag is. R/W bepaalt of het LCD de databus als in of uitgang schakelt. Als je R/W nog zo hebt staan dat 'ie als uitgang geschakeld is (leesmode) en je de poort van je uc ook nog als uitgang hebt geschakeld, krijg je bij bitverschillen dikke stroompjes, busconflict. Met RS maakt het niet zoveel uit.

Komt er eigenlijk op neer dat de "best practice" is om het instellen van de lijnen te doen voordat je E actief maakt, of te wel wanneer E laag is.

Ok ik snap niet heel je verhaal, maar zal me eraan houden!

Het schrijven van een code is al goed gelukt. Ik heb meestal gedaan wat jij zegt, omdat het ook makkelijker te coden is.

Ik ben nu bezig om uit te zoeken hoe ik naar de volgende regel van het display kom met de cursor.

Kan het kloppen dat bij een 4-regel display lijn 1 en 3 samen 1 regel vormen? Volgens mij is dat wel zo want de tekst van regel 1 loopt door op regel 3.

Anyway, dit heb ik tot nu toe als code.. Voor de geïnteresseerde en misschien ziet iemand nog een fout. (niet dat iemand deze code gaat lezen maar toch ;))
Normale bestand:

.include "m32def.inc"
.device ATMEGA32

;--------------- Define LCD parameters ------------------------
.equ LCDPORT  = PORTD			; Change to port you're using
.equ LCDDDR   = DDRD			; Use PIN[4-7] as data pins
.equ LCDPIN   = PIND			; Connect these to pins DB[4-7] of LCD
.equ RSPIN    = 1				; RS pin on LCDPORT
.equ RWPIN    = 2				; RW pin on LCDPORT
.equ EPIN     = 3				; E pin on LCDPORT
.set N        = 1				; Number of lines;  N=1: 2 lines, N=0: 1 line

.def temp   = r16
.def argument = r17


.org 0
	rjmp   RESET

RESET:
	ldi	   r16, low(RAMEND)		; Define stack
	out	   SPL, r16
	ldi	   r16, high(RAMEND)
	out	   SPH, r16

	.include "lcdinc.asm"
	call   LCDINIT				; Initialize LCD

	nop
	nop
	nop

	ldi    r17, 0b01001000
	call   LCDPRTCHAR			; Print character
	ldi    r17, 0b01001000
	call   LCDPRTCHAR			; Print character
	ldi    r17, 'a'
	call   LCDPRTCHAR			; Print character
	ldi    r17, 'a'
	call   LCDPRTCHAR			; Print character
	ldi    r17, 'a'
	call   LCDPRTCHAR			; Print character
	ldi    r17, 'B'
	call   LCDPRTCHAR			; Print character
	ldi    r17, 'c'
	call   LCDPRTCHAR			; Print character
	ldi    r17, 'D'
	call   LCDPRTCHAR			; Print character
	ldi    r17, 'e'
	call   LCDPRTCHAR			; Print character
	ldi    r17, 'F'
	call   LCDPRTCHAR			; Print character
	ldi    r17, 'G'
	call   LCDPRTCHAR			; Print character
	ldi    r17, 'h'
	call   LCDPRTCHAR			; Print character
	ldi    r17, 'i'
	call   LCDPRTCHAR			; Print character
	ldi    r17, 'J'
	call   LCDPRTCHAR			; Print character
	ldi    r17, 'K'
	call   LCDPRTCHAR			; Print character

STOP:
	rjmp   STOP

De include die al het werk doet.
lcdinc.asm

LCDLOAD:	; - Do not execute file when it is only included
	rjmp   LCDEND

LCDINIT:	; - Initialize the LCD to use 4 bit mode
	ser    r16
	out    LCDDDR, r16			; AVRPort as output
	cbi    LCDPORT, RWPIN		; RW set to write
	sbi    LCDPORT, RSPIN       ; RS to RAM mode
	rcall  LCDDELAY				; Wait untill LCD is turned on
	rcall  LCDWAIT				; Wait for LCD to be ready
	ldi    r17, 0b00100000		; Function set: 4 bit mode
	rcall  LCDCMD8				; Command LCD in 8 bit mode
	ldi    r17, 0b00101000		; Set 4 bit, lines, chartype
	rcall  LCDCMD				; Send command
	ldi    r17, 0x0F			; Display on
	rcall  LCDCMD
	ldi    r17, 0b0000110		; Entry mode set
	rcall  LCDCMD
	ldi    r17, 0b0000001		; Clear display
	rcall  LCDCMD
	rcall  LCDDELAY
	ret

LCDCLEAR:	; - Clears display and sets DDRAM adress to 0
	ldi    r17, 0b00000001
	rcall  LCDCMD				; Clear display command
	ret

LCDCMD:		; - 4 bit mode command 
	push   r17					; Backup command data to stack
	cbr    r17, 0b00001111		; Only high nibble is left
	out    LCDPORT, r17			; Set data on LCD
	cbi    LCDPORT, RSPIN		; RS to command mode
	sbi    LCDPORT, EPIN		; Rising flank on Enable pin
	nop							; Give E some time to get high
	nop
	nop
	cbi    LCDPORT, EPIN		; Falling flank on Enable pin   	
	pop    r17					; Get command data from stack
	swap   r17					; Swap nibbles
	cbr    r17, 0b00001111		; Only low nibble is left
	out    LCDPORT, r17			; Set data on LCD
	cbi    LCDPORT, RSPIN		; RS to command mode
	sbi    LCDPORT, EPIN		; Rising flank on Enable pin
	nop							; Give E some time to get high
	nop
	nop
	cbi    LCDPORT, EPIN		; Falling flank on Enable pin   
	rcall  LCDWAIT
	ret

LCDPRTCHAR:	; - Print a character at current position
	push   r17					; Backup command data to stack
	cbr    r17, 0b00001111		; Only high nibble is left
	out    LCDPORT, r17			; Set data on LCD
	sbi    LCDPORT, RSPIN		; RS to RAM mode
	sbi    LCDPORT, EPIN		; Rising flank on Enable pin
	nop							; Give E some time to get high
	nop
	nop
	cbi    LCDPORT, EPIN		; Falling flank on Enable pin   	
	pop    r17					; Get command data from stack
	swap   r17					; Swap nibbles
	cbr    r17, 0b00001111		; Only low nibble is left
	out    LCDPORT, r17			; Set data on LCD
	sbi    LCDPORT, RSPIN		; RS to RAM mode
	sbi    LCDPORT, EPIN		; Rising flank on Enable pin
	nop							; Give E some time to get high
	nop
	nop
	cbi    LCDPORT, EPIN		; Falling flank on Enable pin   
	rcall  LCDWAIT
	rcall   LEDON
	ret

LCDCMD8:	; - 8 bit mode command, used to initialize 4 bit mode
	out    LCDPORT, r17			; Put data to LCD
	cbi    LCDPORT, RSPIN		; RS to command mode
	sbi    LCDPORT, EPIN		; Rising flank on Enable pin
	nop							; Give E some time to get high
	nop
	nop
	cbi    LCDPORT, EPIN		; Falling flank on Enable pin
	rcall  LCDWAIT				; Wait for LCD to be ready
	ret	

LCDWAIT:	; - Wait for the LCD busyflag to be cleared
	cbi    LCDPORT, RSPIN		; RS to command mode
	sbi    LCDPORT, RWPIN		; RW set to read
	sbi    LCDPORT, EPIN		; Rising flank on Enable pin
	ldi    r16, 0b00001111
	out    LCDDDR, r16			; AVRPort 4-7 as input
	nop							; Wait for DDR change
	in     r16, LCDPIN			; Read data from LCD
	cbi    LCDPORT, EPIN		; Falling flank on Enable pin
	nop
	nop
	nop
	sbrc   r16, 7				; Skip if busyflag cleared
	rjmp   LCDWAIT				; LCD still busy, wait again
	ser    r16
	out    LCDDDR, r16			; AVRPort as output
	cbi    LCDPORT, RWPIN		; RW set to write
	sbi    LCDPORT, RSPIN		; RS to RAM mode
	ret

LCDDELAY:
	clr	r2
	LCD_delay_outer:
	clr	r3
		LCD_delay_inner:
		dec	r3
		brne	LCD_delay_inner
	dec	r2
	brne	LCD_delay_outer
	ret

LEDON:
	ser   r16
	out   DDRA,r16
	out   PORTA,r16
	ret

LCDEND:

Op 4 juli 2007 22:02:26 schreef Babylon:

Kan het kloppen dat bij een 4-regel display lijn 1 en 3 samen 1 regel vormen? Volgens mij is dat wel zo want de tekst van regel 1 loopt door op regel 3.

Dat klopt ja, in de datasheet kun je de "ram adres map" bekijken.

Wat je zou kunnen toevoegen is een routine die aan de hand van een X en Y coordinaat het juiste adres bepaalt.

Dan nog een routine die de huidige X en Y aanpast om een letter op te schuiven. X verhogen, als die 16 is, dan weer op 0 zetten en Y verhogen.

Deze twee routines kun je ook combineren zodat je text op een logische manier op het LCD kan krijgen :)

Verder ziet de source er prima uit wat ik er zo van kan zien. Je maakt ook geen gebruik van het uitlezen van het busy bit. Dit kun je altijd later nog toevoegen als je wil dat je code onafhankelijk van de uC kloksnelheid blijft werken. Had de LCDWAIT over het hoofd gezien ;)

En dat is wat ik bedoelde:

	sbi    LCDPORT, EPIN		; Rising flank on Enable pin
	ldi    r16, 0b00001111
	out    LCDDDR, r16			; AVRPort 4-7 as input 
	nop							; Wait for DDR change

Hier zet je de poort richting pas om nadat je E al hoog hebt gezet. Zou moeten zijn:

	ldi    r16, 0b00001111
	out    LCDDDR, r16			; AVRPort 4-7 as input 
	nop							; Wait for DDR change
        sbi    LCDPORT, EPIN		; Rising flank on Enable pin

[Bericht gewijzigd door MagicBox op (19%)]

Hardstikke bedankt MagicBox voor de tips!

Ik ga verder proggen en inderdaad een logische manier verzinnen om de tekst op het LCD te zetten. Ik dacht aan iets van LCDPRT_ROW1

Als het af is, post ik het weer hier.

Trouwens, Ik ken al bijna de hele HD44780 datasheet uit m'n hoofd ;)

[Bericht gewijzigd door Babylon op (13%)]

MagicBox, wat jij zei heb ik er niet ingedaan want dat kreeg ik niet helemaal goed werken. Echter, is dat echt zo belangrijk? Want mijn code werkt nu perfect en is mooi aan te sturen met commando's.

Edit: Werkt toch niet perfect! Bij frequenties van 4Mhz of hoger gaan dingen raar doen. Ik vermoed dat dit de LCDWAIT functie is die de busy flag niet helemaal correct uitleest??? Als iemand ziet wat fout is, zou ik daar erg dankbaar om zijn.

Als iemand nog opmerkingen heeft, hoor ik het graag.

Voor het geval iemand geinteresseerd is in de code; Download het inclusief readme.txt via mijn site, of de code hieronder:

Normale bestand:


.include "m32def.inc"

.org 0
	rjmp   RESET

RESET:
	ldi	   r16, low(RAMEND)		; Define stack
	out	   SPL, r16
	ldi	   r16, high(RAMEND)
	out	   SPH, r16

	.include "lcdinc.asm"		; Include HD44780 command file
	call   LCDINIT				; Initialize LCD

	call   LCDTOROW2
	ldi    r17, 'F'	call   LCDPRTCHAR
	ldi    r17, 'A'	call   LCDPRTCHAR
	ldi    r17, 'N'	call   LCDPRTCHAR
	ldi    r17, ' '	call   LCDPRTCHAR
	ldi    r17, 'S'	call   LCDPRTCHAR
	ldi    r17, 'p'	call   LCDPRTCHAR
	ldi    r17, 'e'	call   LCDPRTCHAR
	ldi    r17, 'e'	call   LCDPRTCHAR
	ldi    r17, 'd'	call   LCDPRTCHAR
	ldi    r17, ':'	call   LCDPRTCHAR
	ldi    r17, ' '	call   LCDPRTCHAR
	ldi    r17, '1'	call   LCDPRTCHAR
	ldi    r17, '2'	call   LCDPRTCHAR
	ldi    r17, '3'	call   LCDPRTCHAR
	ldi    r17, '2'	call   LCDPRTCHAR

	call   LCDTOROW3
	ldi    r17, 'I'	call   LCDPRTCHAR
	ldi    r17, 'n'	call   LCDPRTCHAR
	ldi    r17, 't'	call   LCDPRTCHAR
	ldi    r17, 'e'	call   LCDPRTCHAR
	ldi    r17, 'r'	call   LCDPRTCHAR
	ldi    r17, 'n'	call   LCDPRTCHAR
	ldi    r17, 'e'	call   LCDPRTCHAR
	ldi    r17, 't'	call   LCDPRTCHAR
	ldi    r17, ':'	call   LCDPRTCHAR
	ldi    r17, ' '	call   LCDPRTCHAR
	ldi    r17, ' '	call   LCDPRTCHAR
	ldi    r17, 'O'	call   LCDPRTCHAR
	ldi    r17, 'K'	call   LCDPRTCHAR
	ldi    r17, ' '	call   LCDPRTCHAR
	ldi    r17, ' '	call   LCDPRTCHAR
	ldi    r17, ' '	call   LCDPRTCHAR

	call   LCDTOROW1
	ldi    r17, 'C'	call   LCDPRTCHAR
	ldi    r17, 'P'	call   LCDPRTCHAR
	ldi    r17, 'U'	call   LCDPRTCHAR
	ldi    r17, '1'	call   LCDPRTCHAR
	ldi    r17, ' '	call   LCDPRTCHAR
	ldi    r17, 'T'	call   LCDPRTCHAR
	ldi    r17, 'e'	call   LCDPRTCHAR
	ldi    r17, 'm'	call   LCDPRTCHAR
	ldi    r17, 'p'	call   LCDPRTCHAR
	ldi    r17, ':'	call   LCDPRTCHAR
	ldi    r17, ' '	call   LCDPRTCHAR
	ldi    r17, '3'	call   LCDPRTCHAR
	ldi    r17, '5'	call   LCDPRTCHAR
	ldi    r17, 0b11011111	call   LCDPRTCHAR
	ldi    r17, 'C'	call   LCDPRTCHAR
	ldi    r17, ' '	call   LCDPRTCHAR
	
	call   LCDTOROW1
	call   LCDGOR11
	ldi    r17, '4'	call   LCDPRTCHAR
	ldi    r17, '3'	call   LCDPRTCHAR
	
	call   LCDGOL10
	ldi    r17, '2'	call   LCDPRTCHAR

	call   LCDTOROW4
	ldi    r17, '@'	call   LCDPRTCHAR
	call   LCDTOROW4
	call   LCDCLEARROW

STOP:
	rjmp   STOP

lcdinc.asm


;=============== LCD HD44780 driver ===========================
;By Simon van Veen
;Last update: 05 jul 2007
;I advise you to read the readme file for instructions


;--------------- Define LCD parameters ------------------------
.equ LCDPORT  	= PORTD			; Change to port you're using
.equ LCDDDR   	= DDRD			; Use PIN[4-7] as data pins
.equ LCDPIN   	= PIND			; Connect these to pins DB[4-7] of LCD
.equ RSPIN    	= 1				; RS pin on LCDPORT
.equ RWPIN    	= 2				; RW pin on LCDPORT
.equ EPIN     	= 3				; E pin on LCDPORT

.set lcdn       = 1				; Number of lines;  n=1: 2 lines, n=0: 1 line
.set lcdch	    = 16			; Number of characters per row
.set lcdc		= 0				; Cursor on/off;  c=1: on, c=0: off
.set lcdb		= 0             ; Cursor blink on/off;  b=1: on; b=0: off
.set lcdavrspd  = 1				; AVR speed; mess around with this value
								;  untill the LCD starts nicely
								; The higher your AVR speed, the higher this value



;--- LCD controll, Nothing needs changing beyond this line ----


LCDLOAD:	; - Do not execute file when it is only included
	rjmp   LCDEND

LCDINIT:	; - Initialize the LCD to use 4 bit mode
	ser    r16
	out    LCDDDR, r16			; AVRPort as output
	cbi    LCDPORT, RWPIN		; RW set to write
	sbi    LCDPORT, RSPIN       ; RS to RAM mode
	rcall  LCDDELAY				; Wait >15ms untill LCD is turned on
	ldi    r17, 0b00110000		; Function set: 4 bit mode
	rcall  LCDCMD8				; Command LCD in 8 bit mode
	rcall  LCDDELAY				; Wait >4.1ms 
	ldi    r17, 0b00110000		; Function set: 4 bit mode
	rcall  LCDCMD8				; Command LCD in 8 bit mode
	rcall  LCDDELAY				; Wait > 100us
	ldi    r17, 0b00110000		; Function set: 4 bit mode
	rcall  LCDCMD8				; Command LCD in 8 bit mode
	rcall  LCDDELAY				; Wait > 100us
	ldi    r17, 0b00100000		; Function set: 4 bit mode
	rcall  LCDCMD8				; Command LCD in 8 bit mode
	rcall  LCDDELAY				; Wait > 100us

	ldi    r17, (1<<5|lcdn<<3)	; Set 4 bit, lines, chartype
	rcall  LCDCMD
	ldi    r17, (1<<5|lcdn<<3)	; Send again, LCD's really in 4bit mode
	rcall  LCDCMD
	ldi    r17, (1<<3|1<<2|lcdc<<1|lcdb<<0)
	rcall  LCDCMD				; Display on, set cursor / blink
	ldi    r17, 0b0000110		; Entry mode set, cursor direction
	rcall  LCDCMD
	rcall  LCDCLEAR
	rcall  LCDDELAY
	ret

LCDCLEAR:	; - Clears display and sets DDRAM adress to 0
	ldi    r17, 0b00000001
	rcall  LCDCMD				; Clear display command
	ret

LCDCMD:		; - 4 bit mode command 
	push   r17					; Backup command data to stack
	cbr    r17, 0b00001111		; Only high nibble is left
	out    LCDPORT, r17			; Set data on LCD
	cbi    LCDPORT, RSPIN		; RS to command mode
	sbi    LCDPORT, EPIN		; Rising flank on Enable pin
	nop							; Give E some time to get high
	nop
	nop
	cbi    LCDPORT, EPIN		; Falling flank on Enable pin   	
	pop    r17					; Get command data from stack
	swap   r17					; Swap nibbles
	cbr    r17, 0b00001111		; Only low nibble is left
	out    LCDPORT, r17			; Set data on LCD
	cbi    LCDPORT, RSPIN		; RS to command mode
	sbi    LCDPORT, EPIN		; Rising flank on Enable pin
	nop							; Give E some time to get high
	nop
	nop
	cbi    LCDPORT, EPIN		; Falling flank on Enable pin   
	rcall  LCDWAIT
	ret

LCDPRTCHAR:	; - Print a character at current position
	push   r17					; Backup command data to stack
	cbr    r17, 0b00001111		; Only high nibble is left
	out    LCDPORT, r17			; Set data on LCD
	sbi    LCDPORT, RSPIN		; RS to RAM mode
	sbi    LCDPORT, EPIN		; Rising flank on Enable pin
	nop							; Give E some time to get high
	nop
	nop
	cbi    LCDPORT, EPIN		; Falling flank on Enable pin   	
	pop    r17					; Get command data from stack
	swap   r17					; Swap nibbles
	cbr    r17, 0b00001111		; Only low nibble is left
	out    LCDPORT, r17			; Set data on LCD
	sbi    LCDPORT, RSPIN		; RS to RAM mode
	sbi    LCDPORT, EPIN		; Rising flank on Enable pin
	nop							; Give E some time to get high
	nop
	nop
	cbi    LCDPORT, EPIN		; Falling flank on Enable pin   
	rcall  LCDWAIT
	ret

LCDTOROW1:	; - Move cursor to first row
	ldi    r17, 0b10000000		; Adress to go to
	call   LCDCMD				; Cursor to adress 
	ret
LCDTOROW2:	; - Move cursor to second row
	ldi    r17, 0b11000000		; Adress to go to
	call   LCDCMD				; Cursor to adress 
	ret
LCDTOROW3:	; - Move cursor to third row
	ldi    r17, 0b10000000		; Adress to go to
	ori    r17, lcdch			; Add n.o. chars to addres
								; Because row3 is part of line1
	call   LCDCMD				; Cursor to adress 
	ret
LCDTOROW4:	; - Move cursor to fourth row
	ldi    r17, 0b11000000		; Adress to go to
	ori    r17, lcdch			; Add n.o. chars to addres
								; Because row4 is part of line2
	call   LCDCMD				; Cursor to adress 
	ret

; Shift cursor right
LCDGOR20: rcall LCDGOR
LCDGOR19: rcall LCDGOR
LCDGOR18: rcall LCDGOR
LCDGOR17: rcall LCDGOR
LCDGOR16: rcall LCDGOR
LCDGOR15: rcall LCDGOR
LCDGOR14: rcall LCDGOR
LCDGOR13: rcall LCDGOR
LCDGOR12: rcall LCDGOR
LCDGOR11: rcall LCDGOR
LCDGOR10: rcall LCDGOR
LCDGOR9:  rcall LCDGOR
LCDGOR8:  rcall LCDGOR
LCDGOR7:  rcall LCDGOR
LCDGOR6:  rcall LCDGOR
LCDGOR5:  rcall LCDGOR
LCDGOR4:  rcall LCDGOR
LCDGOR3:  rcall LCDGOR
LCDGOR2:  rcall LCDGOR
LCDGOR1:  rcall LCDGOR
	ret
LCDGOR:		; - Shift cursor right X times
	ldi    r17,0b00010100		; Shift cursor right
	rcall  LCDCMD				; Send command
	ret

; Shift cursor left
LCDGOL20: rcall LCDGOL
LCDGOL19: rcall LCDGOL
LCDGOL18: rcall LCDGOL
LCDGOL17: rcall LCDGOL
LCDGOL16: rcall LCDGOL
LCDGOL15: rcall LCDGOL
LCDGOL14: rcall LCDGOL
LCDGOL13: rcall LCDGOL
LCDGOL12: rcall LCDGOL
LCDGOL11: rcall LCDGOL
LCDGOL10: rcall LCDGOL
LCDGOL9:  rcall LCDGOL
LCDGOL8:  rcall LCDGOL
LCDGOL7:  rcall LCDGOL
LCDGOL6:  rcall LCDGOL
LCDGOL5:  rcall LCDGOL
LCDGOL4:  rcall LCDGOL
LCDGOL3:  rcall LCDGOL
LCDGOL2:  rcall LCDGOL
LCDGOL1:  rcall LCDGOL
	ret
LCDGOL:		; - Move cursor to left X times
	ldi    r17,0b00010000		; Shift cursor left
	rcall  LCDCMD				; Send command
	ret


LCDTOCOL1:	; - Move cursor to column
	ldi    r17,1				; Column to move to
	rjmp   LCDTOCOL				; Go move
LCDTOCOL2:	; - Move cursor to column
	ldi    r17,2				; Column to move to
	rjmp   LCDTOCOL				; Go move
LCDTOCOL3:	; - Move cursor to column
	ldi    r17,3				; Column to move to
	rjmp   LCDTOCOL				; Go move
LCDTOCOL4:	; - Move cursor to column
	ldi    r17,4				; Column to move to
	rjmp   LCDTOCOL				; Go move
LCDTOCOL12:	; - Move cursor to column
	ldi    r17,12				; Column to move to
	rjmp   LCDTOCOL				; Go move
LCDTOCOL:	; - Move cursor to column
	rcall  LCDDDRAMADD
	ret

LCDDDRAMADD: ; - Get current DDRAM address | UNDER CONSTRUCTION
	;First we need to know the current column position
	cbi    LCDPORT, RSPIN		; RS to command mode
	sbi    LCDPORT, RWPIN		; RW set to read
	sbi    LCDPORT, EPIN		; Rising flank on Enable pin
	ldi    r16, 0b00001111		; r16 holds no data anymore, so can be used
	out    LCDDDR, r16			; AVRPort 4-7 as input
	nop							; Wait for DDR change
	in     r16, LCDPIN			; Read data from LCD
	cbi    LCDPORT, EPIN		; Falling flank on Enable pin
	nop
	nop
	nop
	sbrc   r16, 7				; Skip if busyflag cleared
	rjmp   LCDWAIT				; LCD still busy, wait again

	cbr    r16, 0b10000000		; Don't need busy flag anymore
	cp     r16, r17
	brne   LCDDDRAMADD

	ser    r16
	out    LCDDDR, r16			; AVRPort as output
	cbi    LCDPORT, RWPIN		; RW set to write
	sbi    LCDPORT, RSPIN		; RS to RAM mode


	ret

LCDCLEARROW:
	ldi    r16, lcdch
	LCDCLEARROWLOOP:
	ldi    r17, 0b00100000
	call   LCDPRTCHAR
	dec    r16
	tst    r16
	breq   LCDCLEARROWEND
	rjmp   LCDCLEARROWLOOP
	LCDCLEARROWEND:
	ret

LCDCMD8:	; - 8 bit mode command, used to initialize 4 bit mode
	out    LCDPORT, r17			; Put data to LCD
	cbi    LCDPORT, RSPIN		; RS to command mode
	sbi    LCDPORT, EPIN		; Rising flank on Enable pin
	nop							; Give E some time to get high
	nop
	nop
	cbi    LCDPORT, EPIN		; Falling flank on Enable pin
	ret	

LCDWAIT:	; - Wait for the LCD busyflag to be cleared
	cbi    LCDPORT, RSPIN		; RS to command mode
	sbi    LCDPORT, RWPIN		; RW set to read
	sbi    LCDPORT, EPIN		; Rising flank on Enable pin
	ldi    r17, 0b00001111		; r17 holds no data anymore, so can be used
	out    LCDDDR, r17			; AVRPort 4-7 as input
	nop							; Wait for DDR change
	in     r17, LCDPIN			; Read data from LCD
	cbi    LCDPORT, EPIN		; Falling flank on Enable pin
	nop
	nop
	nop
	sbrc   r17, 7				; Skip if busyflag cleared
	rjmp   LCDWAIT				; LCD still busy, wait again
	ser    r17
	out    LCDDDR, r17			; AVRPort as output
	cbi    LCDPORT, RWPIN		; RW set to write
	sbi    LCDPORT, RSPIN		; RS to RAM mode
	ret

LCDDELAY:	; - Wait when we can't read busyflag yet
	clr    r16					; r16 is 0
	LCDDELAYLOOP:
	ldi    r17, lcdavrspd		; r17 is lcdwait
	LCDDELAYLOOP2:		
	dec    r17					; r17 = r17 -1
	tst    r17
	brne   LCDDELAYLOOP2		; r17 is 0?
	dec    r16 					; r16 = r16 -1 
	tst    r16
	brne   LCDDELAYLOOP			; r16 is 0 again?
	ret

LCDEND:

Readme.txt


= HD44780 LCD include in ASM =
= By Simon van Veen          =

This zip contains a working beta version of a LCD driver using HD44780 in 4bit mode.
Newer versions will include more functions and more compatability with AVR's.
For now this one works fine.


All you need to do is:
 - Connect LCD datapins [4-7] to pins [4-7] on an AVR port
 - Connect LCD E, R/W, RS pins to 3 other pins on the same AVR port.
 - include lcdinc.asm in your project
 - Adjust definitions in lcdinc.asm
 - Call LCDfunctions from your main .asm file
 - An example of how to do this can be seen in LCDcontroller.asm.
   This example connected the LCD to portD of an ATmega32.

Functions you can use:
 - LCDINIT,     Initializes LCD. Set lcdc and lcdb to select cursor/blinking.
 - LCDTOROWX,   Sets cursor to first column of row X.    X = [1-4]
 - LCDPRTCHAR,  Prints character that is set in r17
 - LCDCLEARROW, Clears current row. Cursor has to be at column 1!
 - LCDGORX,     Shifts cursor X times to the right.      X = [1-20]
 - LCDGOLX,     Shifts cursor X times to the left.       X = [1-20]

Functions that will be in a future update:
 - LCDTOCOLX    Sets cursor to column X in current row.
 - LCDDDRAMADDR Sets DDRAM address in r17
 - LCDGETCHAR   Reads character at cursor position to r17
 - Functions to easially generate your own characters
 - LCD

IMPORTANT:
 This script uses r16 and 17. Make sure these registers only contain temporary data.

Info:
 I hope with this readme it is pretty self-explanatory. 
 If not, contact me via my website: 
 http://home.deds.nl/~cmon/   OR    www.cmon.nl.tt

 Thanks to avrbeginners.net because of their excellent LCD driver. [but mine's better ;) ]
 
Disclaimer:
 In order to use this file, read the disclaimer on my website.
 Non of the contents in the .zip file may be used for commercial ends.