ESP32 開發筆記(三)源碼示例 8_DHT11_RMT 使用RMT實現讀取DHT11溫溼度傳感器

開發板購買連接windows

https://item.taobao.com/item.htm?spm=a2oq0.12575281.0.0.50111deb2Ij1As&ft=t&id=626366733674緩存

開發板簡介
開發環境搭建 windows
基礎例程:
    0_Hello Bug (ESP_LOGX與printf)    工程模板/打印調試輸出
    1_LED                                                    LED亮滅控制       
    2_LED_Task                                          使用任務方式控制LED
    3_LEDC_PWM                                      使用LEDC來控制LED實現呼吸燈效果
    4_ADC_LightR                                      使用ADC讀取光敏電阻實現光照傳感
    5_KEY_Short_Long                              按鈕長按短按實現
    6_TouchPad_Interrupt                          電容觸摸中斷實現
    7_WS2812_RMT                                  使用RMT實現RGB_LED彩虹變色示例
    8_DHT11_RMT                                    使用RMT實現讀取DHT11溫溼度傳感器
    9_SPI_SDCard                                    使用SPI總線實現TF卡文件系統示例
    10_IIC_ADXL345                                使用IIC總線實現讀取ADXL345角度加速度傳感器
    11_IIC_AT24C02                                 使用IIC總線實現小容量數據儲存測試
    12_IR_Rev_RMT                                使用RMT實現紅外遙控接收解碼(NEC編碼)
    13_IR_Send_RMT                              使用RMT實現紅外數據發送(NEC編碼)
    14_WIFI_Scan                                    附近WIFI信號掃描示例    
    15_WIFI_AP                                        建立軟AP示例
    16_WIFI_AP_TCP_Server                  在軟AP模式下實現TCP服務端
    17_WIFI_AP_TCP_Client                   在軟AP模式下實現TCP客戶端
    18_WIFI_AP_UDP                              在軟AP模式下實現UDP通信
    19_WIFI_STA                                      建立STA站模鏈接路由器
    20_WIFI_STA_TCP_Server                在站模式STA下實現TCP服務端
    21_WIFI_STA_TCP_Client                 在站模式STA下實現TCP客戶端
    22_WIFI_STA_UDP                            在站模式STA下實現UDP通信
    23_LCD_Test                                      LCD液晶觸摸屏顯示測試 
    24_LVGL_Test                                     LVGL圖形庫簡單示例app

RMT(Remote Control)模塊驅動程序可用於發送和接收紅外遙控信號。 因爲RMT模塊的靈活性,該驅動程序還可用於生成或接收許多其餘類型的信號。函數

信號由一系列脈衝組成,由RMT的發射器根據值列表生成。 這些值定義了脈衝持續時間和二進制電平,請參見下文。 發射器還能夠提供載波,並使用提供的脈衝對其進行調製。性能

發送調製圖示:測試

在接收器中,一系列脈衝被解碼爲包含脈衝持續時間和二進制電平的值列表。 能夠應用濾波器以從輸入信號中去除高頻噪聲。ui

接收調製圖示:編碼

DHT11.net

DHT11是一款有已校準數字信號輸出的溫溼度傳感器。 其精度溼度+-5%RH, 溫度+-2℃,量程溼度20-90%RH, 溫度0~50℃。設計

DHT11數字溫溼度傳感器是一款含有已校準數字信號輸出的溫溼度複合傳感器,它應用專用的數字模塊採集技術和溫溼度傳感技術,確保產品具備極高的可靠性和卓越的長期穩定性。傳感器包括一個電阻式感溼元件和一個NTC測溫元件,並與一個高性能8位單片機相鏈接。所以該產品具備品質卓越、超快響應、抗干擾能力強、性價比極高等優勢。每一個DHT11傳感器都在極爲精確的溼度校驗室中進行校準。校準係數以程序的形式存在OTP內存中,傳感器內部在檢測信號的處理過程當中要調用這些校準係數。單線制串行接口,使系統集成變得簡易快捷。超小的體積、極低的功耗,使其成爲該類應用中,在苛刻應用場合的最佳選擇。產品爲4針單排引腳封裝,鏈接方便。

