Подключение LCD на базе HD44780
Схема
Внешний вид LCD WH1602C-YGH-CTK
Текст программы микроконтроллера
.include "m8515def.inc"
.equ LCD_RS = 1
.equ LCD_RW = 2
.equ LCD_E = 3
.def temp = r16
.def argument = r17 ;argument for calling subroutines
.def return = r18 ;return value from subroutines
;**************************************************************************************
.MACRO outi
ldi r16,@1
out @0,r16
.ENDMACRO
;**************************************************************************************
.MACRO send_lcd
ldi argument,@0
rcall LCD_putchar
rcall LCD_wait
.ENDMACRO
;**************************************************************************************
.MACRO command
ldi argument,@0 ;now let the cursor go to line 0, col 0 (address 0)
rcall LCD_command ;for setting a cursor address, bit 7 of the commands has to be set
rcall LCD_wait
.ENDMACRO
.org 0
rjmp RESET
;**************************************************************************************
RESET:
outi SPL,low(RAMEND)
outi SPH,high(RAMEND)
rcall LCD_init
command 0x80
send_lcd 't'
send_lcd 'i'
send_lcd 'm'
send_lcd 'e'
send_lcd ' '
send_lcd '0'
send_lcd '0'
command 0xC0
send_lcd 'd'
send_lcd 'a'
send_lcd 't'
send_lcd 'a'
send_lcd ' '
send_lcd '0'
send_lcd '0'
loop:
rjmp loop
;**************************************************************************************
lcd_command8: ;used for init (we need some 8-bit commands to switch to 4-bit mode!)
in temp,DDRD ;we need to set the high nibble of DDRD while leaving
;the other bits untouched. Using temp for that.
sbr temp,0b11110000 ;set high nibble in temp
out DDRD,temp ;write value to DDRD again
in temp,PortD ;then get the port value
cbr temp,0b11110000 ;and clear the data bits
cbr argument,0b00001111 ;then clear the low nibble of the argument
;so that no control line bits are overwritten
or temp,argument ;then set the data bits (from the argument) in the
;Port value
out PortD,temp ;and write the port value.
sbi PortD,LCD_E ;now strobe E
nop
nop
nop
cbi PortD,LCD_E
in temp,DDRD ;get DDRD to make the data lines input again
cbr temp,0b11110000 ;clear data line direction bits
out DDRD,temp ;and write to DDRD
ret
;**************************************************************************************
lcd_putchar:
push argument ;save the argmuent (it's destroyed in between)
in temp,DDRD ;get data direction bits
sbr temp,0b11110000 ;set the data lines to output
out DDRD,temp ;write value to DDRD
in temp,PortD ;then get the data from PortD
cbr temp,0b11111110 ;clear ALL LCD lines (data and control!)
cbr argument,0b00001111 ;we have to write the high nibble of our argument first
;so mask off the low nibble
or temp,argument ;now set the argument bits in the Port value
out PortD,temp ;and write the port value
sbi PortD,LCD_RS ;now take RS high for LCD char data register access
sbi PortD,LCD_E ;strobe Enable
nop
nop
nop
cbi PortD,LCD_E
pop argument ;restore the argument, we need the low nibble now...
cbr temp,0b11110000 ;clear the data bits of our port value
swap argument ;we want to write the LOW nibble of the argument to
;the LCD data lines, which are the HIGH port nibble!
cbr argument,0b00001111 ;clear unused bits in argument
or temp,argument ;and set the required argument bits in the port value
out PortD,temp ;write data to port
sbi PortD,LCD_RS ;again, set RS
sbi PortD,LCD_E ;strobe Enable
nop
nop
nop
cbi PortD,LCD_E
cbi PortD,LCD_RS
in temp,DDRD
cbr temp,0b11110000 ;data lines are input again
out DDRD,temp
ret
;**************************************************************************************
lcd_command: ;same as LCD_putchar, but with RS low!
push argument
in temp,DDRD
sbr temp,0b11110000
out DDRD,temp
in temp,PortD
cbr temp,0b11111110
cbr argument,0b00001111
or temp,argument
out PortD,temp
sbi PortD,LCD_E
nop
nop
nop
cbi PortD,LCD_E
pop argument
cbr temp,0b11110000
swap argument
cbr argument,0b00001111
or temp,argument
out PortD,temp
sbi PortD,LCD_E
nop
nop
nop
cbi PortD,LCD_E
in temp,DDRD
cbr temp,0b11110000
out DDRD,temp
ret
;**************************************************************************************
LCD_getaddr: ;works just like LCD_getchar, but with RS low, return.7 is the busy flag
in temp,DDRD
andi temp,0b00001111
out DDRD,temp
cbi PortD,LCD_RS
sbi PortD,LCD_RW
sbi PortD,LCD_E
nop
in temp,PinD
andi temp,0b11110000
mov return,temp
cbi PortD,LCD_E
nop
nop
sbi PortD,LCD_E
nop
in temp, PinD
andi temp,0b11110000
swap temp
or return,temp
cbi PortD,LCD_E
cbi PortD,LCD_RW
ret
;**************************************************************************************
LCD_wait: ;read address and busy flag until busy flag cleared
rcall LCD_getaddr
andi return, 0x80
brne LCD_wait
ret
;**************************************************************************************
LCD_delay:
clr r2
LCD_delay_outer:
clr r3
LCD_delay_inner:
dec r3
brne LCD_delay_inner
dec r2
brne LCD_delay_outer
ret
;**************************************************************************************
LCD_init:
outi DDRD,0b00001110 ;control lines are output, rest is input
rcall LCD_delay ;first, we'll tell the LCD that we want to use it
ldi argument,0x20 ;in 4-bit mode.
rcall LCD_command8 ;LCD is still in 8-BIT MODE while writing this command!!!
rcall LCD_wait
command 0x28 ;NOW: 2 lines, 5*7 font, 4-BIT MODE!
command 0x0C ;now proceed as usual: Display on, cursor off, blinking
command 0x01 ;clear display, cursor -> home
command 0x06 ;auto-inc cursor
ret
Скачать файлы проекта для AVR Studio 4 и модель для Proteus 7.5 (40,0 КБ)
Внешний вид LCD WH1602C-YGH-CTK
Текст программы микроконтроллера
.include "m8515def.inc"
.equ LCD_RS = 1
.equ LCD_RW = 2
.equ LCD_E = 3
.def temp = r16
.def argument = r17 ;argument for calling subroutines
.def return = r18 ;return value from subroutines
;**************************************************************************************
.MACRO outi
ldi r16,@1
out @0,r16
.ENDMACRO
;**************************************************************************************
.MACRO send_lcd
ldi argument,@0
rcall LCD_putchar
rcall LCD_wait
.ENDMACRO
;**************************************************************************************
.MACRO command
ldi argument,@0 ;now let the cursor go to line 0, col 0 (address 0)
rcall LCD_command ;for setting a cursor address, bit 7 of the commands has to be set
rcall LCD_wait
.ENDMACRO
.org 0
rjmp RESET
;**************************************************************************************
RESET:
outi SPL,low(RAMEND)
outi SPH,high(RAMEND)
rcall LCD_init
command 0x80
send_lcd 't'
send_lcd 'i'
send_lcd 'm'
send_lcd 'e'
send_lcd ' '
send_lcd '0'
send_lcd '0'
command 0xC0
send_lcd 'd'
send_lcd 'a'
send_lcd 't'
send_lcd 'a'
send_lcd ' '
send_lcd '0'
send_lcd '0'
loop:
rjmp loop
;**************************************************************************************
lcd_command8: ;used for init (we need some 8-bit commands to switch to 4-bit mode!)
in temp,DDRD ;we need to set the high nibble of DDRD while leaving
;the other bits untouched. Using temp for that.
sbr temp,0b11110000 ;set high nibble in temp
out DDRD,temp ;write value to DDRD again
in temp,PortD ;then get the port value
cbr temp,0b11110000 ;and clear the data bits
cbr argument,0b00001111 ;then clear the low nibble of the argument
;so that no control line bits are overwritten
or temp,argument ;then set the data bits (from the argument) in the
;Port value
out PortD,temp ;and write the port value.
sbi PortD,LCD_E ;now strobe E
nop
nop
nop
cbi PortD,LCD_E
in temp,DDRD ;get DDRD to make the data lines input again
cbr temp,0b11110000 ;clear data line direction bits
out DDRD,temp ;and write to DDRD
ret
;**************************************************************************************
lcd_putchar:
push argument ;save the argmuent (it's destroyed in between)
in temp,DDRD ;get data direction bits
sbr temp,0b11110000 ;set the data lines to output
out DDRD,temp ;write value to DDRD
in temp,PortD ;then get the data from PortD
cbr temp,0b11111110 ;clear ALL LCD lines (data and control!)
cbr argument,0b00001111 ;we have to write the high nibble of our argument first
;so mask off the low nibble
or temp,argument ;now set the argument bits in the Port value
out PortD,temp ;and write the port value
sbi PortD,LCD_RS ;now take RS high for LCD char data register access
sbi PortD,LCD_E ;strobe Enable
nop
nop
nop
cbi PortD,LCD_E
pop argument ;restore the argument, we need the low nibble now...
cbr temp,0b11110000 ;clear the data bits of our port value
swap argument ;we want to write the LOW nibble of the argument to
;the LCD data lines, which are the HIGH port nibble!
cbr argument,0b00001111 ;clear unused bits in argument
or temp,argument ;and set the required argument bits in the port value
out PortD,temp ;write data to port
sbi PortD,LCD_RS ;again, set RS
sbi PortD,LCD_E ;strobe Enable
nop
nop
nop
cbi PortD,LCD_E
cbi PortD,LCD_RS
in temp,DDRD
cbr temp,0b11110000 ;data lines are input again
out DDRD,temp
ret
;**************************************************************************************
lcd_command: ;same as LCD_putchar, but with RS low!
push argument
in temp,DDRD
sbr temp,0b11110000
out DDRD,temp
in temp,PortD
cbr temp,0b11111110
cbr argument,0b00001111
or temp,argument
out PortD,temp
sbi PortD,LCD_E
nop
nop
nop
cbi PortD,LCD_E
pop argument
cbr temp,0b11110000
swap argument
cbr argument,0b00001111
or temp,argument
out PortD,temp
sbi PortD,LCD_E
nop
nop
nop
cbi PortD,LCD_E
in temp,DDRD
cbr temp,0b11110000
out DDRD,temp
ret
;**************************************************************************************
LCD_getaddr: ;works just like LCD_getchar, but with RS low, return.7 is the busy flag
in temp,DDRD
andi temp,0b00001111
out DDRD,temp
cbi PortD,LCD_RS
sbi PortD,LCD_RW
sbi PortD,LCD_E
nop
in temp,PinD
andi temp,0b11110000
mov return,temp
cbi PortD,LCD_E
nop
nop
sbi PortD,LCD_E
nop
in temp, PinD
andi temp,0b11110000
swap temp
or return,temp
cbi PortD,LCD_E
cbi PortD,LCD_RW
ret
;**************************************************************************************
LCD_wait: ;read address and busy flag until busy flag cleared
rcall LCD_getaddr
andi return, 0x80
brne LCD_wait
ret
;**************************************************************************************
LCD_delay:
clr r2
LCD_delay_outer:
clr r3
LCD_delay_inner:
dec r3
brne LCD_delay_inner
dec r2
brne LCD_delay_outer
ret
;**************************************************************************************
LCD_init:
outi DDRD,0b00001110 ;control lines are output, rest is input
rcall LCD_delay ;first, we'll tell the LCD that we want to use it
ldi argument,0x20 ;in 4-bit mode.
rcall LCD_command8 ;LCD is still in 8-BIT MODE while writing this command!!!
rcall LCD_wait
command 0x28 ;NOW: 2 lines, 5*7 font, 4-BIT MODE!
command 0x0C ;now proceed as usual: Display on, cursor off, blinking
command 0x01 ;clear display, cursor -> home
command 0x06 ;auto-inc cursor
ret
Скачать файлы проекта для AVR Studio 4 и модель для Proteus 7.5 (40,0 КБ)