目录一、DHT22概述1.关键特性2.引脚定义4.单总线协议描述4.1数据格式4.2数据计算4.3负值的处理5.通信时序5.1 起始信号主机发起5.2 从机响应5.3 数据位传输5.4 结束信号二、硬件搭建1.总览编辑2.DHT22 → ESP323.ESP32 → USB to TLL三、软件环境四、驱动代码1.DHT22dht22.cdht22.hCMakeLists.txt2.串口发送uart_sender.cuart_sender.hCMakeLists.txt3.主函数main.cCMakeLists.txt五、运行示例一、DHT22概述DHT22 是一款数字温湿度复合传感器使用AM2302温湿度传感器并连接了一个 8 位单片机输出已校准的数字信号采用单总线协议。1.关键特性湿度测量范围0 ~ 100% RH精度±2% RH温度测量范围-40 ~ 80℃精度±0.5℃分辨率16 位湿度/16 位温度采样周期≥ 2 秒供电电压3.3 ~ 6V DC接口单总线DATA2.引脚定义引脚号名称功能说明1VDD供电电源3.3 ~ 6V DC2DATA串行数据总线单总线3NC空脚请悬空不连接4GND电源地3.原理图注模块已内置4.7k上拉电阻和100nF电容4.单总线协议描述DHT22 使用单总线协议一次完整通信约5ms传输40 bit数据高位先出4.1数据格式字节内容说明0湿度高 8 位整数部分16 bit 湿度数据1湿度低 8 位小数部分2温度高 8 位整数部分16 bit 温度数据3温度低 8 位小数部分4校验和CRC用于验证数据完整性4.2数据计算湿度值%RH(湿度高8位 8 | 湿度低8位) / 10.0温度值℃(温度高8位 8 | 温度低8位) / 10.0校验规则(Byte0 Byte1 Byte2 Byte3)的低 8 位应等于Byte44.3负值的处理当温度低于 0℃时温度数据16 bit的最高位第 15 位置 1。eg-10.1℃的原始数据为1000 0000 1010 1010即 0x80AA5.通信时序5.1 起始信号主机发起主机MCU将 DATA 线拉低≥ 500 μs建议 1~2 ms。释放总线等待20 ~ 40 μs。5.2 从机响应DHT22 拉低 DATA 线约80 μs响应信号。随后拉高 DATA 线约80 μs准备发送数据。5.3 数据位传输每个 bit 以约 50 μs 的低电平开始位同步信号。随后是高电平其持续时间决定 bit 值高电平持续 26~28 μs→ 逻辑0高电平持续 70 μs→ 逻辑15.4 结束信号40 bit 数据传输完成后从机拉低 DATA 线约50 μs然后释放总线由外部上拉电阻拉高。二、硬件搭建1.总览2.DHT22 → ESP32DHT22 引脚ESP32 引脚说明VCC3.3V供电3.3V ~ 5VGNDGND共地DATAGPIO 4数据线内部上拉已启用3.ESP32 → USB to TLLESP32 引脚功能USB to TLL说明GPIO 17TXRXESP32 发送 → 对端设备接收GPIO 16RXTXESP32 接收 ← 对端设备发送GND—GND共地确保参考电平一致三、软件环境VS Code esp-idf插件串口助手四、驱动代码1.DHT22dht22.c#include dht22.h #include driver/gpio.h #include esp_rom_sys.h // 提供 esp_rom_delay_us #include freertos/FreeRTOS.h #include freertos/task.h // 提供 vTaskDelay #include esp_log.h // 提供 ESP_LOGI 宏定义 // 宏定义微秒延迟 #define DELAY_US(us) esp_rom_delay_us(us) // 引脚操作宏 #define DHT22_PIN DHT22_GPIO_PIN #define DHT22_HIGH() gpio_set_level(DHT22_PIN, 1) // 拉高总线 #define DHT22_LOW() gpio_set_level(DHT22_PIN, 0) // 拉低总线 #define DHT22_READ() gpio_get_level(DHT22_PIN) // 读取总线电平 // 设置引脚方向 #define DHT22_OUTPUT() gpio_set_direction(DHT22_PIN, GPIO_MODE_OUTPUT) #define DHT22_INPUT() gpio_set_direction(DHT22_PIN, GPIO_MODE_INPUT) // 上电初始化 void dht22_init(void){ gpio_config_t io_conf { .pin_bit_mask (1ULL DHT22_PIN), .mode GPIO_MODE_INPUT, .pull_up_en GPIO_PULLUP_ENABLE, .pull_down_en GPIO_PULLDOWN_DISABLE, .intr_type GPIO_INTR_DISABLE }; gpio_config(io_conf); // 延时 1 秒保证传感器稳定 vTaskDelay(pdMS_TO_TICKS(1000)); ESP_LOGI(DHT22, DHT22 初始化完成, 引脚: %d, DHT22_PIN); } // 读取原始 40bit 数据5 字节成功返回 true static bool dht22_read_raw(uint8_t data[5]){ uint8_t i, j; uint8_t counter 0; // 1. 主机发起起始信号拉低总线至少 500us此处用 2ms后释放总线等待 20~40us 后检测从机响应 DHT22_OUTPUT(); DHT22_LOW(); DELAY_US(2000); DHT22_HIGH(); DELAY_US(40); // 释放后等待 20~40us // 2. 切换为输入检测从机响应 DHT22_INPUT(); // 等待从机拉低总线从机响应低电平约 80us uint32_t timeout 0; while (DHT22_READ() 1){ DELAY_US(1); if (timeout 100) return false; // 超时 } timeout 0; while (DHT22_READ() 0){ DELAY_US(1); if (timeout 100) return false; // 超时 } // 响应后的高电平约 80us随后进入数据传输阶段 timeout 0; while (DHT22_READ() 1){ DELAY_US(1); if (timeout 100) return false; // 超时 } // 3. 读取 40 位数据5 字节 for (j 0; j 5; j){ data[j] 0; for (i 0; i 8; i){ // 等待每个 bit 开始的低电平约 50us即数据位起始位 timeout 0; while (DHT22_READ() 0){ DELAY_US(1); if (timeout 100) return false; // 超时 } // 测量高电平持续时间 timeout 0; while (DHT22_READ() 1){ DELAY_US(1); if (timeout 100) return false; } // 高电平持续时间 50us 视为 1否则为 0高电平持续时间70us表示126-28us表示0 if (timeout 40) { data[j] | (1 (7 - i)); // 高位先出 } } } // 4. 结束信号从机拉低 50us 后释放总线无需特殊处理 return true; } /* 数据格式 40bit数据16bit湿度数据16bit温度数据8bit校验和 高位先出 校验 湿度高8位湿度低8位温度高8位温度低8位的末8位校验和 */ // CRC 校验前 4 字节之和的低 8 位等于校验字节 static bool dht22_check_crc(const uint8_t data[5]){ uint8_t sum data[0] data[1] data[2] data[3]; // 截取后8位 return (sum data[4]); } // 解析数据处理负温度 static void dht22_parse_data(const uint8_t data[5], float *humidity, float *temperature){ uint16_t rawHum (data[0] 8) | data[1]; // 高位左移 8 位低位直接拼接形成16位湿度数据 uint16_t rawTemp (data[2] 8) | data[3]; // 高位左移 8 位低位直接拼接形成16位温度数据 *humidity rawHum / 10.0f; if (rawTemp 0x8000){ // 温度最高位为 1 表示负值 rawTemp rawTemp 0x7FFF; *temperature - (rawTemp / 10.0f); } else{ *temperature rawTemp / 10.0f; } } // 公开的读取函数 bool dht22_read(float *humidity, float *temperature){ uint8_t data[5] {0}; if (!dht22_read_raw(data)) { ESP_LOGE(DHT22, 读取原始数据失败); return false; } ESP_LOGI(DHT22, Raw: %02X %02X %02X %02X %02X, data[0], data[1], data[2], data[3], data[4]); if (!dht22_check_crc(data)) { ESP_LOGE(DHT22, 校验和错误计算和0x%02X, 收到0x%02X, (data[0]data[1]data[2]data[3]) 0xFF, data[4]); return false; } dht22_parse_data(data, humidity, temperature); return true; }dht22.h#ifndef DHT22_H #define DHT22_H #include stdint.h #include stdbool.h #define DHT22_GPIO_PIN GPIO_NUM_4 void dht22_init(void); bool dht22_read(float *humidity, float *temperature); #endifCMakeLists.txtidf_component_register( SRCS dht22.c INCLUDE_DIRS . REQUIRES driver )2.串口发送uart_sender.c#include uart_sender.h #include driver/uart.h #include esp_log.h #include stdio.h #include string.h static const char *TAG UART_SENDER; void uart_sender_init(void) { // 配置 UART 参数 const uart_config_t uart_config { .baud_rate UART_SEND_BAUDRATE, .data_bits UART_DATA_8_BITS, .parity UART_PARITY_DISABLE, .stop_bits UART_STOP_BITS_1, .flow_ctrl UART_HW_FLOWCTRL_DISABLE, .source_clk UART_SCLK_DEFAULT, }; // 安装 UART 驱动 ESP_ERROR_CHECK(uart_driver_install(UART_SEND_PORT, 2048, 0, 0, NULL, 0)); // 配置 UART 参数 ESP_ERROR_CHECK(uart_param_config(UART_SEND_PORT, uart_config)); // 设置 TX/RX 引脚 ESP_ERROR_CHECK(uart_set_pin(UART_SEND_PORT, UART_SEND_TX_PIN, UART_SEND_RX_PIN, UART_PIN_NO_CHANGE, // RTS UART_PIN_NO_CHANGE)); // CTS ESP_LOGI(TAG, UART 发送器初始化完成, TX:%d, RX:%d, 波特率:%d, UART_SEND_TX_PIN, UART_SEND_RX_PIN, UART_SEND_BAUDRATE); } bool uart_send_th(float temperature, float humidity) { // 格式化数据: T:xx.x,H:xx.x\n char buffer[64]; //发送缓冲区 int len snprintf(buffer, sizeof(buffer), T:%.1f,H:%.1f\r\n, temperature, humidity); if (len 0 || len sizeof(buffer)) { ESP_LOGE(TAG, 数据格式化失败); return false; } // 通过 UART 发送 int sent uart_write_bytes(UART_SEND_PORT, buffer, len); if (sent ! len) { ESP_LOGE(TAG, UART 发送失败, 预期:%d, 实际:%d, len, sent); return false; } ESP_LOGI(TAG, 已发送: %s, buffer); return true; }uart_sender.h#ifndef UART_SENDER_H #define UART_SENDER_H #include stdbool.h #include driver/gpio.h #include driver/uart.h // UART 配置参数 #define UART_SEND_PORT UART_NUM_1 // 使用 UART1UART0 一般用于调试输出 #define UART_SEND_TX_PIN GPIO_NUM_17 // TX 引脚 #define UART_SEND_RX_PIN GPIO_NUM_16 // RX 引脚 #define UART_SEND_BAUDRATE 115200 // 波特率 /** * brief 初始化 UART 发送通道 */ void uart_sender_init(void); /** * brief 通过串口发送温湿度数据 * param temperature 温度值 (℃) * param humidity 湿度值 (%RH) * return true 发送成功, false 发送失败 */ bool uart_send_th(float temperature, float humidity); #endifCMakeLists.txtidf_component_register( SRCS uart_sender.c INCLUDE_DIRS . REQUIRES driver )3.主函数main.c#include stdio.h #include freertos/FreeRTOS.h #include freertos/task.h #include dht22.h #include uart_sender.h #include wifi_sender.h void app_main(void) { dht22_init(); // 初始化 DHT22 传感器 uart_sender_init(); // 初始化 UART 有线通道始终可用 wifi_sender_init(); // 初始化 WiFi 无线通道尽力而为 float h, t; while (1) { // 两次读取之间间隔必须 ≥ 2 秒 vTaskDelay(pdMS_TO_TICKS(3000)); if (dht22_read(h, t)) { // 控制台打印 printf(湿度: %.1f %%RH, 温度: %.1f ℃\n, h, t); // 有线通道: 通过串口发送给 ARM 开发板始终发送 uart_send_th(t, h); // 无线通道: 通过 WiFi 发送给 ESP8266 → ARM尽力而为 wifi_sender_send_th(t, h); } else { printf(读取失败请检查连接\n); } } }CMakeLists.txtidf_component_register( SRCS main.c INCLUDE_DIRS . REQUIRES dht-22 uart-sender wifi-sender )五、运行示例串口助手esp-idf监视设备
基于esp-idf框架的DHT22驱动
目录一、DHT22概述1.关键特性2.引脚定义4.单总线协议描述4.1数据格式4.2数据计算4.3负值的处理5.通信时序5.1 起始信号主机发起5.2 从机响应5.3 数据位传输5.4 结束信号二、硬件搭建1.总览编辑2.DHT22 → ESP323.ESP32 → USB to TLL三、软件环境四、驱动代码1.DHT22dht22.cdht22.hCMakeLists.txt2.串口发送uart_sender.cuart_sender.hCMakeLists.txt3.主函数main.cCMakeLists.txt五、运行示例一、DHT22概述DHT22 是一款数字温湿度复合传感器使用AM2302温湿度传感器并连接了一个 8 位单片机输出已校准的数字信号采用单总线协议。1.关键特性湿度测量范围0 ~ 100% RH精度±2% RH温度测量范围-40 ~ 80℃精度±0.5℃分辨率16 位湿度/16 位温度采样周期≥ 2 秒供电电压3.3 ~ 6V DC接口单总线DATA2.引脚定义引脚号名称功能说明1VDD供电电源3.3 ~ 6V DC2DATA串行数据总线单总线3NC空脚请悬空不连接4GND电源地3.原理图注模块已内置4.7k上拉电阻和100nF电容4.单总线协议描述DHT22 使用单总线协议一次完整通信约5ms传输40 bit数据高位先出4.1数据格式字节内容说明0湿度高 8 位整数部分16 bit 湿度数据1湿度低 8 位小数部分2温度高 8 位整数部分16 bit 温度数据3温度低 8 位小数部分4校验和CRC用于验证数据完整性4.2数据计算湿度值%RH(湿度高8位 8 | 湿度低8位) / 10.0温度值℃(温度高8位 8 | 温度低8位) / 10.0校验规则(Byte0 Byte1 Byte2 Byte3)的低 8 位应等于Byte44.3负值的处理当温度低于 0℃时温度数据16 bit的最高位第 15 位置 1。eg-10.1℃的原始数据为1000 0000 1010 1010即 0x80AA5.通信时序5.1 起始信号主机发起主机MCU将 DATA 线拉低≥ 500 μs建议 1~2 ms。释放总线等待20 ~ 40 μs。5.2 从机响应DHT22 拉低 DATA 线约80 μs响应信号。随后拉高 DATA 线约80 μs准备发送数据。5.3 数据位传输每个 bit 以约 50 μs 的低电平开始位同步信号。随后是高电平其持续时间决定 bit 值高电平持续 26~28 μs→ 逻辑0高电平持续 70 μs→ 逻辑15.4 结束信号40 bit 数据传输完成后从机拉低 DATA 线约50 μs然后释放总线由外部上拉电阻拉高。二、硬件搭建1.总览2.DHT22 → ESP32DHT22 引脚ESP32 引脚说明VCC3.3V供电3.3V ~ 5VGNDGND共地DATAGPIO 4数据线内部上拉已启用3.ESP32 → USB to TLLESP32 引脚功能USB to TLL说明GPIO 17TXRXESP32 发送 → 对端设备接收GPIO 16RXTXESP32 接收 ← 对端设备发送GND—GND共地确保参考电平一致三、软件环境VS Code esp-idf插件串口助手四、驱动代码1.DHT22dht22.c#include dht22.h #include driver/gpio.h #include esp_rom_sys.h // 提供 esp_rom_delay_us #include freertos/FreeRTOS.h #include freertos/task.h // 提供 vTaskDelay #include esp_log.h // 提供 ESP_LOGI 宏定义 // 宏定义微秒延迟 #define DELAY_US(us) esp_rom_delay_us(us) // 引脚操作宏 #define DHT22_PIN DHT22_GPIO_PIN #define DHT22_HIGH() gpio_set_level(DHT22_PIN, 1) // 拉高总线 #define DHT22_LOW() gpio_set_level(DHT22_PIN, 0) // 拉低总线 #define DHT22_READ() gpio_get_level(DHT22_PIN) // 读取总线电平 // 设置引脚方向 #define DHT22_OUTPUT() gpio_set_direction(DHT22_PIN, GPIO_MODE_OUTPUT) #define DHT22_INPUT() gpio_set_direction(DHT22_PIN, GPIO_MODE_INPUT) // 上电初始化 void dht22_init(void){ gpio_config_t io_conf { .pin_bit_mask (1ULL DHT22_PIN), .mode GPIO_MODE_INPUT, .pull_up_en GPIO_PULLUP_ENABLE, .pull_down_en GPIO_PULLDOWN_DISABLE, .intr_type GPIO_INTR_DISABLE }; gpio_config(io_conf); // 延时 1 秒保证传感器稳定 vTaskDelay(pdMS_TO_TICKS(1000)); ESP_LOGI(DHT22, DHT22 初始化完成, 引脚: %d, DHT22_PIN); } // 读取原始 40bit 数据5 字节成功返回 true static bool dht22_read_raw(uint8_t data[5]){ uint8_t i, j; uint8_t counter 0; // 1. 主机发起起始信号拉低总线至少 500us此处用 2ms后释放总线等待 20~40us 后检测从机响应 DHT22_OUTPUT(); DHT22_LOW(); DELAY_US(2000); DHT22_HIGH(); DELAY_US(40); // 释放后等待 20~40us // 2. 切换为输入检测从机响应 DHT22_INPUT(); // 等待从机拉低总线从机响应低电平约 80us uint32_t timeout 0; while (DHT22_READ() 1){ DELAY_US(1); if (timeout 100) return false; // 超时 } timeout 0; while (DHT22_READ() 0){ DELAY_US(1); if (timeout 100) return false; // 超时 } // 响应后的高电平约 80us随后进入数据传输阶段 timeout 0; while (DHT22_READ() 1){ DELAY_US(1); if (timeout 100) return false; // 超时 } // 3. 读取 40 位数据5 字节 for (j 0; j 5; j){ data[j] 0; for (i 0; i 8; i){ // 等待每个 bit 开始的低电平约 50us即数据位起始位 timeout 0; while (DHT22_READ() 0){ DELAY_US(1); if (timeout 100) return false; // 超时 } // 测量高电平持续时间 timeout 0; while (DHT22_READ() 1){ DELAY_US(1); if (timeout 100) return false; } // 高电平持续时间 50us 视为 1否则为 0高电平持续时间70us表示126-28us表示0 if (timeout 40) { data[j] | (1 (7 - i)); // 高位先出 } } } // 4. 结束信号从机拉低 50us 后释放总线无需特殊处理 return true; } /* 数据格式 40bit数据16bit湿度数据16bit温度数据8bit校验和 高位先出 校验 湿度高8位湿度低8位温度高8位温度低8位的末8位校验和 */ // CRC 校验前 4 字节之和的低 8 位等于校验字节 static bool dht22_check_crc(const uint8_t data[5]){ uint8_t sum data[0] data[1] data[2] data[3]; // 截取后8位 return (sum data[4]); } // 解析数据处理负温度 static void dht22_parse_data(const uint8_t data[5], float *humidity, float *temperature){ uint16_t rawHum (data[0] 8) | data[1]; // 高位左移 8 位低位直接拼接形成16位湿度数据 uint16_t rawTemp (data[2] 8) | data[3]; // 高位左移 8 位低位直接拼接形成16位温度数据 *humidity rawHum / 10.0f; if (rawTemp 0x8000){ // 温度最高位为 1 表示负值 rawTemp rawTemp 0x7FFF; *temperature - (rawTemp / 10.0f); } else{ *temperature rawTemp / 10.0f; } } // 公开的读取函数 bool dht22_read(float *humidity, float *temperature){ uint8_t data[5] {0}; if (!dht22_read_raw(data)) { ESP_LOGE(DHT22, 读取原始数据失败); return false; } ESP_LOGI(DHT22, Raw: %02X %02X %02X %02X %02X, data[0], data[1], data[2], data[3], data[4]); if (!dht22_check_crc(data)) { ESP_LOGE(DHT22, 校验和错误计算和0x%02X, 收到0x%02X, (data[0]data[1]data[2]data[3]) 0xFF, data[4]); return false; } dht22_parse_data(data, humidity, temperature); return true; }dht22.h#ifndef DHT22_H #define DHT22_H #include stdint.h #include stdbool.h #define DHT22_GPIO_PIN GPIO_NUM_4 void dht22_init(void); bool dht22_read(float *humidity, float *temperature); #endifCMakeLists.txtidf_component_register( SRCS dht22.c INCLUDE_DIRS . REQUIRES driver )2.串口发送uart_sender.c#include uart_sender.h #include driver/uart.h #include esp_log.h #include stdio.h #include string.h static const char *TAG UART_SENDER; void uart_sender_init(void) { // 配置 UART 参数 const uart_config_t uart_config { .baud_rate UART_SEND_BAUDRATE, .data_bits UART_DATA_8_BITS, .parity UART_PARITY_DISABLE, .stop_bits UART_STOP_BITS_1, .flow_ctrl UART_HW_FLOWCTRL_DISABLE, .source_clk UART_SCLK_DEFAULT, }; // 安装 UART 驱动 ESP_ERROR_CHECK(uart_driver_install(UART_SEND_PORT, 2048, 0, 0, NULL, 0)); // 配置 UART 参数 ESP_ERROR_CHECK(uart_param_config(UART_SEND_PORT, uart_config)); // 设置 TX/RX 引脚 ESP_ERROR_CHECK(uart_set_pin(UART_SEND_PORT, UART_SEND_TX_PIN, UART_SEND_RX_PIN, UART_PIN_NO_CHANGE, // RTS UART_PIN_NO_CHANGE)); // CTS ESP_LOGI(TAG, UART 发送器初始化完成, TX:%d, RX:%d, 波特率:%d, UART_SEND_TX_PIN, UART_SEND_RX_PIN, UART_SEND_BAUDRATE); } bool uart_send_th(float temperature, float humidity) { // 格式化数据: T:xx.x,H:xx.x\n char buffer[64]; //发送缓冲区 int len snprintf(buffer, sizeof(buffer), T:%.1f,H:%.1f\r\n, temperature, humidity); if (len 0 || len sizeof(buffer)) { ESP_LOGE(TAG, 数据格式化失败); return false; } // 通过 UART 发送 int sent uart_write_bytes(UART_SEND_PORT, buffer, len); if (sent ! len) { ESP_LOGE(TAG, UART 发送失败, 预期:%d, 实际:%d, len, sent); return false; } ESP_LOGI(TAG, 已发送: %s, buffer); return true; }uart_sender.h#ifndef UART_SENDER_H #define UART_SENDER_H #include stdbool.h #include driver/gpio.h #include driver/uart.h // UART 配置参数 #define UART_SEND_PORT UART_NUM_1 // 使用 UART1UART0 一般用于调试输出 #define UART_SEND_TX_PIN GPIO_NUM_17 // TX 引脚 #define UART_SEND_RX_PIN GPIO_NUM_16 // RX 引脚 #define UART_SEND_BAUDRATE 115200 // 波特率 /** * brief 初始化 UART 发送通道 */ void uart_sender_init(void); /** * brief 通过串口发送温湿度数据 * param temperature 温度值 (℃) * param humidity 湿度值 (%RH) * return true 发送成功, false 发送失败 */ bool uart_send_th(float temperature, float humidity); #endifCMakeLists.txtidf_component_register( SRCS uart_sender.c INCLUDE_DIRS . REQUIRES driver )3.主函数main.c#include stdio.h #include freertos/FreeRTOS.h #include freertos/task.h #include dht22.h #include uart_sender.h #include wifi_sender.h void app_main(void) { dht22_init(); // 初始化 DHT22 传感器 uart_sender_init(); // 初始化 UART 有线通道始终可用 wifi_sender_init(); // 初始化 WiFi 无线通道尽力而为 float h, t; while (1) { // 两次读取之间间隔必须 ≥ 2 秒 vTaskDelay(pdMS_TO_TICKS(3000)); if (dht22_read(h, t)) { // 控制台打印 printf(湿度: %.1f %%RH, 温度: %.1f ℃\n, h, t); // 有线通道: 通过串口发送给 ARM 开发板始终发送 uart_send_th(t, h); // 无线通道: 通过 WiFi 发送给 ESP8266 → ARM尽力而为 wifi_sender_send_th(t, h); } else { printf(读取失败请检查连接\n); } } }CMakeLists.txtidf_component_register( SRCS main.c INCLUDE_DIRS . REQUIRES dht-22 uart-sender wifi-sender )五、运行示例串口助手esp-idf监视设备