Temperature and humidity detection based on STM32F4 (DHT11)


foreword

Today we learn how to use the temperature and humidity module DHT11 to detect temperature and humidity. This module is relatively common in daily life.


1. Temperature and humidity module

1 Introduction

DHT11 digital temperature and humidity sensor is a temperature and humidity composite sensor with calibrated digital signal output
. It uses dedicated digital module acquisition technology and temperature and humidity sensing technology to ensure that the product has extremely high
reliability and excellent long-term stability. The sensor includes a resistive humidity sensing element and an NTC
temperature measuring element, and is connected with a high-performance 8-bit microcontroller. Therefore, the product has the advantages of excellent quality, ultra-fast
response, strong anti-interference ability, and high cost performance.
Each DHT11 sensor is calibrated in an extremely precise humidity calibration chamber. The calibration coefficients are stored in the OTP memory in the form of a program, and
these calibration coefficients are called in the sensor during the processing of the detection signal. The single-wire serial interface makes system integration
easy and fast. Ultra-small size, extremely low power consumption, and the signal transmission distance can reach more than 20 meters, making
it the best choice for various applications and even the most demanding applications. The product is packaged in a 4-pin single-row pin
. The connection is convenient, and the special packaging form can be provided according to the needs of users.

2. Appearance

As shown in the figure below:
insert image description here
the appearance of the module we used for learning is 3 pins, but in fact it has 4 pins, and one pin is floating.

3. Pin diagram

As shown in the figure below:
insert image description here
This time we are using the PG9 pin for learning, and it can be connected to other drawings.

2. Use steps

1. The process of serial communication

As shown in the picture:
insert image description here
insert image description here
From the picture we can clearly see the whole communication process, and we can see the following sentences in the product manual

insert image description here
That is to say, we need to receive five 8-bit data, and finally take the first four bits and finally verify the correctness of the data.
Next write the code for the communication.

Pin initialization

void dht11_init(void)
{
    
    
   //使能PG9时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);
	
	//配置PG9为输出模式
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//复用功能模式
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;//上拉
	GPIO_Init(GPIOG, &GPIO_InitStructure);//初始化
	//配置PE6为输入模式

	//引脚初始状态为高电平
	PGout(9)=1;
}

communication process

int32_t dht11_read(uint8_t *pbuf)
{
    
    
	uint32_t t=0;
	int32_t i=0,j=0;
	uint8_t d=0;
	uint8_t *p=pbuf;
	uint32_t check_sum=0;
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//复用功能模式
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;//上拉
	GPIO_Init(GPIOG, &GPIO_InitStructure);//初始化
	
	PGout(9)=0;
	delay_ms(20);
	PGout(9)=1;
	delay_us(30);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;//复用功能模式
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;//上拉
	GPIO_Init(GPIOG, &GPIO_InitStructure);//初始化
	
	//等待低电平出现
	t=0;
	while(PGin(9))
	{
    
    
		//超时处理
		t++;
		delay_us(1);
		if(t>=4000)
		{
    
    
			return -1;
		}
	}
	
	//检验低电平的合法性
	t=0;
	while(PGin(9)==0)
	{
    
    
		t++;
		delay_us(1);
		if(t>=4000)
		{
    
    
			return -2;
		}
	}
	
	t=0;
	while(PGin(9))
	{
    
    
		t++;
		delay_us(1);
		if(t>=4000)
		{
    
    
			return -3;
		}
	}
	for(j=0;j<5;j++)
	{
    
    
		d=0;
		for(i=7;i>=0;i--)
		{
    
    
			t=0;
			while(PGin(9)==0)
			{
    
    
				t++;
				delay_us(1);
				if(t>=4000)
				{
    
    
					return -4;
				}
			
			}
			delay_us(40);
			//判断当前引脚电平
			if(PGin(9))
			{
    
    
				d|=1<<i;
				
				//等待高电平完毕
				t=0;
				while(PGin(9))
				{
    
    
					t++;
					delay_us(1);
					if(t>=1000)
					{
    
    
						return -5;
					}
				}
			}
				
		}
		p[j]=d;
	
	}
	//校验和
	check_sum = (p[0]+p[1]+p[2]+p[3])&0xFF;
	
	if(p[4]!=check_sum)
	{
    
    
		return -6;
		
	}
	return 0;
	
}

2. Complete code

code show as below:

#include "stm32f4xx.h"                  // Device header
#include "sys.h"
#include "stdio.h"


static GPIO_InitTypeDef  GPIO_InitStructure;
static USART_InitTypeDef USART_InitStructure;
static NVIC_InitTypeDef NVIC_InitStructure;
static uint16_t d;



struct __FILE {
    
     int handle; /* Add whatever you need here */ };
FILE __stdout;
FILE __stdin;
int fputc(int ch, FILE *f) 
{
    
    
	
	USART_SendData(USART1,ch);
	while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
	
	return ch;
}


