ESP32驱动DHT11检测温湿度(ESP IDF环境)

编程入门 行业动态 更新时间:2024-10-05 09:20:55

ESP32驱动DHT11检测<a href=https://www.elefans.com/category/jswz/34/1763887.html style=温湿度(ESP IDF环境)"/>

ESP32驱动DHT11检测温湿度(ESP IDF环境)

DHT11驱动原理

1.1接线:我使用的是ESP32 Wrover,DHT11接线也不复杂,总共三根线,供电电压为3.3V-5V,DATA端就随便接一个IO口即可。

官方使用说明上写着data端上拉5K电阻,而我没有上拉,也能实现数据读取。下面介绍该模块的时序逻辑。

1.2时序图

        用户MCU发送一次开始信号后,DHT11从低功耗模式转换到高速模式,等待主 机开始信号结束后,DHT11发送响应信号,送出40bit的数据,并触发一次信号采集。这个过程主要分为三大步,分别是①单片机开始信号的发送,②检测DHT11的响应信号,③读取温湿度数据。

        那要怎样发送开始信号才能让DHT11模块知道该把数据送到单片机呢?主要分下面几步即可完成开始信号的发送:

(1)将data连接的IO口设置为拉低输出状态,这个过程要大于18ms,那么直接采用延时函数延时个二十多毫秒即可。

(2)在完成第一步之后紧接着把IO口配置为高电平输出,这一步不需要延时处理

(3)完成上面两步后将IO口配置为输入状态,仅仅只是输入,电平状态可以不管,此过程持续20us-40us,我选择延时30us。示例代码如下:                                                                                  

    OutputLow();//低电平输出Delay_ms(25);  //>18MSOutputHigh();//高电平输出InputInitial(); //输入ets_delay_us(30);

         下面介绍如何检测DHT11的响应信号,在我们向DHT11发送开始信号后,DHT11就开始回应一个响应信号,这个信号由80us的低电平和80us的高电平构成,响应信号结束就开始发送温湿度数据。那么我们如何让单片机知道什么时候去读数据呢?

        (1)那我们就去检测IO口的电平值,响应信号不是先低后高吗,我就先判断DHT11是否拉低了IO口电平,如果我读到的IO口电平为高,那说明DHT11根本就没响应,要么传感器坏了,要么开始信号没发送成功。

        (2)在上一步检测到IO口的低电平之后,我们需要等待响应信号的低电平结束,那么直接用一个while循环,循环中我们不断检测端口电平,一旦端口电平变高就跳出循环。

        (3)低电平结束之后迎来高电平信号,用同样的方法等待80us的高电平过去,高电平结束再等待个20—40us即可检测温湿度数据

if(!getData())//表示传感器拉低总线{ucharFLAG=2;//等待低电平结束while((!getData())&&ucharFLAG++) ets_delay_us(10);//等待高电平结束while((getData())&&ucharFLAG++) ets_delay_us(40);}else //没用成功读取,返回0{Humi=0,Temp=0;printf("ReadError");}

        总算来到第三步,开始读数据了,因为DHT11会发送40位的数据。

数据格式:8bit湿度整数数据+8bit湿度小数数据 +8bi温度整数数据+8bit温度小数数据 +8bit校验和

这40位的数据每一位的0/1状态又是怎么确定的呢?下图就是数字0和1的信号表示方法

         因为温湿度数据由四个8bit的数据构成,那我们就读每8位读一次,总共读5次,最后一次获取的是校验和。从上图我们可以看出不管是0信号还是1信号都有低电平+高电平表示,而且低电平持续时间相同,都是50us,那么就要求我们从高电平持续的时间来判断0/1信号。

        具体做法是(1)利用for循环,循环8次,每次读1位数据,每一位数据都由低电平开始,高电平结束。所以我们要等,等这一位数据的低电平部分过去,还是用while循环嵌套电平检测去做,检测到高电平就跳出循环。

        (2)当检测到这一位数据的高电平后,我们要看这段高电平究竟会持续多长时间,0信号的高电平持续26-28us,1信号则持续70us。所以在上一步检测到高电平之后我们不妨等一等,等个30us看看高电平是不是还是存在,若还是高电平,那这一位信号就是1信号,若已经变低了,就是0信号,将这个1或0赋值给一个变量。

        (3)上面读到了一位数据,我们要读8次才行,那要怎样存放变量呢,答案是左移一位再或上你刚读到的这一位数据,这样进行8次就能把一个温湿度部分读完。

