搜索
bottom↓
回复: 21

为什么LCD12864显示大数字的时候花屏,而且显示的慢

[复制链接]

出0入0汤圆

发表于 2013-3-18 09:41:13 | 显示全部楼层 |阅读模式
本帖最后由 学电子 于 2013-3-18 09:43 编辑

以下是我的程序。其中遇到了一点问题,请高手帮帮忙,指点指点。

#include <reg52.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define LCD_data P0
sbit wela=P2^7;
sbit dula=P2^6;
sbit LCD_EN=P3^4;
sbit LCD_RS=P3^5;
sbit LCD_RW=P3^6;
sbit LCD_PSB=P3^7;


uchar code num1[]={0x00,0x00,0x00,0x38,0x00,0x78,0x00,0xF8,0x01,0xF8,0x01,0xF8,0x00,0x78,0x00,0x78,
0x00,0x78,0x00,0x78,0x00,0x78,0x00,0x78,0x00,0x78,0x00,0x78,0x00,0x78,0x00,0x78,
0x00,0x78,0x00,0x78,0x00,0x78,0x00,0x78,0x00,0x78,0x00,0x78,0x00,0x78,0x00,0x78,
0x00,0x78,0x00,0x78,0x00,0x78,0x00,0x78,0x00,0x78,0x00,0x78,0x00,0x78,0x00,0x00};



/***************************************************************
以下是关于12864的子程序
***************************************************************/


void delay(uint z)                                                   //延时函数
{
        uint x,y;
        for(x=z;x>0;x--)
                for(y=110;y>0;y--);
}

void check_lcd_busy()                                           //忙检测
{
        LCD_RS=0;
        LCD_RW=1;
        LCD_EN=1;
        LCD_data=0xff;
        while((LCD_data&0x80)==0x80);
        LCD_EN=0;       
}

void write_cmd(uchar cmd)                                   //12864写指令
{
        check_lcd_busy();
        LCD_RS=0;
        LCD_RW=0;
        LCD_EN=0;
        P0=cmd;
        delay(5);
        LCD_EN=1;
        delay(5);
        LCD_EN=0;
}


void write_dat(uchar dat)                                          //12864写数据
{
        check_lcd_busy();
        LCD_RS=1;
        LCD_RW=0;
        LCD_EN=0;
        P0=dat;
        delay(5);
        LCD_EN=1;
        delay(5);
        LCD_EN=0;
}




void clear_GDRAM()                                                 //清除GDRAM,防止花屏
{
        uchar i,j;
        write_cmd(0x34);
        write_cmd(0x30);
        write_cmd(0x0c);
        write_cmd(0x06);
        write_cmd(0x34);
        for(j=0;j<32;j++)
        {
                write_cmd(0x80+j);
                write_cmd(0x80);
                for(i=0;i<16;i++)
                {
                        write_dat(0x00);
                        write_dat(0x00);
                }
        }       
}

void display_bmp(uchar x,uchar *bmp)                         //显示16*32的数字
{
        uchar i,j,X;
        X=0x80+x;
        write_cmd(0x36);
        for(i=0;i<16;i++)       
        {
                write_cmd(0x90+i);
                write_cmd(X);
                for(j=0;j<2;j++)
                        write_dat(*bmp++);
        }
        for(i=0;i<16;i++)
        {
                write_cmd(0x80+i);
                write_cmd(X+8);
                for(j=0;j<2;j++)
                        write_dat(*bmp++);
        }
        write_cmd(0x36);

}


void lcd_init()                                                                        //12864初始化
{
        LCD_PSB=1;
        write_cmd(0x30);
        write_cmd(0x0c);
        write_cmd(0x01);
        write_cmd(0x06);
}

/***************************************************************
以下是主函数
***************************************************************/

