基于51单片机的DHT11温湿度传感器代码分析
2025-09-30 来源:cnblogs
芯片手册地址:https://www.semiee.com/22bcf613-ecfd-4e04-bfa4-11af41666e4b.html
DHT11的时序分析,读取DHT数据的步骤:
主机发送起始信号(脉冲信号,低电平和高电平)
从机回应响应信号(脉冲信号,低电平和高电平)
开始传输40bit的数据。传输完成后,由于上拉电阻作用,自动拉高


根据数据时序图和信号特性表,还有数据手册中的描述可以看出,在第一个步骤中,主机发送起始信号拉低时间是18-30ms之间,典型值是20ms,在程序中选择的是典型值20ms(我对典型值的理解是比较可靠的一个值),然后是主机释放总线时间是10-20us,由于我在编程的时候选择是10us的一个函数,所以选择的是10us或者20us的值
步骤2中,从机发送一个响应信号,响应信号是80多us低电平,然后80多us高电平,我们直接循环检测电平就可以(为什么不用延时,因为只是从机发送的信号,主机是检测,不能确定延时的长短,循环检测比较容易,如果用延时,我们应该延时最小时间,然后一直检测,代码多一点),输出高电平之后,就会输出低电平,表示数据准备发送
步骤3 开始读取数据,数据总共40bit,就是5个字节,我们采用循环读取,每次读取一个字节,如果判断是每个位是0还是1呢?根据表中可以知道,信号0和信号1的低电平时间是一样的,主要是高电平时间,我们可以使用循环跳过低电平,然后延时超过28us,为什么是28us,因位信号0的高电平时间最长是28us,我们延时超过28us后,如果信号是0,此时检测端口就是低电平(可能是下一次信号的开始发送时间,也有可能是发送40bit结束后的从机主动拉低的时间),如果是信号1,此时检测到端口就是高电平,我们这里选取的是40us(函数的限制,也是取整数的习惯,也可以稍微取大一点,理论上可以取到70左右,但这些值倒是存在偏差的)
/*获取DHT11*/
bit GetDHT11(unsigned char *dat){
unsigned char t,i,j;
unsigned char *p=dat;
EA = 0;
IO_DHT11 = 0;
Delay20ms();//延时20ms
IO_DHT11 = 1;
DelayX10us(1);//主机释放总线,10-20us
while(IO_DHT11);//等待从机拉低,等待响应信号
DelayX10us(10); //延时100us(取个整数而已) ,由于从机输出低电平时间最大85us,所以延时后,从机输入的是高电平
while(IO_DHT11);//等待从机发送信号
//开始读数据
for(j=0;j<5;j++){//共读取5个字节
t = 0;
for(i=0;i<8;i++){ //读取每一个位
while(!IO_DHT11); //跳过50us左右低电平
DelayX10us(4);//延时40us,如果是低电平,则跳过了
t <<= 1; // 先移位,再读取端口信号
t |= IO_DHT11; //读取端口信号
while(IO_DHT11);//等待拉低,读取下一位数据
}
*dat = t;
dat++;
}
//计算校验值是否正确,如果不正确,说明获取失败
t = p[0]+p[1]+p[2]+p[3];
EA = 1;
return (t==p[4]);
}
为了防止获取温度的时候,芯片出现问题,就会无法跳出函数,给等待加上一个时间
/*获取DHT11*/
bit GetDHT11(unsigned char *dat){
unsigned char t,i,j,cnt;
unsigned char *p=dat;
IO_DHT11 = 0;
Delay1ms(20);
EA = 0;
IO_DHT11 = 1;
DelayX10us(1);//主机释放总线,10-20us
cnt = 0;
while(IO_DHT11){
_nop_();
if(cnt++ >= 100){
return 0;
}
}//等待从机拉低
DelayX10us(10);
cnt = 0;
while(IO_DHT11){
_nop_();
if(cnt++ >= 250){
return 0;
}
}//等待从机发送信号
//开始读数据
for(j=0;j<5;j++){
t = 0;
for(i=0;i<8;i++){
cnt = 0;
while(!IO_DHT11){
_nop_();
if(cnt++ >= 100){
return 0;
}
}//跳过50us低电平
DelayX10us(3);//延时30us,如果是低电平,则跳过了
t <<= 1;
t |= IO_DHT11;
while(IO_DHT11){
_nop_();
if(cnt++ >= 100){
return 0;
}
}//等待从机发送信号//等待拉低
}
*dat = t;
dat++;
}
//计算校验值是否正确,如果不正确,说明获取失败
t = p[0]+p[1]+p[2]+p[3];
EA = 1;
return (t==p[4]);
}
上一篇:基于51单片机抢答器的设计
- 六大全新产品系列推出,MCX A微控制器家族迎来创新
- 意法半导体全新STM32C5系列,重新定义入门级微控制器性能与价值,赋能万千智能设备
- 从控制到系统:TI利用边缘AI重塑嵌入式MCU的边界
- 模组复用与整机重测在SRRC、CCC、CTA/NAL认证中的实践操作指南
- 有源晶振与无源晶振的六大区别详解
- 英飞凌持续巩固全球微控制器市场领导地位
- 使用 Keil Studio for Visual Studio Code开发 STM32 设备
- 蓝牙信道探测技术原理与开发套件实践
- LoRa、LoRaWAN、NB-IoT与4G DTU技术对比及工业无线方案选型分析
- Microchip 推出生产就绪型全栈边缘 AI 解决方案,赋能MCU和MPU实现 智能实时决策




