树莓派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, ®, 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
问题分析与修正方案
核心问题点
- I2C初始化顺序错误:先初始化总线再配置GPIO引脚,导致总线启动时引脚功能未生效,通信异常。
- 无用的从模式设置:
i2c_set_slave_mode是将Pico设为I2C从设备时用的,主设备模式下无需调用。 - 未配置磁力计工作模式:GY-511默认处于待机状态,未进入连续测量模式,因此不会更新读数。
- 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, ®, 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
相关产品推荐
相关产品推荐

