本帖最后由 chinacn1989 于 2014-6-3 20:09 编辑
用的芯片是NUC120的片子(就是以前HOT大叔的开发板),用来驱动1602,看电平状态貌似都正常,时序也反复对应了的。就是没任何反应!
接口对应关系 :
PC7-1602EN
PC6-1602RW
PC15-RS
宏定义1602.h:#define LCD1602_RS GPIOC->DOUT.DOUT15
#define LCD1602_RW GPIOC->DOUT.DOUT6
#define LCD1602_EN GPIOC->DOUT.DOUT7
#define LCD1602_W(x) (GPIOA->u32DOUT &= (x<<2) | 0XFFFFFC03)
#define LCD1602_R ((GPIOA->u32PIN>>2) & 0xff)
void Lcd1602Init(void);
void Lcd1602DisChar(uint8_t row,uint8_t line,uint8_t data);
1602.c文件
#include"lcd1602.h"
#include"drvsys.h"
#include"init.h"
void delay(int8_t i)
{
while(i--);
}
uint8_t Lcd1602Busy(void)
{
uint8_t Busy;
LCD1602_RS = 0;
LCD1602_RW = 1;
delay(2);
LCD1602_EN = 1;
delay(8);
LCD1602_EN = 0;
delay(1);
Busy = LCD1602_R;
if(Busy & 0x80)
return 1;
else
return 0;
}
void Lcd1602WriteCmd(uint8_t cmd)
{
LCD1602_RS = 0; //Ö¸Áî
LCD1602_RW = 0; //дÈë
LCD1602_W(cmd);
delay(2);
LCD1602_EN = 1; //1602ʹÄÜ
delay(8);
LCD1602_EN = 0;
delay(2);
}
void Lcd1602WriteData(uint8_t cmd)
{
LCD1602_RS = 1; //дÊý¾Ý
LCD1602_RW = 0; //дÈë
LCD1602_W(cmd);
delay(2);
LCD1602_EN = 1; //1602ʹÄÜ
delay(6);
LCD1602_EN = 0;
delay(2);
}
void Lcd1602Init()
{
Lcd1602WriteCmd(0x38);
Delay10ms(1);
Lcd1602WriteCmd(0x38);
Delay10ms(1);
Lcd1602WriteCmd(0x38);
Delay10ms(1);
Lcd1602WriteCmd(0x38);
while(Lcd1602Busy());
Lcd1602WriteCmd(0x08);
while(Lcd1602Busy());
Lcd1602WriteCmd(0x01);
while(Lcd1602Busy());
Lcd1602WriteCmd(0x06);
while(Lcd1602Busy())
Lcd1602WriteCmd(0x0c);
while(Lcd1602Busy());
}
void Lcd1602DisChar(uint8_t row,uint8_t line,uint8_t data)
{
uint8_t addr;
addr = 0x80+(row-1)*0x40+line;
Lcd1602WriteCmd(addr);
while(Lcd1602Busy())
DrvSYS_Delay(100);
Lcd1602WriteData(data);
while(Lcd1602Busy())
DrvSYS_Delay(100);
}
最开始的时候没有加delay延时,都是用检测忙的命令。但是去百度了下,发现延时的比较多。然后就加了一些延时!!
程序有什么需要优化建议希望大家多喷哈!
谢谢...
PS:
关于1602的时序相关资料
LCD1602的读写时序
LCD1602字符点阵液晶现在已经很常用了。自己学习LCD1602中遇到了很多的问题,但是最主要的还是对1602写命令字,写数据,以及读状态时的时序控制不理解。看看了开发板自带的示例程序,人家写的程序烧到片子里就能运行,而自己写的就不行。很是纳闷啊,仔细研究了他们写的源程序,发现还是自己时序控制的不对。把他们写的程序拿出来和1602的时序操作顺序图一对照,才发现人家看似毫无章法的延时其实都是严格按照1602的时序来写的。
所谓1602指的是现实的内容位16*2,即可以显示两行,每行两个字符。目前市面上的液晶大部分都是基于HD44780控制器的。又14或者16个引脚。HD44780内置了DDRAM(80字节),CGRAM(64字节,用来存放用户自定义字符,每个字符需要用到8个字节,所以以一共可以存放8个用户自定义字符),CGROM(内存了160个字符,包括了标准的ASCII码表上的字符和一些日文假名什么的)。
写操作时序:
读操作时序:
时序操作参数:
图上第一条竖线画面在了RS和R/W上,也就是说首先应该从这里开始,即先将RS设为高或低(高表示数据读或写,低表示指令读或写),而R/W的高低代表是读还是写,上一张图是写时序图,所时是低的。
接着就是先把使能信号E置底,然后可以延时一小会儿(自己买的开发板自带的示例程序上都带有延时,可是根据操作时序图上面画出来的时序,这个地方根本不需要延时的,不过延时也不会出错,就把它理解成为是数据线上电平的变化也是需要时间的);
然后数据线上送数据,从上图的写操作时序图上可以看出,数据线上送完数据后需要延时tsp2(称之为数据建立时间)的时间后才能把E拉高,注意Tsp2的最小时间要求是40ns,最大时间没有要求;
接下来一步就是把E置高电平,并且至少保持Tpw(E脉冲宽度)的时间(150ns,也是很小的);
延时完成后再把E置为低电平就可以把数据写入1602了。最后不需要延时就行。
最后还有一点需要注意的问题就是,时序操作参数表中的各参数的单位都是ns,时间是很短的,而对于51系列单片机如果晶振采用12MHz的话,每个机器周期就有1us,大大超过了参数要求的延时时间,所以有时候就算没有严格按照时序来编写程序,还是能够驱动1602,。但是如果对于那些采用高晶振的高性能单片机来说就不行了。所以最好还是按照时序一步一步来操作,这样才是万无一失的。
下面是对LCD1602进行操作的时候常用到的几个函数:
bit lcd_busy() //忙检测函数
{
bit result;
RS=0;
RW=1;
EN=0;
_nop_();
EN=1;
_nop_(); //按照技术手册上的说明此处只需要延时150ns以上即可,但是经过proteus仿真反复验
_nop_(); //延 时至少四个机器周期,为什么呢?
_nop_();
_nop_();
result=(bit)(P0&0x80);
_nop_();
EN=0;
return result;
}
写命令函数:
void lcd_wcmd(unsigned char cmd)
{
while(lcd_busy());
RS=0;
RW=0;
EN=0;
P0=cmd;
_nop_(); //此处至少延时1个周期,最好也延时两到四个周期
EN=1; //此处延时至少四个周期
_nop_();
_nop_();
_nop_();
_nop_();
EN=0;
}
写数据函数:
void lcd_wdat(unsigned char dat)
{
while(lcd_busy());
RS=1;
RW=0;
EN=0;
P0=dat;
_nop_(); //此处至少延时1个周期,最好也延时两到四个周期
EN=1;
_nop_(); //此处至少延时四个周期
_nop_();
_nop_();
_nop_();
EN=0;
}
|