《ESP32-S3使用指南—IDF版 V1.6》第三十章 DHT11數字溫濕度傳感器
第三十章 DHT11數字溫濕度傳感器
1)實驗平臺:正點原子DNESP32S3開發板
2)章節摘自【正點原子】ESP32-S3使用指南—IDF版 V1.6
3)購買鏈接:https://detail.tmall.com/item.htm?&id=768499342659
4)全套實驗源碼+手冊+視頻下載地址:http://www.openedv.com/docs/boards/esp32/ATK-DNESP32S3.html
5)正點原子官方B站:https://space.bilibili.com/394620890
6)正點原子DNESP32S3開發板技術交流群:132780729


本章,我們將介紹數字溫濕度傳感器DHT11的使用,與前一章的溫度傳感器相比,該傳感器不但能測溫度,還能測濕度。我們將學習如何獲取DHT11傳感器的溫濕度數據,并把數據顯示在LCD上。
本章分為如下幾個小節:
30.1 DHT11及工作時序簡介
30.2 硬件設計
30.3 程序設計
30.4 下載驗證
30.1 DHT11及工作時序簡介
30.1.1 DHT11簡介
DHT11是一款溫濕度一體化的數字傳感器。該傳感器包括一個電容式測濕元件和一個NTC測溫元件,并與一個高性能8位單片機相連接。通過單片機等微處理器簡單的電路連接就能夠實時的采集本地濕度和溫度。DHT11與單片機之間能采用簡單的單總線進行通信,僅僅需要一個I/O口。傳感器內部濕度和溫度數據40Bit的數據一次性傳給單片機,數據采用校驗和方式進行校驗,有效的保證數據傳輸的準確性。DHT11功耗很低,5V電源電壓下,工作平均最大電流0.5mA。
DHT11的技術參數如下:
l 工作電壓范圍:3.3V ~ 5.5V
l 工作電流:平均0.5mA
l 輸出:單總線數字信號
l 測量范圍:濕度5 ~ 95%RH,溫度-20 ~ 60℃
l 精度:濕度±5%,溫度±2℃
l 分辨率:濕度1%,溫度0.1℃
DHT11的管腳排列如圖30.1.1所示:

圖30.1.1.1 DHT11管腳排列圖
30.1.2 DHT11工作時序簡介
雖然DHT11與DS18B20類似,都是單總線訪問,但是DHT11的訪問,相對DS18B20來說簡單很多。下面我們先來看看DHT11的數據結構。
DHT11數字溫濕度傳感器采用單總線數據格式。即,單個數據引腳端口完成輸入輸出雙向傳輸。其數據包由5byte(40bit)組成。數據分小數部分和整數部分,一次完整的數據傳輸為40bit,高位先處。DHT11的數據格式為:8bit濕度整數數據+8bit濕度小數數據+8bit溫度整數數據+8bit溫度小數部分+8bit校驗和。其中校驗和數據為前面四個字節相加。
傳感器數據輸出的是未編碼的二進制數據。數據(濕度、溫度、整數、小數)之間應該分開處理。例如,某次從DHT11讀到的數據如圖30.1.2.1所示:

圖30.1.2.1 某次讀取到DHT11數據
由以上數據就可得到濕度和溫度的值,計算方法:
濕度 = byte4 . byte3= 45.0(%RH)
溫度 = byte2 . byte1 = 28.0(℃)
校驗 = byte4 + byte3 + byte2 + byte1= 73 (= 濕度 + 溫度) (校驗正確)
可以看出,DHT11的數據格式十分簡單的,DHT11和MCU的一次通信最大為34ms左右,建議主機連續讀取時間間隔不要小于2s。
下面,我們介紹一下DHT11的傳輸時序。DHT11的數據發送流程如圖30.1.2.2所示:

圖30.1.2.2 DHT11數據發送流程圖
首先主機發送開始信號,即:拉低數據線,保持t1(至少18ms)時間,然后拉高數據線t2(1035us)時間,然后讀取DHT11的響應,正常的話,DHT11會拉低數據線,保持t3(7888us)時間,作為響應信號,然后DHT11拉高數據線,保持t4(80~92us)時間后,開始輸出數據。
DHT11輸出數字‘0’時序如圖30.1.2.3所示:

圖30.1.2.3 DHT11數字‘0’時序圖
DHT11輸出數字‘1’的時序如圖30.1.2.4所示:

圖30.1.2.4 DHT11輸出數字‘1’時序圖
DHT11輸出數字‘0’和‘1’時序,一開始都是DHT11拉低數據線54us,后面拉高數據線保持的時間就不一樣,數字‘0’就是2327us,而數字‘1’就是6874us。
通過以上了解,我們就可以通過ESP32F103來實現對DHT11的讀取了。DHT11的介紹就到這里,更詳細的介紹,請參考DHT11數據手冊。
30.2 硬件設計
30.2.1 例程功能
DHT11每隔100ms左右讀取一次數據,并把溫度顯示在LCD上。LED閃爍用于提示程序正在運行。
30.2.2 硬件資源
- XL9555
IIC_INT-IO0(需在P5連接IO0)
IIC_SDA-IO41
IIC_SCL-IO42 - SPILCD
CS-IO21
SCK-IO12
SDA-IO11
DC-IO40(在P5端口,使用跳線帽將IO_SET和LCD_DC相連)
PWR- IO1_3(XL9555)
RST- IO1_2(XL9555) - DHT11
1WIRE_DQ-IO0
30.2.3 原理圖
DHT11接口與ESP32的連接關系跟上一章節中DS18B20和ESP32的關系是一樣的,使用到的GPIO口是IO0。這里原理圖就不列出來了,可以翻看上一章節原理圖。
DHT11和DS18B20的接口是共用一個的,不過DHT11有4條腿,需要把U6的4個接口都用上,將DHT11傳感器插入到這個上面就可以通過ESP32來讀取溫濕度值了。連接示意圖如圖30.2.3.1所示:
![image011]()
圖30.2.3.1 DHT11連接示意圖
這里要注意,將DHT11貼有字的一面朝內,而有很多孔的一面(網面)朝外,然后插入如圖所示的四個孔內就可以了。
30.3 程序設計
30.3.1 程序流程圖
程序流程圖能幫助我們更好的理解一個工程的功能和實現的過程,對學習和設計工程有很好的主導作用。下面看看本實驗的程序流程圖:

