原创 M8--LCD1602四线控制程序

2008-7-5 09:44 2800 5 6 分类: MCU/ 嵌入式
;*******************************************************************************
; File: m8_LCD_4bit.asm
; Title: ATmega8 driver for LCD in 4-bit mode (HD44780)
; Assembler: AVR assembler/AVR Studio
; Version: 1.0
; Created: April 5th, 2004
; Target: ATmega8
; Christoph Redecker, http://www.avrbeginners.net
;*******************************************************************************

; Some notes on the hardware:
;ATmega8 (clock frequency doesn't matter, tested with 1 MHz to 8 MHz)
; PortD.1 -> LCD RS (register select)
; PortD.2 -> LCD RW (read/write)
; PortD.3 -> LCd E (Enable)
; PortD.4 ... PortD.7 -> LCD data.4 ... data.7
; the other LCd data lines can be left open or tied to ground.

.include "c:\program files\atmel\avr studio\appnotes\m8def.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

.org 0
rjmp reset

reset:
ldi temp, low(RAMEND)
out SPL, temp
ldi temp, high(RAMEND)
out SPH, temp

;LCD after power-up: ("*" means black bar)
;|****************|
;| |

rcall LCD_init

;LCD now:
;|& | (&: cursor, blinking)
;| |

rcall LCD_wait
ldi argument, 'A' ;write 'A' to the LCD char data RAM
rcall LCD_putchar

;|A& |
;| |

rcall LCD_wait
ldi argument, 0x80 ;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

;|A | (cursor and A are at the same position!)
;| |

rcall LCD_wait
rcall LCD_getchar ;now read from address 0

;|A& | (cursor is also incremented after read operations!!!)
;| |

push return ;save the return value (the character we just read!)

rcall LCD_delay
pop argument ;restore the character
rcall LCD_putchar ;and print it again

;|AA& | (A has been read from position 0 and has then been written to the next pos.)
;| |

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_getchar:
in temp, DDRD ;make sure the data lines are inputs
andi temp, 0b00001111 ;so clear their DDR bits
out DDRD, temp
sbi PortD, LCD_RS ;we want to access the char data register, so RS high
sbi PortD, LCD_RW ;we also want to read from the LCD -> RW high
sbi PortD, LCD_E ;while E is high
nop
in temp, PinD ;we need to fetch the HIGH nibble
andi temp, 0b11110000 ;mask off the control line data
mov return, temp ;and copy the HIGH nibble to return
cbi PortD, LCD_E ;now take E low again
nop ;wait a bit before strobing E again
nop
sbi PortD, LCD_E ;same as above, now we're reading the low nibble
nop
in temp, PinD ;get the data
andi temp, 0b11110000 ;and again mask off the control line bits
swap temp ;temp HIGH nibble contains data LOW nibble! so swap
or return, temp ;and combine with previously read high nibble
cbi PortD, LCD_E ;take all control lines low again
cbi PortD, LCD_RS
cbi PortD, LCD_RW
ret ;the character read from the LCD is now in return

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:

ldi temp, 0b00001110 ;control lines are output, rest is input
out DDRD, temp

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
ldi argument, 0x28 ;NOW: 2 lines, 5*7 font, 4-BIT MODE!
rcall LCD_command ;

rcall LCD_wait
ldi argument, 0x0F ;now proceed as usual: Display on, cursor on, blinking
rcall LCD_command

rcall LCD_wait
ldi argument, 0x01 ;clear display, cursor -> home
rcall LCD_command

rcall LCD_wait
ldi argument, 0x06 ;auto-inc cursor
rcall LCD_command
ret

文章评论1条评论)

登录后参与讨论

用户377235 2016-6-13 18:59

这什么软件编的
相关推荐阅读
用户92689 2013-10-26 08:50
stm32-DAC应用一例
设定:1ms   0-16 输出: 16   3.000V  15  2.813V  14  2.625V 13  2.438V  12 2.250V 11  2.063V 1...
用户92689 2013-10-17 09:19
STM32 ---时序和延迟
#include<stm32f10x_rcc.h> #include<stm32f10x_gpio.h> #include "stm32f10x.h" #inclu...
用户92689 2013-10-12 13:45
STM8(用库)实例赏析---PWM
//占空比50% #include "stm8s.h" void main(void) {  //系统时钟切换配置(自动切换,外部高速晶振,关闭切换中断,  CLK_ClockSwi...
用户92689 2013-10-12 10:43
STM8(用库)实例赏析---TMI1
//0.5秒定时,LED闪烁 #include "stm8S.h" void main(void) {  //系统时钟切换配置(自动切换,外部高速时钟,关切换中断  //,切换新时钟...
用户92689 2013-10-12 10:16
STM8(用库)实例赏析---GPIO
 /*上电系统内部高速时钟默认为2MHz,    可选择不同的时钟分频值,观察LED亮灯速度。*/  #include "stm8s.h" //======= void delay(u...
用户92689 2013-10-05 21:13
STM8(用库)实例赏析---CLK
实例一:内部高速时钟切换 并可在CCO引脚上检测切换后的时钟信号。(红色部分)   #include "stm8s.h" //***************************...
我要评论
1
5
关闭 站长推荐上一条 /2 下一条