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

Raspberry Pi Pico无法通过I2C检测MS5611模块的求助

问题分析与解决方案

核心问题定位

你的代码存在几个语法/逻辑错误,直接导致MS5611无法响应Pico的I2C请求:

  • 数组初始化错误:ms5611_read函数中,D2_G被定义为单字节变量,却用双字节数组初始化,发送的命令完全无效。
  • 缓冲区越界:读取MS5611的3字节D1/D2数据时,仅定义了2字节数组,会破坏内存引发逻辑异常。
  • 缺少转换等待时间:发送D1/D2转换命令后未等待传感器完成模数转换,直接读取会得到无效数据。

ESP32的I2C驱动容错性较强,这些错误未暴露,但Pico对时序和数据格式的敏感度更高,直接引发通信失败。

修正后的代码

main.h

#ifndef __MAIN_H_
#define __MAIN_H_

#define MS5611_ADDRESS        0x77  // 改用#define避免static变量作用域问题
#define MS5611_CMD_RESET      0x1E
#define MS5611_CMD_READ_CMD   0x00
#define MS5611_CMD_READ_PROM  0xA0
#define MS5611_CMD_D1         0x48  // OSR=4096,转换时间约8.2ms
#define MS5611_CMD_D2         0x58  // OSR=4096,转换时间约8.2ms

struct MS5611_CALIBRATION
{
    uint16_t C[10];
    uint32_t D1;
    uint32_t D2;
    int32_t dT;  // dT为有符号值,需用int32_t
    int32_t TEMP; // 温度计算结果为有符号
    int64_t OFF;
    int64_t SENS;
    uint32_t P;
};

void ms5611_init();
void ms5611_read();
void ms5611_calculate(); // 新增温度/压力计算函数

#endif

main.c

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

#define I2C_PORT i2c0
struct MS5611_CALIBRATION ms5611_calibration;

void ms5611_init()
{
    uint8_t src;
    uint8_t buffer[2];
    int ret;

    // 发送复位命令
    src = MS5611_CMD_RESET;
    sleep_ms(10); // 复位需至少2.8ms,10ms足够
    ret = i2c_write_blocking(I2C_PORT, MS5611_ADDRESS, &src, 1, false);
    if (ret != 1) {
        printf("MS5611复位失败\n");
        return;
    }
    sleep_ms(10);

    // 读取PROM校准数据
    for(int offset = 0; offset < 7; offset++)
    {
        src = MS5611_CMD_READ_PROM + (offset * 2);
        ret = i2c_write_blocking(I2C_PORT, MS5611_ADDRESS, &src, 1, true);
        if (ret != 1) {
            printf("读取PROM命令发送失败,offset=%d\n", offset);
            continue;
        }
        ret = i2c_read_blocking(I2C_PORT, MS5611_ADDRESS, buffer, 2, false);
        if (ret != 2) {
            printf("读取PROM数据失败,offset=%d\n", offset);
            continue;
        }
        ms5611_calibration.C[offset] = (uint16_t)buffer[0] << 8 | buffer[1];
        printf("PROM C[%d]: 0x%04X\n", offset, ms5611_calibration.C[offset]);
        sleep_ms(1); // 短延时即可,无需10ms
    }
}

void ms5611_read()
{
    uint8_t cmd[2];
    uint8_t data[3]; // 改为3字节缓冲区,适配D1/D2的3字节数据
    int ret;

    // 读取D1(压力)
    cmd[0] = MS5611_CMD_D1;
    ret = i2c_write_blocking(I2C_PORT, MS5611_ADDRESS, cmd, 1, false);
    if (ret != 1) {
        printf("发送D1命令失败\n");
        return;
    }
    sleep_ms(10); // 等待转换完成(OSR=4096需8.2ms)
    cmd[0] = MS5611_CMD_READ_CMD;
    ret = i2c_write_blocking(I2C_PORT, MS5611_ADDRESS, cmd, 1, true);
    if (ret != 1) {
        printf("发送D1读取命令失败\n");
        return;
    }
    ret = i2c_read_blocking(I2C_PORT, MS5611_ADDRESS, data, 3, false);
    if (ret != 3) {
        printf("读取D1数据失败\n");
        return;
    }
    ms5611_calibration.D1 = (uint32_t)data[0] << 16 | (uint32_t)data[1] << 8 | data[2];
    printf("D1: %lu\n", ms5611_calibration.D1);

    // 读取D2(温度)
    cmd[0] = MS5611_CMD_D2;
    ret = i2c_write_blocking(I2C_PORT, MS5611_ADDRESS, cmd, 1, false);
    if (ret != 1) {
        printf("发送D2命令失败\n");
        return;
    }
    sleep_ms(10); // 等待转换完成
    cmd[0] = MS5611_CMD_READ_CMD;
    ret = i2c_write_blocking(I2C_PORT, MS5611_ADDRESS, cmd, 1, true);
    if (ret != 1) {
        printf("发送D2读取命令失败\n");
        return;
    }
    ret = i2c_read_blocking(I2C_PORT, MS5611_ADDRESS, data, 3, false);
    if (ret != 3) {
        printf("读取D2数据失败\n");
        return;
    }
    ms5611_calibration.D2 = (uint32_t)data[0] << 16 | (uint32_t)data[1] << 8 | data[2];
    printf("D2: %lu\n", ms5611_calibration.D2);
}