static void COM(void)    // 温湿写入
{uchar i=0;for(i=0;i<8;i++){//等待IO口变低,变低后,通过延时去判断是0还是1while((getData()==0)&&ucharFLAG++) ;ets_delay_us(35);//延时35usuchartemp=0;//如果这个位是1,35us后,还是1,则该位为1if(getData()==1) {uchartemp=0x01;} else{uchartemp=0x00;}ucharcomdata<<=1;//左移1位ucharcomdata|=uchartemp;//或上刚读到的值//等待IO口变高,变高后,表示可以读取下一位while((getData()==1)&&ucharFLAG++)ets_delay_us(10);}
}

 其实还有一步,那就是每8位读一次,读5次

 COM();//读取第1字节,ucharRH_data_H_temp=ucharcomdata;COM();//读取第2字节,ucharRH_data_L_temp=ucharcomdata;COM();//读取第3字节,ucharT_data_H_temp=ucharcomdata;COM();//读取第4字节,ucharT_data_L_temp=ucharcomdata;COM();//读取第5字节,ucharcheckdata_temp=ucharcomdata;OutputHigh();//判断校验和是否一致uchartemp=(ucharT_data_H_temp+ucharT_data_L_temp+ucharRH_data_H_temp+ucharRH_data_L_temp);if(uchartemp==ucharcheckdata_temp){//校验和一致,ucharRH_data_H=ucharRH_data_H_temp;ucharRH_data_L=ucharRH_data_L_temp;ucharT_data_H=ucharT_data_H_temp;ucharT_data_L=ucharT_data_L_temp;ucharcheckdata=ucharcheckdata_temp;//保存温度和湿度Humi=ucharRH_data_H;//湿度高8位Humi_small=ucharRH_data_L;//湿度低8位Temp=ucharT_data_H;//温度高8位Temp_small=ucharT_data_L;//温度低8位mytemp = ucharT_data_H;mytemp = ((uint16)mytemp << 8 | ucharT_data_L)/10;//左移8位再或上低8位得到完整数据,再除以10得到最终结果,有零有整myhumi = ucharRH_data_H;myhumi = ((uint16)myhumi << 8 | ucharRH_data_L)/10;//左移8位再或上低8位得到完整数据,再除以10得到最终结果,有零有整printf("temprature=%.2f  humidity=%.2f%%RH \r\n",mytemp,myhumi);//打印至上位机}

代码实现  

        该代码源于(23条消息) esp32 采集dht11温湿度数据_Joker2019.-CSDN博客_esp32读取dht11

         十分感谢这位大佬,我的代码大部分来源于他的代码,但他的代码我试过不对,打印出来的值是有问题的,问题在于他将四段数据分割存放,这就导致数据位权发生改变。在同事唐兄的帮助下(真心感谢唐兄),我终于理清了思路。下面这段代码至关重要,我看了很多帖子,要不就是用传感器库,要不遮遮掩掩,贴几行啥也不是的代码让你抓耳挠腮。他们的方法我发送到上位机后数据都不对,下面是唐兄教我写的:

mytemp = ucharT_data_H;
mytemp = ((uint16)mytemp << 8 | ucharT_data_L)/10;//左移8位再或上低8位得到完整数据,再除以10得到最终结果,有零有整
myhumi = ucharRH_data_H;
myhumi = ((uint16)myhumi << 8 | ucharRH_data_L)/10;//左移8位再或上低8位得到完整数据,再除以10得到最终结果,有零有整printf("temprature=%.2f  humidity=%.2f%%RH \r\n",mytemp,myhumi);//打印至上位机

下面我贴上我的完整代码,只写了一页,没其他.c文件。说是我自己的代码也不准确,因为我也是东拼西凑搞的,十分感谢大家看到这里。

#include <stdio.h>
#include "esp_system.h"
#include "esp_spi_flash.h"
#include "esp_wifi.h"
#include "esp_event_loop.h"
#include "esp_log.h"
#include "esp_err.h"
#include "nvs_flash.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/ledc.h"
#include <stdio.h>
#include "driver/uart.h"
#include "driver/gpio.h"
#include "string.h"#define DHT11_PIN   21//定义DHT11的引脚#define uchar unsigned char
#define uint8 unsigned char
#define uint16 unsigned short//温湿度定义
uchar ucharFLAG,uchartemp;
float Humi,Temp;
uchar ucharT_data_H,ucharT_data_L,ucharRH_data_H,ucharRH_data_L,ucharcheckdata;
uchar ucharT_data_H_temp,ucharT_data_L_temp,ucharRH_data_H_temp,ucharRH_data_L_temp,ucharcheckdata_temp;
uchar ucharcomdata;static void InputInitial(void)//设置端口为输入
{gpio_pad_select_gpio(DHT11_PIN);gpio_set_direction(DHT11_PIN, GPIO_MODE_INPUT);
}static void OutputHigh(void)//输出1
{gpio_pad_select_gpio(DHT11_PIN);gpio_set_direction(DHT11_PIN, GPIO_MODE_OUTPUT);gpio_set_level(DHT11_PIN, 1);
}static void OutputLow(void)//输出0
{gpio_pad_select_gpio(DHT11_PIN);gpio_set_direction(DHT11_PIN, GPIO_MODE_OUTPUT);gpio_set_level(DHT11_PIN, 0);
}static uint8 getData()//读取状态
{return gpio_get_level(DHT11_PIN);
}//读取一个字节数据
static void COM(void)    // 温湿写入
{uchar i;for(i=0;i<8;i++){ucharFLAG=2;//等待IO口变低,变低后,通过延时去判断是0还是1while((getData()==0)&&ucharFLAG++) ets_delay_us(10);ets_delay_us(35);//延时35usuchartemp=0;//如果这个位是1,35us后,还是1,否则为0if(getData()==1)uchartemp=1;ucharFLAG=2;//等待IO口变高,变高后,表示可以读取下一位while((getData()==1)&&ucharFLAG++)ets_delay_us(10);if(ucharFLAG==1)break;ucharcomdata<<=1;ucharcomdata|=uchartemp;}
}void Delay_ms(uint16 ms)
{int i=0;for(i=0; i<ms; i++){ets_delay_us(1000);}
}void DHT11(void)   //温湿传感启动
{OutputLow();Delay_ms(19);  //>18MSOutputHigh();InputInitial(); //输入ets_delay_us(30);if(!getData())//表示传感器拉低总线{ucharFLAG=2;//等待总线被传感器拉高while((!getData())&&ucharFLAG++)ets_delay_us(10);//等待总线被传感器拉低while((getData())&&ucharFLAG++)ets_delay_us(10);COM();//读取第1字节,ucharRH_data_H_temp=ucharcomdata;COM();//读取第2字节,ucharRH_data_L_temp=ucharcomdata;COM();//读取第3字节,ucharT_data_H_temp=ucharcomdata;COM();//读取第4字节,ucharT_data_L_temp=ucharcomdata;COM();//读取第5字节,ucharcheckdata_temp=ucharcomdata;OutputHigh();//判断校验和是否一致uchartemp=(ucharT_data_H_temp+ucharT_data_L_temp+ucharRH_data_H_temp+ucharRH_data_L_temp);if(uchartemp==ucharcheckdata_temp){//校验和一致,ucharRH_data_H=ucharRH_data_H_temp;ucharRH_data_L=ucharRH_data_L_temp;ucharT_data_H=ucharT_data_H_temp;ucharT_data_L=ucharT_data_L_temp;ucharcheckdata=ucharcheckdata_temp;//保存温度和湿度Humi=ucharRH_data_H;Humi=((uint16)Humi<<8|ucharRH_data_L)/10;Temp=ucharT_data_H;Temp=((uint16)Temp<<8|ucharT_data_L)/10;}else{Humi=100;Temp=100;}}else //没用成功读取,返回0{Humi=0,Temp=0;}OutputHigh(); //输出
}void app_main()
{char dht11_buff[50]={0};while(1){DHT11(); //读取温湿度printf("Temp=%.2f--Humi=%.2f%%RH \r\n", Temp,Humi);vTaskDelay(300);  //延时300毫秒}
}

效果图

更多推荐

ESP32驱动DHT11检测温湿度(ESP IDF环境)

本文发布于:2024-03-08 23:04:43,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1722755.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:温湿度   环境   ESP   IDF

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!