void main()
{
        wela=0;
        dula=0;
        delay(10);
        lcd_init();
        clear_GDRAM();                //如果把这句代码取消,屏幕显示花屏。但是如果加上这句,显示的特别慢。why????       
                while(1)
        {
                display_bmp(0,num1);
                display_bmp(1,num1);
                display_bmp(2,num1);
                display_bmp(3,num1);       
                display_bmp(4,num1);
                display_bmp(5,num1);
                display_bmp(6,num1);
                display_bmp(7,num1);
                               
        }

}                                                 

阿莫论坛20周年了!感谢大家的支持与爱护!!

你熬了10碗粥,别人一桶水倒进去,淘走90碗,剩下10碗给你,你看似没亏,其实你那10碗已经没有之前的裹腹了,人家的一桶水换90碗,继续卖。说白了,通货膨胀就是,你的钱是挣来的,他的钱是印来的,掺和在一起,你的钱就贬值了。

出0入0汤圆

发表于 2013-3-18 16:43:58 | 显示全部楼层
我用的12864没出现过这种问题....

出0入0汤圆

 楼主| 发表于 2013-3-18 18:02:33 | 显示全部楼层
白滚滚 发表于 2013-3-18 16:43
我用的12864没出现过这种问题....

这是图片显示,显示的是16*32的大数字。你看看我的程序有问题吗?

出0入0汤圆

 楼主| 发表于 2013-3-18 18:10:48 | 显示全部楼层
高手请您留步

出0入0汤圆

发表于 2013-3-18 19:52:01 | 显示全部楼层
读写时序对吗?

出0入0汤圆

 楼主| 发表于 2013-3-18 20:51:56 | 显示全部楼层
lxa0 发表于 2013-3-18 19:52
读写时序对吗?

我的程序就在这,是参考很多资料写出来的。但是每一份资料关于显示图片的具体时序写的都不是很清楚,您看我的有问题吗?谢谢了

出0入0汤圆

 楼主| 发表于 2013-3-18 20:54:30 | 显示全部楼层
lxa0 发表于 2013-3-18 19:52
读写时序对吗?

这俩个子函数内部的时序我一直都不是很懂,很多资料各有各的写法


void clear_GDRAM()                                                 //清除GDRAM,防止花屏
{
        uchar i,j;
        write_cmd(0x34);
        write_cmd(0x30);
        write_cmd(0x0c);
        write_cmd(0x06);
        write_cmd(0x34);
        for(j=0;j<32;j++)
        {
                write_cmd(0x80+j);
                write_cmd(0x80);
                for(i=0;i<16;i++)
                {
                        write_dat(0x00);
                        write_dat(0x00);
                }
        }        
}

void display_bmp(uchar x,uchar *bmp)                         //显示16*32的数字
{
        uchar i,j,X;
        X=0x80+x;
        write_cmd(0x36);
        for(i=0;i<16;i++)        
        {
                write_cmd(0x90+i);
                write_cmd(X);
                for(j=0;j<2;j++)
                        write_dat(*bmp++);
        }
        for(i=0;i<16;i++)
        {
                write_cmd(0x80+i);
                write_cmd(X+8);
                for(j=0;j<2;j++)
                        write_dat(*bmp++);
        }
        write_cmd(0x36);

}

出0入0汤圆

发表于 2013-3-20 12:21:45 | 显示全部楼层
额,这个问题我会遇到,我就把0x01写几遍。

出0入55汤圆

发表于 2013-3-20 12:50:52 | 显示全部楼层
去掉忙检测看看

出0入0汤圆

发表于 2013-3-20 14:53:33 | 显示全部楼层
本帖最后由 tangyu1211 于 2013-3-20 14:55 编辑
颜靖峰 发表于 2013-3-20 12:21
额,这个问题我会遇到,我就把0x01写几遍。


我现在也在用12864进行大字体显示时,碰到和LZ同样问题(大数字在显示时比较缓慢,不知是何原因),不知你是如何解决,请高手指点,谢谢

出0入0汤圆

