这里先发表字符lcd的通用驱动程序。因为自己感觉这个书写格式非常好,比较模块化。
倡议以后发表的源程序能够这样书写以便照顾仿制的朋友学习。
/********************************************************
本程序只供学习使用,未经作者许可,不得用于其它任何用途
我的邮箱:bg8wj@vip.km169.net
编程、电路设计参考:mcs-51/151/251单片机原理与应用
出版社:中国水利水电出版社。
=============================================================================
16x1 16x2 20x2 20x4字符型液晶屏通用驱动程序8位i/o方式
=============================================================================
连接线图: lcm-----20x4 8位i/o界面控制接线
db0-----p1.0 db4-----p1.4 rs-------p3.3
db1-----p1.1 db5-----p1.5 rw-------p3.4
db2-----p1.2 db6-----p1.6 e--------p3.5
db3-----p1.3 db7-----p1.7
[注]:at89c51的晶振频率为11.0592mhz
如果使用更高频率的晶振可以修改的lcd_delay_time以实现命令的可靠写入。
==============================================================================
/*****************************************************************************/
#include <at89x52.h>
/********************************************************************/
#define lcdio p1
#define line1 1
#define line2 2
#define line3 3
#define line4 4
#define high 1
#define low 0
#define clearscreen lcd_en_command(0x01)
#define lcd_delay_time 40 //控制延时以确保lcd准确写入
/*******************************************************************
定义lcd控制脚p3口
对应脚r/s r/w enable
可以修改定义以对应不同的控制引脚。
********************************************************************/
sbit rs=p3^3; //数据、命令选择 1:数据 0:指令 p3.3脚
sbit rw=p3^4; //读、写操作选择 1:读 0:写 p3.5脚
sbit e=p3^5; //使能信号 p3.5脚
/********************************************************************
/********************************************************************
调用函数申明
********************************************************************/
void lcd_delay(void);
void lcd_en_command(unsigned char command);
void lcd_en_dat(unsigned char temp);
void lcd_set_xy( unsigned char x, unsigned char y );
void lcd_write_char( unsigned x,unsigned char y,unsigned char dat);
void lcd_write_string(unsigned char x,unsigned char y,unsigned char *s);
void lcd_init(void);
void delay_nms(unsigned int n);
void lcd_busy(void);
void delay( unsigned int ms );
void putstr(unsigned char x,unsigned char y,unsigned char *puts);
void set_cgram( unsigned char *puts );
/********************************************************************
lcd函数延时子函数
反正要使用到延时函数不如省去check_lcd_ busy的动作节约空间。
*******************************************************************/
void lcd_delay(void)//
{
unsigned char i;
for(i=lcd_delay_time;i>0;i--); //保证lcd复位的最小延时
}
void delay( unsigned int ms )
{
unsigned char us,usn;
while(ms!=0) //12m crystal
{
usn = 2;
while(usn!=0)
{
us=0xf2;
while (us!=0){us--;};
usn--;
}
ms--;
}
}
//********************************************************************
设置显示地址函数
注意在本函数中未针对列地址作限制可以方便修改驱动其他模块。
********************************************************************/
void lcd_set_xy( unsigned char x, unsigned char y )
{
unsigned char address;
//对于20x4的模块使用20,对于16x2的可以修改成16即可。
if (y == 1&& x<=20)
address = 0x80 + x;
if (y == 2)
address = 0xc0 + x;
if (y == 3)
address = 0x94 + x;
if (y == 4)
address= 0xd4 + x;
if (y == 行)
address= 列地址 + x;
lcd_en_command(address);
}
/********************************************************************
写字符函数
********************************************************************/
void lcd_write_char( unsigned x,unsigned char y,unsigned char dat)//
{
lcd_set_xy( x, y );
lcd_en_dat(dat);
}
/********************************************************************
写字符串函数(使用89c51节约空间可以用来代替putstr()函数)
********************************************************************/
void lcd_write_string(unsigned char x,unsigned char y,unsigned char *s)
{
lcd_set_xy( x, y ); //写地址
while (*s) // 写显示字符
{
lcdio=*s;
lcd_en_dat(*s);
s ++;
}
}
/********************************************************************
初始化函数
********************************************************************/
void lcd_init(void)//
{
clearscreen;//清屏
lcd_en_command(0x38);//设置8位串数据格式
lcd_en_command(0x0c);//开显示器
lcd_en_command(0x80);//显示起始地址
lcd_en_command(0x0e);//光标显示,字符不闪
clearscreen;//清屏
}
/********************************************************************
指定位置写字符串函数
********************************************************************/
void putstr(unsigned char x,unsigned char y,unsigned char *puts)
{
unsigned char i,j;
if(y == line1)
{
lcd_en_command(0x80+x);
j = 0;
for(i=0;i<20;i++) //最多40x2字符点阵
{
lcd_en_dat(puts[j]);
j++;
}
}
if(y == line2)
{
lcd_en_command(0xc0+x); //第二行显示,显示模式不改变
j = 0;
for(i=0;i<20;i++)
{
lcd_en_dat(puts[j]);
j++;
}
}
if(y == line3)
{
lcd_en_command(0x94+x); //第二行显示,和第一行一样
j = 0;
for(i=0;i<20;i++)
{
lcd_en_dat(puts[j]);
j++;
}
}
if(y == line4)
{
lcd_en_command(0xd4+x); //第二行显示,和第一行一样
j = 0;
for(i=0;i<20;i++)
{
lcd_en_dat(puts[j]);
j++;
}
}
}
/********************************************************************
cg-rom显示函数
设置cgram,自定义字符
********************************************************************/
void set_cgram( unsigned char *puts )
{
unsigned char i;
lcd_en_command(0x40); //cgram起始地址,注意cg地址会自动加一。
for(i=0;i<64;i++) //一共可自定义8个字符,每个字符8个字节数据所以8*8=64 地址
{
delay(40);
lcd_en_dat(puts);
}
}
/********************************************************************
主程序
********************************************************************/
void main( void )
{
delay(50);
lcd_init(); //初始化
lcd_delay();
while(1)
{
lcd_write_string(0,1,"abcdefg");
delay(400);
lcd_set_xy(0,2);
set_cgram(custom3);
putstr(0,4,"123456789");
lcd_write_char(12,4,'v');
}
}