利用DHT11温湿度传感器获取温湿度数据

点击查看代码
/**
   ******************************************************************************
   * @file    main.c 
   * @author  
   * @version 
   * @date    2024/07/12
   * @brief   实现利用DHT11传感器学习分析时序图,并设计完整的通信协议的相关接口
						  
							DHT11  -- PG9
							
							
   ******************************************************************************
**/

#include "stm32f4xx.h"  //必须包含
#include <stdio.h>
#include <stdbool.h>


//前台程序就是中断服务程序,该程序是不需要手动调用的,当中断触发之后CPU会自动跳转过来执行该函数
void USART1_IRQHandler(void)
{
	uint8_t data;
  //判断中断是否发生
  if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
  {   
		//从USART1中接收一个字节
		data = USART_ReceiveData(USART1);  //一次只能接收一个字节   
		
		//把接收到的数据转发出去
		USART_SendData(USART1,data);
  }
}




//延时微秒 注意:Systick是24bit的递减计数器  约等于798915us,所以参数不可以超过这个值
void delay_us(u32 nus)
{
	SysTick->CTRL = 0; 						 // 向控制状态寄存器中写入0,目的关闭系统嘀嗒定时器
	SysTick->LOAD = (nus * 21) - 1;// 指的是计数次数,定时时间 = 计数次数 * 计数周期
	SysTick->VAL  = 0; 						 // 清除当前数值寄存器的值
	SysTick->CTRL = 1; 						 // 开启了定时器,并且定时器的时钟源选择了21MHZ--> 计数周期 = 1/21us
	while ((SysTick->CTRL & 0x00010000)==0);//等待延时时间到达
	SysTick->CTRL = 0; 						 // 向控制状态寄存器中写入0,目的关闭系统嘀嗒定时器

}

//延时毫秒 注意:Systick是24bit的递减计数器  约等于798ms,所以参数不可以超过这个值
void delay_ms(u32 nms)
{
	SysTick->CTRL = 0; 						 			// 向控制状态寄存器中写入0,目的关闭系统嘀嗒定时器
	SysTick->LOAD = (nms * 21*1000) - 1;// 指的是计数次数,定时时间 = 计数次数 * 计数周期
	SysTick->VAL  = 0; 						 			// 清除当前数值寄存器的值
	SysTick->CTRL = 1; 						 			// 开启了定时器,并且定时器的时钟源选择了21MHZ--> 计数周期 = 1/21us
	while ((SysTick->CTRL & 0x00010000)==0);//等待延时时间到达
	SysTick->CTRL = 0; 						 			// 向控制状态寄存器中写入0,目的关闭系统嘀嗒定时器
}



void USART1_Config(u32 baud)
{
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	GPIO_InitTypeDef GPIO_InitStructure;
	
	//打开了GPIO端口时钟  PA9和PA10
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
	
	//打开USART1的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
	
	//选择GPIO引脚的复用功能
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource9 , GPIO_AF_USART1);
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);
	
	//配置GPIO引脚 注意:复用模式
	GPIO_InitStructure.GPIO_Mode 	= GPIO_Mode_AF;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_PuPd 	= GPIO_PuPd_UP;
	GPIO_InitStructure.GPIO_Pin 	= GPIO_Pin_9|GPIO_Pin_10;
	GPIO_Init(GPIOA, &GPIO_InitStructure);

	//配置串口参数+对串口初始化
	USART_InitStructure.USART_BaudRate = baud;														//波特率
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;										//数据位
	USART_InitStructure.USART_StopBits = USART_StopBits_1;											//停止位
	USART_InitStructure.USART_Parity = USART_Parity_No;												//无校验
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; 				//无流控
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;									//收发模式
	USART_Init(USART1, &USART_InitStructure);

	//配置NVIC参数 + 对NVIC初始化
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
	
	//选择USART1的中断源,接收到数据则触发中断
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
	
	//打开串口
	USART_Cmd(USART1, ENABLE);
}




//DHT11引脚输出配置
void DHT11_PinOutputModeConfig(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);
	
	GPIO_InitStructure.GPIO_Mode 	= GPIO_Mode_OUT;
	GPIO_InitStructure.GPIO_Speed 	= GPIO_Speed_100MHz;
	GPIO_InitStructure.GPIO_OType 	= GPIO_OType_PP;
	GPIO_InitStructure.GPIO_PuPd 	= GPIO_PuPd_UP;
	GPIO_InitStructure.GPIO_Pin 	= GPIO_Pin_9;	
	GPIO_Init(GPIOG, &GPIO_InitStructure);
	
	//引脚空闲高电平
	GPIO_SetBits(GPIOG,GPIO_Pin_9);
}


