目录
⑦ ESP8266 开发学习笔记_By_GYC 【ESP8266 驱动 DHT11 温湿度传感器】
本章介绍ESP8266 IDF 框架下 如何使用GPIO口进行单总线时序模拟,介绍DHT11温湿度传感器的使用方法,实现对温湿度的采集。
一、准备材料
①开发板:NodeMcu (ESP8266)
②环境:Ubuntu 18.04 、 ESP-IDF 操作系统( ESP8266_RTOS_SDK V3.2)
③传感器:DHT11
④辅助材料:杜邦线、面包板
二、硬件连接
DHT11的硬件只包含三个引脚,分别是VCC、GND和数据输出引脚DATA。其模块输入电压VCC的输入范围是3.3V~5V。采样周期为1秒。传感器接3.3V电源、GND和ESP8266的GPIO5,信号引脚DATA接5kΩ上拉电阻,完成DHT11的硬件系统。
三、软件编程
DHT11能够使用单总线传输协议与ESP8266进行通信。其中ESP8266作为主机,DHT11作为从机。主机给传感器DHT11发送起始信号,收到从机应答信号后初始化成功,能够进行数据传输。
DHT11回复响应信号后,会发送40bit的传感器数据,包括两个字节的湿度数据(一个字节整数、一个字节小数),两个字节的温度数据整数(一个字节整数、一个字节小数),最后是一个字节的校验和数据。通过求和校验的数据将会作为最后发送的数据。
![](https://i-blog.csdnimg.cn/blog_migrate/f97879ac389d50cfc034e788619df029.png)
本次例程是基于EPS8266 IDF的example “project_template” 进行开发,直接在模板基础上进行新内容的添加。
1、修改工程名
首先,将MakeFile中模板中的工程名字
PROJECT_NAME := project_template
修改为
PROJECT_NAME := project_DHT11
2、添加组件
然后添加工程组件文件夹 dht11_driver 到自己工程的 components (组件) 下
(PS:本次首先提供C++版本的驱动,工程中C++的具体使用方法可以参考我的系列博客内容)
3、编程
修改user_main.c 为 user_main.cpp
添加 dht11驱动的头文件 "dht11_driver.hpp"
为 void app_main(void) 函数添加修饰符 extern "C" 如下:
#include <stdio.h>
#include "esp_system.h"
#include "dht11_driver.hpp"
//生成 DHT11 的实例化对象
DHT_Sensor my_DHT11(GPIO_NUM_5,DHT11);
/******************************************************************************
* FunctionName : app_main
* Description : entry of user application, init user function here
* Parameters : none
* Returns : none
*******************************************************************************/
extern "C" void app_main(void)
{
printf("SDK version:%s\n", esp_get_idf_version());
my_DHT11.DHTInit();
while(1)
{
my_DHT11.DHTRead();
ESP_LOGI("DHT11","DHT: Temperature*100 = %d *C, Humidity*100 = %d %% (GPIO%d)",
(int) (my_DHT11.Sensor_Data.temperature * 100), (int) (my_DHT11.Sensor_Data.humidity * 100), my_DHT11.data_pin);
vTaskDelay(1000 / portTICK_RATE_MS);
}
}
4、反馈结果
5、核心代码
//温湿度传感器数据读取(并将数据写入到传入指针)
bool DHT_Sensor::DHTRead(DHT_Sensor_Data* output)
{
int counter = 0;
int laststate = 1;
int i = 0;
int j = 0;
int checksum = 0;
int data[100];
data[0] = data[1] = data[2] = data[3] = data[4] = 0;
gpio_num_t pin = (gpio_num_t)data_pin;
gpio_set_direction(pin,GPIO_MODE_OUTPUT);
// Wake up device, 250ms of high
gpio_set_level(pin, 1);
sleepms(250);
// Hold low for 20ms
gpio_set_level(pin, 0);
sleepms(20);
// High for 40ns
gpio_set_level(pin, 1);
delay_us(40);
// Set DHT_PIN pin as an input
gpio_set_direction(pin,GPIO_MODE_INPUT); //GPIO_DIS_OUTPUT(pin);
// wait for pin to drop?
while (gpio_get_level(pin) == 1 && i < DHT_MAXCOUNT) {
delay_us(1);
i++;
}
if(i == DHT_MAXCOUNT)
{
DHT_DEBUG("DHT: Failed to get reading from GPIO%d, dying\r\n", pin);
return false;
}
// read data
for (i = 0; i < DHT_MAXTIMINGS; i++)
{
// Count high time (in approx us)
counter = 0;
while (gpio_get_level(pin) == laststate)
{
counter++;
delay_us(1);
if (counter == 1000)
break;
}
laststate = gpio_get_level(pin);
if (counter == 1000)
break;
// store data after 3 reads
if ((i>3) && (i%2 == 0)) {
// shove each bit into the storage bytes
data[j/8] <<= 1;
if (counter > DHT_BREAKTIME)
data[j/8] |= 1;
j++;
}
}
if (j >= 39) {
checksum = (data[0] + data[1] + data[2] + data[3]) & 0xFF;
DHT_DEBUG("DHT%s: %02x %02x %02x %02x [%02x] CS: %02x (GPIO%d)\r\n",
sensor_type==DHT11?"11":"22",
data[0], data[1], data[2], data[3], data[4], checksum, pin);
if (data[4] == checksum) {
// checksum is valid
output->temperature = scale_temperature(data);
output->humidity = scale_humidity(data);
DHT_DEBUG("DHT: Temperature*100 = %d *C, Humidity*100 = %d %% (GPIO%d)\n",
(int) (output->temperature * 100), (int) (output->humidity * 100), pin);
} else {
DHT_DEBUG("DHT: Checksum was incorrect after %d bits. Expected %d but got %d (GPIO%d)\r\n",
j, data[4], checksum, pin);
return false;
}
} else {
DHT_DEBUG("DHT: Got too few bits: %d should be at least 40 (GPIO%d)\r\n", j, pin);
return false;
}
return true;
}
四、总结
驱动DHT11主要就是遵从时序图,按照时序图中规定的时序控制和读取单线的DHT11传感器数据,最终通过原始数据换算得到最终的温湿度数据的值。
本次的工程我会开源到自己的github上(https://github.com/gengyuchao),欢迎大家来和我一起交流呀。