搜索
bottom↓
回复: 6

初始化LCD12864时遇到的有趣问题

[复制链接]

出0入0汤圆

发表于 2011-10-22 21:56:16 | 显示全部楼层 |阅读模式
最近在玩LCD12864,M051驱动,为了节省硬件引脚开支,采用4线驱动。
硬件连接:P2.7-P2.4 → D7-D4;  
          P2.1 → RS;
          P2.2 → RW;
          P2.3 → E。

之前有做过LCD1602的4线模式,而1602和12864的大部分指令集是兼容的,当初写1602的库时,是直接从网上拿的他人的初始化代码,没有深入研究。我基本没对原始库做任何改动,初始化12864就成功了,也显示了出来,改了一下显示位置的函数,整屏显示都没问题了,今天突然想研究下初始化,于是拿出DATASHEET细细看了一番。按照datasheet的初始化流程怎么也不成功,忒奇怪,后来好不容易搞定。

原因是:我在写4BIT的数据发送程序时,先发高四位,在发低四位,而4BIT模式下,初始化只要求发高4位,我加了个标志位,就搞定了。贴上代码:
void LCD_Send_Data(unsigned char Data_Type, unsigned char Data, unsigned char ChkBF){
    if(ChkBF)  LCD_Check_Busy();
    switch (Data_Type) {
    case  DT_Cmd:
        LCD_Set_Status(OP_Write_Cmd);
        break;
    case  DT_Data:
        LCD_Set_Status(OP_Write_Data);
        break;
    }

    LCD_Bus_Port &= 0x0F;
    LCD_Bus_Port |= (Data & 0xF0);         /* High 4bits */
    LCD_Positive_Pulse();

    System_Delay_Ms(15);

if(!Init_Flag) {
        LCD_Bus_Port &= 0x0F;
        LCD_Bus_Port |= ((Data & 0x0F) << 4);  /* Low 4 bits */
        LCD_Positive_Pulse();
    }

    if(ChkBF)  LCD_Check_Busy();
}

以上是发送数据的代码,改好后的初始化代码如下:

void LCD_Init(void){
System_Delay_Ms(800);
    Init_Flag = 1;
LCD_Send_Data(DT_Cmd, 0x20, 0);   /* 4BIT传送模式,只发高四位 */
    Init_Flag = 0;
    System_Delay_Ms(15);
LCD_Send_Data(DT_Cmd, 0x02, 0);   /* 复位AC位置 */
    System_Delay_Ms(15);
    LCD_Send_Data(DT_Cmd, 0x0C, 1);          /* 显示开启,无游标,无反白 */
    LCD_Send_Data(DT_Cmd, 0x06, 1);          /* 游标移动方向为正 */
    LCD_Send_Data(DT_Cmd, 0x01, 1);          /* 清除显示屏 */
    System_Delay_Ms(100);
}

上面的这段代码可以正常工作。如果不加入对标志位的控制,把第一条初始化指令改为0x03,则也能完成初始化!只是有点不太稳定。代码如下。

void LCD_Init(void){
System_Delay_Ms(800);
    Init_Flag = 0;
LCD_Send_Data(DT_Cmd, 0x03, 0);
//    Init_Flag = 0;
LCD_Send_Data(DT_Cmd, 0x20, 0);  /* 4BIT模式了 */
LCD_Send_Data(DT_Cmd, 0x00, 0);
    System_Delay_Ms(15);
LCD_Send_Data(DT_Cmd, 0x0C, 1);
LCD_Send_Data(DT_Cmd, 0x06, 1);
    LCD_Send_Data(DT_Cmd, 0x01, 1);
    System_Delay_Ms(100);
}

我好奇了,于是继续更改初始化代码。

void LCD_Init(void){
System_Delay_Ms(800);
    Init_Flag = 0;
LCD_Send_Data(DT_Cmd, 0x03, 0);  /* 如果直接去掉这条指令,初始化就不成功 */
System_Delay_Ms(15);
//    Init_Flag = 0;
LCD_Send_Data(DT_Cmd, 0x02, 0);  /* 设置4BIT模式 */
// LCD_Send_Data(DT_Cmd, 0x00, 0);
    System_Delay_Ms(15);
LCD_Send_Data(DT_Cmd, 0x0C, 1);
LCD_Send_Data(DT_Cmd, 0x06, 1);
    LCD_Send_Data(DT_Cmd, 0x01, 1);
//    LCD_Send_Data(DT_Cmd, 0x06, 1);
    System_Delay_Ms(100);
}

这段代码还是可以工作!!而且很稳定。但是如果把首先发的0x03这条命令去掉,就不行了,先发0x02再发0x20还是不行。这是第一个奇怪的问题。

第二个奇怪的问题就是:对于进入点设定指令0x06(游标右移),必须放在清屏指令0x01之前,否则初始化也不成功!

贴上ST7920的初始化流程图和相关命令解释:


(原文件名:LCD12864初始化流程图.JPG)