採用單總線雙向串行通訊協議,每次採集都要由單片機發起開始信號,而後DHT11會向單片機發送響應並開始傳輸40位數據幀,高位在前。數據格式爲:8bit溼度整數數據+8bit溼度小數數據+8bit溫度整數數據+8bit溫度小數數據+8bit校驗位,溫溼度小數部分默認爲0,即單片機採集的數據都是整數,校驗位爲4個字節的數據相加取結果的低8位數據做爲校驗和:

用戶主機( MCU) 發送一次開始信號後, DHT11 從低功耗模式轉換到高速模式, 待主機開始信號結束後, DHT11 發送響應信號, 送出 40bit 的數據, 並觸發一次信採集。 信號發送如圖所示。

外設讀取步驟
主機和從機之間的通訊可經過以下幾個步驟完成( 外設( 如微處理器) 讀取 DHT11 的數據的步驟)。
步驟一:
DHT11 上電後( DHT11 上電後要等待 1S 以越過不穩定狀態在此期間不能發送任何指令), 測試環境
溫溼度數據, 並記錄數據, 同時 DHT11 的 DATA 數據線由上拉電阻拉高一直保持高電平; 此時 DHT11 的
DATA 引腳處於輸入狀態, 時刻檢測外部信號。
步驟二:
微處理器的 I/O 設置爲輸出同時輸出低電平, 且低電平保持時間不能小於 18ms( 最大不得超過 30ms),
而後微處理器的 I/O 設置爲輸入狀態, 因爲上拉電阻, 微處理器的 I/O 即 DHT11 的 DATA 數據線也隨之變
高, 等待 DHT11 做出回答信號, 發送信號如圖所示:

步驟三:
DHT11 的 DATA 引腳檢測到外部信號有低電平時, 等待外部信號低電平結束, 延遲後 DHT11 的 DATA
引腳處於輸出狀態, 輸出 83 微秒的低電平做爲應答信號, 緊接着輸出 87 微秒的高電平通知外設準備接
收數據, 微處理器的 I/O 此時處於輸入狀態, 檢測到 I/O 有低電平( DHT11 迴應信號) 後, 等待 87 微秒
的高電平後的數據接收, 發送信號如圖所示:

步驟四:
由 DHT11 的 DATA 引腳輸出 40 位數據, 微處理器根據 I/O 電平的變化接收 40 位數據, 位數據「0」
的格式爲: 54 微秒的低電平和 23-27 微秒的高電平, 位數據「1」 的格式爲: 54 微秒的低電平加 68-74
微秒的高電平。 位數據「0」、「1」 格式信號如圖所示:

結束信號:
DHT11 的 DATA 引腳輸出 40 位數據後, 繼續輸出低電平 54 微秒後轉爲輸入狀態, 因爲上拉電阻隨
之變爲高電平。 但 DHT11 內部重測環境溫溼度數據, 並記錄數據, 等待外部信號的到來。
 

1、硬件設計/原理

查看開發板原理圖,DHT11信號引腳鏈接在主控的GPIO26引腳上,知道了RMT的功能和DHT11的控制時序就能夠進行代碼的編寫了。

2、程序設計

先引用必要頭文件

// DHT11 Example

#include <string.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/event_groups.h>
#include <esp_log.h>
#include <nvs_flash.h>

#include "dht11.h"

主函數

const static char *TAG = "DHT11_Demo";
#define DHT11_GPIO 26


void app_main(void)
{
	ESP_LOGI(TAG, "APP Start......");
	ESP_ERROR_CHECK(nvs_flash_init());
	vTaskDelay(1000 / portTICK_PERIOD_MS);
	int temp = 0,hum = 0;
	dht11_init(DHT11_GPIO);
	while (1){
		if (dht11_start_get(&temp, &hum)){
			ESP_LOGI(TAG, "[%lld] temp->%i.%i C     hum->%i%%", esp_timer_get_time(), temp / 10, temp % 10, hum);
		}
		vTaskDelay(3000 / portTICK_PERIOD_MS);
	}
}

初始化DHT11,其實就是配置RMT用來接收DHT11返回的數據

