1. 介绍
DHT11是一款含有已校准数字信号输出的温湿度复合传感器,采用了自主研发的集成式数字温湿度元件,应用专用的数字模块采集技术和温湿度传感技术,确保产品具有极高的可靠性与卓越的长期稳定性。DHT11传感器内包含一个温湿度测量元件和一个高性能MCU
更多详细介绍见《DHT11 中文资料 ------ C语言例程》
2. 传感器原理
(1) 原理图
DQ ------ PG9
单总线上必须有一个上拉电阻(R26)以实现单总线闲置时,其处于高电平状态
(2) 由参考资料《DHT11中文资料 ----- C语言例程》可知数据格式:
一次完整的数据传输为40bit,高位先发 数据格式:8bit 湿度整数数据 + 8bit 湿度小数数据 + 8bit 温度整数数据 + 8bit 温度小数数据 + 8bit 校验和 数据传输正确时校验和数据等于 “8bit 湿度整数数据 + 8bit 湿度小数数据 + 8bit 温度整数数据 + 8bit 温度小数数据” 所得结果的未8位
工作时序:
a. 数字0信号表示方法
b. 数字1信号表示方法
(3) DHT11温湿度获取流程GPIO:通信规则 1. 起始信号 STM32 通过 DHT11_DATA_GPIO 输出高 ---> 低电平 持续时间>18ms 2. 等待响应 STM32 先将引脚电平拉高 DHT11_DATA_GPIO 切换输入模式, 延时20-40us 读取引脚上的电平状态, 如果引脚电平为低电平则DHT11响应 3. 响应信号 DHT11收到启动信号,发送80us的低电平响应信号 4. 准备输出 DHT11会将 DHT11_DATA_GPIO 拉高 80us的时间 5. 温湿度数据发送 40bit 高位先发 湿度整数最开始的8bit 0:50us低电平 26-28us高电平 1:50us低电平 70us高电平 6. 结束输出 当最后 1bit 数据抄送完毕后,DHT11 拉低总线50us,随后总线由上拉电阻拉高进入空闲状态
3. 实验要求
a. 对温度湿度的测量
b. 通过串口将温度、湿度输出
c. 设置温度的阈值,通过按键进行设置
===> 按 按键1 温度阈值 +1,按 按键2 温度阈值 -1 ===> 中断控制
d. 当温度超过了阈值,LED灯常亮,蜂鸣器报警
e. 按键控制串口输出当前的信息
===> 按一次 按键3 打印当前温度的阈值和当前温湿度 ===> 中断控制
4. 程序设计
DHT11.h
#ifndef __DHT11_H__ #define __DHT11_H__ #include "stm32f4xx.h" #include "systick.h" // DHT11需要配置的时钟外设 #define DHT11_DATA_RCC_AHB1Periph RCC_AHB1Periph_GPIOG // 使能时钟 #define DHT11_DATA_Clock() RCC_AHB1PeriphClockCmd(DHT11_DATA_RCC_AHB1Periph, ENABLE) // DQ ===> PG9 #define DHT11_DATA_GPIO GPIOG #define DHT11_DATA_Pin GPIO_Pin_9 // DHT11_DATA_IDLE 设置空闲状态(IDLE) ===> 高电平 #define DHT11_DATA_IDLE() GPIO_SetBits(DHT11_DATA_GPIO, DHT11_DATA_Pin) // 往总线输出高电平 #define DHT11_DATA_SET() DHT11_DATA_IDLE() // 往总线输出低电平 #define DHT11_DATA_RESET() GPIO_ResetBits(DHT11_DATA_GPIO, DHT11_DATA_Pin) // 读取总线上的电平状态 #define DHT11_DATA_STATE() GPIO_ReadInputDataBit(DHT11_DATA_GPIO, DHT11_DATA_Pin) // data线设置为输出 void DHT11_DATA_Mode_OUT(void); // data线设置为输入 void DHT11_DATA_Mode_IN(void); // 发送开始信号 void DHT11_Start(void); // 每次8bit接收数据,通过返回值返回,高位先发 uint8_t DHT11_Get8Bit(void); /* 获取温度和湿度 @humi:湿度 @temp:温度 @返回值:成功返回0,失败返回-1 */ int DHT11_GetData(uint8_t *humi, uint8_t *temp); #endif
DHT11.c
#include "DHT11.h" // data线设置为输出模式 void DHT11_DATA_Mode_OUT(void) { // 初始化配置GPIO(完成GPIO的4个配置寄存器的赋值) // a. 定义GPIO初始化信息结构体 GPIO_InitTypeDef g; // b. 根据配置需要,对结构体成员赋值 g.GPIO_Pin = DHT11_DATA_Pin; // 几号引脚 g.GPIO_Mode = GPIO_Mode_OUT; // 输出模式 g.GPIO_Speed = GPIO_Speed_2MHz; // 2MHz g.GPIO_OType = GPIO_OType_PP; // 输出类型 g.GPIO_PuPd = GPIO_PuPd_NOPULL; // 无上拉也无下拉 // c. 根据结构体信息,完成GPIO配置 GPIO_Init(DHT11_DATA_GPIO, &g); } // data线设置为输入模式 void DHT11_DATA_Mode_IN(void) { // 初始化配置GPIO(完成GPIO的4个配置寄存器的赋值) // a. 定义GPIO初始化信息结构体 GPIO_InitTypeDef g; // b. 根据配置需要,对结构体成员赋值 g.GPIO_Pin = DHT11_DATA_Pin; // 几号引脚 g.GPIO_Mode = GPIO_Mode_IN; // 输入模式 g.GPIO_PuPd = GPIO_PuPd_NOPULL; // 无上拉也无下拉 // c. 根据结构体信息,完成GPIO配置 GPIO_Init(DHT11_DATA_GPIO ,&g); } /* GPIO:通信规则 1.起始信号 STM32 通过 DHT11_DATA_GPIO 输出高->低电平 持续时间>18ms 2.等待响应 STM32 先将引脚电平拉高 DHT11_DATA_GPIO 切换输入模式, 延时20-40us 读取引脚上的电平状态, 如果引脚电平为低电平则DHT11响应 3.响应信号 DHT11收到启动信号,发送80us的低电平响应信号 4.准备输出 DHT11会将 DHT11_DATA_GPIO 拉高 80us的时间 5.温湿度数据发送 40bit 高位先发 湿度整数最开始的8bit 0:50us低电平 26-28us高电平 1:50us低电平 70us高电平 6.结束输出 当最后 1bit 数据抄送完毕后,DHT11 拉低总线50us,随后总线由上拉电阻拉高进入空闲状态 */ // 发送开始信号 void DHT11_Start(void) { // data线设置为输出 DHT11_DATA_Mode_OUT(); // 将数据线设置为空闲状态 DHT11_DATA_IDLE(); delay_ms(1); // 发送开始信号 DHT11_DATA_RESET(); delay_ms(19); } // 每次8bit接收数据,通过返回值返回,高位先发 uint8_t DHT11_Get8Bit(void) { uint8_t x = 0; // 高位先发 for (int i = 7; i >= 0; i--) { // 跳过最开始的50us while (DHT11_DATA_STATE() == RESET); delay_us(30); // 30us之后 DATA引脚还是高电平,意味着这个bit是1 if (DHT11_DATA_STATE() == SET) { x |= (1 << i); // 跳过剩下的高电平时间 while (DHT11_DATA_STATE() == SET); } } return x; } /* 获取温度和湿度 @humi:湿度 @temp:温度 @返回值:成功返回0,失败返回-1 */ int DHT11_GetData(uint8_t *humi, uint8_t *temp) { // 使能时钟 DHT11_DATA_Clock(); // 1. 发送起始信号 DHT11_Start(); // 2. 等待响应 DHT11_DATA_SET(); // 拉高 DHT11_DATA_Mode_IN(); // 切换为输入模式 delay_us(40); // 如果读取到的引脚电平状态为低电平 则表示dht11发送了响应信号 if (DHT11_DATA_STATE() == RESET) { // 跳过响应时间 80us while (DHT11_DATA_STATE() == RESET); // 3. DHT11 准备输出阶段 DATA线会被拉高80us while (DHT11_DATA_STATE() == SET); // 4. 接收湿度、温度 I整数 F小数 par校验和 uint8_t humiI, humiF, tempI, tempF, par; humiI = DHT11_Get8Bit(); humiF = DHT11_Get8Bit(); tempI = DHT11_Get8Bit(); tempF = DHT11_Get8Bit(); par = DHT11_Get8Bit(); // 5. 验证数据 if ((uint8_t)(humiI + humiF + tempI + tempF) != par) { return -1; } *humi = humiI; *temp = tempI; return 0; } return -1; }
main.c
#include "stm32f4xx.h" #include "systick.h" #include "DHT11.h" #include "usart.h" #include "stdio.h" int main(void) { Usart1_Init(9600); // 湿度,温度 uint8_t humi = 0, temp = 0; while (1) { if (DHT11_GetData(&humi, &temp) == -1) { printf("DHT11 Getdata failed\r\n"); // 延时 2s delay_ms(2000); continue; } printf("humi = %d, temp = %d\r\n", humi, temp); // 延时 2s delay_ms(2000); } }