这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » STM32 » 【原创】关于proteus仿真的LCD12864的显示问题--from恶龙咆哮

共3条 1/1 1 跳转至

【原创】关于proteus仿真的LCD12864的显示问题--from恶龙咆哮

工程师
2022-07-20 15:09:24     打赏

今天给大家分享一下关于proteus的LCD12864的问题,很多小伙伴在做关于LCD12864仿真的时候会遇到一个问题,就是仿真里面的LCD12864没有字库,这个真的让人头大,如果按照我们平常在12864里编写代码的话,结果就是不显示,所以我们需要先自己取字模,一定要注意,取模方式采用倒序、纵向取模:

1.png

2.png

接着,在proteus软件里打开并新建一个工程,设计一个简单的电路,如图:

3.png

编程是重点,LCD12864又把整个显示屏分为左右两边,想要同时显示,必须写代码把左右两边同时打开,即图中的CS1、CS2,根据LCD12864的手册里的时序编写读写代码,网上都可以找到他的中文手册,这里直接把代码放出来:

#define LCDLCDDisp_Off   0x3e
#define LCDLCDDisp_On    0x3f
#define Page_Add     0xb8//页地址
#define LCDCol_Add     0x40//列地址
#define Start_Line     0xC0//行地址
/*****液晶显示器的端口定义*****/
#define data_ora P0 /*液晶数据总线*/
sbit LCDMcs=P2^4 ;    /*片选1*/
sbit LCDScs=P2^3 ;    /*片选2*/
sbit RESET=P2^3 ;  /*复位信号*/
sbit LCDDi=P2^2 ;     /*数据/指令 选择*/
sbit LCDRW=P2^1 ;     /*读/写 选择*/
sbit LCDEnable=P2^0 ;     /*读/写 使能*/
 
/****************************************************************************
函数功能:LCD延时程序
入口参数:t
出口参数:
****************************************************************************/
void LCDdelay(unsigned int t)
{
       unsigned int i,j;
       for(i=0;i<t;i++);
       for(j=0;j<10;j++);
}
/****************************************************************************
状态检查,LCD是否忙
 
 
*****************************************************************************/
void CheckState()       
{
   unsigned char dat,DATA;//状态信息(判断是否忙)
   LCDDi=0; // 数据\指令选择,D/I(RS)="L" ,表示 DB7∽DB0 为显示指令数据
   LCDRW=1; //R/W="H" ,E="H"数据被读到DB7∽DB0
   do
   {
      DATA=0x00;
      LCDEnable=1;   //EN下降源
         LCDdelay(2);//延时
         dat=DATA;
      LCDEnable=0;
      dat=0x80 & dat; //仅当第7位为0时才可操作(判别busy信号)
    }
    while(!(dat==0x00));
}
/*****************************************************************************
函数功能:写命令到LCD程序,RS(DI)=L,RW=L,EN=H,来一个脉冲写一次
入口参数:cmdcode
出口参数:
*****************************************************************************/
void write_com(unsigned char cmdcode)
{
    CheckState();//检测LCD是否处于忙状态
       LCDDi=0;
       LCDRW=0;
       P1=cmdcode;             
       LCDdelay(2);
       LCDEnable=1;
       LCDdelay(2);
       LCDEnable=0;
}
/*****************************************************************************
函数功能:LCD初始化函数
*****************************************************************************/
void init_lcd()
{
       LCDdelay(100);    
       LCDMcs=1;//刚开始关闭两屏
       LCDScs=1;
       LCDdelay(100);
       write_com(LCDLCDDisp_Off);      //写初始化命令
       write_com(Page_Add+0);
       write_com(Start_Line+0);
       write_com(LCDCol_Add+0);
       write_com(LCDLCDDisp_On);
}
/*****************************************************************************
函数功能:写数据到LCD程序,RS(DI)=H,RW=L,EN=H,来一个脉冲写一次
入口参数:LCDDispdata
*****************************************************************************/
void write_data(unsigned char LCDDispdata)
{
    CheckState();//检测LCD是否处于忙状态
       LCDDi=1;
       LCDRW=0;
       P1=LCDDispdata;
       LCDdelay(2);
       LCDEnable=1;
       LCDdelay(2);
       LCDEnable=0;
}
/*****************************************************************************
函数功能:清除LCD内存程序
入口参数:pag,col,hzk
*****************************************************************************/
void Clr_Scr()
{
       unsigned char j,k;
       LCDMcs=0; //左、右屏均开显示
       LCDScs=0;
      write_com(Page_Add+0);
      write_com(LCDCol_Add+0);
      for(k=0;k<8;k++)//控制页数0-7,共8页
      {
              write_com(Page_Add+k); //每页每页进行写
            for(j=0;j<64;j++)  //每页最多可写32个中文文字或64个ASCII字符
              {
                write_com(LCDCol_Add+j);
                     write_data(0x00);//控制列数0-63,共64列,写点内容,列地址自动加1
              }
       }
}
/*****************************************************************************
函数功能:指定位置显示汉字16*16程序
入口参数:page,column,hzk
*****************************************************************************/
void hz_LCDDisp16(unsigned char page,unsigned char column, unsigned char code *hzk)
{
       unsigned char j=0,i=0;
       for(j=0;j<2;j++)
       {
              write_com(Page_Add+page+j);
              write_com(LCDCol_Add+column);
              for(i=0;i<16;i++)
                     write_data(hzk[16*j+i]);
       }
}
 
