当前位置:   article > 正文

stm32-DHT11原理及代码解读_stm32拉低dq是什么意思

stm32拉低dq是什么意思

目录

一、基础知识

1.功能:温湿度检测

2.应用范围

3.硬件电路连接

二、底层代码原理分析

1.基础知识

1.单总线说明

2.单总线传送数据位定义

3.数据格式

4.校验位数据定义

2.代码分析

1.数据时序图

2.数据传输步骤


一、基础知识

1.功能:温湿度检测

        测量范围湿度:湿度:5-95%RH        精度:(±5)%RH

                          温度:-20-60℃        精度:(±2)℃

2.应用范围

        暖通空调、除湿器、农业、冷链仓储、测试及检测设备、消费品、汽车、自动控制、数据记录器、气 象站、家电、湿度调节器、医疗、其他相关湿度检测控制。

3.硬件电路连接

        1.VDD 供电 3.3~5.5V DC

        2.DATA 串行数据,单总线

        3.NC 空脚

        4.GND 接地,电源负极

 注意点:

        1. 建议连接线长度短于 5m 时用 4.7K 上拉电阻,大于 5m 时根据实际情况降低上拉电 阻的阻值。

        2. 使用 3.3V 电压供电时连接线尽量短,接线过长会导致传感器供电不足,造成测量偏差。

        3. 每次读出的温湿度数值是上一次测量的结果,欲获取实时数据,需连续读取 2 次,但不建议连续多次 读取传感器,每次读取传感器间隔大于 2 秒即可获得准确的数据。

4. 电源部分如有波动,会影响到温度。如使用开关电源纹波过大,温度会出现跳动。

二、底层代码原理分析

1.基础知识

1.单总线说明

        DHT11 器件采用简化的单总线通信。单总线即只有一根数据线,系统中的数据交换、控制均由单总线 完成。它们是主从结构,只有主机呼叫从机时,从机才能应答。

2.单总线传送数据位定义

        DATA 用于微处理器与 DHT11 之间的通讯和同步,采用单总线数据格式,一次传送 40 位数据,高位先出

3.数据格式

        8bit 湿度整数数据 + 8bit 湿度小数数据 + 8bit 温度整数数据 + 8bit 温度小数数据 + 8bit 校验位。

        注:其中湿度小数部分为 0。

4.校验位数据定义

        “8bit 湿度整数数据 + 8bit 湿度小数数据 + 8bit 温度整数数据 + 8bit 温度小数数据”8bit 校验位等于 所得结果的末 8 位

2.代码分析

1.数据时序图

        用户主机(MCU)发送一次开始信号后,DHT11 从低功耗模式转换到高速模式,待主机开始信号结束 后,DHT11 发送响应信号,送出 40bit 的数据,并触发一次信采集。信号发送如图所示。

         注:主机从 DHT11 读取的温湿度数据总是前一次的测量值,如两次测间隔时间很长,请连续读两次以 第二次获得的值为实时温湿度值。

2.数据传输步骤

​​​        步骤一二三准备步骤即初始化。步骤四发送数据。

步骤一

        DHT11 上电后(DHT11 上电后要等待 1S 以越过不稳定状态在此期间不能发送任何指令),测试环境 温湿度数据,并记录数据,同时 DHT11 的 DATA 数据线由上拉电阻拉高一直保持高电平;此时 DHT11 的 DATA 引脚处于输入状态,时刻检测外部信号。       

 步骤二:

        上图中主机发送信号:

        微处理器的 I/O 设置为输出同时输出低电平,且低电平保持时间不能小于 18ms(最大不得超过 30ms), 然后微处理器的 I/O 设置为输入状态,由于上拉电阻,微处理器的 I/O 即 DHT11 的 DATA 数据线也随之变 ,等待 DHT11 作出回答信号,发送信号如图所示:

        由此得到代码:

        DHT11_IO_OUT();设置为引脚输出模式的函数,写个函数(简单)或直接宏定义寄存器操作(简洁);DHT11_IO_IN()同理;

        DHT11_DQ_OUT();即引脚输出高电平,可以用位带操作宏定义一番;DHT11_DQ_IN();同理;

  1. void DHT11_Rst(void)
  2. {
  3. DHT11_IO_OUT(); //SET OUTPUT
  4. DHT11_DQ_OUT=0; //拉低DQ
  5. delay_ms(20); //拉低至少18ms
  6. DHT11_DQ_OUT=1; //DQ=1
  7. delay_us(30); //主机拉高20~40us
  8. DHT11_IO_IN();
  9. ​}

