Arduino接LCD1602:I2C转接板接线与自定义字符

2026-11-11 15:42:44 21阅读

一块16×2的LCD1602,接Arduino最省事的方案不是拖一把杜邦线硬啃并口,而是在屏背后加一块指甲盖大小的I2C转接板。并口4-bit模式至少要占RS、E加D4到D7这6个数字脚,换成I2C之后只剩VCC、GND、SDA、SCL四根线,而且SDA和SCL挂在A4、A5上,还能和其他I2C传感器共享同一条总线。这篇把接线、地址确认、LiquidCrystal_I2C库的用法和自定义字符一次说清,代码全部逐段给出,照着敲就能亮屏。

封面

先认清两块东西:屏是屏,转接板是转接板

LCD1602本体是HD44780控制器的并口字符屏:16列×2行,最多显示32个ASCII字符,每个字符由5×8像素的点阵拼出来,点亮不同像素组合就得到不同字形。转接板上的核心是PCF8574——按NXP官方数据手册的口径,它是一颗8位准双向I/O扩展芯片,把I2C两线信号展开成P0到P7八个口,正好喂给LCD的并口。I2C总线是开漏输出,需要上拉,转接板上那两颗4.7kΩ电阻R4、R5就是干这个的,所以模块买回来不用自己加上拉。

转接板上还有三样东西必须认识:10kΩ电位器RV1,调字符对比度,屏上看不见字先拧它而不是先怀疑代码;背光跳线JP1,拔掉可以改外接控制背光亮度;A0、A1、A2三个地址跳线焊盘,决定模块在I2C总线上的地址,后面单独说。背光则由P3脚经一颗S9013三极管开关,lcd.backlight()控制的就是它,不需要额外接线。

PCF8574 I2C转接板

四根线接完:接线表与两个注意点

I2C转接板Arduino UNO说明
VCC5V必须5V,3.3V供电背光和逻辑都不可靠
GNDGND共地是I2C通信的前提
SDAA4数据线,与模拟输入A4复用
SCLA5时钟线,与模拟输入A5复用

接线图

两个注意点。第一,用了I2C之后A4、A5就别再当模拟输入脚读传感器,它们已被总线占用。第二,代码里用0x27这个地址的前提是A0、A1、A2跳线全部断开;三个焊盘全短接时地址会落到0x20,接错地址屏自然不动。

先扫地址,再写代码

不少教程上来就写0x27,但这是PCF8574变体出厂全跳线断开的默认值,不是承诺。PCF8574的7位地址由固定基址0x20加A2、A1、A0三位拼成,短接某个焊盘就把对应位拉低,地址在0x20到0x27之间变;如果模块用的是PCF8574A变体,基址不同,常见默认地址是0x3F。与其猜,不如先上传一段地址扫描程序,把结果打在串口监视器和LCD屏上,一次定案。

按站点排版要求,代码里include的尖括号统一改成了引号形式,两种写法在Arduino工具链下编译等价,其余字符原样搬运。

/* 
Code to display LCD's own address on I2C LCD
by www.playwithcircuit.com
*/
#include "Wire.h"
#include "LiquidCrystal_I2C.h"

LiquidCrystal_I2C lcd(0x27, 16, 2); // 0x27 is the Default address, will reinitialize later with correct address

void setup() {
  Wire.begin();
  Serial.begin(9600);

  byte lcdAddress = 0;
  Serial.println("Scanning for I2C devices...");

  // Scan for I2C devices
  for (byte address = 1; address < 127; address++) {
    Wire.beginTransmission(address);
    if (Wire.endTransmission() == 0) {
      lcdAddress = address;
      Serial.print("I2C device found at 0x");
      Serial.println(address, HEX);
      break; // Take the first device found (LCD expected)
    }
  }

  if (lcdAddress == 0) {
    Serial.println("No I2C device found.");
    while (1); // Halt if nothing found
  }

  // Initialize LCD with found address
  LiquidCrystal_I2C lcd(lcdAddress, 16, 2);
  lcd.init();
  lcd.backlight();

  // Display the address on the LCD
  lcd.setCursor(0, 0);
  lcd.print("My Address is:");
  lcd.setCursor(0, 1);
  lcd.print("0x");
  if (lcdAddress < 16) lcd.print("0"); // Add leading zero if needed
  lcd.print(lcdAddress, HEX);
}

void loop() {
  // Nothing here
}

地址扫描输出

扫描逻辑不复杂:从0x01到0x7E逐个发起传输,Wire.endTransmission()返回0说明该地址有设备应答,记下它就是LCD的地址;一个都没应答就打印提示并停机。把扫到的地址记下来,后面初始化都要用它。

装库与点屏:Hello World

库管理器里搜LiquidCrystal I2C,装Frank de Brabander维护的那一版,这是社区用得最广的LiquidCrystal_I2C实现。装完先来一段最小示例,第一行打印Hello,第二行打印PlayWithCircuit。

/* 
Code to display Strings on I2C LCD
by www.playwithcircuit.com
*/

#include "LiquidCrystal_I2C.h"

LiquidCrystal_I2C lcd(0x27, 16, 2); // Format -> (Address,Width,Height )

void setup()
{
  // initialize the lcd
  lcd.init();
  // Turn on the Backlight
  lcd.backlight();
}

void loop()
{
  // Clear the display buffer
  lcd.clear(); 
  // Set cursor (Column, Row)
  lcd.setCursor(0, 0);
  // print "Hello" at (0, 0)   
  lcd.print("Hello"); 
  // Set cursor (Column, Row) 
  lcd.setCursor(0,1);
  // print "PlayWithCircuit" at (0, 1)
  lcd.print("PlayWithCircuit");
  while(1);
}

几个常用函数列一张表,用的时候对号入座:

函数作用
lcd.init()初始化LCD
lcd.backlight()打开背光
lcd.clear()清屏并把光标归位
lcd.setCursor(col, row)设置光标,左上角是(0, 0),第二行行首是(0, 1)
lcd.print() / lcd.write()打印字符串 / 写单个字节或自定义字符
lcd.display() / lcd.noDisplay()开关显示,关掉后显存数据还在
lcd.cursor() / lcd.blink()下划线光标 / 闪烁块光标
lcd.scrollDisplayLeft() / Right()整屏左移 / 右移一格

顺手纠一个网上教程里常见的笔误:有的文章把backlight()写成初始化、把init()写成开背光,正好写反了。init()负责初始化,backlight()负责开背光,setup里两个都要调,缺一个屏要么不亮要么不理你。另外示例loop里那句while(1)不是偷懒,没有它每轮clear再重写,屏会闪。

自定义字符:CGRAM里只有64字节

HD44780控制器有两块字模存储。CGROM是出厂固化的只读存储,装着A到Z、0到9这些标准字模,断电不丢;CGRAM是易失的字符生成RAM,按Hitachi HD44780U数据手册的规格总容量64字节,断电即清空,自定义字符就存在这里。5×8字模每个占8字节,每字节对应一行、低5位有效,64除以8正好是8个槽位,编号0到7,这是上限,塞不下第9个。

做法分三步:先用8字节数组画出字模,1代表像素点亮;再用lcd.createChar(槽号, 数组)把数组写进CGRAM;最后用lcd.write(byte(槽号))显示。下面的示例定义了笑脸、举手、无表情三个字符,先逐字打出一行提示文字,再在第二行依次亮出三个图标。

/* 
Code to display custom characters on I2C LCD
by www.playwithcircuit.com
*/
#include "LiquidCrystal_I2C.h"

// Initialize LCD at default I2C address 0x27, 16x2 display
LiquidCrystal_I2C lcd(0x27, 16, 2);

// Custom Characters
byte smiley[8] = {
  0b00000,
  0b00000,
  0b01010,
  0b00000,
  0b00000,
  0b10001,
  0b01110,
  0b00000
};

byte armsUp[8] = {
  0b00100,
  0b01010,
  0b00100,
  0b10101,
  0b01110,
  0b00100,
  0b00100,
  0b01010
};

byte face[8] = {
  0b11111,
  0b10001,
  0b00000,
  0b01010,
  0b00000,
  0b00100,
  0b00000,
  0b01110
};

char u8Buffer[17]="Smile ArmUp Face";

void setup() {
  lcd.init();       // Initialize the LCD
  lcd.backlight();   // Turn on the backlight

  // Create custom characters
  lcd.createChar(0, smiley);
  lcd.createChar(1, armsUp);
  lcd.createChar(2, face);

  // Display custom characters on LCD
  lcd.setCursor(0, 0);
  for(int i=0; i < 17; i++){
    lcd.print(u8Buffer[i]);
    delay(100);
  } 
  
  lcd.setCursor(0, 1);
  lcd.write(byte(0)); // smiley
  lcd.print("       ");
  delay(300);
  lcd.write(byte(1)); // armsUp
  lcd.print("      ");
  delay(300);
  lcd.write(byte(2)); // face
}

void loop() {
  // Nothing in loop
}

自定义字符显示效果

画字模不用手算二进制,网上有现成的5×8点阵生成器,点格子自动出数组,选hex格式直接抄进代码就行。

排错清单:五种常见翻车

  • 屏完全黑、背光也不亮:先查供电是不是5V,再查SDA、SCL有没有接反,最后确认共地。
  • 背光亮但看不到字:九成是对比度,拧转接板上的蓝色电位器,慢慢转到字符清晰。
  • 满屏乱码:多半是杜邦线松动或面包板接触不良,也可能地址写错,重跑一遍地址扫描。
  • 自定义字符不显示或显示错位:数组必须恰好8字节,createChar()要在显示之前、init()之后调用。
  • 字符很淡:还是对比度和供电的问题,电位器加稳定5V双管齐下。

小结

从数据角度看这笔账很划算:花4根线省下6个数字IO,64字节CGRAM换8个自定义图标,背光和对比度都在I2C这侧解决。对做传感器面板、小型仪表的人来说,LCD1602加PCF8574转接板仍是性价比最高的文本显示方案——想要图形和动画再上OLED,纯文本场景它就是最优解。


作者:数据媛小满
链接:https://www.aiddithome.com/p/d25f9a648be6.html
本作版权归作者所有,未经允许请勿转载。若存在违规行为,您可以点击 “举报”。


登录 后发表评论
5条评论
拆开看看再说
1楼 · 5小时前

4根线换6个IO这笔账确实划算,I2C还能挂别的传感器

刷视频进来围观
2楼 · 5小时前

自定义字符那段讲得细,createChar要在init之后这个坑我也踩过

学生党玩机
3楼 · 5小时前

进度条动画这个玩法不错,用 partial block 能做出五级填充

触底反弹的Tony
4楼 · 5小时前

这个思路我去年做温湿度面板时验证过一遍:并口版LCD1602占了我6个IO,加了个PCF8574背板之后A4/A5两根线搞定,剩下的脚全留给传感器。补充一个数据点,PCF8574的地址基址0x20、PCF8574A是0x38起,所以市面上两种背板默认地址分别是0x27和0x3F,扫描程序跑一遍最稳。CGRAM那64字节也别浪费,温度计、电池、信号强度几个图标做出来面板观感立刻不一样,就是记住每个字模严格8字节,我少写一个0x00导致后面字符错位过。

阿强焊点总飞
5楼 · 5小时前

上手第一课就是拧那个蓝色电位器,屏没字先别怀疑代码