dht11温湿度模块功能实现(STM32)

认识模块

        DTH11内部集成了温湿度传感器模块和数字式信号处理电路,它可以将温度和湿度值转换为数字信号输出。数字信号输出格式为二进制数,包括40位数据,其中包含8位的湿度整数数据、8位的湿度小数数据、8位的温度整数数据、8位的温度小数数据以及8位校验和。STM32通过读取DTH11输出的数字信号,就可以得到温度和湿度的精确值,进而对环境进行控制。

        STM32单片机通过引脚与dth11传感器进行连接,包括VCC、GND、DATA三个引脚。单片机向dth11传感器发送开始信号,即拉低DATA引脚,持续至少18ms,然后再将DATA引脚拉高,等待dth11传感器的响应。此时dth11传感器会发送一个80us的低电平响应信号,然后再发送一个80us的高电平信号,表示已经准备好发送数据。接着,dth11传感器开始向单片机发送40位二进制数据,包括湿度值、温度值、校验位等信息。每一位数据都有固定的发送方式,即:首先,dth11传感器会将DATA引脚拉低50us,表示开始发送一位数据;其次,dth11传感器会根据实际数值将DATA引脚拉高26~28us表示0,或者拉高70us表示1;最后,单片机需要在每一位数据发送完毕后,将DATA引脚拉高,等待下一位数据的发送。当单片机接收到40位数据后,需要对数据进行解析,获取温度和湿度数值,以及校验位信息。

        通过查阅资料,可知dht11的DATA引脚与PG9相连。如下图所示:

代码实现

        DHT11.c

#include "DHT11.h"

void dht11_outputmode(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
	//初始化DHT11对应的引脚 PG9 的时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);
	
	//2、通过结构体初始化DHT11引脚
	/* 配置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);

}

void dht11_inputmode(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
	//初始化DHT11对应的引脚 PG9 的时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);
	
	//2、通过结构体初始化DHT11引脚
	/* 配置PG9 引脚为输出模式 */
	GPIO_InitStructure.GPIO_Pin 	= GPIO_Pin_9;			//配置的引脚
	GPIO_InitStructure.GPIO_Mode 	= GPIO_Mode_IN;			//输入模式
	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);

}

//发送开始信号和接收响应信号
uint32_t dht11_start(void)
{
	uint32_t i;
	/* 发送开始信号 */
	//配置PG9位输出模式
	dht11_outputmode();
	
	//引脚输出低电平
	PGout(9) = 0;
	delay_ms(20);

	//引脚输出高电平
	PGout(9) = 1;
	delay_us(30);
	
	/* 接收响应信号 */ 
	//配置PG9位输入模式
	dht11_inputmode();
	
	//检测低电平,最多持续100us
	i=0;
	while(i<100)
	{
		//检测到低电平跳出循环
		if(PGin(9) == 0)
			break;
		
		i++;
		delay_us(1);
	}
	
	if(i>=100)	//上面的循环是超时跳出,对方无响应
		return 1;
		
	//检测高电平,最多持续100us
	i=0;
	while(i<100)
	{
		//检测到高电平跳出循环
		if(PGin(9))
			break;
		
		i++;
		delay_us(1);
	}
	
	if(i>=100)	//上面的循环是超时跳出,对方无响应
		return 2;

	return 0;
}

uint8_t dht11_readbyte(void)
{
	int i;
	uint8_t d=0;
	
	//跳过前面的高电平
	while(PGin(9));
	
	for(i=0; i<8; i++)
	{
		//跳过前面50us低电平
		while(PGin(9)==0);
		
		delay_us(40);
		
		if(PGin(9))	//引脚为高电平,说明数据为1
		{
			d |= 1<<(7-i);//保存数据
		
			while(PGin(9));	//跳过剩余的高电平时间
		}
	}
	
	return d;
}

int dht11_read_data(uint8_t *buf)
{

	//让DHT11启动
	int i=0;
	while(i<100)
	{
		//启动成功,跳出循环
		if(dht11_start() == 0)
			break;
		
		i++;
		delay_us(1);
	}
	if(i>=100)//上面循环是由于超时退出,DHT11没有启动
		return -1;
	
	//读取5字节数据
	for(i=0; i<5; i++)
	{
		buf[i] = dht11_readbyte();
	}
	
	//计算检验和
	if(buf[4] != buf[0]+buf[1]+buf[2]+buf[3])
		return -2;

	return 0;

}

        DHT11.h 

#ifndef _DHT11_H
#define _DHT11_H

//C文件中需要的其他的头文件
#include <stm32f4xx.h>
#include "sys.h"
#include "delay.h"


//C文件中定义的函数的声明
int dht11_read_data(uint8_t *buf);

#endif

主函数部分

        main.c

#include <stm32f4xx.h>
#include "sys.h"
#include <stdio.h>
#include "delay.h"
#include "uart.h"
#include "DHT11.h"

//重定向fputc函数
int fputc(int ch, FILE *F)
{
	//通过串口1发送数据到PC
	USART_SendData(USART1, ch);
	while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);//等待发送数据完毕
	
	return ch;
}

u8 Temperature_yu = 40;//温度的阈值

int main(void)
{
	uint8_t buf[5];//保存温湿度数值的数组

	//确定系统定时器的工作频率  内核的工作频率/8 = 168MHz/8 = 21MHz
	SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);
	
	UART1_Config();//配置串口
	
	while(1)
	{

		if(dht11_read_data(buf)==0)
		{

			printf("湿度:%d.%d  温度:%d.%d\n",buf[0], buf[1],buf[2],buf[3]);
			
		}
        else
        {
            printf("采集校验错误\n");
        }
		
		
	}
	
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/nazonomaster/article/details/129324209