发表于 2013-3-20 15:15:30 | 显示全部楼层
这个函数是清RAM的啊,如果你不清的话,肯定会花屏的,我以前用的时候也遇到过,要显示图片,就要加上这个函数,值显示文字的话则不必。建议你看下数据手册。

出0入0汤圆

发表于 2013-3-20 15:36:01 | 显示全部楼层
这个一般初始化完后,你直接写个清屏指令清一次屏

出0入0汤圆

发表于 2013-3-20 15:47:07 | 显示全部楼层
忙检测一下,估计就可以了,要不多加点延迟就搞定

出0入0汤圆

发表于 2013-3-21 13:22:47 | 显示全部楼层
这个问题,我已经解决了,是延时函数延时时间较长导致的.
void delay(uint z)                                                   //延时函数
{
        uint x,y;
        for(x=z;x>0;x--)
                for(y=5;y>0;y--);  / //时间太长,改为5
}

写指令和数据时间调用也相应改短
void write_cmd(uchar cmd)                                   //12864写指令
{
        check_lcd_busy();
        LCD_RS=0;
        LCD_RW=0;
        LCD_EN=0;
        P0=cmd;
       // delay(5); 去除
        LCD_EN=1;
        delay(1);///参数改为1
        LCD_EN=0;
}


void write_dat(uchar dat)                                          //12864写数据
{
        check_lcd_busy();
        LCD_RS=1;
        LCD_RW=0;
        LCD_EN=0;
        P0=dat;
        //delay(5);
        LCD_EN=1;
        delay(1););///参数改为1
        LCD_EN=0;
}




出0入0汤圆

 楼主| 发表于 2013-3-21 15:30:44 | 显示全部楼层
jssd 发表于 2013-3-20 12:50
去掉忙检测看看

不是忙检测的问题

出0入0汤圆

 楼主| 发表于 2013-3-21 15:32:03 | 显示全部楼层
颜靖峰 发表于 2013-3-20 12:21
额,这个问题我会遇到,我就把0x01写几遍。

额,请你把意思说明白

出0入0汤圆

 楼主| 发表于 2013-3-21 15:32:40 | 显示全部楼层
彼岸花开 发表于 2013-3-20 15:15
这个函数是清RAM的啊,如果你不清的话,肯定会花屏的,我以前用的时候也遇到过,要显示图片,就要加上这个 ...

嗯,谢谢了

出0入0汤圆

 楼主| 发表于 2013-3-21 15:34:14 | 显示全部楼层
莫回头 发表于 2013-3-20 15:36
这个一般初始化完后,你直接写个清屏指令清一次屏

显示图片用到DGRAM,你说的清屏指令是清DDRAM的

出0入0汤圆

 楼主| 发表于 2013-3-21 15:34:54 | 显示全部楼层
DiaoMao_Huang 发表于 2013-3-20 15:47
忙检测一下,估计就可以了,要不多加点延迟就搞定

不懂。。。。

出0入0汤圆

 楼主| 发表于 2013-3-21 17:09:18 | 显示全部楼层
tangyu1211 发表于 2013-3-21 13:22
这个问题,我已经解决了,是延时函数延时时间较长导致的.
void delay(uint z)                               ...

刚才试过了,一下子就快了,原来是延时时间太长了。
不愧是高手!!!一针见血!!!感谢感谢!!!

出0入0汤圆

发表于 2013-9-3 12:32:12 | 显示全部楼层
/*********************************************************
                                液晶采用串口通讯方式
*********************************************************/
#ifndef __LCD12864_H__
#define __LCD12864_H__
#define uchar unsigned char
#define uint  unsigned int
#include "zk.h"
#include "shengming.h"

