微波EDA网,见证研发工程师的成长!
首页 > 研发问答 > 嵌入式设计讨论 > MCU和单片机设计讨论 > 为什么我的LCD1602程序中指定显示位置的函数必须调用2次

为什么我的LCD1602程序中指定显示位置的函数必须调用2次

时间:10-02 整理:3721RD 点击:
#include <reg52.h>
#include<intrins.h>  //包含_nop_()函数定义的头文件
#define uchar unsigned char
#define uint unsigned int
sbit RS=P2^0;
sbit RW=P2^1;
sbit E=P2^2;
sbit BF=P0^7;    //忙碌标志位,,将BF位定义为P0.7引脚
sbit P32=P3^2;
void LCD_init(void);//初始化函数
void LCD_write_command(uchar command);//写指令函数
void LCD_write_data(uchar dat);//写数据函数
void WriteAddress(unsigned char x);        //指定字符显示的实际地址 例如WriteAddress(0x03);表示:写地址,从第1行第4列开始显示
//void LCD_disp_char(uchar x,uchar y,uchar dat);//在某个屏幕位置上显示一个字符,X(0-16),y(1-2)
uchar BusyTest(void);//检查忙函数。
void delay(uchar n);//延时函数
//********延时函数***************
void delay1ms(void)   //误差 0us
{
    unsigned char a,b,c;
    for(c=1;c>0;c--)
        for(b=142;b>0;b--)
            for(a=2;a>0;a--);
}

void delay(unsigned char n)
{
   unsigned char i;
        for(i=0;i<n;i++)
           delay1ms();
}
void delay500ms(void)   //误差 0us
{
    unsigned char a,b,c;
    for(c=23;c>0;c--)
        for(b=152;b>0;b--)
            for(a=70;a>0;a--);
}
/*****************************************************
函数功能:判断液晶模块的忙碌状态
返回值:result。result=1,忙碌;result=0,不忙
***************************************************/
uchar BusyTest(void)
  {
    bit result;
        RS=0;       //根据规定,RS为低电平,RW为高电平时,可以读状态
    RW=1;
    E=1;        //E=1,才允许读写
    _nop_();   //空操作
    _nop_();
    _nop_();
    _nop_();   //空操作四个机器周期,给硬件反应时间       
    result=BF;  //将忙碌标志电平赋给result
   E=0;         //将E恢复低电平
   return result;
  }

void LCD_init()
{
  delay(15);             //延时15ms,首次写指令时应给LCD一段较长的反应时间
    LCD_write_command(0x38);  //显示模式设置:16×2显示,5×7点阵,8位数据接口
        delay(5);               //延时5ms ,给硬件一点反应时间
    LCD_write_command(0x38);
        delay(5);
         LCD_write_command(0x38); //连续三次,确保初始化成功
        delay(5);
         LCD_write_command(0x0C);  //显示模式设置:显示开,没光标,光标不闪烁
        delay(5);
         LCD_write_command(0x06);  //显示模式设置:光标右移,字符不移
        delay(5);
         LCD_write_command(0x01);  //清屏幕指令,将以前的显示内容清除
        delay(5);
}

/*****************************************************
函数功能:将模式设置指令或显示地址写入液晶模块
入口参数:command
***************************************************/
void  LCD_write_command(uchar command)
{   
   while(BusyTest()==1); //如果忙就等待
         RS=0;                  //根据规定,RS和R/W同时为低电平时,可以写入指令
         RW=0;   
         E=0;                   //E置低电平(根据表8-6,写指令时,E为高脉冲,
                          // 就是让E从0到1发生正跳变,所以应先置"0"
         E=1;                   //E置高电平          
                   P0=command;            //将数据送入P0口,即写入指令或地址
         E=0;                  //当E由高电平跳变成低电平时,液晶模块开始执行命令
}
/*****************************************************
函数功能:指定字符显示的实际地址
入口参数:x
***************************************************/
void WriteAddress(unsigned char x)
{
    LCD_write_command(x|0x80); //显示位置的确定方法规定为"80H+地址码x"
}
/*****************************************************
函数功能:将数据(字符的标准ASCII码)写入液晶模块
入口参数:y(为字符常量)
***************************************************/
void LCD_write_data(unsigned char y)
{
   while(BusyTest()==1);  
          RS=1;           //RS为高电平,RW为低电平时,可以写入数据
          RW=0;
          E=0;            //E置低电平(根据表8-6,写指令时,E为高脉冲,
                       // 就是让E从0到1发生正跳变,所以应先置"0"
          P0=y;           //将数据送入P0口,即将数据写入液晶模块
/*          _nop_();
          _nop_();
          _nop_();
     _nop_();       //空操作四个机器周期,给硬件反应时间
*/
          E=1;          //E置高电平
/*          _nop_();
          _nop_();
          _nop_();
         _nop_();        //空操作四个机器周期,给硬件反应时间
*/
          E=0;            //当E由高电平跳变成低电平时,液晶模块开始执行命令
}                             
//*******************************
//*********主函数*****************
void main(void)
{
                uchar temp[]={"ABCDEFGHI"};
                uint i = 0;  
        LCD_init();
                E=0;                           
  WriteAddress(0x01);          //写地址,从第1行第4列开始显示
  WriteAddress(0x01);          //此处实验多次,该函数执行两次才能达到效果,不知为何,后面则没有出现类似情况,求解?
         i=0;              //从字符数组的第1个元素开始显示
         while(temp[i]!='\0')
       {
            LCD_write_data(temp[i++]);
                delay500ms();
                }               
WriteAddress(0x41);          //写地址,从第1行第4列开始显示
         i=0;              //从字符数组的第1个元素开始显示
          while(temp[i]!='\0')
          {
                LCD_write_data(temp[i++]);
                   delay(500);           //此处并不是预期的500ms,比500ms短很多,求解?
          }
/*        WriteAddress(0x06);
                LCD_write_data('A');
           WriteAddress(0X07);
                LCD_write_data('B');
*/
                while(1)
                {
                   if(!P32)
                   {
                            WriteAddress(0x0D);
                         LCD_write_data('P');
                         //delay(2000);
                   }
                   else
                   {
                   WriteAddress(0x0D);
                   LCD_write_data('B');
                   //delay(2000);
                   }
               
                }          
}
========================分割线=============================
就是上面程序中连续两个WriteAddress(0x01);这个位置,我调用一次没有,两次就有用,后面的都没有这个问题...
小弟昨晚搞了好久不知道怎么弄,程序是典型的LCD1602程序,有点长,烦劳有耐心的大哥大姐们看看。


调用后是否需要加个延时呢

先说你的延时吧   你的定义是char  他的范围是0-255 你写了个500 可定不会是500ms  你定义一个别的
unsigned int a,b,c;肯定就好了
再说你的你的两个延续  我认为你的当E由高电平跳变成低电平时开始写数据的时间有点短 还没有把数据写入
就开始了下一条语句 你加下延时看看吧  

把你的程序改了下,可以试试。
========================================================
#include <reg52.h>
#include<intrins.h>  //包含_nop_()函数定义的头文件
#define uchar unsigned char
#define uint unsigned int
sbit RS=P2^0;
sbit RW=P2^1;
sbit E=P2^2;
sbit BF=P0^7;    //忙碌标志位,,将BF位定义为P0.7引脚
sbit P32=P3^2;
void LCD_init(void);//初始化函数
void LCD_write_command(uchar command);//写指令函数
void LCD_write_data(uchar dat);//写数据函数
void WriteAddress(unsigned char x);        //指定字符显示的实际地址 例如WriteAddress(0x03);表示:写地址,从第1行第4列开始显示
//void LCD_disp_char(uchar x,uchar y,uchar dat);//在某个屏幕位置上显示一个字符,X(0-16),y(1-2)
uchar BusyTest(void);//检查忙函数。
void delay(uchar n);//延时函数
//********延时函数***************
void delay1ms(void)   //误差 0us
{
    unsigned char a,b,c;
    for(c=1;c>0;c--)
        for(b=142;b>0;b--)
            for(a=2;a>0;a--);
}

void delay(unsigned int n)//这里声明变量类型错误
{
   unsigned int i;
        for(i=0;i<n;i++)
           delay1ms();
}
void delay500ms(void)   //误差 0us
{
    unsigned char a,b,c;
    for(c=23;c>0;c--)
        for(b=152;b>0;b--)
            for(a=70;a>0;a--);
}
/*****************************************************
函数功能:判断液晶模块的忙碌状态
返回值:result。result=1,忙碌;result=0,不忙
***************************************************/
uchar BusyTest(void)
  {
    bit result;
        RS=0;       //根据规定,RS为低电平,RW为高电平时,可以读状态
    RW=1;
    E=1;        //E=1,才允许读写
    _nop_();   //空操作
    _nop_();
    _nop_();
    _nop_();   //空操作四个机器周期,给硬件反应时间        
    result=BF;  //将忙碌标志电平赋给result
   E=0;         //将E恢复低电平
   return result;
  }