void delay_ms(uint32_t n)
{
    
    
	while(n--)
	{
    
    
		SysTick->CTRL = 0; // Disable SysTick
		SysTick->LOAD = (168000)-1; // Count from 255 to 0 (256 cycles)
		SysTick->VAL = 0; // Clear current value as well as count flag
		SysTick->CTRL = 5; // Enable SysTick timer with processor clock
		while ((SysTick->CTRL & 0x00010000)==0);// Wait until count flag is set
	}
	
	SysTick->CTRL = 0; // Disable SysTick
}
void delay_us(uint32_t n)
{
    
    
	while(n--)
	{
    
    
		SysTick->CTRL = 0; // Disable SysTick
		SysTick->LOAD = (168)-1; // Count from 255 to 0 (256 cycles)
		SysTick->VAL = 0; // Clear current value as well as count flag
		SysTick->CTRL = 5; // Enable SysTick timer with processor clock
		while ((SysTick->CTRL & 0x00010000)==0);// Wait until count flag is set
	}
	
	SysTick->CTRL = 0; // Disable SysTick
}

void usart1_init(uint32_t band)
{
    
    
	
	//打开硬件时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
	
	//打开串口1硬件时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
	
	//配置PA9和PA10为服用功能
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_10;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能模式
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
	GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化
	
	
	//将PA9和PA10引脚连接到串口1的硬件
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1);
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1);
	
	//配置串口1相关参数:波特率、无校验位、8位数位、1位停止位
	USART_InitStructure.USART_BaudRate = band;					//波特率
    USART_InitStructure.USART_WordLength = USART_WordLength_8b; //8位数据位
    USART_InitStructure.USART_StopBits = USART_StopBits_1;		//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);
	
	//配置串口1的中断触发方法 接收一个字节触发中断
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
	//配置串口1的中断优先级

	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);

	//使能串口1工作
	USART_Cmd(USART1,ENABLE);
}

void dht11_init(void)
{
    
    
   //使能PG9时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);
	
	//配置PG9为输出模式
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//复用功能模式
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;//上拉
	GPIO_Init(GPIOG, &GPIO_InitStructure);//初始化
	//配置PE6为输入模式

	
	PGout(9)=1;
}



int32_t dht11_read(uint8_t *pbuf)
{
    
    
	uint32_t t=0;
	int32_t i=0,j=0;
	uint8_t d=0;
	uint8_t *p=pbuf;
	uint32_t check_sum=0;
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//复用功能模式
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;//上拉
	GPIO_Init(GPIOG, &GPIO_InitStructure);//初始化
	
	PGout(9)=0;
	delay_ms(20);
	PGout(9)=1;
	delay_us(30);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;//复用功能模式
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;//上拉
	GPIO_Init(GPIOG, &GPIO_InitStructure);//初始化
	
	//等待低电平出现
	t=0;
	while(PGin(9))
	{
    
    
		//超时处理
		t++;
		delay_us(1);
		if(t>=4000)
		{
    
    
			return -1;
		}
	}
	
	//检验低电平的合法性
	t=0;
	while(PGin(9)==0)
	{
    
    
		t++;
		delay_us(1);
		if(t>=4000)
		{
    
    
			return -2;
		}
	}
	
	t=0;
	while(PGin(9))
	{
    
    
		t++;
		delay_us(1);
		if(t>=4000)
		{
    
    
			return -3;
		}
	}
	for(j=0;j<5;j++)
	{
    
    
		d=0;
		for(i=7;i>=0;i--)
		{
    
    
			t=0;
			while(PGin(9)==0)
			{
    
    
				t++;
				delay_us(1);
				if(t>=4000)
				{
    
    
					return -4;
				}
			
			}
			delay_us(40);
			//判断当前引脚电平
			if(PGin(9))
			{
    
    
				d|=1<<i;
				
				//等待高电平完毕
				t=0;
				while(PGin(9))
				{
    
    
					t++;
					delay_us(1);
					if(t>=1000)
					{
    
    
						return -5;
					}
				}
			}
				
		}
		p[j]=d;
	
	}
	//校验和
	check_sum = (p[0]+p[1]+p[2]+p[3])&0xFF;
	
	if(p[4]!=check_sum)
	{
    
    
		return -6;
		
	}
	return 0;
	
}


int main(void)
{
    
    
	int32_t rt=0;
	uint8_t buf[5]={
    
    0};

	usart1_init(115200);
	dht11_init();
	
	
	while(1)
	{
    
    
		rt=dht11_read(buf);
		
		if(rt==0)
		{
    
    
			printf("T:%d.%d,H:%d.%d\r\n",buf[2],buf[3],buf[0],buf[1]);
		}else
		{
    
    
			printf("dht11 error code %d\r\n",rt);
		}
		delay_ms(2000);
	}
}


void USART1_IRQHandler(void)
{
    
    
	
	//检查标志位
	if(USART_GetITStatus(USART1,USART_IT_RXNE)==SET)
	{
    
    
		d=USART_ReceiveData(USART1);
		
		printf(d+"");
		//清空标志位
		USART_ClearITPendingBit(USART1,USART_IT_RXNE);
	}
	
	
}



We print the data to the serial port assistant through the serial port. If you are not familiar with the serial port, you can use the following introduction
to realize serial port communication based on STM32F4 (usart)

Finally, let's take a look at the running effect, as shown in the figure:
insert image description here

Guess you like

Origin blog.csdn.net/weixin_46155589/article/details/128082473