/*========================定义12864液晶屏数据线=====================================*/
sbit LCM_PSB = P1^3;   //   
/*========================定义12864液晶屏数据线=====================================*/
sbit cs2=P1^4  ;
sbit LCM_cs   = P2^3;
sbit LCM_std  = P2^4;
sbit LCM_sclk = P2^5;/*==========================12864液晶显示屏并口驱动程序=============================*/
//===========检查忙位
void Delay123(int num)//延时函数
{
        while(num--);
}
void LCM_WriteDatOrCom(bit dat_comm,uchar content)
{
  uchar a,i,j;
  Delay123(10);
  a=content        ;
   LCM_cs=1;
  LCM_sclk=0;
  LCM_std=1;
  for(i=0;i<5;i++)
  {
    LCM_sclk=1;
    LCM_sclk=0;
  }
  LCM_std=0;
  LCM_sclk=1;
  LCM_sclk=0;
  if(dat_comm)
    LCM_std=1;   //data
  else
   LCM_std=0;   //command
  LCM_sclk=1;
  LCM_sclk=0;
  LCM_std=0;
  LCM_sclk=1;
  LCM_sclk=0;
  for(j=0;j<2;j++)
  {
    for(i=0;i<4;i++)
    {
      a=a<<1;
      LCM_std=CY;
      LCM_sclk=1;
      LCM_sclk=0;
    }
    LCM_std=0;
    for(i=0;i<4;i++)
    {
      LCM_sclk=1;
      LCM_sclk=0;
    }
  }
}
void lcd_pos(uchar X,uchar Y)//设定显示位置
{                          
   uchar  pos;
   if (X==1)
     {X=0x80;}
   else if (X==2)
     {X=0x90;}
   else if (X==3)
     {X=0x88;}
   else if (X==4)
     {X=0x98;}
   pos = X+Y ;
   LCM_WriteDatOrCom(0,pos);     //显示地址
}
//================写指令到LCD=============================
void write_com(uchar cmdcode)
{
        LCM_WriteDatOrCom(0,cmdcode);
}
//=================写数据到LCD==============================
void write_data(uchar Dispdata)
{        LCM_WriteDatOrCom(1,Dispdata);
}
//==========向LCM发送一个字符串,长度64字符之内============
void lcm_w_word(uchar *s)
{
        while(*s>0) { write_data(*s); s++; }  //应用:lcm_w_word("您好!");
}
/**************在X(行)Y(列)显示字符串********************/
void LCD_Display_String( uchar x,uchar y,uchar *str )
  {
    lcd_pos(x,y);         //先确定起始行和列
        while (*str!='\0')
      {
        write_data(*str);
            str++;
          }
  }
  void LCD_Display_Array( uchar x,uchar y,uchar *Array,uchar Lenth )
{
        lcd_pos(x,y);                           //先确定起始行和列
        while(Lenth--)
                {
                        write_data(*Array);
                        Array++;
                }
}
/******************************************************************************/
void lcm_w_test(bit i,unsigned char word){//写指令或数据(被调用层)
        if(i == 0){
                write_com(word);//写指令(0,指令)
        }else{
                write_data(word);//写数据(1,数据)
        }
}
//===========清屏函数=====================================
void lcm_clr(void)
{
        write_com(0x30);       
        write_com(0x01);
        delayms(5);       
}

//=========================================================

void lcm_clr2(void){//清屏上面3行(用空格填满要清显示的地方,因为液晶屏是静态显示的,所以这办法常用)
        lcm_w_test(0,0x80);//第一行
        lcm_w_word("                ");
            //标尺("1234567812345678"应该能够显示满一行)
        lcm_w_test(0,0x90);//第二行
        lcm_w_word("                ");
            //标尺("1234567812345678"应该能够显示满一行)
        lcm_w_test(0,0x88);//第一行
        lcm_w_word("                ");
            //标尺("1234567812345678"应该能够显示满一行)
}

