"); //-->
点阵字符液晶显示模块的驱动程序设计
众所周知液晶(LCD)显示器件以其低功耗的特点被广泛应用于各种领域,如智能仪表.办公自动化.通讯.军工等。
本文将以常用的1602系列显示模块详细介绍其驱动程序的设计及在设计中需要注意的一些问题。1602系列液晶显示模块常用的驱动芯片有HD44780(日立公司) 对应的兼容芯片有 KS0066(韩国三星) SED1278(Seiko Epson) NJU6408(New Japan Radio Co.Ltd)等。
下面以采用日本日立公司的HD44780驱动片为例简要介绍其内部功能,如果读者需要更详细的资料请查阅相关手册,而且贵报在2006年第29期也有相关介绍。
1:HD44780驱动片具有字符发生器ROM , 可显示192 种字符(160 个5 ×7 点阵字符及32 个5 ×11 点阵字符) 。
2:具有64 个单元的自定义字符RAM , 可自定义8 个5 ×7 点阵字符或4 个5 ×11 点阵字符。
3:具有80 个单元的显示RAM 。
4:标准的接口特性, 适配M6800 系列M PU 的操作时序。
下表为1602显示模块接口引脚功能表
引脚号 符号 功能
1 VSS 电源地
2 VDD + 5V 逻辑电源
3 VLCD 液晶驱动电源
4 RS 寄存器选择:“1”选传送数据数据;“0”选控制指令
5 R/ W 读/ 写操作选择:“1”为读;“0”为写
6 E 使能信号端口
7~10 DB0~DB3 数据总线低4位(采用4位数据传送时不用)
11~14 DB4~DB7 数据总线高4位
15 LED+ LCD背光+电源输入端
16 LED- LCD背光-电源输入端
了解了其接口功能后,现在就可以设计硬件原理图了,本文采用Microchip公司的PIC单片机进行驱动程序设计,限于笔者调试设备支持原因,故选用一款16F716进行实验,考虑到能兼容54等芯片故程序中基本没有用到716的其他硬件资源,如中断等,加之HI-TECH公司强大的C编译软件,使代码变得更加精简。由于HD44780系列驱动芯片的数据传送方式为并行传送,其缺点就是大大占用了单片机宝贵的IO口资源,考虑到这点,生产厂家也在该驱动片中扩展了另外一种驱动方式即4位数据传送方式,下图为8位数据连接图,4位数据连接只要把低4位数据连接线空出就可以,读者可以根据实际情况合理选择,但4位连接也需要占用单片机7个IO口,这跟串行数据传送方式的HT1621系列驱动片是不可比的,但相比之下这种并行数据传送方式作为软件编程就显得简单些。
有了驱动原理图,再画好PCB板图接下来的工作就是软件设计了,在进行程序设计之前让我们再去了解和熟悉一下有关HD44780驱动片的控制指令.
RS RW DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0
0 0 0 0 0 0 0 0 0 1
清屏 1.64MS(250KHZ)
RS RW DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0
0 0 0 0 0 0 0 0 1 *
AC清0 1.64MS(250KHZ)
RS RW DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0
0 0 0 0 0 0 0 1 I/D S
输入方式 40US(250KHZ)
I/D=1: 数据读写后AC(地址)自动增1
I/D=0: 数据读写后AC(地址)自动减1
S=1: 数据读写后画面平移
S=0: 数据读写后画面不动
RS RW DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0
0 0 0 0 0 0 1 D C B
显示开关控制 40US(250KHZ)
D=1: 打开显示 D=0: 关闭显示
C=1: 打开光标 C=0: 关闭光标
B=1: 打开闪烁 B=0: 关闭闪烁
RS RW DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0
0 0 0 0 0 1 S/C R/L * *
光标画面位移 40US(250KHZ)
S/C=1: 画面平移一个字符位
S/C=0: 光标平移一个字符位
R/L=1: 右移
R/L=0: 左移
RS RW DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0
0 0 0 0 1 DL N F * *
功能设置 40US(250KHZ)
DL=1: 8位数据接口 DL=0: 4位数据接口
N=1: 2行显示 N=0: 1行显示
F=1: 5*10点阵 F=0: 5*7点阵
说明:表格中*符号为二进制任意数字0/1
了解了以上功能指令后就可以开始写程序了,首先根据硬件原理图来定义下单片机IO口,这样做的好处有利于程序的移植和后续的维护,也使程序看上去清晰明了.
#define RS RA0 //RA0为数据(1)或指令(0)控制端
#define E RA1 //RA1为时钟端口,下降沿写入数据,上升沿读出数据
#define RW RA2 //RA2为读写控制端
#define LCD_DATA PORTB //RB为8位或者4位数据连接端口,4位时空出RB0~RB3
#define LCD_DATATRIS TRISB //方向口
#define INPUT 0XFF
#define OUTPUT 0
#define BF lcddata_temp&0x80 //HD44780 “忙”检测标志位
建立一个单片机初始化函数,此函数建议在主循环程序分时调用,这样做的好处是能有效避免在强干扰环境中误改方向口和其他特殊RAM的值从而造成单片机工作不正常甚至死机
void init_mcu (void)
{ CLRWDT();
TRISA=0;
TRISB=0;
ADCON1=7;
INTCON=0;
OPTION=0X80;
}
建立一个查询HD44780忙标志信号的函数,由于HD44780在数据写入需要有一定的延时,如果在前次操作还未完成前又有新的数据写入,这时的数据写入是无效的。
bit lcd_busy (void) //检测"忙"
{ unsigned char lcddata_temp;
CLRWDT();
LCD_DATATRIS=INPUT; //设为数据接收
RS=0; //命令类型
RW=1; //读
E=1;
lcddata_temp=LCD_DATA;
E=0;
if (BF) return (0); //忙标志
else
return (1); //不忙
}
此函数用于8位数据传送方式,带有一个返回标志位,查询其“真”“假”就可判断HD44780现在的工作状态,具体操作在下面“写数据函数”中作介绍。至于4位数据传送方式只要在增加一个周期的时钟信号就可以了,对应程序如下:
bit lcd_busy (void) //检测"忙"
{ unsigned char lcddata_temp;
CLRWDT();
LCD_DATATRIS=INPUT; //设为数据接收
RS=0; //命令类型
RW=1; //读
E=1;
NOP();
lcddata_temp=LCD_DATA;
E=0;
NOP();
E=1;
NOP();
E=0;
if (BF) return (0); //忙标志
else
return (1); //不忙
}
从程序中不难看出HD44780在进行4位数据传送中,在第一个时钟的上升沿读取的高4位数据即DB7~DB4的值。
然后再建立一个数据写操作函数,由于HD44780驱动在每输入一个命令或数据后必须要CPU接收一个HD44780的响应信号(这点我在前面已经提起),表明其现在的工作状态,这很像24**系列EEPROM。初始化命令最长时间为1.64MS(250KHZ)这个时间用CPU循环检测作为一般的程序我想应该没问题,但是考虑到HD44780由于意外损坏等原因造成其长时间不作 “忙” 标志应答,所以我个人认为还是别死等待,给定一个时间,比如3MS,在3MS内检测不到应答信号就自动跳出去执行其他的子程序,或者进行错误处理,从中也可以判别LCD模块的好坏,这样CPU的执行就显得不是那么被动,也不会影响其他程序的正常工作.
基于以上思路对应8位数据传送的控制程序如下:
void write_bytelcd (unsigned char lcddata,unsigned char r_s) //命令数据写函数
{ unsigned int i;
for (i=2000;i!=0;i--) //给定一个时间进行查询“忙”标志
{ if (lcd_busy()) //调用检测忙标志函数从中判断其工作状态
{ LCD_DATATRIS=OUTPUT; //设为数据发送
RS=r_s; //0=写指令, 1=写数据
RW=0; //写操作
E=1;
LCD_DATA=lcddata; //送入数据
NOP();
NOP();
E=0; //写入HD44780
break;
}
}
}
函数中带有两个字符型形式参数,用于载入主调函数的实参值,这样做的好处是使命令控制和数据传送都统一由此函数完成,从而使程序变得更加精简。对于4位数据写也就多加一个时钟周期,在这里就不再加以说明,请参考上面的。
有了以上的写数据函数现在我们想建立一个HD44780初始化程序就简单多了。
void lcd_init (void)
{ write_bytelcd(0X38,0); //8位接口2行显示 5*7
write_bytelcd(8,0); //关显示,光标不闪烁
write_bytelcd(1,0); //清屏
write_bytelcd(2,0); //AC清0
write_bytelcd(0xC,0); //开显示
write_bytelcd(0X14,0); //光标右移,文字不动
}
以上命令参数读者可以根据实际情况加以调整以满足您现有模块的显示标准。
下面就以笔者在实际实验中调试成功的范例加以组合,使其成为一个完整的显示驱动程序。如果读者还有不明白之处或者有更好的改进思路请EMAIL与我联系,谢谢。
先定义显示内容,建立一张显示表:
const unsigned char Disp_tab[]=
{" <LCD Display> \
date:2007.01.18 \
layout:feng zhe jun \
qq:62363**** ^_^ \
Tel:137******** \
E-mail:fengzhejunmcu@21cn.com"
};//113(0-112)
建立一个延时函数,使每显示完一行内容保留一段显示时间.
void delayms (unsigned char i)
{ unsigned int k;
while (i)
{ i--;
for (k=800;k!=0;k--) ;
}
}
再建立一个主函数
void main (void)
{ unsigned int i;
unsigned char fg_ddram,ddram_ress,count=16;
unsigned char count1;
unsigned char data_lcd;
PORTA=0;
PORTB=0;
fg_ddram=ddram_ress=count1=0;
ddram_ress=0x80;
init_mcu();
lcd_init();
for (i=10000;i!=0;i--) {init_mcu();}
lcd_init();
while (1)
{ write_bytelcd( ddram_ress,0); //DDRAM地址设置
do{
data_lcd=Disp_tab[count1];
count1++;
write_bytelcd(data_lcd,1); //写数据
if (count1>=113) count1=0;
delayms(30);
}
while (--count);
count=16;
++fg_ddram;
if (fg_ddram&0x1) ddram_ress=0xc0; //two
else
{ ddram_ress=0x80; //one
delayms(250);
lcd_init();
delayms(50);
}
}
}
以上程序只要再增加个头文件和设置一下配置位就是一个完整的显示驱动程序,笔者已经在MPLAB IDE 7.41+PICC8.05环境下调试通过,感兴趣的读者不妨一试。
*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。