本帖最后由 WangChong 于 2024-9-9 16:02 编辑
外设介绍
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
烧录验证
此时发现串口每隔一秒输出环境的湿温度信息, 由此代码验证通过
代码解读
- #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
- #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
- #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);
- #endif
复制代码
SHT3x.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, 下载次数: 0)
|
|