可能对于初学者来说,控制LCD1602比较难,或许还只是停留在调库的阶段,那么如果你能耐心看完本篇,我保证你就算没有单片机,给你一个电池,一堆导线,你就能手工控制它!!!关于液晶屏显示原理如果有兴趣的可以了解一下光的偏振,然后再了解一下液态晶体的旋光性即可,具体不再赘述。我们知道LCD1602在控制时主要起作用的有8根数据线,3根控制线。对于纯小白来说,在弄懂如何控制液晶屏之前,你要知道什么是时钟信号。
时钟信号
------时钟信号的含义可能比较宽泛,但我们今天要说的是关于同步通信是所采用的时钟线上传输的时钟信号。下面我举一个例子来解释一下时钟信号是干什么的,以及怎么用:
------想象一下你是一个快递员,每天你都要送包裹,但由于现在是疫情期间,人与人之间要避免接触。所以你每次送包裹时都是先将包裹放到客户门口,然后去敲一下窗户。随后期待拆快递的客户立即就打开门把快递抱进去。好了,美妙的幻想到此为止。现在我们该回到电路上了。我这里画电路图展示效果较好的只有Proteus了,凑合着看吧。。。------这里我将各个引脚连到arduino的(D2~D12)IO口上,因为你上传程序时所用的串口就是D0和D1,所以我习惯先避开这两个口,实在没有资源来才来用这两个IO。如你所愿,这样的控制方式使你的单片机数字IO资源几乎占用殆尽。后面我们再说解决办法。
------对了,还有一点就是VSS是供电的负极,VDD是供电的正极,VEE是调节的偏压,其作用是控制液晶显示的对比度。如果哪个朋友真的拿了一块液晶屏按照这一期教程试了一下但并没有显示成功,首先你要考虑你有没有按照如图所示电路给VEE一个偏压信号(加一个可调电阻即可,阻值建议在1KΩ~10KΩ之间),从而使显示的对比度达到你能看清的程度。
控制原理
------好了,要点和注意事项讲清楚了,下面我们就应该进入控制环节了。首先我们来看8根数据线,这8根数据线就是我们传信息的通道。正如我们上文送快递的比喻,这8根线就代表客户的门。我们再看液晶屏上有一个引脚叫做E,那这个是干什么用的呢?这个相当客户的窗户。我们需要把东西放在客户门前,就是我们要将我们发给液晶屏的信息转化为八位二进制,从而一位一位的摆在液晶屏的D0~D7这八个位上。然后敲一下窗户,让液晶屏把这八位二进制接收了。
------那么如何敲窗户呢?这就和E引脚有关了,E引脚叫做使能引脚,它就是窗户。那我们该如何敲它?答案是:给他一个上升沿!!!你不要告诉我你不知道什么是上升沿。好吧,如果你是一个小白,那么遇到我算你走运。我给你解释一下。请看如图所示电路:
------如上图,当按键松开时,探针检测到的电压就是0V,
而当按键按下时,电压则会变为+5V。如下图:
------因此,在按下开关,然后你一松手,开关又自动弹开。这个过程中你会获得一个如下的图所示的电压信号:这个波形由低变到高的一瞬间,就叫上升沿。而由高变成低的一瞬间就叫做下降沿。所以你只需要先将E脚接低电压,然后当要敲窗户时给一个瞬间的高脉冲即可。当它的E引脚检测到上升沿,它就会将你放在8位数据端的数据读进去。
------好了,这下应该弄明白了。那刚刚我们说主要控制的8根线还剩两根,分别是RS和RW。我们先来说一下RS,这个引脚的叫做数据/指令选择端。这如何理解?简单类比一下,你给客户送包裹的时候,会往每个包裹上贴一个便签,上面写好物品类型,比如易燃物,易碎品等等。客户收包裹时会将便签一起带进去,然后根据便签上的提示拆快递。液晶显示器除了接受你发给它想要让他显示的信息外,还要接受你的控制指令从而接受控制,比如说清屏就是一种指令。指令也是8位二进制。我们举个例子,如果你发了一串数(1 0 1 0 1 0 0 0)给屏幕,它怎么知道你给它发的是让它显示的信息还是一条让它执行的控制指令呢?这就是RS引脚的作用。你再给他发信息之前,如果将RS引脚接低电压,那么你发给它的信息就会被当作指令来执行。如果你将RS引脚接高电压,那么你发的信息就会被当作数据来显示到屏幕上。
------那么现在只剩下一个引脚RW了,这个更好理解。我们平时控制东西,不光是要给其发信息,还要接受其发送的信息。所以如果你给液晶屏发送一个指令,想要获取它目前的工作状态。那么就需要液晶屏给你发送消息了。这时候就有读和写的选择,所以涉及到了RW引脚。当你把RW引脚接低电压,那么就可以发信息给液晶屏,反之,液晶屏就会回发给你你想要的信息。不过我们一般之给液晶屏发信息即可。
-------还有,给液晶屏的数据是以ASCLL编码的二进制。不懂的请查阅ASCLL码表。我已经仁至义尽了哈哈。这就完事儿了?当然不,说了这么多,不实际操作一下又和纸上谈兵有什么两样?下面我们就来实际操作一下。(不过先说好,我的C语言比较基础,我可不会玩儿什么花活儿)
------我们以arduino为例,根据电路连接图,我们用Proteus做电路仿真(实际我找了块液晶也没问题)如图:
根据以上电路连接,我们编写C程序,先根据连接图给个宏定义吧,也让我凑个字数。
#define RS 10
#define RW 11
#define EN 12
#define D0 2
#define D1 3
#define D2 4
#define D3 5
#define D4 6
#define D5 7
#define D6 8
#define D7 9
然后我们在setup函数中把这些用到的IO全部设为输出模式:
void setup()
{
for(int i=2;i<13;i++)
{
pinMode(i,OUTPUT);
}
}
我传8位信息的方法是定义一个8位short型数组,然后将数组头指针传进发送函数里,发送函数将8位数组里面的8个元素分别分配到8位数据IO上并通过给E引脚高脉冲而将数据发出,程序如下:
short CMD_SETUP[8] = {0,1,1,0,0,0,0,0};//工作模式设定为每次写入数据光标右移且屏幕整体不滚动
short CMD_RUN[8] = {1,1,1,1,0,0,0,0};//开关设置设定为显示功能开且有闪烁的光标
short CMD_FUNCTION[8] = {0,0,0,1,1,1,0,0};//功能设置设定为8位数据总线、显示2行、每个字符点阵5*7个像素
short CMD_CLS[8] = {1,0,0,0,0,0,0,0}; //清屏、光标归位
short CMD_SENSOR_RESET[8] ={0,0,0,0,0,0,1,1}; //光标重置(只让光标归位)
short ascll_a[8] = {1,0,0,0,0,1,1,0}; //ascll码‘a’
short ascll_b[8] = {0,1,0,0,0,1,1,0}; //ascll码‘b’
void send_cmd(short*date) //指令发送函数
{
digitalWrite(RS,0); //将RS置为低电压,表明所发信息为指令
for(int i=0;i<8;i++) //循环将状态分配到8个IO口上
{
digitalWrite(i+2,*(date+i));
}
digitalWrite(EN,1); //将E口拉高
delay(3);
digitalWrite(EN,0); //将E口拉低
}
void send_dat(short*date) //数据发送函数
{
digitalWrite(RS,1); //将RS置为低电压,表明所发信息为所要显示的数据
for(int i=0;i<8;i++)
{
digitalWrite(i+2,*(date+i));
}
digitalWrite(EN,1);
delay(3);
digitalWrite(EN,0);
}
我们上来需要先给液晶显示器发送指令,控制其工作方式和工作状态。因此我们在setup函数里面调用send_cmd函数,将我们要发的控制指令发送给液晶屏。
void setup()
{
send_cmd(CMD_SETUP); //发送工作模式设定指令
delay(1000); //测试而已嘛,每条指令发完间隔一秒也无所谓,到需要的时候自己调喽
send_cmd(CMD_RUN); //发送开关设置指令
delay(1000);
send_cmd(CMD_FUNCTION); //发送功能设置指令
delay(1000);
}
然后我们就可以在loop函数中发送我们想要显示的数据了,如下:
void loop()
{
send_cmd(CMD_CLS); //发送清屏指令
delay(1000);
send_dat(ascll_a); //发送字母‘a’,使其显示在屏幕上
delay(1000);
send_dat(ascll_b); //发送字母‘b’,使其显示在屏幕上
delay(1000);
}
好啦,整体代码如下:其运行效果为不断在屏幕上显示a和b然后清屏,以此循环。
#define RS 10
#define RW 11
#define EN 12
#define D0 2
#define D1 3
#define D2 4
#define D3 5
#define D4 6
#define D5 7
#define D6 8
#define D7 9
short CMD_SETUP[8] = {0,1,1,0,0,0,0,0}; //工作模式设定
short CMD_RUN[8] = {1,1,1,1,0,0,0,0}; //开关设置
short CMD_FUNCTION[8] = {0,0,0,1,1,1,0,0}; //功能设置
short CMD_CLS[8] = {1,0,0,0,0,0,0,0}; //清屏
short CMD_SENSOR_RESET[8] ={0,0,0,0,0,0,1,1}; //光标重置
short ascll_a[8] = {1,0,0,0,0,1,1,0}; //ascll码‘a’
short ascll_b[8] = {0,1,0,0,0,1,1,0}; //ascll码‘b’
void send_cmd(short*date)
{
digitalWrite(RS,0);
for(int i=0;i<8;i++)
{
digitalWrite(i+2,*(date+i));
}
digitalWrite(EN,1);
delay(3);
digitalWrite(EN,0);
}
void send_dat(short*date)
{
digitalWrite(RS,1);
for(int i=0;i<8;i++)
{
digitalWrite(i+2,*(date+i));
}
digitalWrite(EN,1);
delay(3);
digitalWrite(EN,0);
}
void setup()
{
for(int i=2;i<13;i++)
{
pinMode(i,OUTPUT);
}
send_cmd(CMD_SETUP);
delay(1000);
send_cmd(CMD_RUN);
delay(1000);
send_cmd(CMD_FUNCTION);
delay(1000);
}
void loop()
{
send_cmd(CMD_CLS);
delay(1000);
send_dat(ascll_a);
delay(1000);
send_dat(ascll_b);
delay(1000);
}
显示效果:
这里只显示了a和b,如果有需要,可以另加字符二进制哦。希望对你有所帮助。得了,我去调库了。