(原文件名:进入点设定.JPG)

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

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!

出0入0汤圆

发表于 2011-10-22 22:29:23 | 显示全部楼层
不错不错。。赞一个。。。

出0入0汤圆

 楼主| 发表于 2011-10-22 22:37:10 | 显示全部楼层
回复【1楼】kingwaykingway
-----------------------------------------------------------------------

啊……但是那两个问题我到现在还没搞懂……

出0入0汤圆

发表于 2011-10-23 14:44:33 | 显示全部楼层
不好,参考一下51的代码。

#include<reg52.h>
#include<string.h>
#define uchar unsigned char
#define uint  unsigned int
#define DATA 1
#define COMMAND 0
sbit rs=P1^0;
sbit rw=P1^1;
sbit en=P1^2;
sbit psb=P1^3;
sbit rst=P1^4;

void delayUs(uint z);
void init();
void writeByte(uchar flag, uchar content);
void writeBytes(uchar address,uchar *buffer);

void main()
{
init();
writeBytes(0x80,"我爱祖国");
while(1);
}
void delayUs(uint z)  
{
while(z--);
}
void init()
{
rst=0;
delayUs(40);
rst=1;
delayUs(40);
psb=1;
delayUs(8);
writeByte(COMMAND,0x20);  //基本指令集 4bit数据
delayUs(8);
writeByte(COMMAND,0x01);
delayUs(8);
writeByte(COMMAND,0x06);
delayUs(8);
writeByte(COMMAND,0x0c);
delayUs(8);
}
void writeByte(uchar flag,uchar content)
{
delayUs(1000);
en=0;
delayUs(5);
if(flag)
  rs=1;
else
  rs=0;
rw=0;
en=1;
P0=content&0xf0;//数据高4位放到P0口高四位上

delayUs(10);
en=0;
if(flag)
  rs=1;
else
  rs=0;
delayUs(5);
rw=0;
en=1;
P0=(content<<4)&0xf0;//数据低4位放到P0口高四位上
en=0;
}
void writeBytes(uchar address,uchar *buffer)
{
uchar i;
i=strlen(buffer);
writeByte(COMMAND,address);
for(;i>0;i--)
  writeByte(DATA,*(buffer++));
}

出0入0汤圆

 楼主| 发表于 2011-10-23 15:09:21 | 显示全部楼层
回复【3楼】machao
-----------------------------------------------------------------------

我按照这样的风格修改了代码,0x20依然不行。

#include "LCD12864.h"

extern void System_Delay_Ms(unsigned int Delay_Time);

static unsigned char Init_Flag;

void LCD_Delay(unsigned int Delay){
    while(Delay) {
        Delay--;
    }
}

void LCD_Positive_Pulse(void){
    LCD_E = 1;
    LCD_Delay(300);
    LCD_E = 0;
}

void LCD_Set_Status(unsigned char Operation_Type){
    switch (Operation_Type) {
    case OP_Read_Status:
        LCD_RS = 0;
        LCD_RW = 1;
        break;
    case OP_Write_Cmd:
        LCD_RS = 0;
        LCD_RW = 0;
        break;
    case OP_Read_Data:
        LCD_RS = 1;
        LCD_RW = 1;
        break;
    case OP_Write_Data:
        LCD_RS = 1;
        LCD_RW = 0;
        break;
    }
}

void LCD_Check_Busy(void){
    unsigned char Busy_Flag;
        unsigned char Data_Tmp;
    do {
        LCD_Set_Status(OP_Read_Status);
//        LCD_Delay(40);                   /* Address set up time */
        LCD_E = 1;
                LCD_Delay(1000);
        Data_Tmp = LCD_Bus_Pin;
                Data_Tmp &= 0xF0;                   /* 获得高四位 */               
                LCD_E = 0;

                LCD_E = 1;
                LCD_Delay(1000);
                Busy_Flag = LCD_Bus_Pin;
                Busy_Flag >>= 4;
                Busy_Flag = Busy_Flag | Data_Tmp;        
                LCD_E = 0;
    } while (Busy_Flag & 0x80);
}

void LCD_Send_Data(unsigned char Data_Type, unsigned char Data, unsigned char ChkBF){
    if(ChkBF)  LCD_Check_Busy();
//    switch (Data_Type) {
//    case  DT_Cmd:
//        LCD_Set_Status(OP_Write_Cmd);
//        break;
//    case  DT_Data:
//        LCD_Set_Status(OP_Write_Data);
//        break;
//    }
        if(Data_Type == DT_Cmd)  LCD_RS = 0;
        else LCD_RS = 1;
        LCD_RW = 0;
        LCD_Bus_Port &= 0x0F;
        LCD_E = 1;
    LCD_Bus_Port |= (Data & 0xF0);         /* High 4bits */
//        LCD_Delay(1000);
        LCD_E = 0;
//    LCD_Positive_Pulse();

    System_Delay_Ms(15);

        if(!Init_Flag) {
            if(Data_Type == DT_Cmd)  LCD_RS = 0;
            else LCD_RS = 1;
            LCD_RW = 0;
            LCD_Bus_Port &= 0x0F;
            LCD_E = 1;
        LCD_Bus_Port |= ((Data & 0x0F) << 4);  /* Low 4 bits */
//                LCD_Delay(1000);
                LCD_E = 0;
//        LCD_Positive_Pulse();
    }

    if(ChkBF)  LCD_Check_Busy();
}

