📄 lcd4x40.c
字号:
/*
LCD driver routines for 4x40 alphanumeric LCD
CodeVisionAVR C Compiler
(C) 1998-2004 Pavel Haiduc, HP InfoTech S.R.L.
*/
#asm
.equ __lcd_direction=__lcd_port-1
.equ __lcd_pin=__lcd_port-2
.equ __lcd_rs=0
.equ __lcd_rd=1
.equ __lcd_enable1=2
.equ __lcd_enable2=3
.equ __lcd_busy_flag=7
#endasm
#define LCD_MAXX 40
#define LCD_EN1 4
#define LCD_EN2 8
#pragma used+
#pragma regalloc-
unsigned char _en1_msk;
#pragma regalloc+
unsigned char _lcd_x,_lcd_y;
#pragma used-
static void _lcd_delay(void)
{
#asm
ldi r31,15
__lcd_delay0:
dec r31
brne __lcd_delay0
#endasm
}
void _lcd_ready(void)
{
#asm
ldi r26,0xf ;set as input
out __lcd_direction,r26
sbi __lcd_port,__lcd_rd ;RD=1
cbi __lcd_port,__lcd_rs ;RS=0
in r26,__lcd_port
lds r27,__en1_msk
__lcd_busy:
#endasm
_lcd_delay();
#asm
or r26,r27
out __lcd_port,r26 ;EN=1
#endasm
_lcd_delay();
#asm
in r30,__lcd_pin
andi r26,0xf3
out __lcd_port,r26 ;EN=0
#endasm
_lcd_delay();
#asm
or r26,r27
out __lcd_port,r26 ;EN=1
#endasm
_lcd_delay();
#asm
andi r26,0xf3
out __lcd_port,r26 ;EN=0
#endasm
_lcd_delay();
#asm
sbrc r30,__lcd_busy_flag
rjmp __lcd_busy
#endasm
}
static void _lcd_write_nibble(void)
{
#asm
andi r26,0xf0
or r26,r27
out __lcd_port,r26 ;write
or r26,r30
out __lcd_port,r26 ;EN=1
#endasm
_lcd_delay();
#asm
andi r26,0xf3
out __lcd_port,r26 ;EN=0
#endasm
_lcd_delay();
}
void _lcd_write_data(unsigned char data)
{
#asm
cbi __lcd_port,__lcd_rd ;RD=0
ldi r26,0xff ;set as output
out __lcd_direction,r26
lds r30,__en1_msk
in r27,__lcd_port
andi r27,0xf
ld r26,y
#endasm
_lcd_write_nibble(); //RD=0, write MSN
#asm
ld r26,y
swap r26
#endasm
_lcd_write_nibble(); //write LSN
#asm
sbi __lcd_port,__lcd_rd ;RD=1
#endasm
}
// write a byte to the LCD character generator or display RAM
void lcd_write_byte(unsigned char addr, unsigned char data)
{
_lcd_ready();
_lcd_write_data(addr);
_lcd_ready();
#asm
sbi __lcd_port,__lcd_rs ;RS=1
#endasm
_lcd_write_data(data);
}
static void _lcd_read_nibble(void)
{
#asm
in r27,__lcd_port
lds r30,__en1_msk
or r27,r30
out __lcd_port,r27 ;EN=1
#endasm
_lcd_delay();
#asm
in r30,__lcd_pin ;read
andi r27,0xf3
out __lcd_port,r27 ;EN=0
#endasm
_lcd_delay();
#asm
andi r30,0xf0
#endasm
}
static unsigned char lcd_read_byte0(void)
{
_lcd_delay();
_lcd_read_nibble(); //read MSN
#asm
mov r26,r30
#endasm
_lcd_read_nibble(); //read LSN
#asm
cbi __lcd_port,__lcd_rd ;RD=0
swap r30
or r30,r26
#endasm
}
// read a byte from the LCD character generator or display RAM
unsigned char lcd_read_byte(unsigned char addr)
{
_lcd_ready();
_lcd_write_data(addr);
_lcd_ready();
#asm
ldi r26,0xf ;set as input
out __lcd_direction,r26
sbi __lcd_port,__lcd_rs ;RS=1
#endasm
return lcd_read_byte0();
}
// set the LCD display position x=0..39 y=0..3
void lcd_gotoxy(unsigned char x, unsigned char y)
{
unsigned char base_y;
_en1_msk=LCD_EN1;
if (y>1) _en1_msk=LCD_EN2;
base_y=0x80+x;
if (y&1) base_y|=0x40;
_lcd_ready(); // RS=0
_lcd_write_data(base_y);
_lcd_x=x;
_lcd_y=y;
}
// clear the LCD
void lcd_clear1(void)
{
_lcd_ready(); // RS=0
_lcd_write_data(2); // cursor home
_lcd_ready();
_lcd_write_data(0xc); // cursor off
_lcd_ready();
_lcd_write_data(1); // clear
}
void lcd_clear(void)
{
_en1_msk=LCD_EN2;
lcd_clear1();
_en1_msk=LCD_EN1;
lcd_clear1();
_lcd_x=_lcd_y=0;
}
#pragma keep+
void lcd_putchar(char c)
{
#asm
push r30
push r31
ld r26,y
set
cpi r26,10
breq __lcd_putchar1
clt
#endasm
++_lcd_x;
if (_lcd_x>LCD_MAXX)
{
#asm("__lcd_putchar1:")
++_lcd_y;
lcd_gotoxy(0,_lcd_y);
#asm("brts __lcd_putchar0")
};
#asm
rcall __lcd_ready
sbi __lcd_port,__lcd_rs ;RS=1
ld r26,y
st -y,r26
rcall __lcd_write_data
__lcd_putchar0:
pop r31
pop r30
#endasm
}
#pragma keep-
// write the string str located in SRAM to the LCD
void lcd_puts(char *str)
{
char k;
while (k=*str++) lcd_putchar(k);
}
// write the string str located in FLASH to the LCD
void lcd_putsf(char flash *str)
{
char k;
while (k=*str++) lcd_putchar(k);
}
void _long_delay(void)
{
#asm
clr r26
clr r27
__long_delay0:
sbiw r26,1 ;2 cycles
brne __long_delay0 ;2 cycles
#endasm
}
static void _lcd_init_write(unsigned char data)
{
#asm
cbi __lcd_port,__lcd_rd ;RD=0
ldi r26,0xff ;set as output
out __lcd_direction,r26
lds r30,__en1_msk
in r27,__lcd_port
andi r27,0xf
ld r26,y
#endasm
_lcd_write_nibble(); //RD=0, write MSN
#asm
sbi __lcd_port,__lcd_rd ;RD=1
#endasm
}
static unsigned char lcd_init1(void)
{
_long_delay();
_lcd_init_write(0x30);
_long_delay();
_lcd_init_write(0x30);
_long_delay();
_lcd_init_write(0x30);
_long_delay();
_lcd_init_write(0x20);
_long_delay();
_lcd_write_data(0x28);
_long_delay();
_lcd_write_data(4);
_long_delay();
_lcd_write_data(0x85);
_long_delay();
#asm
in r26,__lcd_direction
andi r26,0xf ;set as input
out __lcd_direction,r26
sbi __lcd_port,__lcd_rd ;RD=1
#endasm
if (lcd_read_byte0()!=5) return 0;
_lcd_ready();
_lcd_write_data(6);
return 1;
}
// initialize the LCD controller
unsigned char lcd_init(void)
{
#asm
cbi __lcd_port,__lcd_enable1 ;EN1=0
cbi __lcd_port,__lcd_enable2 ;EN2=0
cbi __lcd_port,__lcd_rs ;RS=0
#endasm
_en1_msk=LCD_EN1;
if (!lcd_init1()) return 0;
_en1_msk=LCD_EN2;
if (!lcd_init1()) return 0;
lcd_clear();
return 1;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -