使用MicroPython实现RPI PICO与MPU6050通信失败求助
Raspberry Pi Pico与MPU6050 I2C通信OSError: [Errno 5] EIO问题解决
问题背景
使用MicroPython驱动Raspberry Pi Pico与MPU6050进行I2C通信时,Thonny IDE抛出OSError: [Errno 5] EIO错误,更换Pico开发板和MPU6050模块后问题依旧。
原代码
import machine import utime MPU6050_ADDR = 0x68 # MPU6050 I2C address def read_i2c_word(i2c, address): # Read a 16-bit word from the specified I2C address return (i2c.readfrom_mem(address, 0x3B, 2)[0] << 8) | i2c.readfrom_mem(address, 0x3C, 2)[1] def read_accel_gyro(i2c): # Read accelerometer and gyroscope data accel_x = read_i2c_word(i2c, MPU6050_ADDR) accel_y = read_i2c_word(i2c, MPU6050_ADDR + 2) accel_z = read_i2c_word(i2c, MPU6050_ADDR + 4) gyro_x = read_i2c_word(i2c, MPU6050_ADDR + 8) gyro_y = read_i2c_word(i2c, MPU6050_ADDR + 10) gyro_z = read_i2c_word(i2c, MPU6050_ADDR + 12) return (accel_x, accel_y, accel_z, gyro_x, gyro_y, gyro_z) def main(): i2c = machine.I2C(0, sda=machine.Pin(0), scl=machine.Pin(1), freq=400000) # I2C bus on Pico while True: accel_data = read_accel_gyro(i2c) print("Accelerometer (X, Y, Z):", accel_data[:3]) print("Gyroscope (X, Y, Z):", accel_data[3:]) print("") utime.sleep(1) # Sleep for 1 second if __name__ == "__main__": main()
报错信息
Traceback (most recent call last): File "<stdin>", line 34, in <module> File "<stdin>", line 26, in main File "<stdin>", line 13, in read_accel_gyro File "<stdin>", line 8, in read_i2c_word OSError: [Errno 5] EIO
错误原因分析
- I2C设备地址误用:
read_accel_gyro中给MPU6050_ADDR加偏移(如MPU6050_ADDR + 2)完全错误,I2C设备地址是固定的0x68,需要偏移的是寄存器地址,而非设备地址。 - 寄存器读取逻辑错误:
read_i2c_word中重复读取相邻寄存器且长度错误,MPU6050的16位数据存储在连续的两个寄存器(高字节+低字节),应一次读取2字节,而非分两次读取。 - 未唤醒MPU6050:MPU6050默认处于休眠状态,必须先写入
PWR_MGMT_1寄存器(0x6B)唤醒设备,否则无法正常通信。
修复方案
步骤1:修正数据读取逻辑
重新实现read_i2c_word函数,从指定设备的目标寄存器读取完整的16位数据。
步骤2:唤醒MPU6050
添加初始化函数,向PWR_MGMT_1寄存器写入0x00唤醒设备。
步骤3:添加I2C设备扫描(可选但推荐)
扫描I2C总线确认MPU6050设备存在,排除硬件连接问题。
完整修复代码
import machine import utime MPU6050_ADDR = 0x68 # MPU6050 I2C设备地址 # 寄存器地址定义 ACCEL_XOUT_H = 0x3B ACCEL_YOUT_H = 0x3D ACCEL_ZOUT_H = 0x3F GYRO_XOUT_H = 0x43 GYRO_YOUT_H = 0x45 GYRO_ZOUT_H = 0x47 PWR_MGMT_1 = 0x6B def read_i2c_word(i2c, dev_addr, reg_addr): # 从指定设备的指定寄存器读取16位数据 data = i2c.readfrom_mem(dev_addr, reg_addr, 2) return (data[0] << 8) | data[1] def init_mpu6050(i2c): # 唤醒MPU6050(默认休眠状态) i2c.writeto_mem(MPU6050_ADDR, PWR_MGMT_1, b'\x00') utime.sleep_ms(100) # 等待初始化完成 def read_accel_gyro(i2c): # 读取加速度计和陀螺仪数据 accel_x = read_i2c_word(i2c, MPU6050_ADDR, ACCEL_XOUT_H) accel_y = read_i2c_word(i2c, MPU6050_ADDR, ACCEL_YOUT_H) accel_z = read_i2c_word(i2c, MPU6050_ADDR, ACCEL_ZOUT_H) gyro_x = read_i2c_word(i2c, MPU6050_ADDR, GYRO_XOUT_H) gyro_y = read_i2c_word(i2c, MPU6050_ADDR, GYRO_YOUT_H) gyro_z = read_i2c_word(i2c, MPU6050_ADDR, GYRO_ZOUT_H) # 转换为16位有符号数值 def twos_complement(val): return val - 0x10000 if val >= 0x8000 else val return ( twos_complement(accel_x), twos_complement(accel_y), twos_complement(accel_z), twos_complement(gyro_x), twos_complement(gyro_y), twos_complement(gyro_z) ) def main(): # 初始化I2C总线 i2c = machine.I2C(0, sda=machine.Pin(0), scl=machine.Pin(1), freq=400000) # 扫描I2C设备,确认MPU6050连接正常 devices = i2c.scan() if MPU6050_ADDR not in devices: print(f"未找到MPU6050,扫描到的I2C设备:{[hex(d) for d in devices]}") return # 初始化MPU6050 init_mpu6050(i2c) while True: accel_data = read_accel_gyro(i2c) print("加速度计(X, Y, Z):", accel_data[:3]) print("陀螺仪(X, Y, Z):", accel_data[3:]) print("") utime.sleep(1) if __name__ == "__main__": main()
额外硬件检查点
- 供电与接地:MPU6050需接3.3V供电,不可接5V;确保Pico与MPU6050共地。
- 上拉电阻:若MPU6050模块无自带上拉电阻,需在SDA、SCL线路各接一个4.7kΩ电阻到3.3V。
- I2C速率:若仍有通信问题,可将I2C频率降至100000(标准速率)尝试。
内容的提问来源于stack exchange,提问作者Abhijith Ravindran
相关产品推荐
相关产品推荐

