STM32第九课:DHT11温湿度传感器

2024-06-29 1495阅读

文章目录

  • 需求
  • 一、DHT11温湿度传感器
  • 二、模块配置流程
    • 1.配置时钟和IO
    • 2.读取数据
    • 3.数据处理
    • 三、导入语音模块
    • 四、关键代码
    • 总结

      需求

      1.完成DHT11温湿度检测模块的配置。

      2.处理DHT11获取的数据,在串口打印处理后的实时数据。

      2.通过Su-03t语音识别模块实现实时温湿度的问答。

      STM32第九课:DHT11温湿度传感器


      一、DHT11温湿度传感器

        DHT11 数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器。它应用专用的数字模块采集技术和温湿度传感技术,确保产品具有枀高的可靠性与卓越的长期稳定性。传感器包括一个电容式感湿元件和一个 NTC 测温元件,并与一个高性能 8 位单片机相连接。

      引脚说明:

      1、VDD 供电 3.3~5.5V DC

      2、DATA 串行数据,单总线

      3、NC 空脚

      4、GND 接地,电源负枀

      二、模块配置流程

      1.配置时钟和IO

      STM32第九课:DHT11温湿度传感器

      STM32第九课:DHT11温湿度传感器

      由原理图可知该模块连接的是stm32的PG11引脚所以此时我们只需要配置PG11的引脚即可。

      STM32第九课:DHT11温湿度传感器

      根据该模块手册中的数据时序图可知:该引脚需要既能输入也能输出,所以为了能够同时满足输入和输出,我们将PG11引脚配置成开漏模式。

      STM32第九课:DHT11温湿度传感器

      代码如下(示例):

      void DHT11_Config()
      {
      	//配置为开漏模式
      	//开时钟
      	 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG,ENABLE);
      	//配置io
      	 GPIO_InitTypeDef GPIO_InitStruct = {0};
      	 GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD;
      	 GPIO_InitStruct.GPIO_Pin = GPIO_Pin_11;
      	 GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
      	 GPIO_Init(GPIOG,&GPIO_InitStruct);
      	 DHT11HIGH();
      }
      

      配置完成后拉高电平是为了满足主机“拉高等待”状态。

      为了方便后续操作,先重定义一下拉高电平,拉低电平和读操作。

      #define DHT11HIGH() GPIO_SetBits(GPIOG,GPIO_Pin_11)
      #define DHT11LOW()  GPIO_ResetBits(GPIOG,GPIO_Pin_11)
      #define DHT11read() GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_11)
      

      2.读取数据

      根据官方提供的外设读取步骤一步步进行操作即可

      STM32第九课:DHT11温湿度传感器

      由图可知要先拉高电平

      STM32第九课:DHT11温湿度传感器

      再拉低电平并持续18ms

      STM32第九课:DHT11温湿度传感器

      再输出高电平,然后用while检测83us的低电平应答信号。

      收到应答信号后,再用while检测87us的高电平外设准备接受信号。

      STM32第九课:DHT11温湿度传感器

      STM32第九课:DHT11温湿度传感器

      接收到高电平外设准备接受信号后就可以接收40位的数据了。

      直接定义一个数组进行for循环接收。

      由于该模块发送的数据为高低电平信号,并且是根据高电平持续时间的不同来判断究竟是高电平还是低电平,此时我们只需要加个延迟,比差值大 ,比74us小即可,此处我用的是45us。

      3.数据处理

      STM32第九课:DHT11温湿度传感器

      由手册可知,为了能够准确的将温湿度转换为10进制

      此刻我们先用for循环将40个数据进行8位分组处理。

      	for(i=0;i //0~7  8~15  16~23  24~31 32~39
      		data[i/8]+=(arr[i]
      	uint16_t i = 0;
      	uint16_t timeout = 0;
      	uint8_t data[5] = {0};
        uint8_t arr[50] = {0};
      	//输出一个最少18ms的低电平,最大30ms
      	DHT11HIGH();
      	DHT11LOW();
      	Delay_nms(18);
      	DHT11HIGH();
      	//检测有持续83us低电平和87us的高电平
      	timeout=0;
      	while(DHT11read()==1)//检测83us低电平
      	{
      		timeout++;
      			 Delay_nus(1);
      		if(timeout=100)
      		{
      			return ;
      		}
      	}
      	timeout=0;
      		while(DHT11read()==0)//检测87us的高电平
      	{
      		timeout++;
      		Delay_nus(1);
      		if(timeout=100)
      		{
      			return ;
      		}
      	}
      	//读取40位数据
      	for(i=0;i
      			timeout=0;
      			while(DHT11read()==1)//等待us低电平
      	   {
      				timeout++;
      			 Delay_nus(1);
      		if(timeout=100)
      		{
      			return ;
      		}
      		}
      		 timeout=0;
      		  while(DHT11read()==0)//等待能判断的高电平标志
         	 {
      		 timeout++;
      		 Delay_nus(1);
      		if(timeout=100)
      		{
      			return ;
      		}
      		}
      		 Delay_nus(45);
      	   arr[i]=DHT11read();
      	}
      			for(i=0;i //0~7  8~15  16~23  24~31 32~39
      		data[i/8]+=(arr[i]
      		return;
      	}
      	hum=data[0]+data[1]/10.0;
      	tem=data[2]+(data[3]&0x7f)/10.0;
      	if((data[3]&0x80) != 0){
      		tem = 0-tem;
      	}
      	printf("读取完毕:湿度:%.1f   温度:%.1f\r\n",hum,tem);
      	return;
      }
      
      		NVIC_SetPriorityGrouping(5);//两位抢占两位次级
          Usart1_Config(); 
      	  SysTick_Config(72000);
      	  Kqm_U4Config();
      	  Su03t_U5Config();
      	  DHT11_Config();
      	    while(1)
          {	
      			if(led2cnt[0]=led2cnt[1])
      			{//过去2s
      			led2cnt[0]=0;
      			DHT11_ReadData();
      			}
      	  	KQM_DealData();
      			Su03tDealData();
          }
      }
      
      	//配置为开漏模式
      	//开时钟
      	 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG,ENABLE);
      	//配置io
      	 GPIO_InitTypeDef GPIO_InitStruct = {0};
      	 GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD;
      	 GPIO_InitStruct.GPIO_Pin = GPIO_Pin_11;
      	 GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
      	 GPIO_Init(GPIOG,&GPIO_InitStruct);
      	 DHT11HIGH();
      }
      //根据DHT11时序读取数据
      void DHT11_ReadData()
      {
      	uint16_t i = 0;
      	uint16_t timeout = 0;
      	uint8_t data[5] = {0};
        uint8_t arr[50] = {0};
      	//输出一个最少18ms的低电平,最大30ms
      	DHT11HIGH();
      	DHT11LOW();
      	Delay_nms(18);
      	DHT11HIGH();
      	//检测有持续83us低电平和87us的高电平
      	timeout=0;
      	while(DHT11read()==1)//检测83us低电平
      	{
      		timeout++;
      			 Delay_nus(1);
      		if(timeout=100)
      		{
      			return ;
      		}
      	}
      	timeout=0;
      		while(DHT11read()==0)//检测87us的高电平
      	{
      		timeout++;
      		Delay_nus(1);
      		if(timeout=100)
      		{
      			return ;
      		}
      	}
      	//读取40位数据
      	for(i=0;i
      			timeout=0;
      			while(DHT11read()==1)//等待us低电平
      	   {
      				timeout++;
      			 Delay_nus(1);
      		if(timeout=100)
      		{
      			return ;
      		}
      		 }
      		 timeout=0;
      		  while(DHT11read()==0)//等待能判断的高电平标志
         	 {
      		 timeout++;
      		 Delay_nus(1);
      		if(timeout>=100)
      		{
      			return ;
      		}
      		}
      		 
      		 Delay_nus(45);
      	   arr[i]=DHT11read();
      	}
      			for(i=0;i //0~7  8~15  16~23  24~31 32~39
      		data[i/8]+=(arr[i]
      		return;
      	}
      	hum=data[0]+data[1]/10.0;
      	tem=data[2]+(data[3]&0x7f)/10.0;
      	if((data[3]&0x80) != 0){
      		tem = 0-tem;
      	}
      		printf("读取完毕:湿度:%.1f   温度:%.1f\r\n",hum,tem);
      		return;
      }
      
      	uint8_t u5_recv[10];//保存数据数组
      	uint8_t  u5_cnt;//数组下标
      	uint8_t u5_tflag;
      }UART5DATA;//数据类型
      void Su03t_U5Config()//串口5 PC12(TX) PD2(RX)
      {
      	
      		//开时钟U5 PD12(TX) PD2(RX)
      	  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD|RCC_APB2Periph_GPIOC,ENABLE);
      	  RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART5,ENABLE);
      	  //配置PC12(TX)
      		GPIO_InitTypeDef GPIO_InitStruct = {0};
      		GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;//复用推完输出
      		GPIO_InitStruct.GPIO_Pin = GPIO_Pin_12;
      		GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
      		GPIO_Init(GPIOC,&GPIO_InitStruct);
      		//PD2(RX)
      		GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
      		GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2;
      		GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
      		GPIO_Init(GPIOD,&GPIO_InitStruct);
      		
        	//配置串口5  波特率9600 数据位8,校验位0,停止位1
      		USART_InitTypeDef USART_InitStruct = {0};//可以通过结构体类型跳转
      		USART_InitStruct.USART_BaudRate = 9600;//波特率
      		USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//硬件控制流不开
      		USART_InitStruct.USART_Mode = USART_Mode_Rx|USART_Mode_Tx;//打开接收
      		USART_InitStruct.USART_Parity = USART_Parity_No;
      		USART_InitStruct.USART_StopBits = USART_StopBits_1;
      		USART_InitStruct.USART_WordLength = USART_WordLength_8b;
      		USART_Init(UART5,&USART_InitStruct);
      	  //使能串口
      		USART_Cmd(UART5,ENABLE);
         	//配置串口4的中断(采用中断接收)
      		USART_ITConfig(UART5,USART_IT_RXNE,ENABLE);//使能串口4	的接收非空中断
      		USART_ITConfig(UART5,USART_IT_IDLE,ENABLE);//总线空闲中断
      		NVIC_SetPriority(UART5_IRQn,6);//设置优先级0~15
      		NVIC_EnableIRQ(UART5_IRQn);//使能中断通道
      }
      //串口5发送单字节函数
      void Uart5Senddata(uint8_t data)
      {
      	//等待发送完成
      	while(USART_GetFlagStatus(UART5,USART_FLAG_TC)==0);
      	//如果上次发送完成,就发送
      	USART_SendData(UART5,data);
      }
      //串口5发送数组函数
      void U5_Sendarr(uint8_t * data,uint32_t len)
      {
      	uint32_t i=0;
      	for(i=0;i
      		Uart5Senddata(*data);
      		data++;
      	}
      }
      UART5DATA u5_data={0};
      void UART5_IRQHandler()//串口5中断执行
      {
      		uint8_t data=0;
      	//判断接收中断是否发生
      	if(USART_GetITStatus(UART5,USART_IT_RXNE)==SET)
      	{
      		data = UART5-DR;
      		//USART1-DR = data;//回显
      		u5_data.u5_recv[u5_data.u5_cnt]=data;
      		u5_data.u5_cnt++;
      		u5_data.u5_cnt%=10;
      	}
      	//触发空闲中断,表示总线空闲,接收完毕
      	if(USART_GetITStatus(UART5,USART_IT_IDLE)==SET)
      	{
      		data = UART5-SR;//清理空闲中断,先读SR再读DR
      		data = UART5-DR;	
      		u5_data.u5_tflag=1;
      	}
      }
      //将double转换成8位类型数组arr
      void DoubleToUint8(double data,uint8_t *arr)
      {
      	
      	uint8_t *p = (uint8_t *)&data;
      	uint8_t i=0;
      	for(i=0;i
      		arr[i]=p[i];
      	printf("%02x ",*(p+i));
      	}
      	printf("\r\n");
      	return;
      }
      extern float voc;
      extern float ch2o;
      extern float co2;
      extern float hum;
      extern float tem;
      int Su03tDealData()
      {
      	
      	if(u5_data.u5_tflag!=1)
      	{
      		return 1;
      	}
      	
      	if(u5_data.u5_recv[0]!=0xAA||u5_data.u5_recv[1]!=0x55)
      	{
      		printf("数据帧头出错\r\n");
      		return 2;
      	}
      		if(u5_data.u5_recv[4]!=0xAA||u5_data.u5_recv[3]!=0x55)
      	{
      		printf("数据帧尾出错\r\n");
      		return 3;
      	}	
      	switch(u5_data.u5_recv[2])
      	{
      		case 1:printf("接收01,空气质量指令\r\n");
      			Su03tSendMsg(1,voc);//voc
      		break;
      		case 2:	printf(" 接收02,甲醛指令\r\n");
      		Su03tSendMsg(2,ch2o);//voc
      			break;
      		case 3:	printf(" 接收03,Co2指令\r\n");
      		Su03tSendMsg(3,co2);//voc
      			break;
      		case 6:	printf(" 接收06,温度指令\r\n");
      		Su03tSendMsg(6,tem);
      		break;
      		case 7:	printf(" 接收07,湿度指令\r\n");
      		Su03tSendMsg(7,hum);
      		break;
      	}
        memset(&u5_data,0,sizeof(u5_data));
      	return 0;
      }
      //拼接指令函数 AA 55 04 00 00 00 00 00 80 37 40 55 AA
      void Su03tSendMsg(uint8_t cmd,double data)
      {
      	uint8_t msg[13]={0};//存放要发送的指令
      	msg[0]=0xAA;
      	msg[1]=0x55;
      	msg[2]=cmd;
      	DoubleToUint8(data,&msg[3]);
      	msg[11]=0x55;
      	msg[12]=0xAA;
      	//通过串口5发送
      	U5_Sendarr(msg,13);
      }	
      
VPS购买请点击我

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们,邮箱:ciyunidc@ciyunshuju.com。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

目录[+]