本帖最后由 lovzx 于 2024-5-20 13:58 编辑
DHT11温湿度传感器
运行效果
实物图
如图所示一般有3线、4线两种,
分别有
- VDD(3.3~5.5V)
- DATA串行线
- NC
- GND
测量范围
1. 湿度
2. 温度
连接方式
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开始工作
通信时序图
主机拉低电平发送开始信号,然后再拉高电平,结束开始信号,后面就由DHT设备回应,然后发送数据了
协议分为三个阶段
并且要严格按照先后顺序,每个信号都有规定的时间范围
信号特性
开始信号
- 先将DATA信号拉高60us
- 拉低20ms发送开始信号
- 拉高13us开始信号结束
DHT响应
- DHT拉低83us响应收到开始数据
- DHT拉高87us结束响应准备发送数据
传输数据
- 拉低54us开始发送数据
- 拉高电平23us~27us表示数据0,68us~74us表示数据1
代码实现
dht11.h代码
- #ifndef __DHT11_H
- #define __DHT11_H
- #include <stdint.h>
- #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文件
- #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中使用读取函数
- #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℃
代码下载 https://gitee.com/jrobot_Q_Q/m61-32-u-dht11.git
|