跳到主要内容

显示设备

显示设备让 Arduino 能够直观地输出信息。本章将介绍 LCD、OLED 和数码管等常用显示设备的使用方法。

LCD1602 液晶显示屏

LCD1602 是最常用的字符型液晶显示屏,可以显示 2 行,每行 16 个字符。

硬件连接(I2C 方式)

使用 I2C 转接板可以大大简化接线:

LCD I2C VCC ── 5V
LCD I2C GND ── GND
LCD I2C SCL ── A5(Uno)
LCD I2C SDA ── A4(Uno)

安装库

项目加载库管理库 → 搜索 "LiquidCrystal I2C"

代码示例

#include <LiquidCrystal_I2C.h>

// 创建 LCD 对象,参数:I2C 地址(通常是 0x27 或 0x3F),列数,行数
LiquidCrystal_I2C lcd(0x27, 16, 2);

void setup() {
lcd.init(); // 初始化
lcd.backlight(); // 开启背光

// 显示文字
lcd.setCursor(0, 0); // 第 0 行,第 0 列
lcd.print("Hello, World!");

lcd.setCursor(0, 1); // 第 1 行,第 0 列
lcd.print("Arduino LCD");
}

void loop() {
// 闪烁效果
lcd.noBacklight();
delay(500);
lcd.backlight();
delay(500);
}

显示传感器数据

#include <LiquidCrystal_I2C.h>
#include <DHT.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);
DHT dht(2, DHT22);

void setup() {
lcd.init();
lcd.backlight();
dht.begin();

lcd.setCursor(0, 0);
lcd.print("Temp: --.- C");
lcd.setCursor(0, 1);
lcd.print("Humi: --.- %");
}

void loop() {
float temp = dht.readTemperature();
float humidity = dht.readHumidity();

if (!isnan(temp) && !isnan(humidity)) {
lcd.setCursor(6, 0);
lcd.print(temp, 1);
lcd.print(" C ");

lcd.setCursor(6, 1);
lcd.print(humidity, 1);
lcd.print(" % ");
}

delay(2000);
}

自定义字符

LCD1602 支持 8 个自定义字符:

#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);

// 定义温度符号(5x8 像素)
byte tempChar[] = {
0b00100,
0b01010,
0b01010,
0b01110,
0b01110,
0b11111,
0b11111,
0b01110
};

// 定义湿度符号
byte humiChar[] = {
0b00100,
0b00100,
0b01110,
0b01110,
0b11111,
0b11111,
0b11111,
0b01110
};

void setup() {
lcd.init();
lcd.backlight();

// 创建自定义字符(0-7)
lcd.createChar(0, tempChar);
lcd.createChar(1, humiChar);

// 显示自定义字符
lcd.setCursor(0, 0);
lcd.write(byte(0)); // 显示温度符号
lcd.print(" 25.5 C");

lcd.setCursor(0, 1);
lcd.write(byte(1)); // 显示湿度符号
lcd.print(" 60.0 %");
}

void loop() {}

OLED 显示屏

OLED 显示屏具有自发光、高对比度、宽视角等优点,常见的有 0.96 寸和 1.3 寸两种尺寸。

硬件连接(I2C)

OLED VCC ── 3.3V 或 5V
OLED GND ── GND
OLED SCL ── A5(Uno)
OLED SDA ── A4(Uno)

安装库

项目加载库管理库 → 搜索 "Adafruit SSD1306"

代码示例

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

void setup() {
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 初始化失败"));
for(;;);
}

display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println(F("Hello, OLED!"));
display.println(F("Arduino 显示测试"));
display.display();
}

void loop() {}

显示图形

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

void setup() {
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
}

void loop() {
display.clearDisplay();

// 画像素
display.drawPixel(10, 10, SSD1306_WHITE);

// 画线
display.drawLine(0, 0, 127, 63, SSD1306_WHITE);

// 画矩形
display.drawRect(20, 20, 40, 30, SSD1306_WHITE);
display.fillRect(70, 20, 40, 30, SSD1306_WHITE);

// 画圆
display.drawCircle(100, 50, 10, SSD1306_WHITE);

// 显示文字
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.print("OLED");

display.display();
delay(100);
}

动画效果

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

int x = 0;
int y = 32;
int dx = 2;
int dy = 1;

void setup() {
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
}

