LCM1602可以用四线驱动,也就是说数据线只连D4~D7,这样的好处是节省了单片机的I/O口。 
/*========================================================= 
 
SMC1602A(16*2)模拟口线接线方式 连接线图: 
 
--------------------------------------------------- 
 
|LCM-----51 | LCM-----51 | LCM------51 | 
 
---------------------------------------------| 
 
DB4-----P1.4 | RW-------P2.0 | 
 
DB5-----P1.5 | RS -------P2.1 | 
 
DB6-----P1.6 | E --------P2.2 | 
 
DB7-----P1.7 | VLCD 接 1K 电阻到 GND| 
 
--------------------------------------------------- 
 
[注:AT89S51 使用 12M 晶体震荡器] 
 
=========================================================*/ 
 
#include <reg51.h> 
 
 
 
sbit LCM_RW=P2^0; //定义引脚 
 
sbit LCM_RS=P2^1; 
 
sbit LCM_E =P2^2; 
 
 
 
#define LCM_Data P1 
 
 
 
#define Busy 0x80 //用于检测 LCM 状态字中的 Busy 标识 
 
 
 
void WriteDataLCM(unsigned char Data); 
 
void WriteCommandLCM(unsigned char Command); 
 
 
 
void LCMInit(void); 
 
void DisplayOneChar(unsigned char X, unsigned char Y, unsigned char DData); 
 
void DisplayListChar(unsigned char X, unsigned char Y, unsigned char code *DData); 
 
 
 
void Delayms(unsigned int n); 
 
void dellay(unsigned int h); 
 
 
 
unsigned char code blog_adr[] = {"EDNchina"}; 
 
unsigned char code email[] = {"tengjingshu@126.com"}; 
 
 
 
void main(void) 
 
 
 
{ 
 
//Delay400Ms(); //启动等待,等 LCM 讲入工作状态 
 
LCMInit(); //LCM 初始化 
 
DisplayListChar(3, 0, blog_adr);  
 
                 DisplayListChar(0, 1, email);  
 
while(1); 
 
} 
 
 
 
//写数据 RS="H",RW=L,D0~D7=数据,E=高脉冲 
 
void WriteDataLCM(unsigned char Data)  
 
{  
 
LCM_RS = 1; 
 
LCM_RW = 0; 
 
         LCM_E = 0; 
 
         LCM_Data =(Data & 0xF0); 
 
         LCM_E = 1; 
 
dellay(100); //短暂延时,代替检测忙状态 
 
         LCM_E = 0; 
 
LCM_Data =(Data & 0x0F)<<4; 
 
LCM_E = 1; 
 
         dellay(100);  
 
         LCM_E = 0; 
 
} 
 
 
 
//写指令 RS="L",RW=L,D0~D7=指令码,E=高脉冲 
 
void WriteCommandLCM(unsigned char Command)  
 
{  
 
dellay(100); //短暂延时,代替检测忙状态 
 
LCM_RS = 0;  
 
         LCM_RW = 0; 
 
         LCM_E = 0; 
 
         LCM_Data =( Command & 0xF0); 
 
         LCM_E = 1; 
 
dellay(100); 
 
         LCM_E = 0; 
 
LCM_Data =( Command & 0x0F )<<4; 
 
LCM_E = 1; 
 
         dellay(100); 
 
LCM_E = 0; 
 
} 
 
 
 
//读数据 RS="H",RW=H,E=H 
 
//读状态 RS="L",RW=H,E=H 
 
//由于不要检测忙,所以读数据和读状态两个函数省略 
 
 
 
void LCMInit(void) //LCM 初始化 
 
{ 
 
LCM_Data = 0; 
 
Delayms(15); 
 
WriteCommandLCM(0x03); //三次显示模式设置,不检测忙信号 
 
Delayms(5); 
 
WriteCommandLCM(0x03);  
 
Delayms(5); 
 
WriteCommandLCM(0x03); 
 
Delayms(5); 
 
WriteCommandLCM(0x02); 
 
         Delayms(5); 
 
WriteCommandLCM(0x28); //显示模式设置,开始要求每次检测忙信号 
 
WriteCommandLCM(0x06); // 显示光标移动设置  
 
         WriteCommandLCM(0x0C); 
 
WriteCommandLCM(0x01); 
 
         Delayms(5); 
 
} 
 
 
 
//按指定位置显示一个字符 
 
void DisplayOneChar(unsigned char X, unsigned char Y, unsigned char DData) 
 
{ 
 
Y &= 0x1; 
 
X &= 0xF; //限制 X 不能大于 15,Y 不能大于 1 
 
if (Y) X |= 0x40; //当要显示第二行时地址码+0x40;  
 
X |= 0x80; //算出指令码 
 
WriteCommandLCM(X); //这里不检测忙信号,发送地址码 
 
WriteDataLCM(DData); 
 
} 
 
 
 