//==================初始化LCD屏===============================
void lcm_init()
{  
        write_com(0x30);  //选择8bit数据流
        write_com(0x0c);  //开显示(无游标、不反白)
        lcm_clr();        //清除显示,并且设定地址指针为00H
        write_com(0x06);  //光标右移,DDRAM位址计数器(AC)加1,不整屏移动
        lcm_clr2();
}
/*-------------------使用绘图的方法让一个16*16的汉字符反白---------------------------
        形式参数:uchar x,uchar y,uchar wide,uchar bkcor
        行参说明:坐标水平位置,坐标垂直位置,反白行数,要反白还是清除(1:反白,0:清除)
-----------------------------------------------------------------------------------*/
void write1616GDRAM(uchar x,uchar y,uchar sign,uchar *bmp)       
{
        uchar i,j,basex;
        write_com(0x36);      //扩展指令,绘图模式命令,开显示也可以绘.(关图片显示0x34)
        if(y==1||y==2)          //第一第二行
        {
                basex=0x80;           //上半屏
                y=(y-1)*16;          //垂直位址从0X80开始.
        }
        if(y==3||y==4)        //第三第四行
        {
                basex=0x88;         //下半屏
                y=(y-3)*16;         //垂直位址都是从0X80开始的,不管上下半屏。
        }
        for(i=0;i<16;i++)        //
        {                                                                                                                       
                write_com(0x80+y+i);  //写入垂直位址。
                write_com(basex+x-1); //再写入水平位址(上半屏第一字为0X80,……第七字为0X87)
                                                           //下半屏第一字为0X88,……第七字为0X8F;
                for(j=0;j<2;j++)   //再写入两个8位元的数据,AC会自动增一,接着写数据
                {
                        if(sign==1)  
                                write_data(~(*bmp++));
                        else  
                                write_data(*bmp++);
                }
        }       
        write_com(0x36);  //写完数据,开图片显示     
}
/**********************************************************
//函数功能:使用绘图的方法让一行反白
//形式参数:uchar row,uchar bkcor
//行参说明:反白行数,要反白还是清除(1:反白,0:清除反白)
//返回参数:无
//使用说明:无
//**********************************************************/   

