Skip to main content

使用 Grove 扩展 MCP

概述

本文档描述了如何在基于 ESP32-S3 的 SenseCAP Watcher 开发板上通过 Grove 接口使用 DHT20 温湿度传感器。

硬件准备

SenseCAP Watcher for XiaoZhiGrove - Temperature & Humidity Sensor V2.0 (DHT20)

Grove 接口定义 (J5)

根据硬件原理图,Grove 接口使用以下引脚:

Grove 引脚功能ESP32-S3 连接
Pin 1SCLGPIO48 (I2C0_SCL)
Pin 2SDAGPIO47 (I2C0_SDA)
Pin 3VCCGROVE_3.3V (3.3V 电源)
Pin 4GNDGND

DHT20 传感器

  • I2C 地址:0x38(固定,无法更改)
  • 供电电压:2.0V - 5.5V(使用 3.3V)
  • 通信协议:I2C(最高 400kHz)
  • 测量范围:
    • 温度:-40°C 至 +80°C(精度:±0.5°C)
    • 湿度:0% 至 100% RH(精度:±3% RH)

执行结果

文件结构

原始代码:

新文件:

  • dht20.h

  • dht20.cc

  • 您应该将上述两个文件放置在以下位置:

    • 文件位置
      main/boards/sensecap-watcher/
      ├── dht20.h # DHT20 driver header
      └── dht20.cc # DHT20 driver implementation

修改的文件

注意

上述示例代码仅供参考。您应该根据您的具体传感器型号、开发环境和固件版本进行修改,以确保正确集成和成功编译。

  • Grove I2C 传感器可以直接连接到 I2C 总线。
  • 非 I2C 传感器可以通过可用的 GPIO 引脚连接,允许灵活集成各种传感器类型。

核心功能(DHT20 传感器)

1. 传感器初始化

DHT20 驱动程序实现了完整的初始化过程:

  • 步骤 1. 重置传感器:发送 0xBA 重置命令
  • 步骤 2. 系统配置:向寄存器 0xE1 写入 [0x08, 0x00]
  • 步骤 3. 校准检查:检查状态寄存器位[3]以确保传感器已校准
  • 步骤 4. 重试机制:如果校准失败,最多重试 5 次
esp_err_t ret = dht20_sensor_->Initialize();
if (ret == ESP_OK) {
ESP_LOGI(TAG, "DHT20 initialized successfully");
}

2. 温湿度读取

读取过程:

  • 步骤 1. 触发测量:发送命令 [0xAC, 0x33, 0x00]
  • 步骤 2. 等待测量:延迟 80ms
  • 步骤 3. 读取 8 字节:[状态, 湿度高, 中, 低 | 温度高, 中, 低, CRC]
  • 步骤 4. 数据解析:
    • 湿度 = (20 位原始值) × 100 / 2^20
    • 温度 = (20 位原始值) × 200 / 2^20 - 50
float temperature, humidity;
esp_err_t ret = dht20_sensor_->ReadTempAndHumidity(temperature, humidity);
if (ret == ESP_OK) {
printf("Temperature: %.2f°C, Humidity: %.2f%%\n", temperature, humidity);
}

3. I2C 通信协议

功能命令/寄存器数据
重置传感器0xBA-
配置寄存器0xE1[0x08, 0x00]
触发测量-[0xAC, 0x33, 0x00]
读取状态-1 字节
读取数据-7 字节

4. 状态字节定义

功能
bit[7]测量状态1=测量中, 0=空闲
bit[6:4]保留-
bit[3]校准状态1=已校准, 0=未校准
bit[2:0]保留-

5. 数据解析算法

// Humidity data (20 bits)
uint32_t humidity_raw = (data[1] << 12) | (data[2] << 4) | (data[3] >> 4);
float humidity = humidity_raw * 100.0f / 1048576.0f;

// Temperature data (20 bits)
uint32_t temperature_raw = ((data[3] & 0x0F) << 16) | (data[4] << 8) | data[5];
float temperature = temperature_raw * 200.0f / 1048576.0f - 50.0f;

核心功能(内部 MCP 工具接口)

1. 功能描述

  • 工具名称:self.grove.get_temperature_humidity
  • 工具应用:从 Grove 连接的 DHT20 传感器读取当前温度和湿度

2. 调用示例

AI 可以如下调用:

result = call_tool("self.grove.get_temperature_humidity", {})

3. 返回格式

  • 成功:

    {
    "temperature": 25.32,
    "humidity": 65.47,
    "status": "ok"
    }
  • 失败:

    {
    "error": "DHT20 sensor not initialized"
    }

    {
    "error": "Failed to read DHT20: ESP_ERR_TIMEOUT"
    }

4. 修改的代码部分和说明

