Contributed by WangChong, organized by Ai-Thinker
[Peripheral Porting] Ai-WB2+SHT30 Temperature and Humidity Sensor
Peripheral introduction The SHT30 is a high-precision, low-power temperature and humidity sensor manufactured by Sensirion. It communicates over the I2C interface and is suitable for a wide range of temperature and humidity monitoring applications, such as environmental monitoring, smart home, and industrial control.
Peripheral specifications
- High precision:
- Temperature accuracy: ±0.3°C (over 0°C to 60°C)
- Humidity accuracy: ±3% RH (over 20% to 80% RH)
- Wide measurement range:
- Temperature range: -40°C to +125°C
- Humidity range: 0% RH to 100% RH
- Low power consumption:
- Current consumption in low-power mode can drop to 2 µA, making it ideal for battery-powered devices.
- Fast response time:
- Fast temperature and humidity response that quickly reflects environmental changes, suitable for real-time monitoring scenarios.
- Digital output:
- The SHT30 communicates over the standard I2C interface, which is simple and easy to use, and also supports multiple I2C address selections, making it suitable for applications with multiple sensors.
- Protective design:
- The sensor offers high stability and anti-interference capability, suitable for harsh environments.
\xa0 \xa0\xa0 \xa0\xa0 \xa0\xa0 \xa0Typical applications of the SHT30 sensor include environmental monitoring, air conditioning control, air quality detection, and automotive climate control.
Porting process
According to the datasheet, the SHT30 communicates over I2C. Since we are using the WB2, we need to check the schematic to confirm the WB2's IIC interface pins. Because I am using the WB2-12f development board, I can find the corresponding schematic in the Wb2 section of the Ai-Thinker community, and use the Bouffalo Lab official GPIO function multiplexing to find which pins support IIC.

A complete implementation is already provided under application/iot-solution/demo_sht3x in the SDK. By reading the code, we found that the IIC interface used in the demo is SCL 12 and SDA 3. Connect the temperature and humidity sensor to the WB2 as shown below; the colored wires are SDA and SCL.

Flashing and verification
At this point, the serial port outputs the ambient temperature and humidity every second, so the code is verified.
Code walkthrough
Click to expand full code
#include <stdio.h> // 标准输入输出头文件
#include <FreeRTOS.h> // FreeRTOS 头文件
#include <task.h> // FreeRTOS 任务管理头文件
#include <hosal_i2c.h> // HOSAL I2C 驱动头文件
#include <bl_gpio.h> // GPIO 驱动头文件
#include <blog.h> // 日志打印库
#define SHT31_DEFAULT_ADDR 0x0044 // SHT31 传感器默认的 I2C 地址
#define SHT31_MEAS_HIGHREP 0x2400 // SHT31 传感器的高精度测量命令
#pragma pack(1) // 结构体字节对齐为 1 字节
struct sht3x_data
{
uint8_t st_high; // 温度高字节
uint8_t st_low; // 温度低字节
uint8_t st_crc8; // 温度 CRC 校验字节
uint8_t srh_high; // 湿度高字节
uint8_t srh_low; // 湿度低字节
uint8_t srh_crc8; // 湿度 CRC 校验字节
};
#pragma pack() // 恢复默认字节对齐
// CRC8 校验函数,参数为数据指针和长度
static uint8_t crc8(uint8_t *data, int len)
{
const uint8_t POLYNOMIAL = 0x31; // 多项式
uint8_t crc = 0xFF; // CRC 初始值
for (int j = len; j; --j)
{
crc ^= *data++; // 异或操作
for (int i = 8; i; --i)
{
crc = (crc & 0x80) // 判断最高位
? (crc << 1) ^ POLYNOMIAL // 如果最高位是 1,左移并异或多项式
: (crc << 1); // 否则仅左移
}
}
return crc;
}
int main(void)
{
// 初始化 I2C 设备结构体
static hosal_i2c_dev_t i2c0 = {
.config = {
.address_width = HOSAL_I2C_ADDRESS_WIDTH_7BIT, // 7 位地址模式
.freq = 100000, // I2C 频率 100kHz
.mode = HOSAL_I2C_MODE_MASTER, // 主机模式
.scl = 12, // SCL 引脚为 GPIO 12
.sda = 3, // SDA 引脚为 GPIO 3
},
.port = 0, // I2C 端口 0
};
hosal_i2c_init(&i2c0); // 初始化 I2C 接口
for (;;) { // 无限循环读取数据
struct sht3x_data data; // 定义用于存储 SHT31 数据的结构体
// SHT31 高精度测量命令
uint8_t command[2] = { SHT31_MEAS_HIGHREP >> 8, SHT31_MEAS_HIGHREP & 0xff };
// 发送测量命令给 SHT31 传感器
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]; // 用于存储湿度字符串
// 验证温度数据的 CRC 校验
if (crc8(&data.st_high, 2) == data.st_crc8) {
uint16_t st = data.st_high; // 获取温度高字节
st <<= 8; // 左移 8 位
st |= data.st_low; // 合并低字节
// 转换为实际温度值
int temp = st;
temp *= 17500;
temp /= 0xffff; // 根据公式转换为温度
temp = -4500 + temp; // SHT31 的温度转换公式
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"); // CRC 校验失败,返回 "N/A"
}
// 验证湿度数据的 CRC 校验
if (crc8(&data.srh_high, 2) == data.srh_crc8) {
uint16_t srh = data.srh_high; // 获取湿度高字节
srh <<= 8; // 左移 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 %%"); // CRC 校验失败,返回 "N/A"
}
// 打印温度和湿度数据
blog_info("temperature: %s\thumidity: %s\r\n", temperature_str, humidity_str);
vTaskDelay(portTICK_RATE_MS * 1000); // 延时 1 秒
}
return 0;
}Library functions We organized the code above into library functions for convenient calling.
Main.c
Click to expand full code
#include <stdio.h>
#include <FreeRTOS.h>
#include <task.h>
#include <hosal_i2c.h>
#include <bl_gpio.h>
#include <blog.h>
#include "bh1750.h"
int main(void)
{
bh1750_init();
xTaskCreate(read_bh1750, "BH1750 Task", 4096, NULL, 10, NULL);
return 0;
}SHT3x.h
Click to expand full code
#ifndef SHT_3X_H
#define SHT_3X_H
#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 // SHT31 传感器默认的 I2C 地址
#define SHT31_MEAS_HIGHREP 0x2400 // SHT31 传感器的高精度测量命令
#pragma pack(1) // 结构体字节对齐为 1 字节
struct sht3x_data
{
uint8_t st_high; // 温度高字节
uint8_t st_low; // 温度低字节
uint8_t st_crc8; // 温度 CRC 校验字节
uint8_t srh_high; // 湿度高字节
uint8_t srh_low; // 湿度低字节
uint8_t srh_crc8; // 湿度 CRC 校验字节
};
#pragma pack() // 恢复默认字节对齐
//初始化
void sht3x_init();
//读取任务
void read_sht3x(void *args);
#endifSHT3x.c
Click to expand full code
#include "sht3x.h"
static hosal_i2c_dev_t i2c0 = {
.config = {
.address_width = HOSAL_I2C_ADDRESS_WIDTH_7BIT,
.freq = 100000,
.mode = HOSAL_I2C_MODE_MASTER,
.scl = 12,
.sda = 17,
},
.port = 0,
};
void sht3x_init()
{
blog_info("Initializing I2C...\n");
hosal_i2c_init(&i2c0);
}
// CRC8 校验函数,参数为数据指针和长度
static uint8_t crc8(uint8_t *data, int len)
{
const uint8_t POLYNOMIAL = 0x31; // 多项式
uint8_t crc = 0xFF; // CRC 初始值
for (int j = len; j; --j)
{
crc ^= *data++; // 异或操作
for (int i = 8; i; --i)
{
crc = (crc & 0x80) // 判断最高位
? (crc << 1) ^ POLYNOMIAL // 如果最高位是 1,左移并异或多项式
: (crc << 1); // 否则仅左移
}
}
return crc;
}
void read_sht3x(void *args)
{
for (;;)
{ // 无限循环读取数据
struct sht3x_data data; // 定义用于存储 SHT31 数据的结构体
// SHT31 高精度测量命令
uint8_t command[2] = {SHT31_MEAS_HIGHREP >> 8, SHT31_MEAS_HIGHREP & 0xff};
// 发送测量命令给 SHT31 传感器
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]; // 用于存储湿度字符串
// 验证温度数据的 CRC 校验
if (crc8(&data.st_high, 2) == data.st_crc8)
{
uint16_t st = data.st_high; // 获取温度高字节
st <<= 8; // 左移 8 位
st |= data.st_low; // 合并低字节
// 转换为实际温度值
int temp = st;
temp *= 17500;
temp /= 0xffff; // 根据公式转换为温度
temp = -4500 + temp; // SHT31 的温度转换公式
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"); // CRC 校验失败,返回 "N/A"
}
// 验证湿度数据的 CRC 校验
if (crc8(&data.srh_high, 2) == data.srh_crc8)
{
uint16_t srh = data.srh_high; // 获取湿度高字节
srh <<= 8; // 左移 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 %%"); // CRC 校验失败,返回 "N/A"
}
// 打印温度和湿度数据
blog_info("temperature: %s\thumidity: %s\r\n", temperature_str, humidity_str);
vTaskDelay(portTICK_RATE_MS * 1000); // 延时 1 秒
}
}Project
Attachments: 
demo_sht3x.zip(306.67 KB, Downloads: 14)

