Raspberry Pi Pico通过I2C读取MPU-6050数据全为0问题求助
树莓派Pico读取MPU-6050数据全为0的问题解决
问题描述
尝试用树莓派Pico通过I2C通信读取MPU-6050的加速度和陀螺仪数据,参考寄存器手册选择了ACCEL_*OUT_H和GYRO_*OUT_H系列寄存器,但所有轴的读取结果均为0。
相关代码
类头文件(Pico_and_MPU_6050.h)
#include <map> #include <string> #include "pico/stdlib.h" #include "hardware/i2c.h" #define MPU6050_ADDRESS 0x68 #define MPU6050_REG_ACCEL_XOUT_H 0x3B #define MPU6050_REG_ACCEL_YOUT_H 0x3D #define MPU6050_REG_ACCEL_ZOUT_H 0x3F #define MPU6050_REG_GYRO_XOUT_H 0x43 #define MPU6050_REG_GYRO_YOUT_H 0x45 #define MPU6050_REG_GYRO_ZOUT_H 0x47 #define MPU6050_REG_PWR_MGMT_1 0x6B class Pico_and_MPU_6050 { private: int GPIO_SDA = -1; int GPIO_SCL = -1; int16_t ACCELEROMETER_X = 0; int16_t ACCELEROMETER_Y = 0; int16_t ACCELEROMETER_Z = 0; int16_t GYROSCOPE_X = 0; int16_t GYROSCOPE_Y = 0; int16_t GYROSCOPE_Z = 0; std::map<std::string, int16_t> MPU_6050_data; public: Pico_and_MPU_6050(int SDA, int SCL); int read_MPU_6050_data(); std::map<std::string, int16_t> get_MPU_6050_data(); };
源文件(Pico_and_MPU_6050.cpp)
#include "Pico_and_MPU_6050.h" Pico_and_MPU_6050::Pico_and_MPU_6050(int SDA, int SCL) { GPIO_SDA = SDA; GPIO_SCL = SCL; i2c_init(i2c0, 100000); gpio_set_function(SDA, GPIO_FUNC_I2C); gpio_set_function(SCL, GPIO_FUNC_I2C); i2c_set_slave_mode(i2c0, false, 0); } int Pico_and_MPU_6050::read_MPU_6050_data() { // 初始化MPU-6050(唤醒设备) uint8_t power_mgmt_reg = MPU6050_REG_PWR_MGMT_1; uint8_t awake_byte = 0x00; // 唤醒MPU-6050 i2c_write_blocking(i2c0, MPU6050_ADDRESS, &power_mgmt_reg, 1, false); i2c_write_blocking(i2c0, MPU6050_ADDRESS, &awake_byte, 1, false); // 读取加速度数据(X、Y、Z) uint8_t accel_x_data[2]; uint8_t accel_x_h_reg = MPU6050_REG_ACCEL_XOUT_H; i2c_write_blocking(i2c0, MPU6050_ADDRESS, &accel_x_h_reg, 1, true); i2c_read_blocking(i2c0, MPU6050_ADDRESS, accel_x_data, 2, false); uint8_t accel_y_data[2]; uint8_t accel_y_h_reg = MPU6050_REG_ACCEL_YOUT_H; i2c_write_blocking(i2c0, MPU6050_ADDRESS, &accel_y_h_reg, 1, true); i2c_read_blocking(i2c0, MPU6050_ADDRESS, accel_y_data, 2, false); uint8_t accel_z_data[2]; uint8_t accel_z_h_reg = MPU6050_REG_ACCEL_ZOUT_H; i2c_write_blocking(i2c0, MPU6050_ADDRESS, &accel_z_h_reg, 1, true); i2c_read_blocking(i2c0, MPU6050_ADDRESS, accel_z_data, 2, false); // 读取陀螺仪数据(X、Y、Z) uint8_t gyro_x_data[2]; uint8_t gyro_x_h_reg = MPU6050_REG_GYRO_XOUT_H; i2c_write_blocking(i2c0, MPU6050_ADDRESS, &gyro_x_h_reg, 1, true); i2c_read_blocking(i2c0, MPU6050_ADDRESS, gyro_x_data, 2, false); uint8_t gyro_y_data[2]; uint8_t gyro_y_h_reg = MPU6050_REG_GYRO_YOUT_H; i2c_write_blocking(i2c0, MPU6050_ADDRESS, &gyro_y_h_reg, 1, true); i2c_read_blocking(i2c0, MPU6050_ADDRESS, gyro_y_data, 2, false); uint8_t gyro_z_data[2]; uint8_t gyro_z_h_reg = MPU6050_REG_GYRO_ZOUT_H; i2c_write_blocking(i2c0, MPU6050_ADDRESS, &gyro_z_h_reg, 1, true); i2c_read_blocking(i2c0, MPU6050_ADDRESS, gyro_z_data, 2, false); ACCELEROMETER_X = (accel_x_data[0] << 8) | accel_x_data[1]; ACCELEROMETER_Y = (accel_y_data[0] << 8) | accel_y_data[1]; ACCELEROMETER_Z = (accel_z_data[0] << 8) | accel_z_data[1]; GYROSCOPE_X = (gyro_x_data[0] << 8) | gyro_x_data[1]; GYROSCOPE_Y = (gyro_y_data[0] << 8) | gyro_y_data[1]; GYROSCOPE_Z = (gyro_z_data[0] << 8) | gyro_z_data[1]; return 0; } std::map<std::string, int16_t> Pico_and_MPU_6050::get_MPU_6050_data() { MPU_6050_data["ACCELEROMETER_X"] = ACCELEROMETER_X; MPU_6050_data["ACCELEROMETER_Y"] = ACCELEROMETER_Y; MPU_6050_data["ACCELEROMETER_Z"] = ACCELEROMETER_Z; MPU_6050_data["GYROSCOPE_X"] = GYROSCOPE_X; MPU_6050_data["GYROSCOPE_Y"] = GYROSCOPE_Y; MPU_6050_data["GYROSCOPE_Z"] = GYROSCOPE_Z; return MPU_6050_data; }
主函数(main.cpp)
#include <stdio.h> #include <map> #include "pico/stdlib.h" #include "hardware/i2c.h" #include "Pico_and_MPU_6050.h" int main() { stdio_init_all(); Pico_and_MPU_6050 mpu_6050(0, 1); printf("Hallo!\n Ich bin aufgewacht!\n"); sleep_ms(1000); mpu_6050.read_MPU_6050_data(); std::map<std::string, int16_t> data = mpu_6050.get_MPU_6050_data(); printf("Hallo!\n Ich bin aufgewacht!\n"); sleep_ms(1000); printf("Hallo!\n Ich bin aufgewacht!\n"); sleep_ms(2000); printf("Hallo!\n Ich bin aufgewacht!\n"); sleep_ms(2000); printf("Hallo!\n Ich bin aufgewacht!\n"); sleep_ms(2000); printf("Hallo!\n Ich bin aufgewacht!\n"); sleep_ms(2000); printf("Hallo!\n Ich bin aufgewacht!\n"); sleep_ms(2000); while(true){ mpu_6050.read_MPU_6050_data(); sleep_ms(50); data = mpu_6050.get_MPU_6050_data(); printf("Beschleunigung\n X-Achse: %d\n", data["ACCELEROMETER_X"]); printf("Y-Achse: %d\n", data["ACCELEROMETER_Y"]); printf("Z-Achse: %d\n", data["ACCELEROMETER_Z"]); printf("Gyroskop\n X-Achse: %d\n", data["GYROSCOPE_X"]); printf("Y-Achse: %d\n", data["GYROSCOPE_Y"]); printf("Z-Achse: %d\n", data["GYROSCOPE_Z"]); sleep_ms(1000); } return 0; }
输出结果
加速度
X轴: 0
Y轴: 0
Z轴: 0
陀螺仪
X轴: 0
Y轴: 0
Z轴: 0
解决方法
1. 修正MPU6050唤醒方式
当前代码分两次发送寄存器地址和唤醒数据,MPU6050无法关联两者,需将寄存器地址和数据打包成数组一次性发送:
// 替换原唤醒代码 uint8_t wakeup_data[] = {MPU6050_REG_PWR_MGMT_1, 0x00}; int ret = i2c_write_blocking(i2c0, MPU6050_ADDRESS, wakeup_data, sizeof(wakeup_data), false); if (ret != sizeof(wakeup_data)) { printf("唤醒MPU6050失败\n"); return -1; }
2. 添加I2C引脚内部上拉
树莓派Pico的I2C引脚默认无内部上拉,需手动启用:
// 在构造函数的gpio_set_function之后添加 gpio_pull_up(SDA); gpio_pull_up(SCL);
3. 检查I2C读写返回值
所有I2C读写操作需检查返回值,确认数据传输成功:
// 示例:读取加速度X轴数据时检查 int write_ret = i2c_write_blocking(i2c0, MPU6050_ADDRESS, &accel_x_h_reg, 1, true); if (write_ret != 1) { printf("写入寄存器地址失败\n"); return -1; } int read_ret = i2c_read_blocking(i2c0, MPU6050_ADDRESS, accel_x_data, 2, false); if (read_ret != 2) { printf("读取加速度X数据失败\n"); return -1; }
4. 批量读取寄存器优化
MPU6050的加速度、温度、陀螺仪寄存器连续排列,可一次性读取所有数据,减少通信错误:
// 替换原所有单个寄存器读取代码 uint8_t start_reg = MPU6050_REG_ACCEL_XOUT_H; i2c_write_blocking(i2c0, MPU6050_ADDRESS, &start_reg, 1, true); uint8_t raw_data[14]; i2c_read_blocking(i2c0, MPU6050_ADDRESS, raw_data, 14, false); // 解析数据 ACCELEROMETER_X = (raw_data[0] << 8) | raw_data[1]; ACCELEROMETER_Y = (raw_data[2] << 8) | raw_data[3]; ACCELEROMETER_Z = (raw_data[4] << 8) | raw_data[5]; // 跳过温度寄存器(raw_data[6]、raw_data[7]) GYROSCOPE_X = (raw_data[8] << 8) | raw_data[9]; GYROSCOPE_Y = (raw_data[10] << 8) | raw_data[11]; GYROSCOPE_Z = (raw_data[12] << 8) | raw_data[13];
5. 验证设备连接
读取MPU6050的WHO_AM_I寄存器(地址0x75),确认设备正常响应:
// 在read_MPU_6050_data函数开头添加 uint8_t who_am_i_reg = 0x75; uint8_t who_am_i_val; i2c_write_blocking(i2c0, MPU6050_ADDRESS, &who_am_i_reg, 1, true); i2c_read_blocking(i2c0, MPU6050_ADDRESS, &who_am_i_val, 1, false); printf("WHO_AM_I: 0x%X\n", who_am_i_val); // 正常返回0x68
内容的提问来源于stack exchange,提问作者Felix
相关产品推荐
相关产品推荐