//DHT11引脚输入配置
void DHT11_PinInputModeConfig(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);
	
	GPIO_InitStructure.GPIO_Mode 	= GPIO_Mode_IN;
	GPIO_InitStructure.GPIO_Speed 	= GPIO_Speed_100MHz;
	GPIO_InitStructure.GPIO_Pin 	= GPIO_Pin_9;	
	GPIO_Init(GPIOG, &GPIO_InitStructure);
}

//DHT11的初始化
void DHT11_Config(void)
{
	DHT11_PinOutputModeConfig();
}


//向DHT11发送开始信号
void DHT11_SendStart(void)
{
	//1.配置引脚为输出模式
	DHT11_PinOutputModeConfig();
	
	//2.把引脚电平拉低并持续20ms
	GPIO_ResetBits(GPIOG,GPIO_Pin_9);
	delay_ms(20);
	
	//3.把引脚电平拉高并持续30us
	GPIO_SetBits(GPIOG,GPIO_Pin_9);
	delay_us(30);

}

//判断DHT11是否响应
bool DHT11_IsACK(void)
{
	uint32_t cnt = 0;  //作为计数器
	
	//1.配置引脚为输入模式
	DHT11_PinInputModeConfig();
	
	//2.判断PG9引脚是否检测到低电平  为了提高程序可靠性,所以人为添加超时机制,超时时间假设为100us
	while( GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_9) == 1 && cnt < 100)
	{
		delay_us(1);
		cnt++;
	}
	
	if(cnt >= 100)
		return false;
	
	cnt = 0;
	
	
	//3.判断PG9引脚检测的低电平是否持续80us
	while( GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_9) == 0 && cnt < 100)
	{
		delay_us(1);
		cnt++;
	}
	
	
	if( cnt >= 100 )
		return false;
	else
		return true;
}


//判断DHT11发送的bit的值,并存储到一个字节的bit0位置中
uint8_t DHT11_ReadBit(void)
{
	//1.等待低电平出现   
	while( GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_9) == 1 );
	
	//1.等待低电平结束   
	while( GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_9) == 0 );
	
	//2.此时高电平出现,则延时 28us < n < 70us
	delay_us(40);
	
	//3.延时结束之后,判断PG9引脚的电平状态,如果电平还是高电平,则说明是bit = 1
	if( GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_9) == 1 )
		return 1;
	else 
		return 0;
}

//DHT11读取1字节  DHT11提供的40bit是以MSB
uint8_t DHT11_ReadByte(void)
{
	int i = 0;
	//1.定义变量并初始化
	uint8_t data = 0;  // 0000 0000
	
	//2.循环8次,接收一个字节
	for(i = 0;i < 8;i++)
	{
		data <<= 1;
		data |= DHT11_ReadBit(); 
	} 
	
	return data;
}

//读取DHT11温湿度传感器的数据
bool DHT11_ReadData(uint8_t buf[5])
{
	int i = 0;
	
	//1.MCU发送开始信号
	DHT11_SendStart();
	
	//2.MCU等待DHT进行响应
	if( true == DHT11_IsACK() )
	{
		//3.循环读取40bit
		for(i=0;i<5;i++)
		{
			buf[i] = DHT11_ReadByte();
		}
		
		//4.对数据进行校验
		if( buf[4] == buf[0] + buf[1] + buf[2] + buf[3] )
		{
			return true;
		}
		else
			return false; //说明读取数据失败,原因是校验未通过
	}
	else
	{
		return false; //说明读取数据失败,原因是DHT未响应
	}
}


//利用串口发送一个字符串
void  USART1_SendString(const char *str)
{
	while(*str)
	{
		 USART_SendData(USART1,*str++);
		 while( USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET );		
	}
}

int main()
{
	uint8_t dhtbuf[5] = {0};
	uint8_t ubuf[128] = {0};
	//1.硬件的初始化
	USART1_Config(9600);
	DHT11_Config();
	
	while(1)
	{
		DHT11_ReadData(dhtbuf); //获取了一次温湿度数据
		sprintf((char *)ubuf,"temp = %d ℃, humi = %d %%RH\r\n",dhtbuf[2],dhtbuf[0]);
		USART1_SendString((char *)ubuf);
		delay_ms(500);
	}
}





posted @ 2025-08-30 12:29  w1888  阅读(11)  评论(0)    收藏  举报