STM32(三十一)DHT11温湿度传感器获取温湿度数据
一、传感器实物图
二、传感器应用电路图:
通过原理图可知dht11通过DQ脚和STM32F407ZE06的PG9连接。通过DQ进行数据传输,串行接口 (单线双向),半双工的工作模式。
串行接口 (单线双向)
DATA 用于微处理器与 DHT11之间的通讯和同步,采用单总线数据格式,一次通讯时间4ms左右,数据分小数部分和整数部分,具体格式在下面说明,当前小数部分用于以后扩展,现读出为零.操作流程如下:
- 一次完整的数据传输为40bit,高位先出。
- 数据格式:8bit湿度整数数据+8bit湿度小数数据+8bi温度整数数据+8bit温度小数数据+8bit校验和
- 数据传送正确时校验和数据等于“ 8bit湿度整数数据+8bit湿度小数数据+8bi温度整数数据+8bit温度小数数据” 所得结果的末8位。
三、数据传输过程
用户MCU发送一次开始信号后,DHT11从低功耗模式转换到高速模式,等待主机开始信号结束后,DHT11发送响应信号,送出40bit的数据,并触发一次信号采集,用户可选择读取部分数据.从模式下,DHT11接收到开始信号触发一次温湿度采集,如果没有接收到主机发送开始信号,DHT11不会主动进行温湿度采集.采集数据后转换到低速模式。
t1~t2 | 至少18ms |
t3~t4 | 20~40us |
t5~t6 | 80us |
t7~t8 | 80us |
t9~t10 | 50us |
t11~t12 | 26us~28us(表示数据0) |
t13~t14 | 50us |
t15~t16 | 70us(表示数据1) |
(1)起始阶段:主机(DQ脚PG9)主动发送至少18ms(t1-t2)的低电平(开始信号)此时PG9是输出模式(MCU给DHT11发),保证DHT11能检测到起始信号,DHT11检测到起始信号后,从低功耗模式转换为高速模式,在拉高延时等待20~40us(t3-t4),此时开始信号结束。
(2)响应阶段:DHT11检测到起始信号后,发送80us(t5-t6)的低电平响应(此时PG9是输入模式,由DHT11向MCU发),在拉高延时80us(t7-t8)准备输出,此时响应结束,准备传输数据。
(3)数据传输阶段:数据传输阶段,每一bit数据都以50us低电平(t9-t10)时隙开 ,数据0和数据1的区别在与高电平的时间长短。
数据0:26us~28us的高电平。(即只要判断高电平的时间超过30us就是传输数据1,否则就是0).
数据1:70us的的高电平。
四、实验:通过串口打印出温湿度数据。
代码分析:有两种方式,一种是使用精准延时,还有一种就是while循环。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | //dht11 .c文件 #include "dht11.h" GPIO_InitTypeDef GPIO_InitStruct; u8 buff; void Dht11_Init(void) { //1 .初始化时钟 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE); //2 .初始化硬件 GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9; //PG9 GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; // 输出模式 GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; // 推挽输出 GPIO_InitStruct.GPIO_Speed = GPIO_Fast_Speed; // 速度 快速 25MHz GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; // 上拉 GPIO_Init(GPIOG,&GPIO_InitStruct); } /***************传入参数确定是输出还是输入**********************/ void pin_mode(GPIOMode_TypeDef mode) { GPIO_InitStruct.GPIO_Mode = mode; // 模式切换 GPIO_Init(GPIOG,&GPIO_InitStruct); // 加进结构体 } /******************初步配置(开始信号)**************************/ uint8_t start_dht11(void) { //1 .设置为输出模式,并且空闲状态为高电平 pin_mode(GPIO_Mode_OUT); PGout(9)=1; delay_us(2); //2 .主机拉低 至少18ms PGout(9)=0; delay_ms(20); //3 .主机拉高 20-40us PGout(9)=1; delay_us(30); //4 .设置为输入模式,进入两个电平跳变 pin_mode(GPIO_Mode_IN); if (!PGin(9)) //if (PGin(9)==0) { // 检测低到高跳变 while (!PGin(9)); // 检测高到底跳变 while (PGin(9)); return 1; } return 0; } /*********************获取8bit数据*******************/ void get_8bit_data(void) { u8 i=0; for (i=0;i<8;i++) { buff = buff <<1; while (!PGin(9)); // 过滤低电平时间,确定高电平到来 delay_us(30); if (PGin(9)) // 如果还是高电平,数据就是1 { buff |= 0x01; } else // 低电平的话,数据就是0 { buff &= 0xfe; } while (PGin(9)); // 过滤剩余的高电平时间 } } /****************获取温湿度数据*******************/ uint8_t get_dht11_data(char DataBuf[]) { if (start_dht11()) { get_8bit_data(); // 获取的是湿度整数 DataBuf[0] = buff; get_8bit_data(); // 获取的是湿度小数 DataBuf[1] = buff; get_8bit_data(); // 获取的是温度整数 DataBuf[2] = buff; get_8bit_data(); // 获取的是温度小数 DataBuf[3] = buff; get_8bit_data(); // 获取的是校验和 DataBuf[4] = buff; } if (DataBuf[4] == DataBuf[0]+DataBuf[1]+DataBuf[2]+DataBuf[3]) { return 1; } else return -1; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | //mian .c文件 #include "stm32f4xx.h" #include "led.h" #include "key.h" #include "exti.h" #include "sys.h" #include "tim.h" #include "pwm.h" #include "uart.h" #include "stdio.h" #include "dht11.h" uint16_t uart1_recv_data; // 重定向fputc 换个方向,此路不通,屏幕输出不了就往串口发 //fputc fputs / fgetc fgets int fputc(int ch,FILE *f) { USART_SendData(USART1,ch); while (USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET); return ch; } // 串口接收中断 void USART1_IRQHandler(void) { // 判断确实进中断标志 //if (USART_GetITStatus(USART1, USART_IT_RXNE) !=RESET) // ==SET if (((USART1->SR) & (0x1<<5)) !=0) // 发生中断 该为由硬件自定置1 { // 清楚中断标志位 往里面写1 记住一定要清空 //USART_ClearITPendingBit (USART1,USART_IT_RXNE); // 用寄存器方式自己去改 USART1->SR &= ~(0x1<<5); uart1_recv_data = USART_ReceiveData(USART1); } } int main(void) { u8 ret; char DataBuf[5] = {0}; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //NVIC 分组 SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); // 滴答定时器8分频 LED_Init(); Key_Init(); //Exti_Init (); //Tim_Init (); //Pwm_Tim14 (); Uart_Init(115200); Dht11_Init(); printf ( "hello uart1\r\n" ); while (1) { ret = get_dht11_data(DataBuf); if (ret == 1) { printf ( "温度:%d ℃ 湿度:%d\r\n" ,DataBuf[2],DataBuf[0]); } else { printf ( "get dht11 failed!" ); } delay_s(2); } return 0; } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)