添加头文件包含

  • sensecap_watcher.cc 的开头添加以下包含语句:

    #include "dht20.h"
    #include "mcp_server.h"
  • 目的

    • dht20.h — 引入 DHT20 传感器的驱动程序 API,实现温湿度读取。

    • mcp_server.h — 提供与内部 MCP 服务器相关的 API,允许通信和注册 MCP 工具。

添加成员变量

  • SensecapWatcher 类中添加以下成员变量:

    DHT20* dht20_sensor_ = nullptr;
  • 目的

    • dht20_sensor_ — 指向通过 Grove 接口连接的 DHT20 传感器对象的指针。
      它用于在 SensecapWatcher 实例的整个生命周期中初始化、存储和访问温湿度传感器。
    • 它在 InitializeDHT20() 中分配,并由 MCP 工具用于读取传感器数据。
    • 初始化为 nullptr 以表示传感器尚未设置,在读取前执行空值检查。

添加 DHT20 初始化和 MCP 工具

  • SensecapWatcher 类中添加以下成员函数:

    void InitializeDHT20() {
    ESP_LOGI(TAG, "Initialize DHT20 sensor on Grove port");

    // Create DHT20 sensor instance
    dht20_sensor_ = new DHT20(i2c_bus_);

    // Initialize and calibrate the sensor
    esp_err_t ret = dht20_sensor_->Initialize();
    if (ret != ESP_OK) {
    ESP_LOGE(TAG, "DHT20 initialization failed: %s", esp_err_to_name(ret));
    delete dht20_sensor_;
    dht20_sensor_ = nullptr;
    return;
    }

    ESP_LOGI(TAG, "DHT20 sensor initialized successfully");

    // Register MCP tool for reading temperature and humidity
    auto& mcp_server = McpServer::GetInstance();
    mcp_server.AddTool("self.grove.get_temperature_humidity",
    "Read temperature and humidity from the Grove-connected DHT20 sensor.\n"
    "Return format: {\"temperature\": value(°C), \"humidity\": value(%), \"status\": \"ok\"}\n"
    "If reading fails, returns an error message.",
    PropertyList(),
    [this](const PropertyList&) -> ReturnValue {
    if (!dht20_sensor_) {
    return "{\"error\": \"DHT20 sensor not initialized\"}";
    }

    float temperature = 0.0f;
    float humidity = 0.0f;

    esp_err_t ret = dht20_sensor_->ReadTempAndHumidity(temperature, humidity);
    if (ret != ESP_OK) {
    std::string error_msg = "{\"error\": \"Failed to read DHT20: ";
    error_msg += esp_err_to_name(ret);
    error_msg += "\"}";
    return error_msg;
    }

    // Format response as JSON
    char buffer[128];
    snprintf(buffer, sizeof(buffer),
    "{\"temperature\": %.2f, \"humidity\": %.2f, \"status\": \"ok\"}",
    temperature, humidity);
    return std::string(buffer);
    });

    ESP_LOGI(TAG, "DHT20 MCP tool registered: self.grove.get_temperature_humidity");
    }
  • 在构造函数中添加 DHT20 初始化调用

    SensecapWatcher() {
    ...
    InitializeCamera();
    InitializeDHT20(); // Initialize Grove DHT20 sensor
    }
  • 目的

    • InitializeDHT20() — 在 Grove 接口上初始化 DHT20 传感器,并注册一个 MCP 工具以允许内部访问温湿度数据。
    • 该函数创建 DHT20 实例,对其进行校准,并检查初始化错误。
    • 如果初始化成功,它会注册 MCP 工具 self.grove.get_temperature_humidity 用于通过 JSON 读取传感器数据。
    • SensecapWatcher 的构造函数中调用,以确保传感器在板子启动时就绪:

故障排除

常见问题

  1. 传感器初始化失败
  • 可能原因:
    • Grove 接口供电不正确
    • I2C 连接问题
    • 传感器未连接或损坏
  • 解决方案
    uint32_t grove_power = esp_io_expander_get_level(io_exp_handle, BSP_PWR_GROVE);
    ESP_LOGI(TAG, "Grove power status: %d", grove_power);
  1. 读取超时
  • 可能原因:
    • 传感器忙碌
    • I2C 总线冲突
  • 解决方案
    • 确保读取间隔 ≥1s
    • 检查 I2C 上的其他设备
  1. 无效数据
  • 可能原因:
    • 传感器未校准
    • CRC 校验失败(当前版本未实现)
  • 解决方案:
    • 重新初始化传感器
    • 考虑实现 CRC 校验(data[6])

参考资料

维护

代码位于 main/boards/sensecap-watcher/,不影响其他板子。

技术支持

Loading Comments...