由 WangChong 贡献,Ai-Thinker 进行整理
【外设移植】Ai-WB2+SHT30 湿温度传感器
外设介绍 SHT30 是一种高精度、低功耗的温湿度传感器,由 Sensirion 公司生产。该传感器使用 I2C 通信接口,适用于广泛的温湿度监测应用,如环境监测、智能家居、工业控制等。
外设规格参数
- 高精度:
- 温度精度:±0.3°C(在 0°C 至 60°C 范围内)
- 湿度精度:±3% RH(在 20% 至 80% RH 范围内)
- 宽测量范围:
- 温度范围:-40°C 到 +125°C
- 湿度范围:0% RH 到 100% RH
- 低功耗:
- 低功耗模式下的电流消耗可以降到 2 µA,非常适合电池供电设备。
- 快速响应时间:
- 温湿度响应时间快,能迅速反映环境变化,适用于需要实时监测的场景。
- 数字输出:
- SHT30 通过标准 I2C 接口进行通信,使用简单方便,并且还支持多种 I2C 地址选择,适合多个传感器的应用。
- 防护性设计:
- 传感器具有高稳定性和抗干扰能力,适合在恶劣环境下使用。
SHT30 传感器的典型应用包括环境监测、空调控制、空气质量检测、汽车气候控制等。
移植过程
根据数据手册得知, SHT30 是使用的 I2C 通信,同时我们使用的是 WB2,因此我们需要根据原理图确认 WB2 的 IIC 接口 PIN,由于我使用的是 WB2-12f 的开发板,所以可以在安信可社区 Wb2 专题下找到对应的原理图,同时根据博流官方 GPIO 的功能复用可以找到哪些 PIN 支持 IIC

在 SDK 下的 application/iot-solution/demo_sht3x下 已经提供了一个完整的实现。通过阅读代码我们发现, demo中使用的IIC的接口为SCL 12 和 SDA3. 我们将湿温度传感器连接到Wb2上,如下图所示, 彩色线分别为SDA和SCL

烧录验证
此时发现串口每隔一秒输出环境的湿温度信息, 由此代码验证通过
代码解读
📜 点击展开完整代码
c
#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;
}库函数 我们将上面的代码整理成库函数的方式方便调用
Main.c
📜 点击展开完整代码
c
#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
📜 点击展开完整代码
c
#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
📜 点击展开完整代码
c
#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 秒
}
}工程
上传的附件: 
demo_sht3x.zip(306.67 KB, 下载次数: 14)