圖30.3.1.1 DHT11實驗程序流程圖
30.3.2 DHT11函數解析
這一章節除了涉及到GPIO的API函數,便沒有再涉及到其他API函數。因此,有關GPIO的API函數介紹,請讀者回顧此前的第十章的內容。接下來,筆者將直接介紹DHT11的驅動代碼。
30.3.3 DHT11驅動解析
在IDF版20_dht11例程中,作者在20_dht11\components\BSP路徑下新增了一個DHT11文件夾,分別用于存放dht11.c、dht11.h這兩個文件。其中,dht11.h文件負責聲明DHT11相關的函數和變量,而dht11.c文件則實現了DHT11的驅動代碼。下面,我們將詳細解析這兩個文件的實現內容。
1,dht11.h文件
/* 引腳定義 */
#define DHT11_DQ_GPIO_PIN GPIO_NUM_0
/* DHT11引腳高低電平枚舉 */
typedef enum
{
DHT11_PIN_RESET= 0u,
DHT11_PIN_SET
}DHT11_GPIO_PinState;
/* IO操作 */
#define DHT11_DQ_IN gpio_get_level(DHT11_DQ_GPIO_PIN) /* 數據端口輸入 */
/* DHT11端口定義 */
#define DHT11_DQ_OUT(x) do{ x ? \
gpio_set_level(DHT11_DQ_GPIO_PIN, DHT11_PIN_SET) : \
gpio_set_level(DHT11_DQ_GPIO_PIN, DHT11_PIN_RESET); \
}while(0)
對DHT11的相關引腳以及IO操作進行宏定義,方便程序中調用。
2,dht11.c文件
/**
* @brief 初始化DHT11
* @param 無
* @retval 0, 正常
* 1, 不存在/不正常
*/
uint8_t dht11_init(void)
{
gpio_config_tgpio_init_struct;
gpio_init_struct.intr_type = GPIO_INTR_DISABLE; /* 失能引腳中斷 */
/* 開漏模式的輸入和輸出 */
gpio_init_struct.mode = GPIO_MODE_INPUT_OUTPUT_OD;
gpio_init_struct.pull_up_en = GPIO_PULLUP_ENABLE; /* 使能上拉 */
gpio_init_struct.pull_down_en = GPIO_PULLDOWN_DISABLE; /* 失能下拉 */
/* 設置的引腳的位掩碼 */
gpio_init_struct.pin_bit_mask = 1ull << DHT11_DQ_GPIO_PIN;
gpio_config(&gpio_init_struct); /* 配置DHT11引腳 */
dht11_reset();
return dht11_check();
}
在DHT11的初始化函數中,主要對用到的GPIO口進行初始化,同時在函數最后調用復位函數和自檢函數,這兩個函數在后面會解釋到。
下面介紹的是復位DHT11函數和等待DHT11的回應函數,它們的定義如下:
/**
* @brief 復位DHT11
* @param data:要寫入的數據
* @retval 無
*/
static void dht11_reset(void)
{
DHT11_DQ_OUT(0); /* 拉低DQ */
vTaskDelay(25); /* 拉低至少18ms */
DHT11_DQ_OUT(1); /* DQ=1 */
esp_rom_delay_us(30); /* 主機拉高10~35us */
}
/**
* @brief 等待DHT11的回應
* @param 無
* @retval 0,DHT11正常
* 1,DHT11異常/不存在
*/
uint8_t dht11_check(void)
{
uint8_t retry = 0;
uint8_t rval = 0;
while (DHT11_DQ_IN && retry < 100) /* DHT11會拉低約83us */
{
retry++;
esp_rom_delay_us (1);
}
if (retry >= 100)
{
rval = 1;
}
else
{
retry = 0;
while (!DHT11_DQ_IN && retry < 100) /* DHT11拉低后會再次拉高87us */
{
retry++;
esp_rom_delay_us (1);
}
if (retry >= 100) rval = 1;
}
return rval;
}
以上兩個函數分別代表著前面所說的復位脈沖與應答信號,大家可以對比前面的時序圖進行理解。那么在上一章DS18B20的實驗中,也對復位脈沖以及應答信號進行了詳細的解釋,大家也可以對比理解。
DHT11與DS18B20有所不同,DHT11是不需要寫函數,只需要讀函數即可,下面我們看一下讀函數:
/**
* @brief 從DHT11讀取一個位
* @param 無
* @retval 讀取到的位值: 0 / 1
*/
uint8_t dht11_read_bit(void)
{
uint8_t retry = 0;
while (DHT11_DQ_IN && retry < 100) /* 等待變為低電平 */
{
retry++;
esp_rom_delay_us (1);
}
retry = 0;
while (!DHT11_DQ_IN && retry < 100) /* 等待變高電平 */
{
retry++;
esp_rom_delay_us (1);
}
esp_rom_delay_us (40); /* 等待40us */
if (DHT11_DQ_IN) /* 根據引腳狀態返回 bit */
{
return 1;
}
else
{
return 0;
}
}
/**
* @brief 從DHT11讀取一個字節
* @param 無
* @retval 讀到的數據
*/
static uint8_t dht11_read_byte(void)
{
uint8_t i, data = 0;
for (i = 0; i < 8; i++) /* 循環讀取8位數據 */
{
data <<= 1; /* 高位數據先輸出, 先左移一位 */
data |= dht11_read_bit(); /* 讀取1bit數據 */
}
return data;
}
在這里dht11_read_bit函數從DHT11處讀取1位數據,大家可以對照前面的讀時序圖進行分析,讀數字0和1的不同,在于高電平的持續時間,所以這個作為判斷的依據。dht11_read_byte函數就是調用一字節讀取函數進行實現。
下面介紹讀取溫濕度函數,其定義如下:
/**
* @brief 從DHT11讀取一次數據
* @param temp:溫度值(范圍:-20~60°)
* @param humi:濕度值(范圍:5%~95%)
* @retval 0, 正常.
* 1, 失敗
*/
uint8_t dht11_read_data(uint8_t *temp, uint8_t *humi)
{
uint8_t buf[5];
uint8_t i;
dht11_reset();
if (dht11_check() == 0)
{
for (i = 0; i < 5; i++) /* 讀取40位數據 */
{
buf = dht11_read_byte();
}
if ((buf[0] + buf[1] + buf[2] + buf[3]) == buf[4])
{
*humi = buf[0];
*temp = buf[2];
}
}
else
{
return 1;
}
return 0;
}
讀取溫濕度函數也是根據時序圖進行實現的,在發送復位信號以及應答信號產生后,即可以讀取5Byte數據進行處理,校驗成功即讀取數據有效成功。
30.3.4 CMakeLists.txt文件
打開本實驗BSP下的CMakeLists.txt文件,其內容如下所示:
set(src_dirs
DHT11
IIC
LCD
LED
SPI
XL9555)
set(include_dirs
DHT11
IIC
LCD
LED
SPI
XL9555)
set(requires
driver)
idf_component_register(SRC_DIRS ${src_dirs}
INCLUDE_DIRS ${include_dirs} REQUIRES ${requires})
component_compile_options(-ffast-math -O3 -Wno-error=format=-Wno-format)
上述的紅色DHT11驅動需要由開發者自行添加,以確保DHT11驅動能夠順利集成到構建系統中。這一步驟是必不可少的,它確保了DHT11驅動的正確性和可用性,為后續的開發工作提供了堅實的基礎。
30.3.5 實驗應用代碼
打開main/main.c文件,該文件定義了工程入口函數,名為app_main。該函數代碼如下。
i2c_obj_t i2c0_master;
/**
* @brief 程序入口
* @param 無
* @retval 無
*/
void app_main(void){
uint8_t err;
uint8_t t = 0;
uint8_t temperature;
uint8_t humidity;
esp_err_t ret;
/* 初始化NVS */
ret = nvs_flash_init();
if (ret ==ESP_ERR_NVS_NO_FREE_PAGES
|| ret == ESP_ERR_NVS_NEW_VERSION_FOUND){
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
/* 初始化LED */
led_init();
/* 初始化IIC0 */
i2c0_master = iic_init(I2C_NUM_0);
/* 初始化SPI2 */
spi2_init();
/* 初始化XL9555 */
xl9555_init(i2c0_master);
/* 初始化LCD */
lcd_init();
lcd_show_string(30, 50, 200, 16, 16, "ESP32", RED);
lcd_show_string(30, 70, 200, 16, 16, "DHT11 TEST", RED);
lcd_show_string(30, 90, 200, 16, 16, "ATOM@ALIENTEK", RED);
/* 初始化DHT11數字溫濕度傳感器 */
err = dht11_init();
if (err != 0)
{
while (1)
{
lcd_show_string(30, 110, 200, 16, 16, "DHT11Error", RED);
vTaskDelay(200);
lcd_fill(30, 110, 239, 130 + 16, WHITE);
vTaskDelay(200);
}
}
lcd_show_string(30, 110, 200, 16, 16, "DHT11 OK", RED);
lcd_show_string(30, 130, 200, 16, 16, "Temp: C", BLUE);
lcd_show_string(30, 150, 200, 16, 16, "Humi: %", BLUE);
while (1)
{
/* 每100ms讀取一次 */
if (t % 10 == 0)
{
/* 讀取溫濕度值 */
dht11_read_data(&temperature, &humidity);
/* 顯示溫度 */
lcd_show_num(30 + 40, 130, temperature, 2, 16, BLUE);
/* 顯示濕度 */
lcd_show_num(30 + 40, 150, humidity, 2, 16, BLUE);
}
vTaskDelay(10);
t++;
if (t == 20)
{
t = 0;
LED_TOGGLE();/* LED閃爍 */
}
}
}
主函數代碼比較簡單,一系列硬件初始化后,如果DHT11初始化成功,那么在循環中調用dht11_get_temperature函數獲取溫濕度值,每隔100ms讀取數據并顯示在LCD上。
30.4 下載驗證
假定DHT11傳感器已經接上去正確的位置,將程序下載到開發板后,可以看到LED0不停的閃爍,提示程序已經在運行了。LCD顯示當前的溫度值的內容如圖30.4.1所示:

圖30.4.1 程序運行效果圖
至此,本章實驗結束。大家可以將本章通過DHT11讀取到的溫度值,和前一章的通過DS18B20讀取到的溫度值對比一下,看看哪個更準確?


浙公網安備 33010602011771號