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

树莓派Pico使用GY-511磁力计读数不更新问题求助

树莓派Pico读取GY-511磁力计读数固定不更新问题排查

我正在用VS Code开发树莓派Pico项目,尝试获取GY-511磁力计的X、Y、Z轴读数,但读数始终固定不变。以下是我的代码和输出结果,求帮忙排查问题:

原代码

#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/i2c.h"

// I2C配置定义
#define I2C_PORT i2c0
#define I2C_SDA 0
#define I2C_SCL 1
#define MAGNETOMETER_ADDR 0x1E  // 磁力计地址

int main() {
    stdio_init_all();

    i2c_init(I2C_PORT, 100000);  // 初始化I2C总线,波特率100kHz
    i2c_set_slave_mode(I2C_PORT, false, MAGNETOMETER_ADDR);

    sleep_ms(1000);
    
    // 设置I2C引脚上拉电阻
    gpio_set_pulls(I2C_SDA, true, false);
    gpio_set_pulls(I2C_SCL, true, false);
    
    i2c_set_baudrate(I2C_PORT, 100000);
    gpio_set_function(I2C_SDA, GPIO_FUNC_I2C);
    gpio_set_function(I2C_SCL, GPIO_FUNC_I2C);

    uint8_t data[6];  // 存储X、Y、Z轴数据的缓冲区
    uint8_t reg = 0x03;  // X轴MSB寄存器地址

    while (1) {
        // 写入要读取的起始寄存器地址
        i2c_write_blocking(I2C_PORT, MAGNETOMETER_ADDR, &reg, 1, false);

        // 读取6字节数据
        int result = i2c_read_blocking(I2C_PORT, MAGNETOMETER_ADDR, data, 6, false);
        if (result == PICO_ERROR_GENERIC) {
            printf("I2C读取错误\n");
            continue;
        }

        // 解析三轴数据
        int16_t x = (data[0] << 8) | data[1];
        int16_t y = (data[4] << 8) | data[5];
        int16_t z = (data[2] << 8) | data[3];

        printf("X: %d, Y: %d, Z: %d\n", x, y, z);
        
        sleep_ms(200);
    }

    return 0;
}

输出结果

X: 277, Y: -77, Z: 139
X: 277, Y: -77, Z: 139
X: 277, Y: -77, Z: 139

问题分析与修正方案

核心问题点

  1. I2C初始化顺序错误:先初始化总线再配置GPIO引脚,导致总线启动时引脚功能未生效,通信异常。
  2. 无用的从模式设置:i2c_set_slave_mode是将Pico设为I2C从设备时用的,主设备模式下无需调用。
  3. 未配置磁力计工作模式:GY-511默认处于待机状态,未进入连续测量模式,因此不会更新读数。
  4. I2C读写的总线保持问题:写入寄存器地址后释放总线,可能导致两次操作间总线状态异常。

修正后的代码

#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/i2c.h"

// I2C配置定义
#define I2C_PORT i2c0
#define I2C_SDA 0
#define I2C_SCL 1
#define MAGNETOMETER_ADDR 0x1E  // 磁力计I2C地址

int main() {
    stdio_init_all();

    // 先配置GPIO为I2C功能并启用上拉电阻
    gpio_set_function(I2C_SDA, GPIO_FUNC_I2C);
    gpio_set_function(I2C_SCL, GPIO_FUNC_I2C);
    gpio_set_pulls(I2C_SDA, true, false);
    gpio_set_pulls(I2C_SCL, true, false);

    // 初始化I2C总线,波特率100kHz
    i2c_init(I2C_PORT, 100000);

    sleep_ms(1000);

    // 配置磁力计为连续测量模式:写入MR_REG_M寄存器(0x02),值为0x00
    uint8_t config[] = {0x02, 0x00};
    i2c_write_blocking(I2C_PORT, MAGNETOMETER_ADDR, config, 2, false);

    uint8_t data[6];
    uint8_t reg = 0x03;  // 起始寄存器:X轴MSB

    while (1) {
        // 写入起始寄存器地址,保持总线连接(最后一个参数为true)
        i2c_write_blocking(I2C_PORT, MAGNETOMETER_ADDR, &reg, 1, true);

        // 读取6字节数据
        int result = i2c_read_blocking(I2C_PORT, MAGNETOMETER_ADDR, data, 6, false);
        if (result < 0) {
            printf("I2C读取错误\n");
            continue;
        }

        // 解析数据:GY-511寄存器顺序为X_MSB,X_LSB,Z_MSB,Z_LSB,Y_MSB,Y_LSB
        int16_t x = (data[0] << 8) | data[1];
        int16_t z = (data[2] << 8) | data[3];
        int16_t y = (data[4] << 8) | data[5];

        printf("X: %d, Y: %d, Z: %d\n", x, y, z);
        
        sleep_ms(200);
    }

    return 0;
}

关键修正说明

  • 调整GPIO配置与I2C初始化顺序:确保引脚功能正确后再启动总线,避免通信异常。
  • 删除i2c_set_slave_mode调用:主设备模式下无需设置从模式。
  • 添加磁力计工作模式配置:通过写入寄存器让传感器进入连续测量模式,持续更新数据。
  • 修改i2c_write_blocking的总线保持参数:写入寄存器地址后保持总线不释放,提高读写操作的可靠性。
  • 优化错误判断逻辑:直接判断读取结果是否小于0,覆盖所有I2C错误情况。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 21:40:05