• 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循环。

    //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; }

      

    //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
    ");
    	while(1)
    	{
    		ret = get_dht11_data(DataBuf);
    		if(ret == 1)
    		{
    			printf("温度:%d ℃   湿度:%d
    ",DataBuf[2],DataBuf[0]); 
    		}
    		else
    		{
    			printf("get dht11 failed!");
    		}
    		delay_s(2);
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    Java实现 LeetCode 32 最长有效括号
    Java实现 LeetCode 31下一个排列
    Java实现 LeetCode 31下一个排列
    Java实现 LeetCode 31下一个排列
    Java实现 蓝桥杯 素因子去重
    Java实现 蓝桥杯 素因子去重
    Java实现 蓝桥杯 素因子去重
    Java实现 LeetCode 30 串联所有单词的子串
    Visual c++例子,可不使用常规的对话框资源模板的情况下,动态创建对话框的方法
    MFC不使用对话框资源模版创建对话框
  • 原文地址:https://www.cnblogs.com/yuanqiangfei/p/14757925.html
Copyright © 2020-2023  润新知