void LCD_init()
{
  delay(15);             //延时15ms,首次写指令时应给LCD一段较长的反应时间
    LCD_write_command(0x38);  //显示模式设置:16×2显示,5×7点阵,8位数据接口
        delay(5);               //延时5ms ,给硬件一点反应时间
    LCD_write_command(0x38);
        delay(5);
         LCD_write_command(0x38); //连续三次,确保初始化成功
        delay(5);
         LCD_write_command(0x0C);  //显示模式设置:显示开,没光标,光标不闪烁
        delay(5);
         LCD_write_command(0x06);  //显示模式设置:光标右移,字符不移
        delay(5);
         LCD_write_command(0x01);  //清屏幕指令,将以前的显示内容清除
        delay(5);
}

/*****************************************************
函数功能:将模式设置指令或显示地址写入液晶模块
入口参数:command
***************************************************/
void  LCD_write_command(uchar command)
{   
   while(BusyTest()==1); //如果忙就等待
         RS=0;                  //根据规定,RS和R/W同时为低电平时,可以写入指令
         RW=0;   
         E=0;                   //E置低电平(根据表8-6,写指令时,E为高脉冲,
                          // 就是让E从0到1发生正跳变,所以应先置"0"
         E=1;                   //E置高电平         
                   P0=command;            //将数据送入P0口,即写入指令或地址
         E=0;                  //当E由高电平跳变成低电平时,液晶模块开始执行命令
}
/*****************************************************
函数功能:指定字符显示的实际地址
入口参数:x
***************************************************/
void WriteAddress(unsigned char x)
{
    LCD_write_command(x|0x80); //显示位置的确定方法规定为"80H+地址码x"
}
/*****************************************************
函数功能:将数据(字符的标准ASCII码)写入液晶模块
入口参数:y(为字符常量)
***************************************************/
void LCD_write_data(unsigned char y)
{
   while(BusyTest()==1);  
          RS=1;           //RS为高电平,RW为低电平时,可以写入数据
          RW=0;
          E=0;            //E置低电平(根据表8-6,写指令时,E为高脉冲,
                       // 就是让E从0到1发生正跳变,所以应先置"0"
          P0=y;           //将数据送入P0口,即将数据写入液晶模块
/*          _nop_();
          _nop_();
          _nop_();
     _nop_();       //空操作四个机器周期,给硬件反应时间
*/
          E=1;          //E置高电平
/*          _nop_();
          _nop_();
          _nop_();
         _nop_();        //空操作四个机器周期,给硬件反应时间
*/
          E=0;            //当E由高电平跳变成低电平时,液晶模块开始执行命令
}                             
//*******************************
//*********主函数*****************
void main(void)
{
                uchar temp[]={"ABCDEFGHI"};
                uint i = 0;  
        LCD_init();
                E=0;                           
  WriteAddress(0x01);          //写地址,从第1行第4列开始显示
  //WriteAddress(0x01);          //此处实验多次,该函数执行两次才能达到效果,不知为何,后面则没有出现类似情况,求解?//这里估计也是由于延时函数的问题导致的
         i=0;              //从字符数组的第1个元素开始显示
         while(temp!='\0')
       {
            LCD_write_data(temp[i++]);
                delay500ms();
                }               
WriteAddress(0x41);          //写地址,从第1行第4列开始显示
         i=0;              //从字符数组的第1个元素开始显示
          while(temp!='\0')
          {
                LCD_write_data(temp[i++]);
                   delay(500);           //此处并不是预期的500ms,比500ms短很多,求解?
          }
/*        WriteAddress(0x06);
                LCD_write_data('A');
           WriteAddress(0X07);
                LCD_write_data('B');
*/
                while(1)
                {
                   if(!P32)
                   {
                            WriteAddress(0x0D);
                         LCD_write_data('P');
                         //delay(2000);
                   }
                   else
                   {
                   WriteAddress(0x0D);
                   LCD_write_data('B');
                   //delay(2000);
                   }
               
                }         
}

谢谢你的指点,我今天白天去试试

谢谢你的修改,指定显示位置的函数一次就成功了。但是显示出现了问题,程序中while(),括号里面判断到字符串结束了就跳出循环。但是在屏幕上显示完“ABCDEFGHI”之后它继续在后面显示了各种乱码。正在找原因...

延时函数确实有问题...谢谢你

我在自己的程序里面把延时函数修改之后就正常了。总之还是要谢谢你帮我发现问题,这么长的程序放上来我真的有点不好意思了

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top