4. 基于 ESP-SR 的唤醒词识别基础测试

任务目标

在 ESP32-S3 上通过 I2C 总线连接 SHT30 温湿度传感器,读取温度与湿度数据,并通过串口打印。通过本案例掌握 I2C 通信协议的基本流程:初始化总线、设备寻址、寄存器读写、数据解析。

硬件与接线

  • 开发板:ESP32-S3-DevKitC-1(或兼容板)
  • 传感器:SHT30(I2C 地址 0x44,默认地址)
  • 接线:SDA → GPIO8,SCL → GPIO9(ESP32-S3 默认 I2C 引脚,可自行修改)
  • 供电:传感器 VIN → 3.3V,GND → GND

实现原理

SHT30 通过 I2C 接口通信,读取数据需两步:先向传感器发送测量命令(0x2C 0x06 表示高重复性测量),等待约 15ms 后读取 6 字节数据(温度高字节、温度低字节、CRC、湿度高字节、湿度低字节、CRC)。温度与湿度均为 16 位无符号整数,按公式换算为实际物理量。

完整代码

#include <stdio.h>
#include "esp_log.h"
#include "driver/i2c.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

#define I2C_MASTER_SCL_IO          9
#define I2C_MASTER_SDA_IO          8
#define I2C_MASTER_NUM             0
#define I2C_MASTER_FREQ_HZ         100000
#define SHT30_ADDR                 0x44
#define SHT30_MEAS_CMD_HIGH        0x2C
#define SHT30_MEAS_CMD_HIGH_2ND    0x06

static const char *TAG = "sht30";

// 初始化 I2C 主机
static void i2c_master_init(void) {
    i2c_config_t conf = {
        .mode = I2C_MODE_MASTER,
        .sda_io_num = I2C_MASTER_SDA_IO,
        .scl_io_num = I2C_MASTER_SCL_IO,
        .sda_pullup_en = GPIO_PULLUP_ENABLE,
        .scl_pullup_en = GPIO_PULLUP_ENABLE,
        .master.clk_speed = I2C_MASTER_FREQ_HZ,
    };
    i2c_param_config(I2C_MASTER_NUM, &conf);
    i2c_driver_install(I2C_MASTER_NUM, conf.mode, 0, 0, 0);
}

// 发送测量命令
static esp_err_t sht30_send_cmd(void) {
    uint8_t cmd[2] = {SHT30_MEAS_CMD_HIGH, SHT30_MEAS_CMD_HIGH_2ND};
    i2c_cmd_handle_t cmd_handle = i2c_cmd_link_create();
    i2c_master_start(cmd_handle);
    i2c_master_write_byte(cmd_handle, (SHT30_ADDR << 1) | I2C_MASTER_WRITE, true);
    i2c_master_write(cmd_handle, cmd, 2, true);
    i2c_master_stop(cmd_handle);
    esp_err_t ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd_handle, pdMS_TO_TICKS(100));
    i2c_cmd_link_delete(cmd_handle);
    return ret;
}

// 读取 6 字节数据
static esp_err_t sht30_read_data(uint8_t *buf, size_t len) {
    i2c_cmd_handle_t cmd_handle = i2c_cmd_link_create();
    i2c_master_start(cmd_handle);
    i2c_master_write_byte(cmd_handle, (SHT30_ADDR << 1) | I2C_MASTER_READ, true);
    i2c_master_read(cmd_handle, buf, len, I2C_MASTER_LAST_NACK);
    i2c_master_stop(cmd_handle);
    esp_err_t ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd_handle, pdMS_TO_TICKS(100));
    i2c_cmd_link_delete(cmd_handle);
    return ret;
}

// 解析并打印温湿度
static void sht30_parse_and_print(uint8_t *data) {
    uint16_t raw_temp = (data[0] << 8) | data[1];
    uint16_t raw_humi = (data[3] << 8) | data[4];
    float temp = -45.0f + 175.0f * (float)raw_temp / 65535.0f;
    float humi = 100.0f * (float)raw_humi / 65535.0f;
    ESP_LOGI(TAG, "Temperature: %.2f °C, Humidity: %.2f %%RH", temp, humi);
}

void app_main(void) {
    i2c_master_init();
    ESP_LOGI(TAG, "I2C initialized successfully");

    uint8_t data[6];
    while (1) {
        if (sht30_send_cmd() == ESP_OK) {
            vTaskDelay(pdMS_TO_TICKS(20));  // 等待测量完成
            if (sht30_read_data(data, 6) == ESP_OK) {
                sht30_parse_and_print(data);
            } else {
                ESP_LOGE(TAG, "Failed to read data");
            }
        } else {
            ESP_LOGE(TAG, "Failed to send command");
        }
        vTaskDelay(pdMS_TO_TICKS(2000));  // 每 2 秒读取一次
    }
}

编译与烧录

idf.py set-target esp32s3
idf.py menuconfig   # 无需额外配置,默认引脚即可
idf.py build
idf.py -p /dev/ttyUSB0 flash monitor

验证方法

烧录并运行后,在串口监视器中观察输出。若接线正确且传感器工作正常,应每 2 秒打印一行温湿度数据,例如:

I (1234) sht30: Temperature: 25.36 °C, Humidity: 48.52 %RH

判定通过条件:

  • 串口持续输出温湿度数据,无报错信息;
  • 温度值在室温合理范围(约 15~35°C),湿度值在 20%~80%RH 范围;
  • 用手捏住传感器或对其哈气,湿度值应明显上升,说明数据真实反映环境变化。

常见问题

  • 读取失败或超时:检查 SDA/SCL 接线是否接反,确认传感器供电为 3.3V,并检查 I2C 地址是否为 0x44(部分模块地址为 0x45,可通过 ADDR 引脚修改)。
  • 数据始终为 0 或固定值:多为传感器未正确响应,可尝试降低 I2C 频率至 50kHz,或检查上拉电阻是否连接。