A闪的 BLOG 技术与人文
本打算关于LCD1602液晶显示器写两篇就完结的,但是到目前看来,可能三篇内容都无法将其中所有的内容都囊括进去。很多人觉得Arduino非常简单,学一学就可以搞定,但殊不知你所能看到的都是那些简单额LED,或者电阻电容之类的元器件拼凑出来的简单货色。对于LCD1602而,则完全是一块独立的IC芯片。
前面我们做过简单的背景灯讲解。事实上,点亮背景灯和点亮一个LED没有任何差别。这篇文章要讲的内容,属于LCD1602中的一个核心内容。通过这篇文章,你能制作出最为简单的文本显示。但是要想增加功能,例如时间显示,自定义字符等,还得看后面得文章。
上图是当前试验的电路图(存在一根跳线,不完美!)。你可以按照这个电路图来搭建你的试验电路。
本文的头图则是我连接完成的电路图。
上一篇文章中,我提及过LCD1602的功能管脚,管脚编号为4、5、6。你可以通过这三个管脚实现四个功能。
RS管脚和RW管脚的功能在这里不再赘述,E管脚和后面的时序相关。我们来看一个表格。
这里0表示低电平,1表示高电平。通过两个管脚的状态切换,我们可以实现两组读写操作。一组针对指令寄存器,一组针对数据寄存器。
E管脚在写入操作的时候,我们需要使用高脉冲。在Arduino中,实现高脉冲的方法是开始时初始化E为0,然后置E为1,再清0。
为了能够更好的理解上面的两种实现方法,实例代码如下:
实现写入指令寄存器
digitalWrite(RS, LOW);
digitalWrite(RW, LOW);
实现E管脚的高脉冲操作
void pulse()
{
digitalWrite(E, LOW);
delayMicroseconds(1); // 延时1us
digitalWrite(E, HIGH);
delayMicroseconds(1); // 延时1us
digitalWrite(E, LOW);
delayMicroseconds(1); // 延时1us
}
注意:高脉冲操作时,对于E关键的电平操作,需要间隔1us才能有脉冲效果。
DB0——BD7 这8个管脚是8个双向数据通道,我们通过它可以向LCD1602传输数据,亦或是读取数据,对于这8个管脚,我依次接入了Arduino的8个IO口,顺序为9——2。
这个VL管脚,实则控制文字的对比度,当你将它接入GND时,需要增加一个电阻,用来控制对比度。我直接接入了一个220欧姆的电阻,理想情况下,你可以通过一个可变电阻来实现对比度的调节。
网上关于LCD1602在Arduino中实现的代码非茶多。但大多数都是吵来吵去,几乎没有变化。但其中一个最大的问题在于,这些代码都没有针对Arduino进行过优化。仅仅是实现了功能而已。在Arduino这种寸土寸金的设备中,节约每一个寄存器都是非常必要的(话说笔者写代码很多年都没有关注过内存问题了)。
我们来看一下,这里如何组织我们的数据。
Arduino中,属于16位操作。当你创建一个int类型的数据时,2个字节就没有了。但在LCD1602中,我们只有8个管脚。换句话说,我们只需要使用一个8位的数据类型即可。你可以选择char,或者选择byte类型,这样就可以在实际操作过程中节约1个字节。
好了,下面的内容,比较有意思,我们的数据是如何和这些管脚结合到一起的。
当我们拥有一个byte类型的数据,其职位0x38。这里0x38是计算机中16进制的表示方法。对应位二进制,为 0011 1000。看下图,我们将这个数值与8个管脚进行对应。
在二进制数据中,0表示低电平,1表示高电平。我们根据这个数据的每一位对应到管脚的电平操作。
通过一个循环操作即可完成我们想要的效果。代码片段如下:
int i = 0;
for (i = DB[0]; i >= DB[7]; i--)
{
digitalWrite(i, value & 01);
value >>= 1;
}
上面代码中的 逻辑and(&) 操作是取当前二进制数据的最后一位。
>>
则是带符号右移,当获取末尾比特后,我们将整个二进制数据向右移动一位,在此进行获取末尾比特操作。
通过这段代码,你可以在LCD1602中完整的显示一行字符。具体其中的逻辑我会放到下篇文章讲解。
int RS = 12;
int RW = 11;
int E = 10;
int DB[] = {9,8,7,6,5,4,3,2};
void pulse()
{
digitalWrite(E, LOW);
delayMicroseconds(1); // 延时1us
digitalWrite(E, HIGH);
delayMicroseconds(1); // 延时1us
digitalWrite(E, LOW);
delayMicroseconds(1); // 延时1us
}
void Write_Command_LCD(byte value)
{
digitalWrite(RS, LOW);
digitalWrite(RW, LOW);
int i = 0;
for (i = DB[0]; i >= DB[7]; i--)
{
digitalWrite(i, value & 01);
value >>= 1;
}
pulse();
}
void Write_Data_LCD(byte value)
{
digitalWrite(RS, HIGH);
digitalWrite(RW, LOW);
int i = 0;
for (i = DB[0]; i >= DB[7]; i--) {
digitalWrite(i, value & 01);
value >>= 1;
}
pulse();
}
void initLCD()
{
delay(15);
Write_Command_LCD(0x38);
delay(5);
Write_Command_LCD(0x38);
delay(5);
Write_Command_LCD(0x38);
Write_Command_LCD(0x06);
Write_Command_LCD(0x0E);
Write_Command_LCD(0x01);
Write_Command_LCD(0x80);
}
void setup() {
int i = 0;
for (i = 2; i <= 13; i++) {
pinMode(i, OUTPUT);
}
initLCD();
}
void writeNum()
{
Write_Command_LCD(0x01);
delay(10);
Write_Command_LCD(0x80 + 0);
delay(10);
Write_Data_LCD('w');
Write_Data_LCD('w');
Write_Data_LCD('w');
Write_Data_LCD('.');
Write_Data_LCD('a');
Write_Data_LCD('s');
Write_Data_LCD('h');
Write_Data_LCD('a');
Write_Data_LCD('n');
Write_Data_LCD('.');
Write_Data_LCD('o');
Write_Data_LCD('r');
Write_Data_LCD('g');
}
boolean running = 0;
void loop (void) {
if(running==false)
{
writeNum();
running = true;
}
}
代码编译后烧录到Arduino效果如下: