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

2009-4-10 22:02 7405 6 7 分类: MCU/ 嵌入式

51单片机1602液晶驱动程序(二)模拟口线方式<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />


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


<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" />


 


点击看大图


 


程序如下:


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


SMC<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />1602A(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 不能大于 15Y 不能大于 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 不能大于 15Y 不能大于 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


** 入口参数:hunsigned int型)


** 出口参数:无


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


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


void dellay(unsigned int  h)


{


  while(h--);    //0.01MS


}


 


     本文程序下载:https://static.assets-stash.eet-china.com/album/old-resources/2009/4/10/296a56e8-0084-4087-950b-d50c57d389ff.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]里面放着的是空格’ ‘ASCII0x20


还要注意的是数组的元素数目一定要比字符多一个。以便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')  //检测到字符串结束符则退出

PARTNER CONTENT

文章评论1条评论)

登录后参与讨论

用户145263 2009-4-11 08:27

好啊。哈哈
相关推荐阅读
藤井树 2015-10-12 14:43
印制电路板的抗干扰设计 zz
印制电路板的抗干扰设计     作者:中船重工集团第707所 肖麟芬   摘   要:本文以印制电路板的电磁兼容性为核心,分析了电磁干扰的产生机理...
藤井树 2013-10-22 15:32
2010.5.30 黄草梁上包饺子一日登山活动——摘韭菜篇
        上次桃花节的时候也有野韭菜,那时候的我连草和韭菜叶分不清,才回去的韭菜也不敢吃,哈哈,这次可算真正见识了韭菜,黄草梁也叫韭菜梁,因为满山遍野都是野韭菜而闻名,比较圆比较粗的就是野韭...
藤井树 2013-10-22 15:28
2010.5.30 黄草梁上包饺子一日登山活动——包饺子篇
摘韭菜回来,大家已经忙开了 我也装模作样地“工作着” 哈哈,还不让我包,包饺子是技术活,一定要皮薄馅厚才有资格包,像我这样的只能旁观了 摘的韭菜应该足够了,旁边那个袋子是我摘来带回学校的 ...
藤井树 2013-08-09 15:19
datasheet下载网站整理(查IC芯片手册)【原创】
*************************************************************************         作为电子工程师,芯片的dat...
藤井树 2010-06-04 00:21
陈伟宁王辉一家捐助渠道(北京菲亚特—英菲尼迪)
       王辉的最新消息请关注 http://chenweining.org/       目前事故责任认定已经出来了——陈家全责。        发信人: program (程序), 信区: D...
藤井树 2010-06-01 13:43
2010.5.30 黄草梁上包饺子一日登山活动——美景篇
这天不得不说的是天空,蓝蓝的天空,白白的云    绿油油的山脊  我、洪涛哥哥、huangna妹妹还有她同事小艾走在黄草梁上    在蓝天白云下合影       阳光照过来,景色真美 象鼻山,走不...
EE直播间
更多
我要评论
1
6
关闭 站长推荐上一条 /3 下一条