单片机
返回首页

基于51单片机的DHT11温湿度传感器代码分析

2025-09-30 来源:cnblogs

芯片手册地址:https://www.semiee.com/22bcf613-ecfd-4e04-bfa4-11af41666e4b.html

DHT11的时序分析,读取DHT数据的步骤:

  1. 主机发送起始信号(脉冲信号,低电平和高电平)

  2. 从机回应响应信号(脉冲信号,低电平和高电平)

  3. 开始传输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]);

}


进入单片机查看更多内容>>
相关视频
  • 【TI MSPM0 应用实战】智能小车+工业角度编码器+血氧仪+烟雾探测器!硬核参考设计详解!

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

  • 直播回放: Microchip Timberwolf™ 音频处理器在线研讨会

  • 基于灵动MM32W0系列MCU的指夹血氧仪控制及OTA升级应用方案分享

精选电路图
  • 1瓦四级调频发射机

  • 500W MOS场效应管电源逆变器,12V转110V/220V

  • 12V 转 28V DC-DC 变换器(基于 LM2585)

  • 红外开关

  • 12V转110V/220V 500W逆变器

  • DS1669数字电位器

    相关电子头条文章