最后,只用在主函数里调用就可以,注意,while(1)里面不用调用LCD的函数:
void main()
{
       init_lcd();
       Clr_Scr();
       LCDMcs=0; //左屏开显示
       LCDScs=1;
       hz_LCDDisp16(0,48,Hz_ni);// Hz_Wo为某个汉字的首地址
        LCDMcs=1; //右屏开显示
       LCDScs=0;
        hz_LCDDisp16(0,0,Hz_hao);
       while(1)
    {
 
       }
}

显示结果如图所示:

4.png

但如果要在同一行显示多个汉字的时候,我们还需要再增加两个函数,左、右屏位置显示,这是因为,之前的代码打开的地址范围小,只是针对数组只有两行的显示,多了也显示不下,这个时候我们就要打开整一行的地址,宽高变为128*16,一共可以显示四行,一行显示8个字,这也是12864的由来,

/*****************************************************************************
函数功能:左屏位置显示
入口参数:page,column,hzk
出口参数:
*****************************************************************************/
void Bmp_Left_Disp(unsigned char page,unsigned char column, unsigned char code *Bmp)
{
       unsigned char j=0,i=0;
       for(j=0;j<2;j++)
       {
              write_com(Page_Add+page+j);
              write_com(LCDCol_Add+column);
              for(i=0;i<64;i++)
                     write_data(Bmp[128*j+i]);
       }
}
/*****************************************************************************
函数功能:右屏位置显示
入口参数:page,column,hzk
出口参数:
*****************************************************************************/
void Bmp_Right_Disp(unsigned char page,unsigned char column, unsigned char code *Bmp)
{
       unsigned char j=0,i=0;
       for(j=0;j<2;j++)
       {
              write_com(Page_Add+page+j);
              write_com(LCDCol_Add+column);
              for(i=64;i<128;i++)
                     write_data(Bmp[128*j+i]);
       }
}

写完这两个函数后,我们就可以在一行显示多个汉字了,每一个数组都要是16行、16列,如图:

5.png

别急,如果你以为剩下的就是直接把取模的数组直接按照顺序放进去就可以了的话,你就又掉进坑了里,因为你会发现他的显示是这样的:

6.png

还有这样的:

7.png

是不是头很大,看起来很乱,但仔细看的话,你会发现,是有迹可循的,第一个显示错误是因为一个数组里没有达到16行,因为你地址已经打开了,如果不够16行他就会显示乱码,所以即使没有字,也要用0x00补全,那么第二个的原因,仔细观察,每一个字的下半个字跑到了他的后面,因为我们编写的代码的原因,导致把这四行字又分成了八行,每一行执行完才会跑到下一行,所以我们取的模要重新拆开,把下边的一半放到第九行开始显示:

8.png

这样的现示结果就正确了:

9.png

主函数的代码和刚才一样:

void main()
{
       init_lcd();
       Clr_Scr();
       LCDMcs=0; //左屏开显示
       LCDScs=1;
       Bmp_Left_Disp(0,0,Bmp1);// Bmp1为某个汉字的首地址
    LCDMcs=1; //右屏开显示
       LCDScs=0;
    Bmp_Right_Disp(0,0,Bmp1);
       while(1)
    {
 
       }
}




专家
2022-07-20 15:30:57     打赏
2楼

感谢分享


助工
2022-07-20 16:20:27     打赏
3楼
此帖仅楼主可见

共3条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]