void LCD_Clear(void){
    LCD_Send_Data(DT_Cmd, 0x01, 1);
    System_Delay_Ms(20);
}

void LCD_Putchar(unsigned char c){
    LCD_Send_Data(DT_Data, c, 1);
    System_Delay_Ms(2);
}

void LCD_Putstring(unsigned char* Str){
    while(*Str) {
        LCD_Putchar(*Str);
        Str ++;
    }
}

void LCD_Gotopos(unsigned char Row, unsigned char Column){
    unsigned char LCD_Addr;
        if(Row <= 2) {
                LCD_Addr = 0x80 + (Row - 1) * 0x10 + (((Column - 1)) % 8);
        }
        else
                LCD_Addr = 0x88 + (Row - 3) * 0x10 + (((Column - 1)) % 8);
        LCD_Send_Data(DT_Cmd, LCD_Addr, 1);
}

void LCD_Putnumber(unsigned int Number, unsigned char Width){
    unsigned char Num_Temp[]={0};
    unsigned char i, i_tmp;
    for(i = 0; i < Width; i++) {
        Num_Temp = Number % 10;
        Number /= 10;
    }
    for(i = Width; i > 0; i--) {
        if(Num_Temp[i-1] == 0 && i != 1) LCD_Putchar('0');
        else{
            i_tmp = i;
            break;
        }
    }
    for(i = i_tmp; i > 0; i--) {
        LCD_Putchar(0x30 + Num_Temp[i-1]);
    }
}

void LCD_Init(void){
        System_Delay_Ms(800);
        LCD_RESET = 0;
        System_Delay_Ms(1);
        LCD_RESET = 1;

        LCD_Send_Data(DT_Cmd, 0x20, 0);
        System_Delay_Ms(15);
//    Init_Flag = 0;
//        LCD_Send_Data(DT_Cmd, 0x02, 0);
//        LCD_Send_Data(DT_Cmd, 0x00, 0);
    System_Delay_Ms(15);
        LCD_Send_Data(DT_Cmd, 0x01, 1);
            System_Delay_Ms(15);

        LCD_Send_Data(DT_Cmd, 0x06, 1);
    System_Delay_Ms(15);

    LCD_Send_Data(DT_Cmd, 0x0c, 1);
    System_Delay_Ms(15);

//    LCD_Send_Data(DT_Cmd, 0x06, 1);
    System_Delay_Ms(100);
}

出0入0汤圆

 楼主| 发表于 2011-10-23 15:38:32 | 显示全部楼层
直接移植!还是不行,只有0x02能通过初始化。

#include "LCD12864.h"

extern void System_Delay_Ms(unsigned int Delay_Time);

void delayUs(uint z)   
{
while(z--);
}
void init(void)
{
System_Delay_Ms(400);
rst=0;
System_Delay_Ms(1);
rst=1;
System_Delay_Ms(15);
// psb=1;
System_Delay_Ms(15);
writeByte(CMD,0x02);  //基本指令集 4bit数据
System_Delay_Ms(15);
//  writeByte(CMD,0x02);  //基本指令集 4bit数据
System_Delay_Ms(15);
writeByte(CMD,0x01);
System_Delay_Ms(15);
writeByte(CMD,0x06);
System_Delay_Ms(15);
writeByte(CMD,0x0c);
System_Delay_Ms(15);
}
void writeByte(uchar flag,uchar content)
{
System_Delay_Ms(15);
en=0;
System_Delay_Ms(15);
if(flag)
  rs=1;
else
  rs=0;
rw=0;
P2_DOUT &= 0x0f;
en=1;
P2_DOUT |= content & 0xf0;//数据高4位放到P0口高四位上

System_Delay_Ms(1);
en=0;  
if(flag)
  rs=1;
else
  rs=0;
System_Delay_Ms(15);
rw=0;
P2_DOUT &= 0x0f;
en=1;
P2_DOUT |= (content<<4) & 0xf0;//数据低4位放到P0口高四位上
en=0;  
}  
void writeBytes(uchar address,uchar *buffer)
{
uchar i;
i=strlen(buffer);
writeByte(CMD,address);
for(;i>0;i--)
  writeByte(DATA,*(buffer++));  
}

出0入0汤圆

 楼主| 发表于 2011-10-23 15:41:26 | 显示全部楼层
4BIT时序图。


(原文件名:4BIT时序.JPG)
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2024-4-24 08:04

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

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