void ms5611_calculate()
{
    // 按照MS5611 datasheet公式计算温度和压力
    ms5611_calibration.dT = (int32_t)ms5611_calibration.D2 - ((int32_t)ms5611_calibration.C[5] << 8);
    ms5611_calibration.TEMP = 2000 + ((int64_t)ms5611_calibration.dT * ms5611_calibration.C[6]) / 0x800000;

    int64_t OFF = (int64_t)ms5611_calibration.C[2] << 16 + ((int64_t)ms5611_calibration.C[4] * ms5611_calibration.dT) / 0x2000;
    int64_t SENS = (int64_t)ms5611_calibration.C[1] << 15 + ((int64_t)ms5611_calibration.C[3] * ms5611_calibration.dT) / 0x4000;

    // 低温补偿(温度低于20℃时)
    if (ms5611_calibration.TEMP < 2000) {
        int32_t T2 = ((int64_t)ms5611_calibration.dT * ms5611_calibration.dT) / 0x80000000;
        int64_t OFF2 = 5 * ((int64_t)(ms5611_calibration.TEMP - 2000) * (ms5611_calibration.TEMP - 2000)) / 2;
        int64_t SENS2 = 5 * ((int64_t)(ms5611_calibration.TEMP - 2000) * (ms5611_calibration.TEMP - 2000)) / 4;

        if (ms5611_calibration.TEMP < -1500) {
            OFF2 += 7 * ((int64_t)(ms5611_calibration.TEMP + 1500) * (ms5611_calibration.TEMP + 1500));
            SENS2 += 11 * ((int64_t)(ms5611_calibration.TEMP + 1500) * (ms5611_calibration.TEMP + 1500)) / 2;
        }

        ms5611_calibration.TEMP -= T2;
        OFF -= OFF2;
        SENS -= SENS2;
    }

    ms5611_calibration.OFF = OFF;
    ms5611_calibration.SENS = SENS;
    ms5611_calibration.P = ((ms5611_calibration.D1 * SENS) / 0x200000 - OFF) / 0x100;
}

int main()
{
    stdio_init_all();
    sleep_ms(2000); // 等待USB串口初始化

    // 初始化I2C,改用100kHz波特率(兼容性更好)
    i2c_init(I2C_PORT, 100000);
    gpio_set_function(8, GPIO_FUNC_I2C);
    gpio_set_function(9, GPIO_FUNC_I2C);
    gpio_pull_up(8);
    gpio_pull_up(9);
    bi_decl(bi_2pins_with_func(8, 9, GPIO_FUNC_I2C));

    sleep_ms(100);
    ms5611_init();

    while(1)
    {
        ms5611_read();
        ms5611_calculate(); // 执行温度压力计算
        printf("#############################\n");
        printf("温度: %.2f ℃\n", ms5611_calibration.TEMP / 100.0);
        printf("压力: %.2f hPa\n", ms5611_calibration.P / 100.0);
        printf("D1: %lu\n", ms5611_calibration.D1);
        printf("D2: %lu\n", ms5611_calibration.D2);
        sleep_ms(1000);
    }
}

CMakeLists.txt

无需修改,保持原文件即可。

额外建议

  1. 先执行I2C扫描:在初始化MS5611前,运行Pico官方I2C扫描代码,确认0x77地址能被检测到,排除硬件连接问题。
  2. 检查引脚连接:再次确认Pico的SDA/SCL引脚与PCB对应引脚连接正确,避免接反。
  3. 波特率调整:若仍有问题,可将I2C波特率降至50kHz,进一步提升兼容性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 13:38:11