用于 Arduino 的 Print 派生串口 LCD 库






4.67/5 (8投票s)
一个全新的、功能强大的、基于 'Print' 类的 Arduino 串口 LCD 库。
引言
LCD 显示屏主要用于基于 Arduino 的系统中,以显示应用程序的输出。它们价格便宜、随处可得、易于使用。因此,你可以在市场上找到各种各样的 LCD 显示屏。一个缺点是它会占用 Arduino 板上过多的引脚。作为一种解决方案,串口 LCD 显示屏应运而生,这得感谢善良的制造商们 :)
背景
Arduino IDE 自带一个用于基于 Hitachi-HD44780 的 LCD([4])的 LiquidCrystal
库([3])。你可以根据需要选择并写入寄存器来命令控制器。在 4 位使用模式下,你需要使用 Arduino 14 个数字引脚中的 6 个。真是浪费。
图 1:一个 2x16 LCD
基于 Hitachi 的控制器提供的一些功能
- 定位光标
- 设置光标类型(隐藏、下划线、闪烁)
- 滚动显示(向左、向右)
- 显示屏开/关
- 清屏
LiquidCrystal
库通过向 Hitachi 控制器发送指令来暴露这些功能。专用引脚在构造函数中指定。
让我们看一个例子:
#include <Arduino.h> #include <LiquidCrystal.h> /* Pin configuration: LCD pin <=> Arduino Digital ----------------------------- register select <=> 12 enable <=> 11 data4 <=> 2 data5 <=> 3 data6 <=> 4 data7 <=> 5 */ LiquidCrystal lcd(12,11,2,3,4,5); void setup() { lcd.begin(16,2); // specify columns & rows count lcd.print("that is a test"); delay(5000); lcd.clear(); // clear screen lcd.setCursor(1,1); // second column of second row } void loop() { while(1); }
在代码的开头,一个带有给定引脚配置的 LiquidCrystal
实例 (lcd
) 被创建。该库使用此引脚配置向 LCD 发送命令和数据。
LiquidCrystal lcd(12,11,2,3,4,5);
在 setup
函数中,LCD 会用其列数和行数进行初始化。当库设置光标位置时会使用这些信息。
lcd.begin(16,2); // specify columns & rows count
例如,如果你想将光标移动到第二行的第二列,目标光标位置是使用在 begin
函数中提供的值来决定的。下一次的 print
将从该位置开始。
lcd.setCursor(1,1); // second column of second row
我希望这个示例足以说明如何使用 LiquidCrystal
库来操作 LCD。
串口 LCD
现在,是时候谈谈串口 LCD 了。当使用串口 LCD 时,那些底层的驱动问题被转移到了另一个微控制器上。你命令这个微控制器,然后它再命令 LCD(Hitachi 控制器)。为此,它为你提供了一个仅需一根线的串行接口。信息流是单向的,从 Arduino 到串口 LCD,因此它只需要你的 Arduino 的一个数字引脚。你只需使用 HardwareSerial
([7])或 SoftwareSerial
([8])的发送线与你的串口 LCD 通信。
图 2:一个串口 LCD(使用 SoftwareSerial
连接)
我在这个库中所做的是为我特定的串口 LCD([1])实现通信协议([2])。我的实现与 LiquidCrystal
有类似的功能,你可能也想到了,因为两者都基于 Hitachi 控制器。
发送给串口 LCD 的命令由带参数的单字节指令组成。要驱动串口 LCD,你需要通过串口发送这些命令。
命令:设置背光
命令字节:0x80
参数:0x00-0xFF (0-255),对应 0%-100% 的亮度
命令:设置波特率(重置后),默认为 9600
命令字节:0x81
参数:0x00-0x0A (0-10),对应的值为 300, 1200, 2400, 2400, 9600, 14400, 19200, 28800, 38400, 57600, 115200
以下命令控制 LCD 的行为,并且都以 0xFE 命令字节为前缀。
命令:清屏,并将光标位置设置为 0
命令字节:0x01(无参数)
命令:光标右移
命令字节:0x14(无参数)
命令:光标左移
命令字节:0x10(无参数)
命令:显示向右滚动
命令字节:0x1C(无参数)
命令:关闭显示(背光不变)
命令字节:0x08(无参数)
命令:打开显示
命令字节:0x0C(无参数)
命令:下划线光标
命令字节:0x0E(无参数)
命令:闪烁光标
命令字节:0x0D(无参数)
命令:关闭光标(如果显示屏是开启的)
命令字节:0x0C(无参数)
命令:设置光标位置
命令字节:0x80
参数:1 字节的位置索引,从 0 开始(左上角)
命令:切换启动画面
命令字节:0x1E(无参数)
(我曾为串口 LCD 开发过另一个库([9]),但在设计和功能方面不够好。我更倾向于将其视为一次实验性研究。)
使用代码
这是 SerialLcd2
的类声明
class SerialLcd2: public Print { protected: // underlying stream connected to serial LCD. // can be HardwareSerial or SoftwareSerial Stream* _Stream; public: // constructor SerialLcd2(Stream* stream): _Stream(stream) { }; // override for Print::write(uint8_t) size_t write(uint8_t b) { return this->_Stream->write(b); }; // line feed, same as print('\n'); void printLine() { this->write(SL_CHR_LF); }; // back space void del() { this->write(SL_CHR_BCK); }; // direction: SL_CMD_CURSOR_MV_R|SL_CMD_CURSOR_MV_L void moveCursor(uint8_t cmd); // cmd = SL_CMD_CURSOR_OFF|SL_CMD_CURSOR_UNDERLINE|SL_CMD_CURSOR_BLINK void showCursor(uint8_t cmd); // pos: 0..(max chars-1) void setCursorPos(uint8_t pos); // clear screen void clr(); // backlight: 0-255 void setBacklight(uint8_t b); // direction: SL_CMD_SCROLL_R|SL_CMD_SCROLL_L void scrollScreen(uint8_t cmd); // on if true void displayOn(bool); // toggle splash screen display. void toggleSplash(); // set baud rate void setBaudRate(uint8_t); };
我在这里做的是实现了串行通信协议和一些其他方便的函数。
让我们看一个例子。
SerialLcd2* lcd; // pointer for SerialLcd2 Stream* s; // stream to be connected
要通过硬件串口 (Serial) 连接,我们首先需要初始化 Arduino 的串口。我没有更改我的 LCD 的波特率,因此连接的波特率将是 9600 bps。
Serial.begin(9600); s = &Serial; // connect to tx(pin 1)
如果我们想用 SoftwareSerial
连接,也需要类似的初始化,只是我们必须为 SoftwareSerial
预留引脚。
SoftwareSerial ss(2,3); // rx=2, tx=3(connection) ss.begin(9600); s = &ss;
然后用它的串行 Stream
([6]) 创建一个 SerialLcd2
实例。
lcd = new SerialLcd2(s);
注意!我们应该将 Stream
的发送线连接到 LCD 的接收线,这是它唯一的通信线路。
现在,我们准备好使用它了。
首先,我们可以像 Print
类([5])一样打印任何东西,无需任何进一步处理。这是通过重写 Print
类的虚函数 write
来实现的,因为 Print
类在所有打印版本中都使用它。
lcd->print(1); // integer lcd->print('A'); // char lcd->print(0.1); // float lcd->print("string"); // const char* lcd->print(F("flash string")); // flashmem string
不要使用 println
,因为它不会像你预期的那样将光标移动到下一行的开头。相反,直接发送 '\n' 或使用 printLine()
函数。然后,光标会移动到下一行,或者如果它在 LCD 的最后一行,则会移动到第一行。
lcd->print('\n'); // or lcd->printLine();
一个好处是,你可以删除最后打印的字符,就像按下退格键一样。
lcd->del();
其余的就和 Arduino 的 LiquidCrystal
库一样,是关于控制 LCD 的。
/* screen control */ lcd->clr(); // clear screen lcd->setBacklight(0); // backlight off lcd->setBacklight(0xFF); // backlight max lcd->scrollScreen(SL_CMD_SCROLL_R); // scroll right lcd->scrollScreen(SL_CMD_SCROLL_L); // scroll left lcd->displayOn(false); // hides printed text and makes backlight off lcd->displayOn(true); // shows printed text and makes backlight max /* cursor control */ lcd->showCursor(SL_CMD_CURSOR_OFF); // cursor off lcd->showCursor(SL_CMD_CURSOR_UNDERLINE); // underline cursor lcd->showCursor(SL_CMD_CURSOR_BLINK); // blink cursor // moves cursor to the first column of the first row lcd->setCursorPos(0); // moves cursor to the first column of the second row // if the total number of columns is 16 lcd->setCursorPos(16); lcd->moveCursor(SL_CMD_CURSOR_MV_R); // increments cursor position lcd->moveCursor(SL_CMD_CURSOR_MV_L); // decrements cursor position /* misc */ lcd->setBaudRate(4); // sets to 9600bps after reset lcd->toggleSplash(); // toggles splash screen for my specific serial LCD
需要提及的一些要点
- 在 LCD 的串口命令中,打开/关闭显示对背光没有任何影响。我在我的实现中改变了这种行为。如果你调用
displayOn(false)
,背光也会被关闭,反之亦然。 - 设置光标位置与
LiquidCrystal
库不同。你需要将 [列, 行] 值传递给LiquidCrystal::setCursor
函数,而将 [距左上角的偏移量] 传递给SerialLcd2::setCursorPos
。 LiquidCrystal
中不存在波特率和启动画面的切换功能。
你可以在下载区找到一个关于该库用法的示例应用程序。
关注点
这个库的好处是它派生自 Print
类。因此它拥有 Print
类的强大功能。你可以像使用 Print 一样打印任何东西,比如格式化的数字或来自 Arduino 闪存的字符串。
另一件事是,它使用 HardwareSerial
或 SoftwareSerial
没有任何区别,因为它将两者都视为 Stream
。因此,你可以将串口 LCD 的接收线连接到任何配置为串口发送的引脚上。
在幕后,串口 LCD 套件在其固件([10])中使用了 LiquidCrystal 库。这是通过与 Arduino 板上使用的相同技术实现的。串口套件有一个 ATmega328 MCU,并且上面上传了 Arduino 引导加载程序。因此,可以通过其串行编程接口上传任何代码。该固件只是另一个 Arduino 代码,可以被看作是你的 Arduino 和 LCD 之间的代理。你甚至可以更改串口 LCD 的通信协议,并创建你自己的协议。尽情享受吧!
如果你对这个实现有任何想法/建议,我将很乐意倾听。
参考
[1] 来自 Cooking-Hacks.com 的串口 LCD 套件
[2] 与串口 LCD 的串行通信
[3] Arduino LiquidCrystal 库
[4] Hitachi LCD 控制器
[5] Arduino Print 类
[6] Arduino Stream 类
[7] Arduino Serial
[8] Arduino SoftwareSerial
[9] 我为 SerialLcd 实现的另一个版本
[10] 串口 LCD 套件的固件