在嵌入式系统开发中,环境监测是一个基础但至关重要的功能模块。FHT31-TR作为一款高精度数字温湿度传感器,凭借其±2%RH的湿度精度和±0.2℃的温度精度,成为工业级应用的理想选择。本项目基于STM32F4系列MCU和HAL库,实现了对FHT31-TR传感器的完整驱动开发。
选择STM32F4XX系列主要考虑其丰富的外设资源(特别是I2C接口的稳定性)和适中的功耗表现。HAL库的采用则大幅降低了底层硬件操作的复杂度,让开发者能更专注于业务逻辑实现。这套方案已成功应用于智能农业大棚监控系统,连续运行6个月保持数据采集零误差。
FHT31-TR采用I2C数字接口,工作电压范围2.4V-5.5V,典型功耗1.08mW(@1次/秒测量)。其特有的CRC校验功能可确保数据传输可靠性。传感器内部结构包含:
关键提示:传感器上电后需要至少15ms的启动时间,过早发送指令会导致初始化失败。这是实际调试中最容易忽视的问题。
典型接线配置如下表:
| STM32F4引脚 | FHT31-TR引脚 | 连接说明 |
|---|---|---|
| PB6 | SCL | 时钟线需接4.7kΩ上拉 |
| PB7 | SDA | 数据线需接4.7kΩ上拉 |
| 3.3V | VDD | 建议独立供电 |
| GND | GND | 共地处理 |
实测中发现,当I2C总线长度超过30cm时,建议:
c复制I2C_HandleTypeDef hi2c1;
void MX_I2C1_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();
}
}
FHT31-TR的核心指令包括:
c复制#define FHT31_MEAS_HIGHREP 0x2400 // 高精度测量
#define FHT31_MEAS_MEDREP 0x240B // 中等精度
#define FHT31_MEAS_LOWREP 0x2416 // 低精度
#define FHT31_READSTATUS 0xF32D // 状态读取
#define FHT31_CLEARSTATUS 0x3041 // 状态清除
#define FHT31_SOFTRESET 0x30A2 // 软复位
实际测试表明,高精度模式下的典型响应时间为15ms,而低精度模式仅需4ms。在电池供电场景建议使用中等精度模式。
完整的数据采集流程包含:
CRC校验算法实现:
c复制uint8_t CheckCRC8(uint8_t *data, uint8_t len)
{
uint8_t crc = 0xFF;
for(uint8_t i=0; i<len; i++){
crc ^= data[i];
for(uint8_t bit=0; bit<8; bit++){
if(crc & 0x80){
crc = (crc << 1) ^ 0x31;
}else{
crc <<= 1;
}
}
}
return crc;
}
温度转换(单位℃):
code复制T = -45 + 175 * (raw_temp / 65535.0)
湿度转换(单位%RH):
code复制RH = 100 * (raw_humidity / 65535.0)
为提高计算效率,建议采用定点数运算:
c复制int32_t temp = (raw_temp * 17500) / 65535 - 4500; // 单位0.01℃
int32_t humi = (raw_humidity * 10000) / 65535; // 单位0.01%RH
针对工业现场干扰,推荐采用滑动平均滤波:
c复制#define FILTER_LEN 5
typedef struct {
int32_t temp_buf[FILTER_LEN];
int32_t humi_buf[FILTER_LEN];
uint8_t index;
} SensorFilter;
void Filter_Update(SensorFilter *f, int32_t temp, int32_t humi)
{
f->temp_buf[f->index] = temp;
f->humi_buf[f->index] = humi;
f->index = (f->index + 1) % FILTER_LEN;
}
void Filter_GetResult(SensorFilter *f, int32_t *temp, int32_t *humi)
{
int64_t sum_temp = 0, sum_humi = 0;
for(uint8_t i=0; i<FILTER_LEN; i++){
sum_temp += f->temp_buf[i];
sum_humi += f->humi_buf[i];
}
*temp = sum_temp / FILTER_LEN;
*humi = sum_humi / FILTER_LEN;
}
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| HAL_I2C_ERROR_AF | 从机无应答 | 检查传感器供电、I2C地址 |
| CRC校验失败 | 信号干扰 | 缩短总线长度,加强滤波 |
| 数据跳变大 | 电源噪声 | 增加10μF去耦电容 |
| 持续返回0xFF | 传感器死机 | 发送软复位指令 |
建议使用Saleae逻辑分析仪捕获I2C波形时,重点关注:
典型故障波形特征:
对于电池供电设备,可采取以下策略:
实测电流对比:
| 工作模式 | 平均电流 |
|---|---|
| 连续高精度 | 1.2mA |
| 间歇低精度 | 85μA |
| 深度休眠 | 12μA |
关键实现代码:
c复制void Enter_LowPowerMode(void)
{
HAL_GPIO_WritePin(SENSOR_PWR_GPIO_Port, SENSOR_PWR_Pin, GPIO_PIN_RESET);
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
SystemClock_Config(); // 唤醒后需重新配置时钟
}
基于现有驱动可进一步实现:
一个典型的报警判断逻辑:
c复制#define TEMP_ALARM_HIGH 5000 // 50.00℃
#define HUMI_ALARM_LOW 3000 // 30.00%RH
void CheckAlarm(int32_t temp, int32_t humi)
{
static uint8_t alarm_flag = 0;
if(temp > TEMP_ALARM_HIGH){
if(!(alarm_flag & 0x01)){
SendAlarm(ALARM_OVER_TEMP);
alarm_flag |= 0x01;
}
}else{
alarm_flag &= ~0x01;
}
if(humi < HUMI_ALARM_LOW){
if(!(alarm_flag & 0x02)){
SendAlarm(ALARM_LOW_HUMI);
alarm_flag |= 0x02;
}
}else{
alarm_flag &= ~0x02;
}
}
在实际部署中发现,传感器长期暴露在结露环境中会导致精度下降。建议在户外应用时增加聚四氟乙烯防水透气膜,这能使传感器寿命延长3倍以上。