新闻  |   论坛  |   博客  |   在线研讨会
51单片机1602液晶驱动程序(二)模拟口线方式
0750long | 2009-04-11 09:13:38    阅读:1874   发布文章

51单片机1602液晶驱动程序(二)模拟口线方式

   LCM1602除了总线方式控制外,还可以用模拟口线方式控制,模拟口线线路图如下:

 

点击看大图

 

程序如下:

/*=========================================================

SMC1602A(16*2)模拟口线接线方式 连接线图:

---------------------------------------------------

|LCM-----51 | LCM-----51 | LCM------51 |

---------------------------------------------|

|DB0-----P1.0 | DB4-----P1.4 | RW-------P2.0 |

|DB1-----P1.1 | DB5-----P1.5 | RS-------P2.1 |

|DB2-----P1.2 | DB6-----P1.6 | E--------P2.2 |

|DB3-----P1.3 | 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 WDLCM);

void WriteCommandLCM(unsigned char WCLCM,BuysC);

unsigned char ReadDataLCM(void);

unsigned char ReadStatusLCM(void); 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(6, 0, blog_adr);

              DisplayListChar(0, 0, email);

 

        while(1);

}

 

//写数据 RS="H",RW=L,D0~D7=数据,E=高脉冲

void WriteDataLCM(unsigned char WDLCM) 

{     

       dellay(100);

       LCM_E = 0;

       LCM_RS = 1;

       LCM_RW = 0;

LCM_Data = WDLCM;

//dellay(100);     //短暂延时,代替检测忙状态

       //ReadStatusLCM(); //检测忙

       LCM_E = 1;

          LCM_E = 0;

}

 

//写指令 RS="L",RW=L,D0~D7=指令码,E=高脉冲

void WriteCommandLCM(unsigned char WCLCM,BuysC)

//BuysC 为 0 时忽略忙检测

{

      //if (BuysC) ReadStatusLCM(); //根据需要检测忙

      dellay(100);       //短暂延时,代替检测忙状态

      LCM_E = 0;

          LCM_RS = 0;

          LCM_RW = 0;

      LCM_Data = WCLCM;

      LCM_E  = 1;

          LCM_E = 0;

}

 

//读数据 RS="H",RW=H,E=H

unsigned char ReadDataLCM(void)

{

      LCM_RS = 1;

      LCM_RW = 1;

      LCM_E = 1; 

      return(LCM_Data);

}

 

//读状态 RS="L",RW=H,E=H

unsigned char ReadStatusLCM(void)

{

      LCM_Data = 0xFF;

      LCM_RS = 0;

      LCM_RW = 1;

      LCM_E = 1;

      //while (LCM_Data & Busy); //检测忙信号

      return(LCM_Data);

}

 

void LCMInit(void) //LCM 初始化

{

      LCM_Data = 0;

      Delayms(15);

      WriteCommandLCM(0x38,0); //三次显示模式设置,不检测忙信号

      Delayms(5);

      WriteCommandLCM(0x38,0);

      Delayms(5);

      WriteCommandLCM(0x38,0);

      WriteCommandLCM(0x38,1); //显示模式设置,开始要求每次检测忙信号

      WriteCommandLCM(0x08,1); //关闭显示

      WriteCommandLCM(0x01,1); //显示清屏

      WriteCommandLCM(0x06,1); // 显示光标移动设置

      WriteCommandLCM(0x0C,1); // 显示开及光标设置

}

 

//按指定位置显示一个字符

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, 1); //这里不检测忙信号,发送地址码

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型)

** 出口参数:无

** 功能描述: 短暂延时,使用12MHz晶体,约0.01MS

****************************************************/

void dellay(unsigned int  h)

{

  while(h--);    //0.01MS

}

 

     本文程序下载:rar

   

要注意的是在读写程序中,没有用 “检测忙”,其实对于1602来说,没有检测忙信号对于实际来说还好,因为常常因为检测忙,而使1602没显示(一直处于忙检测中)。“忙检测”用一个小延时代替。

