You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Raspberry Pi Pico连接20x4 I2C LCD出现OSError: [Errno 5] EIO求助

Raspberry Pi Pico连接20x4 I2C LCD触发OSError: [Errno 5] EIO的问题解决

错误信息

OSError: [Errno 5] EIO

已多次检查接线、重新插拔,问题仍未解决,网上未找到完整可行的解决方案。

触发错误的代码片段

def setup():
    i2c = I2C(0, sda=Pin(8), scl=Pin(9), freq=400000)
    I2C_ADDR = i2c.scan()[0]
    lcd = I2cLcd(i2c, I2C_ADDR, 4, 20)
    lcd.custom_char(1, bytearray([0x1F,
      0x1F,
      0x00,
      0x00,
      0x00,
      0x00,
      0x00,
      0x00]))
    lcd.custom_char(3, bytearray([0x03,
      0x03,
      0x03,
      0x03,
      0x03,
      0x03,
      0x03,
      0x03]))
    lcd.custom_char(5, bytearray([0x00,
      0x00,
      0x00,
      0x00,
      0x00,
      0x00,
      0x1F,
      0x1F]))
    lcd.custom_char(7, bytearray([0x18,
      0x18,
      0x18,
      0x18,
      0x18,
      0x18,
      0x18,
      0x18]))
    return lcd, clock, buzzer

LCD驱动库代码(i2cLcd.py)

import utime
import gc

from lcd_api import LcdApi
from machine import I2C

# PCF8574 pin definitions
MASK_RS = 0x01       # P0
MASK_RW = 0x02       # P1
MASK_E  = 0x04       # P2

SHIFT_BACKLIGHT = 3  # P3
SHIFT_DATA      = 4  # P4-P7

class I2cLcd(LcdApi):
    
    #Implements a HD44780 character LCD connected via PCF8574 on I2C

    def __init__(self, i2c, i2c_addr, num_lines, num_columns):
        self.i2c = i2c
        self.i2c_addr = int(hex(i2c_addr))
        self.i2c.writeto(self.i2c_addr, bytes([0]))
        utime.sleep_ms(20)   # Allow LCD time to powerup
        # Send reset 3 times
        self.hal_write_init_nibble(self.LCD_FUNCTION_RESET)
        utime.sleep_ms(5)    # Need to delay at least 4.1 msec
        self.hal_write_init_nibble(self.LCD_FUNCTION_RESET)
        utime.sleep_ms(1)
        self.hal_write_init_nibble(self.LCD_FUNCTION_RESET)
        utime.sleep_ms(1)
        # Put LCD into 4-bit mode
        self.hal_write_init_nibble(self.LCD_FUNCTION)
        utime.sleep_ms(1)
        LcdApi.__init__(self, num_lines, num_columns)
        cmd = self.LCD_FUNCTION
        if num_lines > 1:
            cmd |= self.LCD_FUNCTION_2LINES
        self.hal_write_command(cmd)
        gc.collect()

    def hal_write_init_nibble(self, nibble):
        # Writes an initialization nibble to the LCD.
        # This particular function is only used during initialization.
        byte = ((nibble >> 4) & 0x0f) << SHIFT_DATA
        self.i2c.writeto(self.i2c_addr, bytes([byte | MASK_E]))
        self.i2c.writeto(self.i2c_addr, bytes([byte]))
        gc.collect()
        
    def hal_backlight_on(self):
        # Allows the hal layer to turn the backlight on
        self.i2c.writeto(self.i2c_addr, bytes([1 << SHIFT_BACKLIGHT]))
        gc.collect()
        
    def hal_backlight_off(self):
        #Allows the hal layer to turn the backlight off
        self.i2c.writeto(self.i2c_addr, bytes([0]))
        gc.collect()
        
    def hal_write_command(self, cmd):
        # Write a command to the LCD. Data is latched on the falling edge of E.
        byte = ((self.backlight << SHIFT_BACKLIGHT) |
                (((cmd >> 4) & 0x0f) << SHIFT_DATA))
        self.i2c.writeto(self.i2c_addr, bytes([byte | MASK_E]))
        self.i2c.writeto(self.i2c_addr, bytes([byte]))
        byte = ((self.backlight << SHIFT_BACKLIGHT) |
                ((cmd & 0x0f) << SHIFT_DATA))
        self.i2c.writeto(self.i2c_addr, bytes([byte | MASK_E]))
        self.i2c.writeto(self.i2c_addr, bytes([byte]))
        if cmd <= 3:
            # The home and clear commands require a worst case delay of 4.1 msec
            utime.sleep_ms(5)
        gc.collect()

    def hal_write_data(self, data):
        # Write data to the LCD. Data is latched on the falling edge of E.
        byte = (MASK_RS |
                (self.backlight << SHIFT_BACKLIGHT) |
                (((data >> 4) & 0x0f) << SHIFT_DATA))
        self.i2c.writeto(self.i2c_addr, bytes([byte | MASK_E]))
        self.i2c.writeto(self.i2c_addr, bytes([byte]))
        byte = (MASK_RS |
                (self.backlight << SHIFT_BACKLIGHT) |
                ((data & 0x0f) << SHIFT_DATA))      
        self.i2c.writeto(self.i2c_addr, bytes([byte | MASK_E]))
        self.i2c.writeto(self.i2c_addr, bytes([byte]))
        gc.collect()

排查与修复方案

  • 验证I2C设备扫描结果:修改setup函数,先确认扫描到的设备列表,避免空列表导致索引错误,同时确认地址正确性:

    def setup():
        i2c = I2C(0, sda=Pin(8), scl=Pin(9), freq=400000)
        devices = i2c.scan()
        print(f"扫描到的I2C设备地址: {[hex(d) for d in devices]}")
        if not devices:
            raise RuntimeError("未检测到任何I2C设备,请检查接线或电源")
        I2C_ADDR = devices[0]
        # 后续代码...
    

    PCF8574模块常见地址为0x27或0x3F,如果扫描结果为空,说明硬件连接存在问题。

  • 降低I2C通信频率:多数PCF8574模块不支持400kHz高速模式,改为100kHz尝试:

    i2c = I2C(0, sda=Pin(8), scl=Pin(9), freq=100000)
    
  • 修复驱动库中的地址错误:I2cLcd.__init__中的self.i2c_addr = int(hex(i2c_addr))完全多余,i2c.scan()返回的是整数地址,这行代码会导致地址处理异常,直接替换为:

    self.i2c_addr = i2c_addr
    
  • 检查电源供应:20x4 LCD的背光需要较大电流,若使用Pico的3.3V供电不足,可尝试切换到5V引脚供电(确保PCF8574模块支持5V电平),或使用外部电源给LCD模块供电。

  • 延长初始化延迟:部分LCD模块需要更长的上电初始化时间,将__init__中的utime.sleep_ms(20)改为utime.sleep_ms(100)。

  • 再次确认接线:确保SDA接Pin8、SCL接Pin9,GND引脚完全接地,电源引脚无虚接,排线或杜邦线无损坏。

内容的提问来源于stack exchange,提问作者Smh Dg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 02:19:51