概述
SHT30 是 SHT3x 系列的温湿度传感器,比入门级 DHT11 精度高得多:温度精度 ±0.2°C、湿度精度 ±2%RH。它通过 I2C 总线(两根线的串行通信,一根时钟 SCL、一根数据 SDA)读取,数据带 CRC 校验(循环冗余校验,一种检查数据在传输中有没有被改错的算法,就像快递单号最后一位是防伪码)。本教程用 Ai-WB2 开发板读取 SHT30 的温湿度,串口实时打印,并走完 接线 → 代码编写 → 编译 → 烧录(把编译好的程序写进开发板芯片)→ 运行验证 的完整流程。
用大白话讲:SHT30 是一颗"精致"的温湿度计。主控通过 I2C 走廊(两根线)喊它的"门牌号"(I2C 地址 0x44),发一条"开工测量"的命令(0x2400),它就回 6 个字节:温度 2 字节 + 防伪码 1 字节、湿度 2 字节 + 防伪码 1 字节。主控先验防伪码(CRC)再换算成温度和湿度——防伪码不对就说明数据传坏了,直接报 N/A 而不是给你一个错数。
本教程基于安信可官方 SDK(Ai-Thinker-Open/Ai-Thinker-WB2,版本
release_bl_iot_sdk_1.6.40)的官方示例applications/iot-solution/demo_sht3x编写,代码可在本地 SDK 中直接找到。
按官方示例接线(见 SDK applications/iot-solution/demo_sht3x/README.md),用杜邦线(两端带插针的连接线)连接:
| Ai-WB2 引脚 | SHT30 引脚 |
|---|---|
| IO12 | SCL |
| IO3 | SDA |
| 3V3 | VCC |
| GND | GND |
💡 SHT30 是 I2C 设备,VCC 接 3.3V(SHT30 支持 2.4V~5.5V,本教程统一 3.3V)。 💡 I2C 的 SCL/SDA 是开漏信号(引脚只能主动拉低、不能主动拉高),需要上拉电阻配合,多数 SHT30 模块已板载上拉;裸芯片需在 SCL/SDA 上各接 4.7kΩ 上拉到 3V3。
本教程直接使用官方 SDK 自带的 demo_sht3x 示例工程,打开终端进入该工程目录:
cd ~/Ai-Thinker-WB2/applications/iot-solution/demo_sht3x
说明:
cd是「进入目录」命令,这里进入 SHT3x 示例工程目录;后续的make编译、make flash烧录命令都必须先在这个目录里执行。
工程目录结构说明:
| 文件 | 作用 |
|---|---|
demo_sht3x/main.c |
主程序源码,本教程主要查看的文件 |
Makefile |
编译入口,一般无需修改 |
proj_config.mk |
工程配置(Flash 大小、功能开关等),一般无需修改 |
打开 demo_sht3x/main.c,本步完整代码已移至文末,见:
📜 完整代码 — 位于本页「完整代码」章节,默认折叠,点击展开,与官方示例(
applications/iot-solution/demo_sht3x/demo_sht3x/main.c)完全一致。
代码要点:
| 代码 | 作用 |
|---|---|
.scl = 12、.sda = 3、.freq = 100000 |
I2C 引脚 IO12/IO3、时钟 100kHz,引脚接错就通信不上 |
SHT31_DEFAULT_ADDR 0x0044 |
SHT30 的 I2C 地址(门牌号):ADDR 引脚悬空/接低为 0x44,接高为 0x45,地址错就找不到传感器 |
SHT31_MEAS_HIGHREP 0x2400 |
高重复度测量命令(精度最高、测量约 15ms),不发命令传感器不测量 |
hosal_i2c_master_send(...) / hosal_i2c_master_recv(...) |
先发 2 字节命令,再收 6 字节数据(温度 2B+CRC、湿度 2B+CRC),收不到就读不出温湿度 |
crc8(&data.st_high, 2) == data.st_crc8 |
CRC8 校验(多项式 0x31)防止传输错误,校验不过打印 N/A,不会把坏数据当真值 |
| 温湿度换算公式 | 温度 = 原始值×17500÷0xFFFF−4500(单位 0.01°C),湿度 = 原始值×10000÷0xFFFF(单位 0.01%RH) |
在工程目录执行编译:
make -j8
说明:
make是「编译工程」命令,把代码变成开发板能运行的固件(程序文件);-j8表示用 8 个核并行编译,速度更快。
编译成功后生成固件 build_out/demo_sht3x.bin。
⚠️ 若提示
riscv64-unknown-elf-gcc: command not found,说明工具链权限未配置,先执行cd toolchain/riscv/Linux && . chmod755.sh再重新编译。
开发板保持 USB 连接,确认串口设备号(Linux 下通常为 /dev/ttyUSB0),执行烧录:
make flash p=/dev/ttyUSB0 b=921600
说明:
make flash是「烧录」命令,把编译好的固件写进开发板芯片。p=后面是串口设备号(要改成你电脑上实际的串口,可用ls /dev/ttyUSB*查看),b=是烧录波特率(传输速度)。
⏳ 烧录过程中按提示长按开发板 EN 键进入下载模式(部分开发板自动进入),等待进度条完成即烧录成功。 Windows 平台烧录方法见 Windows 平台快速开始。
烧录完成后开发板自动重启运行,打开串口助手(波特率 921600,波特率 = 串口传输速度,收发两端必须设成一样),每 1 秒打印一次温湿度:
temperature: 26.54 C humidity: 45 %
temperature: 26.53 C humidity: 45 %
...
对着传感器哈气,湿度数值应明显上升;用手捏住传感器,温度数值应缓慢上升。CRC 校验失败时打印 N/A。
看到串口每 1 秒打印一次实时温湿度即为成功;如果一直打印 N/A 或数值固定不变,说明还没成功,对照文末「常见问题与踩坑提示」排查。
💡 用逻辑分析仪观察 IO12/IO3 波形,可看到 I2C 的 START、地址、数据与 STOP 时序(见官方示例
img/logic_analyzer.jpg)。
代码执行流程
例程从启动到运行的完整流程如下(图中的循环箭头表示反复执行):
本文 API 汇总
hosal_i2c_init(i2c)
按 dev 结构体中的引脚、频率、主从模式配置 I2C 控制器(本教程初始化主机模式读取 SHT30)。
参数:
i2c:hosal_i2c_dev_t结构体指针,必填。关键字段:config.mode(可选值:HOSAL_I2C_MODE_MASTER主机 /HOSAL_I2C_MODE_SLAVE从机)、config.scl/config.sda(SCL/SDA 引脚号,本教程 IO12/IO3)、config.freq(可选值:100000标准 100kHz /400000快速 400kHz)、config.address_width(可选值:HOSAL_I2C_ADDRESS_WIDTH_7BIT/HOSAL_I2C_ADDRESS_WIDTH_10BIT)
返回值:成功返回 0;失败返回负值错误码
hosal_i2c_master_send(i2c, dev_addr, data, size, timeout)
以主机身份向指定地址的从机发送一帧数据(含起始位/地址/停止位,本教程发送 SHT30 测量命令)。
参数:
i2c:hosal_i2c_dev_t结构体指针dev_addr:从机设备地址(7 位地址左移 1 位后的字节),如0x44data:发送数据缓冲区指针,必填size:发送字节数,可选值:1~256timeout:等待超时(单位 ms),可选值:如100
返回值:成功返回 0;失败(无 ACK/超时)返回负值错误码
hosal_i2c_master_recv(i2c, dev_addr, data, size, timeout)
以主机身份从指定从机读取一帧数据(本教程接收 SHT30 的 6 字节温湿度数据)。
参数:
i2c:hosal_i2c_dev_t结构体指针dev_addr:从机设备地址(同master_send规则)data:接收数据缓冲区指针,必填size:期望接收字节数(本教程为6)timeout:等待超时(单位 ms)
返回值:成功返回 0;失败返回负值错误码
crc8(data, len)
按 SHT3x 数据手册的 CRC8 算法(多项式 0x31,初值 0xFF)计算数据校验值,用于比对接收到的校验字节。
参数:
data:待校验数据指针(如温度原始值 2 字节),必填len:待校验字节数,可选值:任意正整数(本教程为2)
返回值:8 位校验值(uint8_t)。本教程中与 data.st_crc8 相等则数据可信。此函数为本示例自实现的工具函数,见 demo_sht3x/main.c
blog_info(fmt, ...)
输出一条 INFO 级日志(UART0,受级别过滤),本教程打印温湿度。
参数:
fmt:格式化字符串,同printf用法,必填...:变参,与fmt占位符对应,可省略
返回值:无
完整代码
以下为 demo_sht3x/main.c 完整源码,与官方示例(applications/iot-solution/demo_sht3x/demo_sht3x/main.c)完全一致:
📜 点击展开 demo_sht3x/main.c 完整代码
#include <stdio.h>
#include <FreeRTOS.h>
#include <task.h>
#include <hosal_i2c.h>
#include <bl_gpio.h>
#include <blog.h>
#define SHT31_DEFAULT_ADDR 0x0044
#define SHT31_MEAS_HIGHREP 0x2400
#pragma pack(1)
struct sht3x_data
{
uint8_t st_high;
uint8_t st_low;
uint8_t st_crc8;
uint8_t srh_high;
uint8_t srh_low;
uint8_t srh_crc8;
};
#pragma pack()
static uint8_t crc8(uint8_t *data, int len)
{
const uint8_t POLYNOMIAL = 0x31;
uint8_t crc = 0xFF;
for (int j = len; j; --j)
{
crc ^= *data++;
for (int i = 8; i; --i)
{
crc = (crc & 0x80)
? (crc << 1) ^ POLYNOMIAL
: (crc << 1);
}
}
return crc;
}
int main(void)
{
static hosal_i2c_dev_t i2c0 = {
.config = {
.address_width = HOSAL_I2C_ADDRESS_WIDTH_7BIT,
.freq = 100000,
.mode = HOSAL_I2C_MODE_MASTER,
.scl = 12,
.sda = 3,
},
.port = 0,
};
hosal_i2c_init(&i2c0);
for (;;) {
struct sht3x_data data;
uint8_t command[2] = { SHT31_MEAS_HIGHREP >> 8, SHT31_MEAS_HIGHREP & 0xff };
hosal_i2c_master_send(&i2c0, SHT31_DEFAULT_ADDR, command, sizeof command, 100);
hosal_i2c_master_recv(&i2c0, SHT31_DEFAULT_ADDR, (uint8_t*)&data, sizeof data, 100);
char temperature_str[8];
char humidity_str[8];
if (crc8(&data.st_high, 2) == data.st_crc8) {
uint16_t st = data.st_high;
st <<= 8;
st |= data.st_low;
int temp = st;
temp *= 17500;
temp /= 0xffff;
temp = -4500 + temp;
int temperature_integer = temp / 100;
if (temp < 0) {
temp = -temp;
}
unsigned temperature_decimal = temp % 100;
sprintf(temperature_str, "%d.%02u C", temperature_integer, temperature_decimal);
}
else {
sprintf(temperature_str, "%s", "N/A C");
}
if (crc8(&data.srh_high, 2) == data.srh_crc8) {
uint16_t srh = data.srh_high;
srh <<= 8;
srh |= data.srh_low;
unsigned humidity = srh;
humidity *= 10000;
humidity /= 0xFFFF;
unsigned humidity_integer = humidity / 100;
sprintf(humidity_str, "%u %%", humidity_integer);
}
else {
sprintf(humidity_str, "N/A %%");
}
blog_info("temperature: %s\thumidity: %s\r\n", temperature_str, humidity_str);
vTaskDelay(portTICK_RATE_MS * 1000);
}
return 0;
}常见问题与踩坑提示
⚠️ 打印 N/A(CRC 校验失败)
原因:接线接触不良、SDA/SCL 无上拉电阻、或模块供电不足
解决:确认 SDA/SCL 有 4.7kΩ 上拉;缩短杜邦线;确认模块 VCC 接 3V3 且共地(GND 接 GND)
⚠️ 数据为 0 或固定不变
原因:从机地址错误(SHT30 的 ADDR 引脚接 3V3 时地址变为 0x45)
解决:确认模块 ADDR 状态,SHT31_DEFAULT_ADDR 改为 0x0045 或对应地址后重新编译烧录
⚠️ 读不到任何数据(无打印)
原因:接线错误、传感器损坏,或 IO12/IO3 被其他复用功能占用
解决:对照接线表逐一核对;确认工程中无其他模块占用这两个引脚;换一块 SHT30 测试
⚠️ 找不到串口设备或提示无权限
原因:Linux 下 /dev/ttyUSB0 不存在或权限不足,Windows 下未安装 USB 转串口驱动
解决:Linux 用 ls /dev/ttyUSB* 确认设备号,权限不足执行 sudo usermod -aG dialout $USER 后重新登录;Windows 在设备管理器安装驱动并确认 COM 口号
⚠️ 烧录一直卡住等待,进度条不动
原因:未进入下载模式,或数据线只能充电不能传数据
解决:烧录时按提示长按 EN 键进入下载模式;换一根能传数据的 Type-C 数据线后重试
⚠️ 执行 make 报找不到 Makefile
原因:在错误的目录执行了编译命令(必须在示例工程目录内)
解决:先执行 cd ~/Ai-Thinker-WB2/applications/iot-solution/demo_sht3x 进入工程目录,再执行 make -j8
运行自检
串口每秒打印一次温湿度,哈气湿度上升、手捏温度上升、数据无 N/A,即 SHT30 温湿度测量验证通过。
遇到问题?
如有其他问题,请到统一的提问与讨论区:Ai-Thinker Discussions

