最近闲来无事,想做个万年历,它的主要元件是DS1302和LCD1602显示,到目前为止,LCD1602显示已经完成,DS1302还在编写,现在就把编写的思路描述一下。
本文采用的是8位数据口,首先是对端口和功能设置的初始化,这里主要是参考数据手册,完成功能设置。
//--------数据端口-------------
#define LCD_DATA_DDR DDRA
#define LCD_DO PORTA
#define LCD_DI PINA
//--------控制端口-------------
#define LCD_CTRL_DDR DDRB
#define LCD_CTRL PORTB
#define LCD_RS PB0
#define LCD_RW PB1
#define LCD_EN PB2
#define LCD_SET_RS LCD_CTRL|=1<<LCD_RS
#define LCD_SET_RW LCD_CTRL|=1<<LCD_RW
#define LCD_SET_EN LCD_CTRL|=1<<LCD_EN
#define LCD_CLR_RS LCD_CTRL&=~(1<<LCD_RS)
#define LCD_CLR_RW LCD_CTRL&=~(1<<LCD_RW)
#define LCD_CLR_EN LCD_CTRL&=~(1<<LCD_EN)
//--------------------初始化设置----------------------
#define iDat 1
#define iCmd 0
//L L H DL N F DL:1--8,0--4;N:1--2行,0--1行;F:1--5*10,0--5*7
#define LCD_FUNCTION 0x38
#define LCD_CLS 0x01 //清屏
#define LCD_HOME 0x02 //地址返回原点,不改变DDRAM内容
//L L L L L H I/D S I/D:1--增量方式,0--减量方式;S:1--屏幕移动,0--屏幕不移动
#define LCD_ENTRY 0x06
//L L L H S/C R/L L L
#define LCD_C2L 0x10 //光标左移
#define LCD_C2R 0x14 //光标右移
#define LCD_S2L 0x18 //屏幕左移
#define LCD_S2R 0x1C //屏幕右移
//L L L L 1 D C B D:1--开显示,0--关显示;C:1--显示光标,0--不显光标;B:1--光标闪烁,0--光标不闪
#define LCD_ON 0x0C
#define LCD_OFF 0x08
#define LCD_CURON 0x0E
#define LCD_CURFLA 0x0F
#define LCD_L1 0x80 //第一行的地址:0x80+addr ,addr为列数
#define LCD_L2 0xC0 //第二行的地址:0x80+0x40+addr
功能函数主要包括读写,检测状态,LCD初始化等。相应的延迟函数也是必须的,这里就不详说。在读操作完成后必须将端口设置为输出,判断LCD是否忙这个也是必须的。
/*******************************************
函数名称: readbyte
功 能: 从1602液晶读出一个字节数据或者指令
参 数: DatCmd--为iDat时是数据,为iCmd时是指令
返回值 : dbyte--读回的数据或者指令
********************************************/
uchar readbyte(uchar DatCmd)
{
uchar dbyte;
if(DatCmd==iDat)
LCD_SET_RS;
else
LCD_CLR_RS;
LCD_SET_RW;
LCD_SET_EN;
LCD_DATA_DDR=0x00; //设置端口为输入
dbyte="LCD"_DI;
Delayms(1);
LCD_CLR_EN;
LCD_DATA_DDR|=0xFF; //数据总线还原为输出,这个是必须的
return dbyte;
}
/*******************************************
函数名称: writebyte
功 能: 向1602液晶写入一个字节数据或者指令
参 数: DatCmd--为iDat时是数据,为iCmd时是指令
dbyte--为写入1602的数据或者指令
返回值 : 无
********************************************/
void writebyte(uchar DatCmd,uchar dbyte)
{
if(DatCmd==iDat)
LCD_SET_RS;
else
LCD_CLR_RS;
LCD_CLR_RW;
LCD_SET_EN;
LCD_DO=dbyte;
Delayms(1);
LCD_CLR_EN;
}
/*******************************************
函数名称: writestr
功 能: 向1602液晶写入一个字符串
参 数: pstr--字符串指针
返回值 : 无
********************************************/
void writestr(uchar *pstr)
{
while((*pstr)!='\0')
writebyte(iDat,*pstr++);
}
/*******************************************
函数名称: readbusy
功 能: 检测1602液晶是否忙
参 数: 无
返回值 : busy--为1时是忙状态,为0时可以接收指令
********************************************/
uchar readbusy(void)
{
uchar busy;
busy="readbyte"(iCmd);
if(busy&0x80)
busy="1";
else
busy="0";
return busy;
}
/*******************************************
函数名称: lcd_clear
功 能: 1602液晶清屏
参 数: 无
返回值 : 无
********************************************/
void lcd_clear(void)
{
writebyte(iCmd,LCD_CLS);//写入清屏指令
Delayms(2);// 清屏指令写入后,2ms 的延时是很必要的!!!
}
/*******************************************
函数名称: lcd_gotoXY
功 能: 移动到指定位置
参 数: Row--指定的行
Col--指定的列
返回值 : 无
********************************************/
void lcd_gotoXY(uchar Row, uchar Col)
{
switch (Row) //选择行
{
case 2:
writebyte(iCmd, LCD_L2 + Col); break; //写入第2行的指定列
default:
writebyte(iCmd, LCD_L1 + Col); break; //写入第1行的指定列
}
}
/*******************************************
函数名称: lcd_init
功 能: 1602液晶初始化
参 数: 无
返回值 : 无
********************************************/
void lcd_init(void)
{
Delayms(100);
LCD_CTRL_DDR|=(1<<LCD_RS)|(1<<LCD_RW)|(1<<LCD_EN);
LCD_DATA_DDR=0xFF;
writebyte(iCmd,LCD_FUNCTION);
while(readbusy());
writebyte(iCmd,LCD_ON);
while(readbusy());
lcd_clear();
while(readbusy());
writebyte(iCmd,LCD_ENTRY);
}
将清屏功能拿出来设置是为了方便控制LCD。虽然程序只完成简单的功能,但是我觉得比较好理解。故在使用到LCD1602液晶时可以当作模板。
用户1518700 2009-1-23 10:26