步骤三:

        DHT11 的 DATA 引脚检测到外部信号有低电平时,等待外部信号低电平结束,延迟后 DHT11 的 DATA 引脚处于输出状态,输出 83 微秒的低电平作为应答信号紧接着输出 87 微秒的高电平通知外设准备接 收数据,微处理器的 I/O 此时处于输入状态,检测到 I/O 有低电平(DHT11 回应信号)后,等待 87 微秒 的高电平后的数据接收,发送信号如 图所示:

         DHT11输出,主机接收所以配置输入模式。

        由此得到代码:

        两个while循环一个检测低电平一个检测高电平。retry其实就是高低电平时间。

  1. //等待DHT11的回应
  2. //返回1:未检测到DHT11的存在
  3. //返回0:存在
  4. u8 DHT11_Check(void)
  5. {
  6. u8 retry=0;
  7. DHT11_IO_IN();
  8. while (DHT11_DQ_IN&&retry<100)//DHT11会拉低
  9. {
  10. retry++;
  11. delay_us(1);
  12. };
  13. if(retry>=100)return 1;
  14. else retry=0;
  15. while (!DHT11_DQ_IN&&retry<100)//DHT11拉低后会再次拉高
  16. {
  17. retry++;
  18. delay_us(1);
  19. };
  20. if(retry>=100)return 1;
  21. return 0;
  22. }

步骤四:

        由 DHT11 的 DATA 引脚输出 40 位数据,微处理器根据 I/O 电平的变化接收 40 位数据,位数据“0” 的格式为: 54 微秒的低电平和 23-27 微秒的高电平,位数据“1”的格式为: 54 微秒的低电平加 68-74 微秒的高电平。位数据“0”、“1”格式信号如图所示

        通过对比得到0,1不同处在于高低电平时间

        所以我们先等度过低电平,高电平到来然后延时40us,此时如果他是低电平,那接收到的数据就是0,如果是高电平那他就是1。

  1. //从DHT11读取一个位
  2. //返回值:1/0
  3. u8 DHT11_Read_Bit(void)
  4. {
  5. u8 retry=0;
  6. while(DHT11_DQ_IN)//等待变为低电平
  7. while(!DHT11_DQ_IN)//等待成为高电平
  8. delay_us(40);//等待40us
  9. if(DHT11_DQ_IN)
  10. return 1;
  11. else
  12. return 0;
  13. }

        根据前文:“一次传送 40 位数据,高位先出。”我们优化代码:

  1. u8 DHT11_Read_Byte(void)
  2. {
  3. u8 dat1,dat2=0;
  4. for(data1=0x80;data1!=0;data1>>1)
  5. {
  6. if(DHT11_Read_Bit())
  7. data2|=data1;
  8. else
  9. data2&=~data1;
  10. }
  11. return data2;
  12. }

步骤五:结束信号

        DHT11 的 DATA 引脚输出 40 位数据后,继续输出低电平 54 微秒后转为输入状态,由于上拉电阻随 之变为高电平。但 DHT11 内部重测环境温湿度数据,并记录数据,等待外部信号的到来。

        根据上文校验位结构:“8bit 湿度整数数据 + 8bit 湿度小数数据 + 8bit 温度整数数据 + 8bit 温度小数数据”8bit 校验位等于 所得结果的末 8 位。

        得出代码

  1. u8 DHT11_Read_Data(u8 *temp,u8 *humi)
  2. {
  3. u8 buf[5];
  4. u8 i;
  5. DHT11_Rst();
  6. if(DHT11_Check()==0)
  7. {
  8. for(i=0;i<5;i++)//读取40位数据
  9. {
  10. buf[i]=DHT11_Read_Byte();
  11. }
  12. if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4])
  13. {
  14. *humi=buf[0];
  15. *temp=buf[2];
  16. }
  17. }else return 1;
  18. return 0;
  19. }

        我们最终顺其自然的得到主函数

  1. int main(void)
  2. {
  3. u8 temper;
  4. u8 humi;
  5. u8 temp;
  6. delay_init();
  7. DHT11_Init();
  8. oled_init();
  9. while(1)
  10. {
  11. temp = DHT11_Read_Data(&temper,&humi);
  12. if(temp ==0)
  13. {
  14. OLED_ShowNum(10,10,humi,5,16);
  15. OLED_ShowNum(10,30,temper,5,16);
  16. }
  17. };
  18. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/606492
推荐阅读
相关标签
  

闽ICP备14008679号