//按指定位置显示一串字符 
 
void DisplayListChar(unsigned char X, unsigned char Y, unsigned char code *DData) 
 
{ 
 
unsigned char ListLength; 
 
ListLength = 0; 
 
Y &= 0x1; 
 
X &= 0xF; //限制 X 不能大于 15,Y 不能大于 1 
 
while (DData[ListLength]>0x1f) //若到达字串尾则退出 
 
{ 
 
if (X <= 0xF) //X 坐标应小于 0xF 
 
{ 
 
DisplayOneChar(X, Y, DData[ListLength]); //显示单个字符 
 
ListLength++; X++; 
 
} 
 
} 
 
} 
 
 
 
void Delayms(unsigned int n) 
 
{ 
 
        unsigned int i,j; 
 
        for(j=n;j>0;j--) 
 
        for(i=112;i>0;i--); 
 
} 
 
 
 
/************************************************** 
 
** 函数名称: dellay 
 
** 入口参数:h(unsigned int型) 
 
** 出口参数:无 
 
** 功能描述: 短暂延时,约0.01MS 
 
****************************************************/ 
 
void dellay(unsigned int h) 
 
{ 
 
while(h--); //0.01MS 
 
} 
 
 
 
 
 
本文程序下载:http://space.ednchina.com/Upload ... b3-d361bc6500cf.rar 
 
 
 
LCM1602的8bit驱动和4bit驱动的电路图差别是4bit只用到数据线D4~D7,而D0~D3没有用到。 
 
1602系列液晶显示模块常用的驱动芯片有HD44780(日立公司),兼容芯片有KS0066(韩国三星)、sEDl278(seikoEpson)、NJu6408(NewJapanRadioC0.Ld)等。 
 
其实不知道LCM1602用的是什么芯片,因为看到的是一大块黑色的集成封装。下面以HD44780为例介绍。(我下过KS0066的DataSHeet,和HD44780芯片的初始化命令代码是不一样的,如果按照KS0066的初始化,LCM1602没有显示) 
 
HD44780 LCD控制器的命令和位的定义: 
 
HD44780 LCD初始化 
 
 
void LCMInit(void) //LCM 初始化 
 
{ 
 
LCM_Data = 0; 
 
//上电初始化 
 
Delayms(15); //等待15ms或更长 
 
WriteCommandLCM(0x03); 
 
Delayms(5); //等待4.1ms或更长 
 
WriteCommandLCM(0x03);  
 
Delayms(5); //等待100us或更长 
 
WriteCommandLCM(0x03); 
 
Delayms(5); //等待40us或更长 
 
WriteCommandLCM(0x02); 
 
         Delayms(5); //等待40us或更长 
 
//显示器配置 
 
WriteCommandLCM(0x28); //配置显示屏 
 
WriteCommandLCM(0x06); //设置显示屏自动增地址指针  
 
         WriteCommandLCM(0x0C); //开显示屏并失能指针和光标 
 
WriteCommandLCM(0x01);//发清屏命令 
 
         Delayms(5); //此后等待至少1.64ms(必不可少) 
 
} 
 
 
 
参考Spartan-3E使用手册中文版 
 
 
 
其实好像初始化没有这么严格,参考网上其它程序,有的程序采用下面的初始化。 
 
/********************************************************************/ 
void LCD_init(void) 
{  
WriteCommandLCM (0x01); 
Delayms (5); 
WriteCommandLCM (0x01); 
Delayms (5);  
WriteCommandLCM (0x28); 
Delayms (5); 
WriteCommandLCM (0x28); 
Delayms (5); 
WriteCommandLCM (0x28); 
Delayms (5);  
WriteCommandLCM (0x0C); 
Delayms (5);  
WriteCommandLCM (0x80); 
Delayms (5);  
WriteCommandLCM (0x01); 
Delayms (5); 
} 
/********************************* *********************************/ 
 
 
 
由于该显示屏是4位操作,每8位命令被送到2个4位(2个半位)。高半位先送,低半位后送。 
 
//写指令 RS="L",RW=L,D0~D7=指令码,E=高脉冲 
 
void WriteCommandLCM(unsigned char Command)  
 
{  
 
dellay(100); //短暂延时,代替检测忙状态 
 
LCM_RS = 0;  
 
         LCM_RW = 0; 
 
         LCM_E = 0; 
 
         LCM_Data =( Command & 0xF0); //屏蔽低4位 
 
         LCM_E = 1; //送高4位 
 
dellay(100); 
 
         LCM_E = 0; 
 
LCM_Data =( Command & 0x0F )<<4; //屏蔽高四位,把低四位移到高四位 
 
LCM_E = 1; //送低4位 
 
         dellay(100); 
 
LCM_E = 0; 
 
} 
 |