void setrowbkcolor(uchar row,uchar bkcor)       
{
        uchar i,j,basex,basey,color;
        if(bkcor==1)        color=0xff;          //全写入0XFF,反白。
        if(bkcor==0)        color=0x00;         //全写入0X00,消白。
        write_com(0x36);      //扩展指令,写图片时,关图片显示
        if(row==1||row==2)          //第一第二行
        {
                basex=0x80;           //上半屏
        }
        if(row==3||row==4)        //第三第四行
        {
                basex=0x88;         //下半屏
                row=row-2;         //垂直位址都是从0X80开始的,不管上下半屏。
        }
        basey=0x80+(row-1)*16;        //从哪一行的首行点阵开始
        for(i=0;i<16;i++)        //一行有16行点阵
        {                                                                                                                       
                write_com(basey+i);  //写入垂直位址。
                write_com(basex); //水平位址(上半屏第一字为0X80)//下半屏第一字为0X88;
                                                             
                for(j=0;j<16;j++)   //再写入两个8位元的数据,AC会自动增一,接着写数据
                        write_data(color);  
        }       
        write_com(0x36);  //写完数据,开图片显示     
}
/*=====================================================================================
        函数功能:显示16X32图形,适用于st7920型液晶
        形式参数:uchar x,uchar y,uchar *bmp
        行参说明:横坐标X列,纵坐标Y行,要显示的图形BMP
=====================================================================================*/           
void write1632GDRAM(uchar x,uchar y,uchar *bmp)       
{
        uchar i,j,basex,basey;
        switch(y)         //由y纵坐标定是上半屏还是下半屏
        {
          case 1: basex=0x80; break;  //上半屏
          case 2: basex=0x80; break;  //先上半屏,下面再下半屏。
          case 3: basex=0x88; break;  //下半屏
          default:   return;   //别的则返回
        }
        basey=basex+x-1;
        write_com(0x36);  
        if(y==1||y==3)        //如为第一第三行,则直接是在同一半屏,直接绘完32行点陈数据。
        {
                  for(i=0;i<32;i++)         //写入32行点阵
                  {                                                                                                               
                            write_com(0x80+i);        //先写入垂直位址,选上下32行的哪一行,
                                                                        //不管上下半屏,首行都为0X80
                            write_com(basey);        //再写入水平位址(选上下半屏)
                            for(j=0;j<2;j++)           //2个8位元的数据,即16BIT宽度
                                    write_data(*bmp++);   
                  }         
        }
        if(y==2)  //从第二行开始则画图将上下半屏都有,所以先画完上半屏16行,再画下半屏16行。
        {                                       
                  for(i=0;i<16;i++)         //写入上半屏16行点阵
                  {                                                                                                               
                            write_com(0x90+i);  //先写入垂直位址,选上下32行的哪一行,不管上下半屏,
                                                                        //首行都为0X80,第二行为0X90。
                            write_com(basey);        //(选上半屏)再写入水平位址
                            for(j=0;j<2;j++)           //2个8位元的数据,即16BIT宽度
                                    write_data(*bmp++);   
                  }
                  for(i=0;i<16;i++)         //写入下半屏16行点阵
                  {                                                                                                               
                            write_com(0x80+i);  //先写入垂直位址,选上下32行的哪一行,不管上下半屏,首行都为0X80
                            write_com(basey+8);   //(选下半屏)再写入水平位址
                            for(j=0;j<2;j++)           //2个8位元的数据,即16BIT宽度
                                    write_data(*bmp++);   
                  }         
        }
        write_com(0x36);  //写完数据,开图片显示     
}
/*=====================================================================================        
        函数名称: init_12864_GDRAM()
        功能描述: 在程写GDRAM时序初始化12864
=====================================================================================*/
void init_12864_GDRAM()         
{
        write_com(0x30);     //基本指令操作(扩充指令操作为:0x34)
        write_com(0x0C);     //整体显示ON,游标OFF,游标位置OFF
        write_com(0x06);           //光标右移,DDRAM位址计数器(AC)加1,不整屏移动
        lcm_clr();           //清屏 (清DDRAM)
}

/*======================================================================================
        函数名称:Clean_12864_GDRAM(void)                                               
        函数功能:清屏函数
        使用说明:GDRAM填满0
=======================================================================================*/
void Clean_12864_GDRAM(void)
{
    uchar x,y;
    write_com(0x36);
    init_12864_GDRAM();                //设置扩展指令集,按手册说明,仅设置了绘图位,
    write_com(0x36);        //需要两次,本次设置扩展指令集。
    for (y=0;y<32;y++)
    {
        write_com(0x80+y);  //设置y=1000+00xx,y+1则往下一行
        write_com(0x80);        //设置x=1000 0000
        for (x=0;x<16;x++)
        {
            write_data(0x00);   //高字节数据
            write_data(0x00);        //低字节数据
        }
    }
}
/*------------------显示图片------------------------*/

void Disp_Img(unsigned char code *img)
{  unsigned int j=0;
   unsigned char x,y,i;
       for(i=0;i<9;i+=8)
       for(y=0;y<32;y++)//原来 为 y<26 ,上下两个半屏不能正常对接显示,导致显示的图片中间有空隙           
         for(x=0;x<8;x++)
         {  write_com(0x36);//功能设置---8BIT控制界面,扩充指令集        
            write_com(y+0x80);        //行地址
            write_com(x+0x80+i);     //列地址
            write_com(0x30);
            write_data(img[j++]); //写数据还要回到基本指令集     
            write_data(img[j++]);
         }   
           
}

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

#endif
慢慢找吧。

出0入0汤圆

发表于 2013-9-3 12:35:09 | 显示全部楼层
lcm_clr2();                                //清屏
        Clean_12864_GDRAM();        //清屏
write1632GDRAM(地址,地址,字符(第几个));
我用串口的都不慢
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-10-3 05:03

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表