# M61-32U-DHT11 **Repository Path**: jrobot_Q_Q/m61-32-u-dht11 ## Basic Information - **Project Name**: M61-32U-DHT11 - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-05-19 - **Last Updated**: 2024-05-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ### DHT11温湿度传感器 ### 实物图 ![1716103031263](image/README/DHT11.png) ![1716103114518](image/README/DHT11模块.png) 如图所示一般有3线、4线两种, 分别有 1. VDD(3.3~5.5V) 1. DATA串行线 1. NC 1. GND ### 测量范围 1. 湿度 ![1716103501220](image/README/湿度参数.png) 1. 温度 ![1716103536632](image/README/温度.png) ### 连接方式 1. VDD与M61-32模块的3v或5v连接 2. GND与M61-32模块的GND相连 3. 将DATA与M61-32模块的GPIO相连 ### 通信/数据 DHT11采用的是单线串行通信协议,一次传输40bit,高位先出 ### 数据格式 8bit湿度整数+8bit湿度小数(湿度小数部分为0)+8bit温度整数+8bit温度小数+8bit校验位 #### 数据示例 00110101 00000000 00011000 00000100 01010001 **数据解析:** **湿度数据:** 00110101(整数)=35H=53%RH 00000000(小数)=0H=0 **最终读数:** 53.0% **温度数据:** 00011000(整数)=18H=24℃ 00000100(小数)=4H=4℃ **最终读数:** 24+0.4=24.4℃ **数据校验:** 8bit温度整数+8bit温度小数+8bit湿度整数+8bit湿度小数=8bit校验位 ### 通信协议 DHT采用单线串行通信协议,DHT作为从机使用,连接到主机后由主机发送信号控制DHT开始工作 通信时序图 ![1716102610422](image/README/时序图.png) 主机拉低电平发送开始信号,然后再拉高电平,结束开始信号,后面就由DHT设备回应,然后发送数据了 协议分为三个阶段 1. 主机发送起始信号 1. 设备回应 1. 设备发送数据 并且要严格按照先后顺序,每个信号都有规定的时间范围 ### 信号特性 ![1716103620522](image/README/信号特性.png) #### 开始信号 1. 先将DATA信号拉高60us 1. 拉低20ms发送开始信号 1. 拉高13us开始信号结束 ![1716104197559](image/README/开始信号.png) #### DHT响应 1. DHT拉低83us响应收到开始数据 1. DHT拉高87us结束响应准备发送数据 ![1716104328417](image/README/响应信号.png) #### 传输数据 1. 拉低54us开始发送数据 1. 拉高电平23us~27us数据0,68us~74us数据1 ![1716106547966](image/README/数据协议.png) ### 代码实现 #### dht11.h代码 ``` c #ifndef __DHT11_H #define __DHT11_H #include #include "bflb_gpio.h" typedef enum { DHT_CODE_SUCCEED = 0, DHT_CODE_NOACK, DHT_CODE_DATA_ERR, }DHT_CODE; typedef enum { DHT_STATUS_INIT = 0, DHT_STATUS_READY, DHT_STATUS_READING, }DHT_STATUS; typedef struct DHT11 { uint8_t pin; DHT_STATUS status; }DHT11_t; #ifdef cplusplus extern "C" { #endif /** * @brief dht初始化 * @param gpio * @param dev * @param pin 设备连接到的pin */ void dht_init(struct bflb_device_s* gpio, DHT11_t* dev, uint8_t pin); /** * @brief 读取温湿度数据 * @param gpio * @param dev * @param temp 温度*10 * @param humidity 湿度*10 * @return DHT_CODE 状态码 */ DHT_CODE dht_read_data(struct bflb_device_s* gpio, DHT11_t* dev, int16_t* temp, uint16_t* humidity); #ifdef cplusplus } #endif #endif ``` dht11.h中定义了dht_init初始化函数和dht_read_data读取函数 #### dht11.c文件 ``` c #include "dht11.h" #include "bflb_gpio.h" #include "bflb_mtimer.h" #define CONFIG_LOG_NCOLOR 1 #include "log.h" #define DHT_read_set(gpio,dev) \ do \ { \ bflb_gpio_init(gpio, \ dev->pin, \ GPIO_INPUT|GPIO_PULLUP|GPIO_SMT_EN|GPIO_DRV_0); \ }while (0) #define DHT_write_set(gpio,dev) \ do \ { \ bflb_gpio_init(gpio, \ dev->pin, \ GPIO_OUTPUT|GPIO_PULLUP|GPIO_SMT_EN|GPIO_DRV_0);\ } while (0); void dht_init(struct bflb_device_s* gpio, DHT11_t* dev, uint8_t pin) { dev->status = DHT_STATUS_INIT; dev->pin = pin; DHT_write_set(gpio, dev); bflb_gpio_set(gpio, dev->pin); //等待1s越过不稳定状态 bflb_mtimer_delay_ms(1000); dev->status = DHT_STATUS_READY; } uint8_t dht_check(struct bflb_device_s* gpio, DHT11_t* dev) { DHT_read_set(gpio, dev); uint8_t retry = 0; //dht会拉低电平80us while (!bflb_gpio_read(gpio, dev->pin) && retry < 100) { retry++; bflb_mtimer_delay_us(1); } if (retry >= 100) { return 0; } retry = 0; //再次拉高80us while (bflb_gpio_read(gpio, dev->pin) && retry < 100) { retry++; bflb_mtimer_delay_us(1); } if (retry >= 100) { return 0; } else { return 1; } } static uint8_t dht_read_bit(struct bflb_device_s* gpio, DHT11_t* dev) { uint8_t retry = 0; //54us低电平 while (!bflb_gpio_read(gpio, dev->pin) && retry < 70) { retry++; bflb_mtimer_delay_us(1); } retry = 0; //高电平23~27us是0,高电平68~71us是1 //延迟30us bflb_mtimer_delay_us(35); uint8_t ret = bflb_gpio_read(gpio, dev->pin); //等待高电平结束 if (ret) { while (bflb_gpio_read(gpio, dev->pin) && retry < 50) { retry++; bflb_mtimer_delay_us(1); } } return ret; } static int8_t dht_read_byte(struct bflb_device_s* gpio, DHT11_t* dev) { int8_t ret = 0; for (int i = 0; i < 8; i++) { ret <<= 1; ret |= dht_read_bit(gpio, dev); } return ret; } DHT_CODE dht_read_data(struct bflb_device_s* gpio, DHT11_t* dev, int16_t* temp, uint16_t* humidity) { //检查dev状态 if (dev->status != DHT_STATUS_READY) { return dev->status; } dev->status = DHT_STATUS_READING; //空闲高电平 DHT_write_set(gpio, dev); bflb_gpio_set(gpio, dev->pin); bflb_mtimer_delay_us(60); //拉低电平20ms上,发送开始信号 bflb_gpio_reset(gpio, dev->pin); bflb_mtimer_delay_ms(20); // //拉高电平延迟10 ~ 20us,结束开始信号 bflb_gpio_set(gpio, dev->pin); bflb_mtimer_delay_us(13); DHT_CODE ret = DHT_CODE_SUCCEED; uint8_t buf[5] = { 0 }; //检测设备 if (dht_check(gpio, dev)) { for (int i = 0;i < 5;i++) { buf[i] = dht_read_byte(gpio, dev); } uint16_t sum = buf[0] + buf[1] + buf[2] + buf[3]; if (sum == buf[4]) { *humidity = buf[0] * 10 + buf[1]; //温度小数数据第8位为1代表负数,低7位代表实际数值 *temp = buf[2] * 10 + (buf[3] & 0x7f); if ((buf[3] & 0x80) == 0x80) { *temp = -*temp; } } else { LOG_E("%d,%d,%d,%d,sum: %d,buf[4]: %d\n", buf[0], buf[1], buf[2], buf[3], sum, buf[4]); ret = DHT_CODE_DATA_ERR; } } else { ret = DHT_CODE_NOACK; LOG_E("设备未回复\n"); } dev->status = DHT_STATUS_READY; return ret; } ``` #### main.c main.c中使用读取函数 ``` c #include "dht11.h" #include "board.h" #define CONFIG_LOG_NCOLOR 1 #include "log.h" #include "bflb_mtimer.h" int main() { board_init(); printf("dht11 start\n"); DHT11_t dht; struct bflb_device_s* gpio; gpio = bflb_device_get_by_name("gpio"); dht_init(gpio, &dht, GPIO_PIN_10); int ret = 0; int16_t temp = 0; uint16_t humidity = 0; while (1) { ret = dht_read_data(gpio, &dht, &temp, &humidity); if (ret == DHT_CODE_SUCCEED) { LOG_I("温度:%.1fC°, 湿度:%.1f%%\n", temp / 10.0f, humidity / 10.0f); } else { LOG_E("ret: %d\n", ret); } bflb_mtimer_delay_ms(2000); } return 0; } ``` ### 可能遇到的问题 1. 数据都是0 确保GPIO模式正确,DATA正确连接到代码所用到GPIO的PIN引脚 1. 数据都是1 这种情况是DHT没有收到开始信号,确保主机发送了开始信号 **注意:** 开始信号发送低电平信号20ms,单位是ms不是us,通信过程中其他信号时间单位都是us 1. 解析出错 一共40个bit数据,高位先出,按照8bit湿度整数数据+8bit湿度小数部分+8bit温度整数部分+8bit温度小数部分+8bit校验位 **注意:** 温度小数部分8bit数据,第8位为1表示负数为零下,为零表示正数,后7位才是真正的数据,第8位只表示正负值 **例:** 温度整数部分为0000 0020,小数部分为:1000 0001 整数部分为2,小数部分为1,第8位为1,所以最终温度为-2.1℃