初始化LCD12864时遇到的有趣问题
最近在玩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) {
caseDT_Cmd:
LCD_Set_Status(OP_Write_Cmd);
break;
caseDT_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的初始化流程图和相关命令解释:
http://cache.amobbs.com/bbs_upload782111/files_46/ourdev_687498IDQ45A.JPG
(原文件名:LCD12864初始化流程图.JPG)
http://cache.amobbs.com/bbs_upload782111/files_46/ourdev_687499CSLVVV.JPG
(原文件名:进入点设定.JPG) 不错不错。。赞一个。。。 回复【1楼】kingwaykingway
-----------------------------------------------------------------------
啊……但是那两个问题我到现在还没搞懂…… 不好,参考一下51的代码。
#include<reg52.h>
#include<string.h>
#define uchar unsigned char
#define uintunsigned 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++));
} 回复【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) {
// caseDT_Cmd:
// LCD_Set_Status(OP_Write_Cmd);
// break;
// caseDT_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 == 0 && i != 1) LCD_Putchar('0');
else{
i_tmp = i;
break;
}
}
for(i = i_tmp; i > 0; i--) {
LCD_Putchar(0x30 + Num_Temp);
}
}
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);
} 直接移植!还是不行,只有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++));
} 4BIT时序图。
http://cache.amobbs.com/bbs_upload782111/files_46/ourdev_687817NAHPZ3.JPG
(原文件名:4BIT时序.JPG)
页:
[1]