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 LOOPMaar 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
WilToyo
Maak me niet gek, ik ben al gek.
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
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:
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.