LCD1602液晶显示器开发总结(中)

IMG_2233-1.jpg

本打算关于LCD1602液晶显示器写两篇就完结的,但是到目前看来,可能三篇内容都无法将其中所有的内容都囊括进去。很多人觉得Arduino非常简单,学一学就可以搞定,但殊不知你所能看到的都是那些简单额LED,或者电阻电容之类的元器件拼凑出来的简单货色。对于LCD1602而,则完全是一块独立的IC芯片。

前面我们做过简单的背景灯讲解。事实上,点亮背景灯和点亮一个LED没有任何差别。这篇文章要讲的内容,属于LCD1602中的一个核心内容。通过这篇文章,你能制作出最为简单的文本显示。但是要想增加功能,例如时间显示,自定义字符等,还得看后面得文章。

1111.png

上图是当前试验的电路图(存在一根跳线,不完美!)。你可以按照这个电路图来搭建你的试验电路。

本文的头图则是我连接完成的电路图。

功能管脚

上一篇文章中,我提及过LCD1602的功能管脚,管脚编号为4、5、6。你可以通过这三个管脚实现四个功能。

RS管脚和RW管脚的功能在这里不再赘述,E管脚和后面的时序相关。我们来看一个表格。

屏幕快照 2016-04-04 上午12.32.26.png

这里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个管脚进行对应。

屏幕快照 2016-04-04 上午12.52.50.png

在二进制数据中,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效果如下:

屏幕快照 2016-04-04 上午1.02.07.png