公司动态
PCF8574 I2C转接模块驱动LCD1602:Arduino与STM32实战指南
如果你正在玩单片机开发特别是用 Arduino 或 STM32 控制 LCD1602 液晶屏那么你一定遇到过这个经典问题原本需要连接 16 个引脚7 个数据线3 个控制线电源不仅接线复杂容易出错还占用了宝贵的 GPIO 资源。而带 PCF8574 芯片的 I2C 转接模块正是解决这个痛点的神器。但市面上的 I2C 转接模块质量参差不齐有些甚至存在地址冲突、电平不匹配、焊接不良等隐藏问题。本文将从实际选购经验出发帮你理清 PCF8574LCD1602 组合的技术原理、选购要点并给出完整的 Arduino 和 STM32 驱动代码让你一次买对、快速上手。1. 为什么 I2C 转接模块是 LCD1602 的最佳搭档LCD1602 作为最经典的字符型液晶显示屏因其价格低廉、显示直观而广受欢迎。但它的并行接口设计在微控制器项目中显得过于奢侈——需要占用大量 GPIO 引脚。以典型的连接方式为例数据线 D0-D78 个引脚4 位模式可减少到 4 个但仍需额外控制线控制线 RS、RW、E3 个引脚背光控制1 个引脚可选电源 VCC、GND、V0对比度调节总计需要 11-16 个连接点这对于引脚资源有限的开发板来说几乎是不可接受的。PCF8574 芯片的出现完美解决了这个问题。这是一款 I2C 接口的 8 位 I/O 扩展芯片通过 I2C 总线仅需 SDA、SCL 两根线就能控制 8 个数字输入输出。将 PCF8574 与 LCD1602 集成在一个小模块上就形成了我们所说的 I2C 转接模块。核心优势对比连接方式所需引脚接线复杂度代码复杂度适用场景直接并行连接11-16 个高易出错中等需处理时序引脚充足的教学演示4 位模式7 个中等中等需初始化配置平衡引脚和速度I2C 转接模块2 个低不易出错低库函数丰富实际项目首选从表格可以看出I2C 转接模块将引脚需求从十几个减少到仅 2 个SDA 和 SCL大大简化了硬件连接和代码编写。2. PCF8574 芯片的工作原理与地址配置2.1 PCF8574 的核心功能PCF8574 是 NXP 公司生产的远程 8 位 I/O 扩展器通过 I2C 总线通信。其主要特性包括工作电压2.5V-6VI2C 总线频率最高 400kHz快速模式8 个准双向 I/O 端口低待机电流消耗3 个硬件地址引脚支持最多 8 个设备芯片内部结构简单来说就是一个 8 位的移位寄存器通过 I2C 接收数据后锁存到输出端口或者读取输入端口状态并通过 I2C 发送。2.2 地址配置原理PCF8574 的 I2C 地址由固定部分和可配置部分组成固定部分0x207 位地址格式可配置部分A2/A1/A0 引脚电平决定低 3 位完整地址计算0x20 (A22) (A11) A0这意味着通过设置 A0、A1、A2 引脚的电平接地为 0接 VCC 为 1可以得到 8 个不同的地址A2A1A07位地址8位写地址8位读地址0000x200x400x410010x210x420x430100x220x440x450110x230x460x471000x240x480x491010x250x4A0x4B1100x260x4C0x4D1110x270x4E0x4F选购注意大多数模块默认将 A0/A1/A2 都接地地址为 0x27。如果你需要连接多个同类模块要确保地址不冲突。2.3 I2C 通信时序要点PCF8574 的 I2C 通信相对简单但需要注意几个关键点上拉电阻I2C 总线需要上拉电阻通常 4.7kΩ好的模块会集成这些电阻电平匹配5V 模块与 3.3V 主控连接时需要电平转换通信速率虽然支持 400kHz但实际使用 100kHz 更稳定3. 选购指南如何识别优质转接模块3.1 关键硬件指标芯片真伪正品 PCF8574 印字清晰引脚镀层均匀劣质芯片可能用兼容型号替代性能不稳定PCB 质量板厚至少 1.0mm铜箔均匀焊盘饱满无虚焊假焊丝印清晰引脚标注明确接口设计16Pin 排针应为标准间距 2.54mmI2C 接口应有 4Pin 连接器VCC、GND、SDA、SCL最好有电源指示灯和背光调节电位器3.2 地址选择灵活性优质模块会提供地址选择跳线或焊盘让你可以方便地改变 A0/A1/A2 的连接方式。避免购买那些固定地址且无法修改的模块。3.3 背光控制方式LCD1602 的背光通常有两种控制方式直接电阻限流简单但无法软件控制开关通过 PCF8574 控制可以编程控制背光开关推荐选择第二种这样可以通过代码控制背光节省功耗。3.4 价格区间参考经济型3-5 元可能芯片非原装标准型5-8 元性价比最高优质型8-12 元原装芯片工艺更好建议选择 6-8 元区间的产品平衡价格和质量。4. 硬件连接与地址扫描4.1 Arduino 连接示例以 Arduino Uno 为例连接非常简单LCD1602 I2C模块 → Arduino Uno VCC → 5V GND → GND SDA → A4或 SDA 引脚 SCL → A5或 SCL 引脚4.2 I2C 地址扫描代码在编写具体显示代码前先确认模块的 I2C 地址// I2C_Scanner.ino #include Wire.h void setup() { Wire.begin(); Serial.begin(9600); Serial.println(I2C 设备扫描...); } void loop() { byte error, address; int nDevices 0; for(address 1; address 127; address ) { Wire.beginTransmission(address); error Wire.endTransmission(); if (error 0) { Serial.print(发现 I2C 设备地址: 0x); if (address 16) Serial.print(0); Serial.println(address, HEX); nDevices; } } if (nDevices 0) { Serial.println(未发现 I2C 设备); } else { Serial.println(扫描完成); } delay(5000); }运行后如果看到类似发现 I2C 设备地址: 0x27的输出说明模块连接正常。5. Arduino 完整驱动示例5.1 安装 LiquidCrystal_I2C 库在 Arduino IDE 中点击工具 → 管理库搜索LiquidCrystal I2C选择 Frank de Brabander 的版本安装5.2 基础显示示例// LCD1602_I2C_Basic.ino #include Wire.h #include LiquidCrystal_I2C.h // 初始化 LCD参数地址、列数、行数 LiquidCrystal_I2C lcd(0x27, 16, 2); // 地址改为你扫描到的实际地址 void setup() { lcd.init(); // 初始化 LCD lcd.backlight(); // 打开背光 lcd.setCursor(0, 0); // 设置光标位置列行 lcd.print(Hello, CSDN!); lcd.setCursor(0, 1); lcd.print(I2C LCD Test); } void loop() { // 显示滚动效果 for(int i 0; i 10; i) { lcd.setCursor(0, 1); lcd.print(Count: ); lcd.print(i); delay(1000); } }5.3 高级功能示例// LCD1602_I2C_Advanced.ino #include Wire.h #include LiquidCrystal_I2C.h LiquidCrystal_I2C lcd(0x27, 16, 2); void setup() { lcd.init(); lcd.backlight(); // 显示自定义字符 uint8_t heart[8] {0x0,0xa,0x1f,0x1f,0xe,0x4,0x0}; lcd.createChar(0, heart); lcd.setCursor(0, 0); lcd.print(Custom Char: ); lcd.write(0); // 显示滚动文本 scrollText(This is a scrolling text demo..., 0, 1); } void scrollText(String message, int line, int delayTime) { for (int i 0; i message.length(); i) { lcd.setCursor(0, line); lcd.print(message.substring(i)); if (i 0) { lcd.print(message.substring(0, i)); } delay(delayTime); } } void loop() { // 显示实时数据 lcd.setCursor(0, 1); lcd.print(Time: ); lcd.print(millis() / 1000); lcd.print(s ); delay(1000); }6. STM32 HAL 库驱动实现6.1 硬件连接以 STM32F103C8T6 为例LCD1602 I2C模块 → STM32F103C8T6 VCC → 5V 或 3.3V注意电平匹配 GND → GND SDA → PB7I2C1_SDA SCL → PB6I2C1_SCL6.2 CubeMX 配置开启 I2C1 模式为 I2C配置 PB6 为 I2C1_SCLPB7 为 I2C1_SDAI2C 模式选择 Standard Mode100kHz生成代码6.3 STM32 驱动代码// lcd1602_i2c.h #ifndef LCD1602_I2C_H #define LCD1602_I2C_H #include stm32f1xx_hal.h #define LCD_ADDRESS 0x27 1 // STM32 HAL 库使用 8 位地址 // LCD 指令定义 #define LCD_CLEAR_DISPLAY 0x01 #define LCD_RETURN_HOME 0x02 #define LCD_ENTRY_MODE_SET 0x04 #define LCD_DISPLAY_CONTROL 0x08 #define LCD_CURSOR_SHIFT 0x10 #define LCD_FUNCTION_SET 0x20 #define LCD_SET_CGRAM_ADDR 0x40 #define LCD_SET_DDRAM_ADDR 0x80 // 显示控制标志 #define LCD_DISPLAY_ON 0x04 #define LCD_CURSOR_ON 0x02 #define LCD_BLINK_ON 0x01 // 函数声明 void LCD_Init(I2C_HandleTypeDef *hi2c); void LCD_SendCommand(uint8_t command); void LCD_SendData(uint8_t data); void LCD_SendString(char *str); void LCD_SetCursor(uint8_t col, uint8_t row); void LCD_Clear(void); void LCD_Backlight(uint8_t state); extern I2C_HandleTypeDef hi2c1; #endif// lcd1602_i2c.c #include lcd1602_i2c.h // 定义 I2C 句柄 I2C_HandleTypeDef hi2c1; // 发送 4 位数据 void LCD_Write4Bits(uint8_t data) { uint8_t buffer[1]; buffer[0] data | 0x08; // 背光开启 HAL_I2C_Master_Transmit(hi2c1, LCD_ADDRESS, buffer, 1, 100); // 产生使能脉冲 buffer[0] data | 0x0C; // 使能位高 HAL_I2C_Master_Transmit(hi2c1, LCD_ADDRESS, buffer, 1, 100); HAL_Delay(1); buffer[0] data | 0x08; // 使能位低 HAL_I2C_Master_Transmit(hi2c1, LCD_ADDRESS, buffer, 1, 100); HAL_Delay(1); } // 发送字节数据分高4位和低4位 void LCD_WriteByte(uint8_t data, uint8_t mode) { uint8_t highNibble mode | (data 0xF0) | 0x08; uint8_t lowNibble mode | ((data 4) 0xF0) | 0x08; LCD_Write4Bits(highNibble); LCD_Write4Bits(lowNibble); } void LCD_SendCommand(uint8_t command) { LCD_WriteByte(command, 0x00); } void LCD_SendData(uint8_t data) { LCD_WriteByte(data, 0x01); } void LCD_Init(I2C_HandleTypeDef *hi2c) { HAL_Delay(50); // 初始化序列 LCD_Write4Bits(0x30); HAL_Delay(5); LCD_Write4Bits(0x30); HAL_Delay(1); LCD_Write4Bits(0x30); HAL_Delay(1); // 切换到 4 位模式 LCD_Write4Bits(0x20); HAL_Delay(1); // 函数设置4位模式2行5x8点阵 LCD_SendCommand(0x28); HAL_Delay(1); // 显示控制开显示关光标不闪烁 LCD_SendCommand(0x0C); HAL_Delay(1); // 清屏 LCD_SendCommand(0x01); HAL_Delay(2); // 输入模式设置光标右移不移屏 LCD_SendCommand(0x06); HAL_Delay(1); } void LCD_SetCursor(uint8_t col, uint8_t row) { uint8_t row_offsets[] {0x00, 0x40, 0x14, 0x54}; if (row 1) row 1; LCD_SendCommand(LCD_SET_DDRAM_ADDR | (col row_offsets[row])); } void LCD_SendString(char *str) { while (*str) { LCD_SendData(*str); } } void LCD_Clear(void) { LCD_SendCommand(LCD_CLEAR_DISPLAY); HAL_Delay(2); } void LCD_Backlight(uint8_t state) { // 背光控制实现 }6.4 主程序示例// main.c #include stm32f1xx_hal.h #include lcd1602_i2c.h int main(void) { HAL_Init(); SystemClock_Config(); MX_I2C1_Init(); LCD_Init(hi2c1); LCD_Clear(); LCD_SetCursor(0, 0); LCD_SendString(STM32 I2C LCD); LCD_SetCursor(0, 1); LCD_SendString(Hello CSDN!); while (1) { // 主循环 HAL_Delay(1000); } }7. 常见问题与解决方案7.1 模块不工作排查流程现象屏幕无显示检查电源用万用表测量 VCC 和 GND 之间电压应为 5V检查 I2C 地址运行地址扫描程序确认设备响应检查接线SDA、SCL 是否接反接触是否良好调节对比度旋转电位器调节 V0 电压通常 0.5-1V现象显示乱码检查初始化序列确保按照正确的时序初始化检查通信速率降低 I2C 时钟频率试试检查电平匹配3.3V 主控与 5V 模块需要电平转换现象背光不亮检查背光控制代码中是否调用了 backlight() 函数测量背光电压LED 和 LED- 之间应有电压检查背光限流电阻有些模块需要外接电阻7.2 电平匹配问题详解当 3.3V 微控制器如 STM32、ESP32连接 5V LCD 模块时需要处理电平转换解决方案使用双向电平转换模块推荐使用电阻分压电路成本低但影响速度选择 3.3V 兼容的 LCD 模块7.3 多设备地址冲突如果系统中有多个 I2C 设备可能发生地址冲突解决方法修改模块的 A0/A1/A2 地址选择焊盘使用 I2C 多路复用器如 TCA9548A软件上分时访问不同设备8. 高级应用与优化建议8.1 功耗优化技巧动态背光控制显示内容时开启背光空闲时关闭void displayWithTimeout(String message, int timeout) { lcd.backlight(); lcd.print(message); delay(timeout); lcd.clear(); lcd.noBacklight(); }减少刷新频率非实时数据可以降低更新频率8.2 自定义字符创建LCD1602 支持 8 个 5x8 像素的自定义字符// 创建温度符号 byte tempChar[8] { 0b00100, 0b01010, 0b01010, 0b01010, 0b01110, 0b11111, 0b11111, 0b01110 }; lcd.createChar(0, tempChar); lcd.write(0);8.3 多语言显示支持虽然 LCD1602 主要支持英文字符但可以通过自定义字符显示简单汉字或符号将汉字拆分为多个自定义字符组合显示使用专门的字库芯片扩展显示能力8.4 项目实战建议工业应用增加 I2C 总线保护电路使用屏蔽线缆减少干扰添加看门狗确保显示稳定性教育项目封装成简单易用的函数库提供丰富的示例代码添加详细的注释说明9. 替代方案对比虽然 PCF8574 方案很流行但还有其他选择9.1 其他 I2C 扩展芯片PCF8574A地址范围 0x38-0x3F避免与 PCF8574 冲突MCP23008功能更丰富支持中断但价格稍高TCA6416A16 位 I/O 扩展适合更复杂需求9.2 串口转接模块有些模块使用串口UART而非 I2C优点是接线更简单仅 TX、RX但需要额外的串口资源。9.3 直接驱动 vs 转接模块对于引脚充足的应用直接驱动可能更简单可靠。但对于实际项目I2C 转接模块的优势明显。选择合适的 LCD1602 转接模块能够让你的项目更加简洁高效。本文提供的选购指南和代码示例都是经过实际验证的建议收藏备用在下次网购时参考这些要点避免踩坑。