对于LCM1602来说,读写时序最重要。

 

点击看大图

                                           LCM1602写操作时序

 

//写数据 RS="H",RW=L,D0~D7=数据,E=高脉冲

void WriteDataLCM(unsigned char WDLCM) 

{     

       dellay(100);     //短暂延时,代替检测忙状态

       LCM_E = 0;

       LCM_RS = 1;

       LCM_RW = 0;

LCM_Data = WDLCM;

       LCM_E = 1;

          LCM_E = 0;

}

 

//写指令 RS="L",RW=L,D0~D7=指令码,E=高脉冲

void WriteCommandLCM(unsigned char WCLCM)

{

      dellay(100);       //短暂延时,代替检测忙状态

      LCM_E = 0;

          LCM_RS = 0;

          LCM_RW = 0;

       LCM_Data = WCLCM;

       LCM_E  = 1;

          LCM_E = 0;

}

 

上面两个分别为写数据函数和写命令函数,检测忙已用小延时代替。其实这个时序好像不太严格,但要保证的是E高脉冲时,写的数据/命令是有效的。

好像函数也可以写成这样:

void WriteCommandLCM(unsigned char WCLCM)

{

dellay(100);       //短暂延时,代替检测忙状态

         LCM_Data = WCLCM;

         LCM_RS = 0;

         LCM_RW = 0;

         LCM_E  = 0;

      dellay(100);

      LCM_E  = 1;

}

 

//按指定位置显示一串字符

函数DisplayListChar的作用是在指定位置显示一串字符,其中有一句

“while (DData[ListLength]>0x1f) //若到达字串尾则退出”

  

   为什么要大于0x20呢?

   unsigned char code blog_adr[] = {"EDNchina"};

unsigned char code email[] = {"tengjingshu@126.com"};

 

  用单引号’’ ( )括起来的字符为字符的ASCII码值,而不是字符串。

  用双引号””(shift+ )括起来的一串字符,成为字符串常量。C编译器会自动地在字符末尾加上结束符’\0’(NULL) (ASCII码为0x00也就是00H)。

 

char a[]={“Bei Jing”};

char a[]={‘B’,’e’,’I’,’ ‘,’J’,’i’,’n’,’g’,’\0’};

  

两者是等价的,数组的每个元素为对应字符的ASCII码,如a[3]数组a的第四个元素是’ ‘空格,则a[3]里面放着的是空格’ ‘的ASCII码0x20。

还要注意的是数组的元素数目一定要比字符多一个。以便C编译器自动在其后面加入结束符’\0’。

 

下面是ASCII表(0~127)

 

点击看大图

摘自:http://www.asciitable.com/

 

NUL

VT 垂直制表

SYN 空转同步

SOH      标题开始

FF       走纸控制

ETB      信息组传送结束

STX      正文开始

CR       回车

CAN      作废

ETX      正文结束

SO       移位输出

EM       纸尽

EOY      传输结束

SI       移位输入

SUB      换置

ENQ      询问字符

DLE      空格

ESC      换码

ACK      承认

DC1      设备控制1

FS       文字分隔符

BEL      报警

DC2      设备控制2

GS       组分隔符

BS       退一格

DC3      设备控制3

RS       记录分隔符

HT       横向列表

DC4      设备控制4

US       单元分隔符

LF       换行

NAK      否定

DEL      删除

摘自:http://hi.baidu.com/ffxung/blog/item/cdccc8e93259533ab90e2d5e.html

 

可以知道

‘\0’ ASCII码为0x00

‘\n’ASCII码为0x0A

 

那知道为什么有这句了吧

“while (DData[ListLength]>0x1F) //若到达字串尾则退出”

因为大于0x1f才能显示字符,小于和等于0x1f的都是键盘控制符。

当然我们也可以检测’\0’(0x00)

“while (DData[ListLength]!='\0')  //检测到字符串结束符则退出”

*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。

参与讨论
登录后参与讨论
推荐文章
最近访客