在嵌入式开发领域,环境参数监测是最基础也最实用的功能之一。温湿度数据采集作为物联网感知层的核心能力,被广泛应用于智能家居、农业大棚、仓储监控等场景。STM32F103作为经典的Cortex-M3内核微控制器,以其出色的性价比和丰富的外设资源,成为众多开发者的首选平台。
DHT11和DHT22(也称AM2302)是市面上最常见的数字温湿度传感器,采用单总线协议通信。两者主要区别在于测量精度和响应速度:
本项目要实现的核心功能包括:
注意:DHT系列传感器对时序要求严格,信号线建议长度不超过20米,且需要外接4.7K-10K上拉电阻。
code复制VDD(3.3V) ---+--- DHTxx_VCC
|
[10K]
|
GPIO_PA1 -----+--- DHTxx_DATA
|
=== 0.1μF
|
GND ---------+--- DHTxx_GND
关键细节:DATA线必须接上拉电阻,否则无法产生正确的高低电平转换。建议使用开发板已有上拉的引脚(如I2C接口的PB6/PB7)。
DHTxx的通信包含三个关键阶段:
c复制void DHT_StartSignal(void) {
GPIO_ResetBits(DHT_PORT, DHT_PIN); // 拉低数据线
Delay_ms(20); // 保持低电平20ms
GPIO_SetBits(DHT_PORT, DHT_PIN); // 释放总线
Delay_us(30); // 等待30μs
}
c复制uint8_t DHT_ReadBit(void) {
while(!GPIO_ReadInputDataBit(DHT_PORT, DHT_PIN)); // 等待低电平结束
Delay_us(40); // 延时40μs后采样
return GPIO_ReadInputDataBit(DHT_PORT, DHT_PIN);
}
完整的数据接收函数示例:
c复制int DHT_ReadData(float *temp, float *humi) {
uint8_t data[5] = {0};
DHT_StartSignal();
if(!DHT_CheckResponse()) return -1;
for(int i=0; i<5; i++) {
for(int j=7; j>=0; j--) {
data[i] |= DHT_ReadBit() << j;
}
}
if(data[4] != (data[0]+data[1]+data[2]+data[3]))
return -2; // 校验失败
if(DHT_TYPE == 11) {
*humi = data[0];
*temp = data[2];
} else {
*humi = data[0] + data[1]*0.1;
*temp = data[2] + (data[3]&0x7F)*0.1;
if(data[3]&0x80) *temp = -*temp; // 负温度处理
}
return 0;
}
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 一直返回校验错误 | 电源不稳定 | 增加去耦电容,检查接线 |
| 读取超时 | 上拉电阻过大/过小 | 更换4.7K-10K标准电阻 |
| 数据跳变严重 | 信号干扰 | 缩短线长,使用屏蔽线 |
| 湿度显示99% | 传感器结露 | 检查环境是否过饱和 |
c复制void EXTIx_IRQHandler(void) {
if(EXTI_GetITStatus(EXTI_Linex) != RESET) {
uint32_t t = TIM_GetCounter(TIMx);
// 计算时间差并判断bit值
EXTI_ClearITPendingBit(EXTI_Linex);
}
}
c复制#pragma import(__use_no_semihosting)
void _sys_exit(int x) { x = x; }
struct __FILE { int handle; };
FILE __stdout;
int fputc(int ch, FILE *f) {
USART_SendData(USART1, (uint8_t)ch);
while(USART_GetFlagStatus(USART1, USART_FLAG_TC)==RESET);
return ch;
}
c复制void Enter_LowPowerMode(void) {
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFI);
SystemInit(); // 唤醒后重新初始化时钟
}
单总线并联:
RS485中继:
通过ESP8266上传至MQTT服务器:
c复制AT+CIPSTART="TCP","mqtt.broker.com",1883
AT+CIPSEND=50
{..."temperature":25.6,"humidity":47.2...}
阿里云物联网平台接入示例:
我在实际项目中发现,DHT22在高温高湿环境下容易出现数据漂移。建议在代码中添加滑动平均滤波:
c复制#define FILTER_LEN 5
float temp_buf[FILTER_LEN] = {0};
float Filter_Value(float new_val) {
static int index = 0;
float sum = 0;
temp_buf[index++] = new_val;
if(index >= FILTER_LEN) index = 0;
for(int i=0; i<FILTER_LEN; i++) {
sum += temp_buf[i];
}
return sum / FILTER_LEN;
}
对于需要更高精度的场景,建议考虑SHT30或BME280等I2C接口传感器,它们的抗干扰能力和长期稳定性明显优于DHT系列。不过对于大多数常规应用,本文介绍的方案已经能够满足需求,且具有极佳的成本优势。