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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 10:44:50