ESP8266 开发学习笔记_By_GYC 【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的传感器数据,包括两个字节的湿度数据(一个字节整数、一个字节小数),两个字节的温度数据整数(一个字节整数、一个字节小数),最后是一个字节的校验和数据。通过求和校验的数据将会作为最后发送的数据。
本次例程是基于EPS8266 IDF的example “project_template” 进行开发,直接在模板基础上进行新内容的添加。
1、修改工程名
首先,将MakeFile中模板中的工程名字
1
| PROJECT_NAME := project_template
|
修改为
1
| 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” 如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| #include <stdio.h> #include "esp_system.h" #include "dht11_driver.hpp"
DHT_Sensor my_DHT11(GPIO_NUM_5,DHT11);
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、核心代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
| 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); gpio_set_level(pin, 1); sleepms(250); gpio_set_level(pin, 0); sleepms(20); gpio_set_level(pin, 1); delay_us(40); gpio_set_direction(pin,GPIO_MODE_INPUT); 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; } for (i = 0; i < DHT_MAXTIMINGS; i++) { 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; if ((i>3) && (i%2 == 0)) { 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) { 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),欢迎大家来和我一起交流呀。