void loop() {
display.clearDisplay();

// 绘制跳动的球
display.fillCircle(x, y, 5, SSD1306_WHITE);

// 更新位置
x += dx;
y += dy;

// 边界检测
if (x <= 5 || x >= SCREEN_WIDTH - 5) dx = -dx;
if (y <= 5 || y >= SCREEN_HEIGHT - 5) dy = -dy;

display.display();
delay(20);
}

数码管显示

四位数码管(TM1637)

TM1637 驱动的四位数码管只需要两根数据线。

硬件连接

TM1637 CLK ── D2
TM1637 DIO ── D3
TM1637 VCC ── 5V
TM1637 GND ── GND

安装库:搜索 "TM1637Display"

代码示例

#include <TM1637Display.h>

const int CLK = 2;
const int DIO = 3;

TM1637Display display(CLK, DIO);

void setup() {
display.setBrightness(7); // 亮度 0-7
display.clear();
}

void loop() {
// 显示数字
display.showNumberDec(1234);
delay(1000);

// 显示带小数点
display.showNumberDecEx(1234, 0b01000000); // 12.34
delay(1000);

// 显示时间格式
display.showNumberDecEx(1530, 0b01000000, true); // 15:30
delay(1000);

// 倒计时
for (int i = 100; i >= 0; i--) {
display.showNumberDec(i);
delay(100);
}
}

74HC595 驱动数码管

使用移位寄存器节省 IO 引脚:

const int DATA_PIN = 11;   // DS
const int LATCH_PIN = 12; // ST_CP
const int CLOCK_PIN = 13; // SH_CP

// 共阴极数码管段码(0-9)
const byte segmentPatterns[] = {
0x3F, // 0
0x06, // 1
0x5B, // 2
0x4F, // 3
0x66, // 4
0x6D, // 5
0x7D, // 6
0x07, // 7
0x7F, // 8
0x6F // 9
};

// 位选引脚
const int digitPins[] = {2, 3, 4, 5};

void setup() {
pinMode(DATA_PIN, OUTPUT);
pinMode(LATCH_PIN, OUTPUT);
pinMode(CLOCK_PIN, OUTPUT);

for (int i = 0; i < 4; i++) {
pinMode(digitPins[i], OUTPUT);
digitalWrite(digitPins[i], HIGH); // 共阴极,高电平关闭
}
}

void loop() {
// 显示 1234
int number = 1234;
displayNumber(number);
}

void displayNumber(int num) {
int digits[4];
digits[0] = num / 1000;
digits[1] = (num / 100) % 10;
digits[2] = (num / 10) % 10;
digits[3] = num % 10;

// 动态扫描显示
for (int i = 0; i < 4; i++) {
// 关闭所有位
for (int j = 0; j < 4; j++) {
digitalWrite(digitPins[j], HIGH);
}

// 发送段码
digitalWrite(LATCH_PIN, LOW);
shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, segmentPatterns[digits[i]]);
digitalWrite(LATCH_PIN, HIGH);

// 打开当前位
digitalWrite(digitPins[i], LOW);

delay(5); // 延时让眼睛能看到
}
}

综合示例:多功能仪表

整合多种显示设备的多功能仪表:

#include <LiquidCrystal_I2C.h>
#include <TM1637Display.h>
#include <DHT.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);
TM1637Display tm1637(2, 3);
DHT dht(4, DHT22);

const int LDR_PIN = A0;

void setup() {
lcd.init();
lcd.backlight();

tm1637.setBrightness(7);

dht.begin();

lcd.setCursor(0, 0);
lcd.print("Multi-Display");
delay(1000);
lcd.clear();
}

void loop() {
float temp = dht.readTemperature();
float humidity = dht.readHumidity();
int light = analogRead(LDR_PIN);

// LCD 显示温湿度
lcd.setCursor(0, 0);
lcd.print("T:");
lcd.print(temp, 1);
lcd.print((char)223); // 度符号
lcd.print("C");

lcd.setCursor(9, 0);
lcd.print("H:");
lcd.print(humidity, 1);
lcd.print("%");

lcd.setCursor(0, 1);
lcd.print("Light:");
lcd.print(light);
lcd.print(" ");

// 数码管显示温度整数部分
int tempInt = (int)temp;
tm1637.showNumberDec(tempInt);

delay(2000);
}

显示设备对比

特性LCD1602OLED数码管
显示内容字符图形+文字数字
背光需要自发光自发光
可视角度有限
功耗中等中等
价格便宜稍贵便宜
适用场景简单文字复杂显示数字显示

下一步

掌握了显示设备后,我们将学习如何存储数据,包括 EEPROM 和 SD 卡的使用。