void dht11_init(uint8_t dht11_pin)
{
	DHT11_PIN = dht11_pin;
	const int RMT_CLK_DIV = 80;                                   // RMT計數器時鐘分頻器
	const int RMT_TICK_10_US = (80000000 / RMT_CLK_DIV / 100000); // RMT計數器10us.(時鐘源是APB時鐘)
	const int rmt_item32_tIMEOUT_US = 1000;                       // RMT接收超時us
	rmt_config_t rmt_rx;
	rmt_rx.gpio_num = dht11_pin;
	rmt_rx.channel = channel;
	rmt_rx.clk_div = RMT_CLK_DIV;
	rmt_rx.mem_block_num = 1;
	rmt_rx.rmt_mode = RMT_MODE_RX;
	rmt_rx.rx_config.filter_en = false;
	rmt_rx.rx_config.filter_ticks_thresh = 100;
	rmt_rx.rx_config.idle_threshold = rmt_item32_tIMEOUT_US / 10 * (RMT_TICK_10_US);
	rmt_config(&rmt_rx);
	rmt_driver_install(rmt_rx.channel, 1000, 0);
}

使用RMT接收DHT11返回的數據

// 使用RMT接收DHT11數據
int dht11_start_get(int *temp_x10, int *humidity)
{
	RingbufHandle_t rb = NULL;
	size_t rx_size = 0;
	rmt_item32_t *item;
	int rtn = 0;
	//得到RMT RX環形緩衝區句柄,並處理RX數據
	rmt_get_ringbuf_handle(channel, &rb);
	if (!rb){
		return 0;
	}
	//發送20ms脈衝啓動DHT11單總線
	gpio_set_level(DHT11_PIN, 1);
	gpio_set_direction(DHT11_PIN, GPIO_MODE_OUTPUT);
	ets_delay_us(1000);
	gpio_set_level(DHT11_PIN, 0);
	ets_delay_us(20000);

	//將rmt_rx_start和rmt_rx_stop放入緩存
	rmt_rx_start(channel, 1);
	rmt_rx_stop(channel);

	//信號線設置爲輸入準備接收數據
	gpio_set_level(DHT11_PIN, 1);
	gpio_set_direction(DHT11_PIN, GPIO_MODE_INPUT);

	//此次啓動RMT接收器以獲取數據
	rmt_rx_start(channel, 1);

	//從環形緩衝區中取出數據
	item = (rmt_item32_t *)xRingbufferReceive(rb, &rx_size, 2);
	if (item != NULL){
		int n;
		n = rx_size / 4 - 0;
		// 解析來自ringbuffer的數據值.
		rtn = parse_items(item, n, humidity, temp_x10);
		// 解析數據後,將空格返回到ringbuffer.
		vRingbufferReturnItem(rb, (void *)item);
	}
	//中止RMT接收
	rmt_rx_stop(channel);
	return rtn;
}

解析數據中的溫度溼度數據並檢查校驗

// 將RMT讀取到的脈衝數據處理爲溫度和溼度
static int parse_items(rmt_item32_t *item, int item_num, int *humidity, int *temp_x10)
{
	int i = 0;
	unsigned rh = 0, temp = 0, checksum = 0;
	if (item_num < 42){					// 檢查是否有足夠的脈衝數
		return 0;
	}
	item++;								// 跳過開始信號脈衝
	for (i = 0; i < 16; i++, item++){	// 提取溼度數據
		rh = (rh << 1) + (item->duration1 < 35 ? 0 : 1);
	}
	for (i = 0; i < 16; i++, item++){	// 提取溫度數據
		temp = (temp << 1) + (item->duration1 < 35 ? 0 : 1);
	}
	for (i = 0; i < 8; i++, item++){	// 提取校驗數據
		checksum = (checksum << 1) + (item->duration1 < 35 ? 0 : 1);
	}
	// 檢查校驗
	if ((((temp >> 8) + temp + (rh >> 8) + rh) & 0xFF) != checksum){
		printf("Checksum failure %4X %4X %2X\n", temp, rh, checksum);
		return 0;
	}
	// 返回數據
	*humidity = rh >> 8;
	*temp_x10 = (temp >> 8) * 10 + (temp & 0xFF);
	return 1;
}

3、下載測試

打開ESP-IDF Command Prompt

cd命令進入此工程目錄

cd F:\ESP32_DevBoard_File\8_DHT11_RMT

查看電腦設備管理器中開發板的串口號

執行idf.py -p COM9 flash monitor從串口9下載並運行打開口顯示設備調試信息   Ctrl+c退出運行,觀察串口打印。