目录
一、DHT11模块
Dht11温湿度检测模块,模块引出引脚有VCC、GND和DATA,只有一根DATA线用于传输数据。数据格式内容手册中有介绍:
二、时序图分析
总的时序:
总的流程:
主机发送开始信号->主机读取响应信号->开始接收数据->主机发送停止信号。
空闲状态为高电平。
开始信号与响应信号:
主机引脚配置输出模式,主机将信号线拉低至少18ms后拉高,随后主机引脚配置输入模式,此处可以等待60us后读取读取信号若为低电平,再等待80us后若读到高电平则认为成功读取到响应信号。
读取数据:
数据0和1的发送都是从低电平开始的,因此当读到低电平时该准备接收数据,0与1的表示由高电平的持续时间有关,0为26-28us,1为70us,因此当读到高电平时开始计时,若在28-70us后读到高电平则数据为1,否则为0。为确保准确取28-70us的中间部分值。
40bit为5个字节,可一个字节一个字节数据接收,接收5次即可。
停止信号:
接收结束主机将信号线拉高为空闲状态即可。
串口打印数据:
三、程序部分
在整个读取过程中需要来回改变数据引脚的输入输出模式,直接对寄存器操作即可;
改变输入输出模式:
{GPIOE->MODER &= ~(3<<2*0);GPIOE->MODER |= (1<<2*0);} //输出模式
{GPIOE->MODER &= ~(3<<2*0);GPIOE->MODER &= ~(3<<2*0);} //输入模式
完整的程序:
dht11.h文件:
#ifndef _DHT11_H__
#define _DHT11_H__
#include "stm32f4xx.h"
#include "sys.h" //实现位带操作的头文件
#define DHT11_IO_GROUP_RCC RCC_AHB1Periph_GPIOE //使能的IO组
#define DHT11_IO_GROUP GPIOE //IO组
#define DHT11_IO_PIN GPIO_Pin_3 //引脚
#define DHT11_DAT_OUT (PEout(0))
#define DHT11_DAT_IN (PEin(0))
#define DHT11_DAT_OUT_MODE() {GPIOE->MODER &= ~(3<<2*0);GPIOE->MODER |= (1<<2*0);} //输出模式
#define DHT11_DAT_IN_MODE() {GPIOE->MODER &= ~(3<<2*0);GPIOE->MODER &= ~(3<<2*0);} //输入模式
extern char dht11_data[5];
void DHT11_Init(void);
char DHT11_Read_Data(void);
#endif
dht11.c文件:
#include "dht11.h"
#include "delay.h"
#include <stdio.h>
#include <string.h>
char dht11_data[5]; //温湿度缓存区
/***************************************************************************
* 函数名称:DHT11_Init
* 功 能:DHT11数据引脚初始化
* 说 明:无
* 参 数:无
* 返 回:无
* 作 者:chengzhou
****************************************************************************/
void DHT11_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(DHT11_IO_GROUP_RCC, ENABLE); //使能GPIO时钟
//GPIO初始化设置
GPIO_InitStructure.GPIO_Pin = DHT11_IO_PIN ;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; //普通输出模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //50MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉
GPIO_Init(DHT11_IO_GROUP, &GPIO_InitStructure); //初始化GPIO
GPIO_SetBits(DHT11_IO_GROUP,DHT11_IO_PIN ); //设置高
}
/***************************************************************************
* 函数名称:DHT11_Star
* 功 能:DHT11开始信号
* 说 明:无
* 参 数:无
* 返 回:无
* 作 者:chengzhou
****************************************************************************/
static void DHT11_Star(void)
{
DHT11_DAT_OUT_MODE(); //输出模式
DHT11_DAT_OUT = 1;
// delay_ms(10);
DHT11_DAT_OUT = 0;
delay_ms(20); //拉低至少18ms
DHT11_DAT_OUT = 1; //主机拉高
}
/***************************************************************************
* 函数名称:DHT11_Ack
* 功 能:读取DHT11响应信号
* 说 明:无
* 参 数:无
* 返 回:成功:1,失败:0
* 作 者:chengzhou
****************************************************************************/
static char DHT11_Ack(void)
{
DHT11_DAT_IN_MODE(); //输入模式
delay_us(60); //加上需等待的20-40us
if(DHT11_DAT_IN == 0) //DHT开始发送响应信号,低电平
{
delay_us(80);
if(DHT11_DAT_IN) //再发高电平
return 1;
}
return 0;
}
/***************************************************************************
* 函数名称:DHT11_Stop
* 功 能:DHT11停止信号
* 说 明:无
* 参 数:无
* 返 回:无
* 作 者:chengzhou
****************************************************************************/
static void DHT11_Stop(void)
{
DHT11_DAT_OUT_MODE(); //输出模式
DHT11_DAT_OUT = 1;
}
/***************************************************************************
* 函数名称:DHT11_Read_One_Byte
* 功 能:DHT11读取一个字节数据
* 说 明:无
* 参 数:无
* 返 回:读取到的数值
* 作 者:chengzhou
****************************************************************************/
static char DHT11_Read_One_Byte(void)
{
char i,data = 0,time = 0;
for(i=0;i<8;i++)
{
time =0;
while(DHT11_DAT_IN ==1 && time <100)//等待上一个信号结束,等待100us
{
time++;
delay_us(1);
}
time =0;
while(DHT11_DAT_IN ==0 && time <100)//等待高电平到来(信号到来),等待100us
{
time++;
delay_us(1);
}
delay_us(35); //延时大于28us小于70us
data <<=1; //先左移再读取
if(DHT11_DAT_IN) //读到1
data +=1;
}
return data;
}
/***************************************************************************
* 函数名称:DHT11_Read_Data
* 功 能:DHT11读取数据
* 说 明:无
* 参 数:无
* 返 回:成功:1,失败:0
* 作 者:chengzhou
****************************************************************************/
char DHT11_Read_Data(void)
{
char j,time = 0;
memset(dht11_data,0,5); //清空缓存区
DHT11_Star();
if(DHT11_Ack()) //正常读取到ack信号
{
DHT11_DAT_IN_MODE(); //引脚输入模式
while(DHT11_DAT_IN && time<100) //等待响应信号结束,等待100us
{
time++;
delay_us(1);
}
for(j=0;j<5;j++) //5个字节40bit,读5次
{
dht11_data[j] = DHT11_Read_One_Byte();
}
DHT11_Stop();
if(dht11_data[0] + dht11_data[1] + dht11_data[2] + dht11_data[3] == dht11_data[4]) //校验
return 1; //读取成功
return 0;//读取失败
}
else
{
DHT11_Stop();
return 0;//读取失败
}
}
main.c文件中:
#include "stm32f4xx.h" // Device header
#include "sys.h"
#include "delay.h"
#include "dht11.h"
#include "usart.h"
int main(void)
{
float tem = 0.0,hum = 0.0;
delay_init(168);
uart_init(115200);
DHT11_Init();
printf("DHT11实验\r\n");
for(;;)
{
delay_ms(500);
delay_ms(500);
delay_ms(500);
delay_ms(500);
if(DHT11_Read_Data())
{
printf("DHT11读取成功\r\n");
}
hum = dht11_data[0] + dht11_data[1]/256.0;
tem = dht11_data[2] + dht11_data[3]/256.0;
printf("tem:%.2f ℃\r\n",tem);
printf("hum:%.2f %\r\n",hum);
printf("\r\n");
}
}