1602的相关概念这里就不赘述了,网上有好多现成的,比如1602工作原理
在里只大致记录下将时序转换成代码。
1602主要是用的最多的是写数据,接下来先讲下写操作时序。
先对使用的三个主要引脚做下解释,以下摘录自手册。
第 4 脚 : RS 为寄存器选择,高电平时选择数据寄存器、低电平时选择指令寄存器。第 5 脚 : R/W 为读写信号线,高电平时进行读操作,低电平时进行写操作。当 RS 和 R/W 共同为低电平时可以写入指令或者显示地址,当 RS 为低电平 R/W 为高电平时可以读忙信号,当 RS 为高电平 R/W 为低电平时可以写入数据。第 6 脚 : E 端为使能端,当 E 端由高电平跳变成低电平时,液晶模块执行命令。
一、写操作时序
在正式写指令寄器操作时(即上图中tpw开始的时间点),RS = 0, RW = 0, E = 0 所以读取数据之前直接将RS = 0, RW = 0,E = 0。设置完成之后需要在tsp1时间后才能将E拉成高电平, 且在将E拉到高电平之前需要提前效固定数据,即tsp2所示的时间,所以可以将数据写入端口,并延迟一断时间,再将E拉成高电平,延迟一断时间(tpw)等待数据操作完成。完成之后再将E拉成低电平。所以写指令的操作代码可以转换成如下:
void write_cmd(char cmd) {
busy_check();
RS = 0;
RW = 0;
EN = 0;
P0 = cmd;
_nop_(); // tsp2
EN = 1;
_nop_(); // tsw
EN = 0;
}
1602各时序参数都是ns为单位,单片机一个指令周期是1/11.0593MHZ = 90ns, 是完全可以的。
同理写地址操作也一样,只不过RS = 1。
void write_data(char d) {
busy_check();
RS = 1;
RW = 0;
EN = 0;
P0 = d;
_nop_(); //tsp2
EN = 1;
_nop_(); // tpw
EN = 0;
}
二、读操作时序
读操作时序这里有一个体现的地方,就是忙时检测。忙时检测时RS引脚为低电平,在正式读取数据之前可以将RS为了低电平 ,RW设置为高电平,E设置为低电平,另外需要在tsp1时间后才能将E拉成高电平,在tpw时间开始时后的td时间后才能读取有效数据,那么需要在tpw开始之后进行延时,读取完成之后将E拉成低电平即可。换算成代码如下:
void busy_check() {
char temp = 0x80;
P0 = 0X80;
while(temp & 0x80) {
RS = 0;
RW = 1;
EN = 0;
_nop_(); // tsp1
EN = 1;
_nop_(); // td
temp = P0;
EN = 0;
}
}
当然因为单片机执行的速度比液晶模块快,所以有些延迟其实是没有必要的,比如`busy_check`中的延迟都可以去掉并不影响执行结果。
三、源码(只是简单的进行显示)
#include "reg52.h"
#include <intrins.h>
#include <string.h>
#define dataBuffer P0;
sbit led = P3^7;
sbit RS = P1^0;
sbit RW = P1^1;
sbit EN = P1^4;
void Delay15ms() //@11.0592MHz
{
unsigned char i, j;
i = 27;
j = 226;
do
{
while (--j);
} while (--i);
}
void Delay5ms() //@11.0592MHz
{
unsigned char i, j;
i = 9;
j = 244;
do
{
while (--j);
} while (--i);
}
// 忙检测
void busy_check() {
char temp = 0x80;
P0 = 0X80;
while(temp & 0x80) {
RS = 0;
RW = 1;
EN = 0;
_nop_(); // tscp
EN = 1;
_nop_(); // td
temp = P0;
EN = 0;
}
}
void write_cmd(char cmd) {
busy_check();
RS = 0; // 写地址
RW = 0;
EN = 0;
P0 = cmd;
_nop_();
_nop_();
_nop_();
EN = 1;
_nop_();
EN = 0;
}
void write_data(char d) {
busy_check();
RS = 1;
RW = 0;
EN = 0;
P0 = d;
_nop_();
EN = 1;
_nop_();
_nop_();
_nop_();
EN = 0;
}
void init() {
Delay15ms();
write_cmd(0x38);
Delay5ms();
write_cmd(0x38);
write_cmd(0x08);
write_cmd(0x01);
write_cmd(0x06);
write_cmd(0x0c);
}
void Delay1000ms() //@11.0592MHz
{
unsigned char i, j, k;
_nop_();
i = 8;
j = 1;
k = 243;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void main() {
char temp[] = "hello everyone!";
char position = 0x80;
char dataShow = 'C';
int i = 0;
init();
write_cmd(position);//选择要显示的地址
for(i = 0; i < 15;i ++) {
write_data(temp[i]);
Delay1000ms();
}
//write_data(dataShow);//发送要显示的字符
while(1);
}
四,效果图: