先看完成后要观察什么
接好一块 SHT40 后,让串口每两秒出现一条带单位、时间和状态的温湿度记录。正常时输出新读数;通信或校验失败时输出 NA;重新读到有效数据时标一次 RECOVERED。下面按接线、编译、上传、观察的顺序完成,再试一次可恢复的断线实验。
本篇只连一个模块,不加屏幕、Wi-Fi 或加热器。温度用摄氏度 °C,湿度用相对湿度 %RH。I2C 扫描成功只表示地址应答,还要让真正的测量命令和数据校验通过。
| 条件 | 应观察的字段 | 怎样判断 |
|---|---|---|
| 正常连接 | state=VALID;T_C、RH_raw、RH_display | 每条都来自本轮成功读取,保留时间与样本号 |
| SDA 开关断开 | state=ERROR T=NA RH=NA;error、detail | 记录实际错误,不把旧温湿度当新值 |
| 闭合开关后重新读成功 | state=RECOVERED,随后 state=VALID | 先看到新的有效值,再判恢复 |
参考:[1] Sensirion SHT4x datasheet V6.4:数据格式、CRC、命令、换算与复位[2] Sensirion Arduino SHT4x 1.1.2:高精度读取与错误返回
先确认模块版本,再接四根线
这里采用带稳压、电平转换和上拉的 Adafruit PID4885,不是裸 SHT40 芯片。模块 VIN 接主控 3V3,让电源和逻辑处于同一电平;3Vo 是模块稳压器输出,保持不接。地址固定为 0x44,不能通过改软件地址让这一模块变成 0x45。其他 SHT4x 料号可能有不同地址选项,需另查其完整后缀。
完全断电后按端点表连接,GPIO 指信号号而非排针序号。只接 USB-to-UART 供电与监视。模块已有上拉,初次用短线、单模块和 100kHz;先不额外并联电阻。
| 主控端 | 模块端 | 核对 |
|---|---|---|
| 3V3 / J1-1 | VIN | 不使用5V或3Vo作为输入 |
| GND / J1-22 | GND | 共地 |
| GPIO8 / J1-12 | SDA | 按程序显式指定 |
| GPIO9 / J1-15 | SCL | 100kHz |
| 无 | 3Vo | 留空 |
- 做到这里,你应该看到
- 断电逐端追线,四条连接与表一致,其他端口无第二路供电。
参考:[4] Adafruit SHT40 PID4885:供电、地址、上拉和引脚[5] 乐鑫 DevKitC-1 v1.1:固定修订排针与 N8R8 范围[6] Arduino-ESP32 3.3.12 Wire 实现:超时与总线初始化
装好两个指定库,先确认程序能编译
先完成 F05 的 Arduino-ESP32 3.3.12 环境。安装 Sensirion Core 0.7.3,再以 --no-deps 安装 Sensirion I2C SHT4x 1.1.2,避免自动换掉前一个依赖。本例不使用 Adafruit_SHT4x 类,下载库时看完整名字。
Windows 使用 PowerShell,macOS/Linux 使用终端;下方单引号命令不适用于 Windows cmd.exe。命令从本项目仓库根目录执行。只下载本页 ZIP 的读者,先解压并进入 esp32-sht40-thermometer 目录,把编译命令末尾的 examples/esp32/esp32-sht40-thermometer 换成一个点“.”。IDE 用户可在库管理器选择同样版本,打开目录内的同名 .ino,按 F05 的 N8R8 菜单配置后点击 Verify。
arduino-cli lib install 'Sensirion Core@0.7.3'
arduino-cli lib install --no-deps 'Sensirion I2C SHT4x@1.1.2'
arduino-cli compile --fqbn 'esp32:esp32:esp32s3:FlashSize=8M,PSRAM=opi,FlashMode=qio,PartitionScheme=default_8MB,CDCOnBoot=default,USBMode=hwcdc' examples/esp32/esp32-sht40-thermometer- 做到这里,你应该看到
- 编译结束没有最终错误,日志使用指定 core 和两份库。编译阶段不需要插传感器。
- 如果卡住了
- 头文件找不到时先检查库名、版本和安装路径;sketch 路径不存在时,先核对是在仓库根目录还是 ZIP 解压目录。
参考:[2] Sensirion Arduino SHT4x 1.1.2:高精度读取与错误返回[3] Sensirion Core 0.7.3:接收帧与 CRC 验证[6] Arduino-ESP32 3.3.12 Wire 实现:超时与总线初始化
上传后,在 115200 串口里找启动行
先关闭占用端口的其他串口窗口。板子通过 USB-to-UART 接口连接电脑,USB CDC On Boot 保持 Disabled,按 F06 的方法用插拔确认真实端口。下方 PORT 是占位符,运行前替换为自己的端口名;不要原样照抄。
仓库用户沿用下方路径;ZIP 用户在刚才的解压目录内,把 upload 命令最后的项目路径也换成“.”。上传完成后打开监视器;如果没看到启动行,保持监视器打开,按一下板上复位键重新观察。IDE 用户可直接上传,再打开串口监视器并选择 115200。
| 启动时寻找 | 后续动作 |
|---|---|
| S01 core=3.3.12 driver=1.1.2 SDA=8 SCL=9 address=0x44 bus=1 | 核对程序版本、引脚、地址和总线初始化状态 |
| sensor_serial= 后的实际序列号 | 保存自己的序列号;若是错误说明,保留完整文本 |
| attempt=… uptime_ms=… state=VALID T_C=… RH_raw=… RH_display=… clipped=… | 这些省略号代表实际读数;继续记录至少 10 条 |
arduino-cli upload --fqbn 'esp32:esp32:esp32s3:FlashSize=8M,PSRAM=opi,FlashMode=qio,PartitionScheme=default_8MB,CDCOnBoot=default,USBMode=hwcdc' -p PORT examples/esp32/esp32-sht40-thermometer
arduino-cli monitor -p PORT --config baudrate=115200- 做到这里,你应该看到
- 能看到本程序的启动信息和后续采样行;出现 ERROR 也先保存,按末尾症状表排查。
- 如果卡住了
- 窗口完全空白先查接口、实际端口、115200 和复位;有 S01 启动行却持续 ERROR,再查传感器线路。两种现象不要混在一起处理。
参考:[2] Sensirion Arduino SHT4x 1.1.2:高精度读取与错误返回[5] 乐鑫 DevKitC-1 v1.1:固定修订排针与 N8R8 范围[6] Arduino-ESP32 3.3.12 Wire 实现:超时与总线初始化
让完整程序处理校验、失效与重试
SHT4x 每个 16 位数据字后跟一个 CRC。固定驱动的高精度函数发出 0xFD,等待 10ms 后读取数据;Sensirion Core 的 receiveFrame 检查每个数据字的 CRC,错误沿返回码传给应用。程序必须先判断返回值,再使用输出变量。两个浮点变量每轮都初始化,失败分支只输出 NA,不会把上一次成功的温湿度再次作为新值。
周期计时采用无符号差值。Wire 的等待设为 20ms,测量不无限等待串口打开。每三次连续失败尝试一次传感器软复位,再等下一轮;软复位本身失败也记录错误。首次重新读到有效数据输出 RECOVERED,后续为 VALID。
湿度换算可能在量程边界产生小于0或大于100的原始数。按厂商建议,展示值限制到0–100 %RH,同时保留 RH_raw 和 clipped;裁边只改变显示,不证明误差变小。示例从不启动加热器。
// SPDX-License-Identifier: MIT
// S01: S3 DevKitC-1 v1.1 N8R8 + Adafruit SHT40 breakout PID 4885.
#include <Arduino.h>
#include <Wire.h>
#include <SensirionI2cSht4x.h>
#include <math.h>
SensirionI2cSht4x sensor;
constexpr uint8_t SDA_PIN = 8, SCL_PIN = 9;
constexpr uint32_t PERIOD_MS = 2000;
bool busReady = false, hadError = false;
uint32_t sampledAt = 0, attempts = 0, failures = 0;
bool startBus() {
const bool ok = Wire.begin(SDA_PIN, SCL_PIN, 100000);
Wire.setTimeOut(20);
sensor.begin(Wire, SHT40_I2C_ADDR_44);
return ok;
}
void setup() {
Serial.begin(115200);
busReady = startBus();
delay(10);
Serial.printf("S01 core=3.3.12 driver=1.1.2 SDA=8 SCL=9 address=0x44 bus=%u\n", busReady);
if (busReady) {
uint32_t serialNumber = 0;
const int16_t error = sensor.serialNumber(serialNumber);
if (error == 0) Serial.printf("sensor_serial=%lu\n", (unsigned long)serialNumber);
else Serial.printf("sensor_serial_unavailable error=%d; measurements will retry\n", error);
}
sampledAt = millis();
}
void loop() {
const uint32_t now = millis();
if (uint32_t(now - sampledAt) < PERIOD_MS) return;
sampledAt = now;
++attempts;
if (!busReady) busReady = startBus();
if (!busReady) {
hadError = true;
Serial.printf("attempt=%lu uptime_ms=%lu state=BUS_ERROR T=NA RH=NA\n", (unsigned long)attempts, (unsigned long)now);
return;
}
float temperature = NAN, humidityRaw = NAN;
const int16_t error = sensor.measureHighPrecision(temperature, humidityRaw);
if (error != 0 || !isfinite(temperature) || !isfinite(humidityRaw)) {
hadError = true;
++failures;
char message[128] = "non-finite sensor result";
if (error != 0) errorToString(error, message, sizeof(message));
Serial.printf("attempt=%lu uptime_ms=%lu state=ERROR T=NA RH=NA error=%d detail=%s\n",
(unsigned long)attempts, (unsigned long)now, error, message);
if (failures % 3 == 0) {
const int16_t resetError = sensor.softReset();
Serial.printf("retry_soft_reset error=%d\n", resetError);
delay(10);
}
return;
}
const float humidityDisplay = fminf(100.0f, fmaxf(0.0f, humidityRaw));
Serial.printf("attempt=%lu uptime_ms=%lu state=%s T_C=%.2f RH_raw=%.2f RH_display=%.2f clipped=%u\n",
(unsigned long)attempts, (unsigned long)now, hadError ? "RECOVERED" : "VALID",
temperature, humidityRaw, humidityDisplay, humidityRaw != humidityDisplay);
hadError = false;
failures = 0;
}
参考:[1] Sensirion SHT4x datasheet V6.4:数据格式、CRC、命令、换算与复位[2] Sensirion Arduino SHT4x 1.1.2:高精度读取与错误返回[3] Sensirion Core 0.7.3:接收帧与 CRC 验证[6] Arduino-ESP32 3.3.12 Wire 实现:超时与总线初始化
把正常、断线、恢复各留一段记录
上传后先保存启动版本、总线状态与真实序列号。之后至少记录10条 VALID,保留 attempt 和 uptime_ms,检查单位与采样间隔。不要用本页截图或任意示例数值填自己的观察表。程序的2秒间隔是实验配置,不是精度保证。
故障实验先断电在 SDA 串入一只开关,再上电。通过开关断开信号,观察后续记录转为 ERROR、T=NA、RH=NA;错误码以实际结果为准。闭合后等待下一轮读取和必要的重试,第一次成功应是 RECOVERED。用开关执行断线,不带电移动供电导线。
将三种条件写入下载包 observations.csv,包含日期、板修订、驱动版本、样本号、错误与恢复。若对照另一温湿度计,记下其型号、摆放、等待时间和误差来源;普通仪表互相比对不等于完成计量校准。
- 正常连接保存启动和连续10条读数。
- 断开预装的SDA开关,保存失败码与NA,不把旧值算为有效。
- 闭合开关,观察RECOVERED之后重新进入VALID。
- 断电并恢复最小接线,保存CSV和未通过项目。
- 做到这里,你应该看到
- 每条记录都能分清当前条件与有效性;没有实板条件就保留空白观察表。
参考:[1] Sensirion SHT4x datasheet V6.4:数据格式、CRC、命令、换算与复位[2] Sensirion Arduino SHT4x 1.1.2:高精度读取与错误返回[4] Adafruit SHT40 PID4885:供电、地址、上拉和引脚
按看到的现象排错,再调整摆放
先保留实际错误文本,再按下表从最贴近现象的一项检查。扫描应答、数据读取、CRC 校验和环境精度分别回答不同问题;0x44 出现过,并不能让持续 ERROR 的测量变成有效。
读数稳定后,把模块移离 S3、稳压器、手指、USB 线接头和局部热源,等环境稳定再比较。湿度异常时检查水滴、溶剂、灰尘和气流影响,不向敏感窗口喷水或用热风烘烤。普通温湿度计对照只能帮助观察差异;要记录其型号、位置和等待时间,不写成完成计量校准。
| 现象 | 先做这项检查 | 恢复判据 |
|---|---|---|
| 没有任何启动或采样文字 | 核对 USB-to-UART、端口、115200,打开监视器后复位 | 出现 S01 启动行和采样行 |
| 持续 state=BUS_ERROR | 核对板目标和 Wire.begin(8, 9) 的总线初始化;保留启动状态 | 总线初始化成功,程序进入测量 |
| 持续 state=ERROR | 用 P06 扫描 0x44,再断电核对 VIN/GND、SDA8/SCL9、模块型号和短线 | 重新读取成功,输出新的有效值 |
| 扫描有 0x44,测量仍报错 | 保存 error/detail,核对两个库版本、接触和 CRC 相关错误 | 测量返回成功;不能只以扫描应答收口 |
| 闭合 SDA 开关后没有恢复 | 等待后续采样与重试;仍失败则断电复核线路,再按原版本重启 | 出现 RECOVERED 或重启后的 VALID,并继续得到新值 |
| 能读数,但温度持续偏高 | 远离板上热源与手指,稳定后与已记录条件的参考仪表比较 | 保留调整前后真实记录,不以任意固定温度为答案 |
参考:[1] Sensirion SHT4x datasheet V6.4:数据格式、CRC、命令、换算与复位[4] Adafruit SHT40 PID4885:供电、地址、上拉和引脚[5] 乐鑫 DevKitC-1 v1.1:固定修订排针与 N8R8 范围[6] Arduino-ESP32 3.3.12 Wire 实现:超时与总线初始化
资料来源与版本说明
按具体模块供电、SHT4x V6.4 手册和固定版本驱动核对。无本站温湿度测量、拔线与恢复实测。资料核对日期:。资料核对、程序构建与实板测试分别记录,不互相替代。