1. 项目概述
SHT25-TR-0.4KS是Sensirion公司推出的一款高精度数字温湿度传感器,采用I2C接口与STM32微控制器通信。在实际项目中,我发现很多工程师在使用这款传感器时都会遇到一些共性问题,比如I2C通信不稳定、数据校验错误、功耗控制不当等。本文将基于STM32F4系列MCU和HAL库,详细讲解如何实现一个稳定可靠的SHT25驱动。
提示:SHT25虽然接口简单,但要发挥其最佳性能需要注意多个细节,包括I2C时序控制、CRC校验、低功耗设计等。
2. 硬件设计与连接
2.1 传感器引脚定义
SHT25采用DFN-6封装,引脚定义如下:
| 引脚编号 | 引脚名称 | 功能描述 |
|---|---|---|
| 1 | SDA | I2C数据线 |
| 2 | VDD | 电源(2.1-3.6V) |
| 3 | ALERT | 报警输出(可选) |
| 4 | GND | 地 |
| 5 | SCL | I2C时钟线 |
| 6 | NC | 不连接 |
2.2 STM32连接方案
推荐使用STM32F4的硬件I2C接口连接SHT25:
-
电源连接:
- VDD接3.3V
- GND接系统地
- 建议在VDD和GND之间加0.1μF去耦电容
-
I2C连接:
- SDA接PB9(I2C1_SDA)或PB11(I2C2_SDA)
- SCL接PB8(I2C1_SCL)或PB10(I2C2_SCL)
- 上拉电阻:4.7kΩ(典型值)
-
ALERT引脚(可选):
- 可连接到任意GPIO用于中断检测
- 如果不使用可悬空
3. 软件驱动实现
3.1 HAL库初始化
首先配置I2C外设:
c复制I2C_HandleTypeDef hi2c1;
void I2C_Init(void)
{
hi2c1.Instance = I2C1;
hi2c1.Init.ClockSpeed = 100000; // 100kHz
hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c1) != HAL_OK)
{
Error_Handler();
}
}
3.2 传感器命令定义
c复制#define SHT25_ADDR 0x40 // 7位地址
#define SHT25_CMD_TEMP_NOHOLD 0xF3
#define SHT25_CMD_HUMI_NOHOLD 0xF5
#define SHT25_CMD_READ_REG 0xE7
#define SHT25_CMD_WRITE_REG 0xE6
#define SHT25_CMD_SOFT_RESET 0xFE
// 用户寄存器位定义
#define SHT25_REG_RES_MASK 0x81
#define SHT25_REG_END_OF_BAT 0x40
#define SHT25_REG_HEATER_ON 0x04
#define SHT25_REG_OTP_RELOAD 0x02
3.3 温度读取函数实现
c复制float SHT25_ReadTemperature(void)
{
uint8_t cmd = SHT25_CMD_TEMP_NOHOLD;
uint8_t data[3];
uint16_t rawTemp;
float temperature;
// 发送温度测量命令
HAL_I2C_Master_Transmit(&hi2c1, SHT25_ADDR, &cmd, 1, HAL_MAX_DELAY);
// 等待测量完成(典型时间85ms)
HAL_Delay(85);
// 读取3字节数据(2字节数据+1字节CRC)
HAL_I2C_Master_Receive(&hi2c1, SHT25_ADDR, data, 3, HAL_MAX_DELAY);
// 校验CRC
if(!SHT25_CheckCRC(data, 2, data[2]))
{
return -999.9f; // CRC错误
}
// 计算温度值
rawTemp = (data[0] << 8) | data[1];
temperature = -46.85f + 175.72f * (rawTemp / 65536.0f);
return temperature;
}
3.4 湿度读取函数实现
c复制float SHT25_ReadHumidity(void)
{
uint8_t cmd = SHT25_CMD_HUMI_NOHOLD;
uint8_t data[3];
uint16_t rawHumi;
float humidity;
// 发送湿度测量命令
HAL_I2C_Master_Transmit(&hi2c1, SHT25_ADDR, &cmd, 1, HAL_MAX_DELAY);
// 等待测量完成(典型时间29ms)
HAL_Delay(29);
// 读取3字节数据
HAL_I2C_Master_Receive(&hi2c1, SHT25_ADDR, data, 3, HAL_MAX_DELAY);
// 校验CRC
if(!SHT25_CheckCRC(data, 2, data[2]))
{
return -999.9f; // CRC错误
}
// 计算湿度值
rawHumi = (data[0] << 8) | data[1];
humidity = -6.0f + 125.0f * (rawHumi / 65536.0f);
// 限制湿度范围
if(humidity > 100.0f) humidity = 100.0f;
if(humidity < 0.0f) humidity = 0.0f;
return humidity;
}
3.5 CRC校验函数
c复制uint8_t SHT25_CheckCRC(uint8_t *data, uint8_t len, uint8_t checksum)
{
uint8_t crc = 0;
uint8_t i, j;
for(i = 0; i < len; i++)
{
crc ^= data[i];
for(j = 0; j < 8; j++)
{
if(crc & 0x80)
{
crc = (crc << 1) ^ 0x31;
}
else
{
crc <<= 1;
}
}
}
return (crc == checksum);
}
4. 高级功能实现
4.1 用户寄存器配置
SHT25的用户寄存器可以配置多项参数:
c复制void SHT25_ConfigUserReg(uint8_t config)
{
uint8_t cmd[2];
cmd[0] = SHT25_CMD_WRITE_REG;
cmd[1] = config;
HAL_I2C_Master_Transmit(&hi2c1, SHT25_ADDR, cmd, 2, HAL_MAX_DELAY);
}
uint8_t SHT25_ReadUserReg(void)
{
uint8_t cmd = SHT25_CMD_READ_REG;
uint8_t reg;
HAL_I2C_Master_Transmit(&hi2c1, SHT25_ADDR, &cmd, 1, HAL_MAX_DELAY);
HAL_I2C_Master_Receive(&hi2c1, SHT25_ADDR, ®, 1, HAL_MAX_DELAY);
return reg;
}
4.2 低功耗模式实现
SHT25具有极低的待机功耗,可以通过以下方式优化功耗:
- 在两次测量之间将传感器置于空闲模式
- 使用非保持模式测量
- 适当延长测量间隔
c复制void SHT25_EnterLowPowerMode(void)
{
// 关闭加热器
uint8_t reg = SHT25_ReadUserReg();
reg &= ~SHT25_REG_HEATER_ON;
SHT25_ConfigUserReg(reg);
// 发送软复位命令确保传感器处于已知状态
uint8_t cmd = SHT25_CMD_SOFT_RESET;
HAL_I2C_Master_Transmit(&hi2c1, SHT25_ADDR, &cmd, 1, HAL_MAX_DELAY);
HAL_Delay(15); // 等待复位完成
}
4.3 加热器控制
SHT25内置加热器可用于:
- 除湿
- 验证传感器功能
- 在冷凝环境下使用
c复制void SHT25_EnableHeater(uint8_t enable)
{
uint8_t reg = SHT25_ReadUserReg();
if(enable)
{
reg |= SHT25_REG_HEATER_ON;
}
else
{
reg &= ~SHT25_REG_HEATER_ON;
}
SHT25_ConfigUserReg(reg);
}
5. 实际应用中的问题与解决方案
5.1 I2C通信失败排查
常见问题及解决方法:
-
无应答:
- 检查硬件连接是否正确
- 确认上拉电阻值合适(4.7kΩ)
- 用逻辑分析仪检查I2C波形
-
CRC校验失败:
- 降低I2C时钟频率
- 增加测量后的延迟时间
- 检查电源稳定性
-
数据异常:
- 检查电源电压是否在2.1-3.6V范围内
- 确保传感器未暴露在结露环境
- 尝试软复位传感器
5.2 精度优化技巧
-
温度补偿:
- 避免将传感器靠近热源
- PCB布局时远离MCU等发热元件
- 必要时进行软件补偿
-
采样策略:
- 连续测量时保持适当间隔
- 取多次测量平均值
- 避免快速连续切换温湿度测量模式
-
校准方法:
- 在已知温湿度环境下进行单点校准
- 记录偏移量并在软件中补偿
- 定期检查传感器精度
5.3 长期稳定性维护
-
定期自检:
- 检查电池状态位(End of Battery)
- 定期读取电子识别码验证传感器
- 监控测量值的变化趋势
-
异常处理:
- 实现超时机制
- 添加数据合理性检查
- 记录错误日志便于分析
-
固件更新:
- 保留校准参数存储区
- 支持通过I2C更新校准参数
- 实现传感器诊断功能
6. 完整示例代码
下面是一个完整的SHT25驱动示例,包含所有必要功能:
c复制#include "stm32f4xx_hal.h"
#include <stdint.h>
#include <math.h>
#define SHT25_ADDR 0x40
#define SHT25_CMD_TEMP_NOHOLD 0xF3
#define SHT25_CMD_HUMI_NOHOLD 0xF5
#define SHT25_CMD_READ_REG 0xE7
#define SHT25_CMD_WRITE_REG 0xE6
#define SHT25_CMD_SOFT_RESET 0xFE
typedef struct {
float temperature;
float humidity;
uint8_t error;
} SHT25_Data;
I2C_HandleTypeDef hi2c1;
uint8_t SHT25_Init(void);
uint8_t SHT25_ReadData(SHT25_Data *data);
uint8_t SHT25_CheckCRC(uint8_t *data, uint8_t len, uint8_t checksum);
void SHT25_SoftReset(void);
uint8_t SHT25_Init(void)
{
// 初始化I2C
hi2c1.Instance = I2C1;
hi2c1.Init.ClockSpeed = 100000;
hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if(HAL_I2C_Init(&hi2c1) != HAL_OK)
{
return 0;
}
// 复位传感器
SHT25_SoftReset();
return 1;
}
uint8_t SHT25_ReadData(SHT25_Data *data)
{
uint8_t tempCmd = SHT25_CMD_TEMP_NOHOLD;
uint8_t humiCmd = SHT25_CMD_HUMI_NOHOLD;
uint8_t tempData[3], humiData[3];
uint16_t rawTemp, rawHumi;
// 读取温度
if(HAL_I2C_Master_Transmit(&hi2c1, SHT25_ADDR, &tempCmd, 1, 100) != HAL_OK)
{
data->error = 1;
return 0;
}
HAL_Delay(85);
if(HAL_I2C_Master_Receive(&hi2c1, SHT25_ADDR, tempData, 3, 100) != HAL_OK)
{
data->error = 2;
return 0;
}
if(!SHT25_CheckCRC(tempData, 2, tempData[2]))
{
data->error = 3;
return 0;
}
// 读取湿度
if(HAL_I2C_Master_Transmit(&hi2c1, SHT25_ADDR, &humiCmd, 1, 100) != HAL_OK)
{
data->error = 4;
return 0;
}
HAL_Delay(29);
if(HAL_I2C_Master_Receive(&hi2c1, SHT25_ADDR, humiData, 3, 100) != HAL_OK)
{
data->error = 5;
return 0;
}
if(!SHT25_CheckCRC(humiData, 2, humiData[2]))
{
data->error = 6;
return 0;
}
// 计算温度
rawTemp = (tempData[0] << 8) | tempData[1];
data->temperature = -46.85f + 175.72f * (rawTemp / 65536.0f);
// 计算湿度
rawHumi = (humiData[0] << 8) | humiData[1];
data->humidity = -6.0f + 125.0f * (rawHumi / 65536.0f);
// 限制湿度范围
if(data->humidity > 100.0f) data->humidity = 100.0f;
if(data->humidity < 0.0f) data->humidity = 0.0f;
data->error = 0;
return 1;
}
uint8_t SHT25_CheckCRC(uint8_t *data, uint8_t len, uint8_t checksum)
{
uint8_t crc = 0;
uint8_t i, j;
for(i = 0; i < len; i++)
{
crc ^= data[i];
for(j = 0; j < 8; j++)
{
if(crc & 0x80)
{
crc = (crc << 1) ^ 0x31;
}
else
{
crc <<= 1;
}
}
}
return (crc == checksum);
}
void SHT25_SoftReset(void)
{
uint8_t cmd = SHT25_CMD_SOFT_RESET;
HAL_I2C_Master_Transmit(&hi2c1, SHT25_ADDR, &cmd, 1, 100);
HAL_Delay(15);
}
7. 实际项目应用建议
在实际项目中应用SHT25时,我有以下几点经验分享:
-
PCB布局要点:
- 尽量缩短传感器与MCU的距离
- I2C走线避免与高频信号平行
- 在传感器下方铺地以提高抗干扰能力
-
软件架构设计:
- 将传感器驱动与业务逻辑分离
- 实现异步测量模式提高系统响应性
- 添加传感器健康状态监测
-
长期运行优化:
- 定期检查传感器精度
- 实现自动校准功能
- 记录传感器工作时间和使用环境
-
多传感器组网:
- 通过I2C多路复用器支持多个SHT25
- 实现地址自动分配功能
- 设计分布式温湿度监测方案
通过以上方法,可以构建一个稳定可靠的温湿度监测系统。在我的多个项目中,这种实现方式已经连续稳定运行超过2年,精度保持在厂商标称范围内。