STM32F103读取DHT22温湿度传感器参数
1、首先通过DHT22的说明书获取操作流程 (觉得文字太多可直接向下翻,有完整.c和.h )
通信启动规则:
它有一条通信总线,空闲时总线为高电平,发送一次开始信号后,DHT22从低功耗模式转换到高速模式,通讯开始时主机(MCU)拉低总线500us后释放总线,延时20-40us后主机开始检测从机(DHT22)的响应信号。 从机的响应信号是一个80us左右的低电平,随后从机在拉高总线80us左右代表即将进入数据传送。
数据传送规则:
首先传送50us左右的低电平时隙,它代表数据位的起始,其后的高电平的长度决定数据位所代表的数值,70us的高电平代表1,26-28us的高电平代表0。 共40bit数据,当最后一Bit数据传送完毕后,从机将再次拉低总线50us左右。
下面进行分析:
(1)只有一条数据总线,所以端口既做输入也做输出,功能有拉高、拉低和读取
//其中CRH用来设置高8-15引脚,CRL用来设置0-7引脚,这里是PA0,选择CRL寄存器
#define DHT22_IO_IN() {DHT22_PORT->CRL&=0XFFFFFFF0;DHT22_PORT->CRL|=8<<0;}//设为输入
#define DHT22_IO_OUT() {DHT22_PORT->CRL&=0XFFFFFFF0;DHT22_PORT->CRL|=3<<0;}//设为输出
#define DHT22_IO_HIGH() GPIO_SetBits(DHT22_PORT,DHT22_PIN); //输出1,拉高
#define DHT22_IO_LOW() GPIO_ResetBits(DHT22_PORT,DHT22_PIN); //输出0,拉低
#define DHT22_IO_READ (GPIO_ReadInputDataBit(DHT22_PORT,DHT22_PIN)) //读端口值
(2)空闲为高,初始化端口时让端口输出高电平。
void DHT22_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(DHT22_PORT_CLK, ENABLE); //使能PORTA口时钟
GPIO_InitStructure.GPIO_Pin = DHT22_PIN; //PORTA0 推挽输出
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(DHT22_PORT, &GPIO_InitStructure);
DHT22_IO_HIGH(); //输出1
}
(3)开始信号,拉低500us,再拉高等待20到40us,等待传感器响应。
static void DHT22_Awake(void)//唤醒
{
DHT22_IO_OUT();//设为输出
DHT22_IO_LOW();//拉低500us,激活传感器
delay_us(500);
DHT22_IO_HIGH();//拉高,释放总线
delay_us(30);
DHT22_IO_IN();//等待20到40us设为输入,等待响应
}
(4)传感器响应,先拉低80us,再拉高80us
while(DHT22_IO_READ);//检测响应信号,传感器拉低80us
while((!DHT22_IO_READ));//传感器将总线拉高80us,标志马上进入数据传输
(5)传感器发送40bit的数据,根据规则进行读取
for(i = 0;i < 40;i ++)//获取40bit数据
{
while(DHT22_IO_READ);//等待50us低电平间隙到来
while(!DHT22_IO_READ);//间隙结束,等待数据高电平到来
//高电平保持26~28us表示低电平,保持70us表示高电平。
delay_us(30);//这里等待30us,越过28us(但不能大于28+50),直接判断是不是1
if(DHT22_IO_READ)//读取当前总线的状态,是不是为1
{
//为真则:
data <<= 1;//右移1位空出末位
data |= 1;//把1添入末位
}
else
//为假则:
data <<= 1;右移1位空出末位,末位就是0
}
(6)最后依旧释放总线,以便下次数据获取
DHT22_IO_OUT();//设为输出
DHT22_IO_HIGH();//拉高,释放总线
2、完整.c和.h
dht22.h
#ifndef __DHT22_H
#include "common.h"
#define DHT22_PORT GPIOA
#define DHT22_PIN GPIO_Pin_0
#define DHT22_PORT_CLK RCC_APB2Periph_GPIOA
//其中CRH用来设置高8-15引脚,CRL用来设置0-7引脚,这里是PA0,选择CRL寄存器
#define DHT22_IO_IN() {DHT22_PORT->CRL&=0XFFFFFFF0;DHT22_PORT->CRL|=8<<0;}//设为输入
#define DHT22_IO_OUT() {DHT22_PORT->CRL&=0XFFFFFFF0;DHT22_PORT->CRL|=3<<0;}//设为输出
#define DHT22_IO_HIGH() GPIO_SetBits(DHT22_PORT,DHT22_PIN); //输出1
#define DHT22_IO_LOW() GPIO_ResetBits(DHT22_PORT,DHT22_PIN); //输出0
#define DHT22_IO_READ (GPIO_ReadInputDataBit(DHT22_PORT,DHT22_PIN)) //读端口值
void DHT22_Init(void);
u8 DHT22_GetValue(int* temp,u16* humi);
#endif
dht22.c
#include "dht22.h"
/*************************
*作 用:初始化传感器引脚
*参 数:无
*返回值:无
**************************/
void DHT22_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(DHT22_PORT_CLK, ENABLE); //使能PORTA口时钟
GPIO_InitStructure.GPIO_Pin = DHT22_PIN; //PORTA0 推挽输出
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(DHT22_PORT, &GPIO_InitStructure);
DHT22_IO_HIGH(); //输出1
}
/**************************
*作 用:唤醒传感器
*参 数:无
*返回值:无
***************************/
static void DHT22_Awake(void)
{
DHT22_IO_OUT();//设为输出
DHT22_IO_LOW();//拉低500us,激活传感器
delay_us(500);
DHT22_IO_HIGH();//拉高,释放总线
delay_us(30);
DHT22_IO_IN();//等待20到40us设为输入,等待响应
}
/************************************************
*作 用:与DHT传感器通信,获取数据
*参 数:无
*返回值:返回获取的40位数据,小于0xff表示失败
*************************************************/
static uint64_t DHT22_ReadData(void)
{
u8 waitTime = 0;//响应等待时间
u16 i = 0;//循环变量
uint64_t data = 0;//数据存储变量
DHT22_Awake();//传感器唤醒
waitTime = 100;//响应超时时间设定
while(DHT22_IO_READ)//检测响应信号,传感器拉低80us
{
if((waitTime--) > 0)
delay_us(1);
else
return 1;
}
waitTime = 100;//响应超时时间设定
while((!DHT22_IO_READ))//传感器将总线拉高80us,标志马上进入数据传输
{
if((waitTime--) > 0)
delay_us(1);
else
return 2;
}
for(i = 0;i < 40;i ++)//获取40bit数据
{
waitTime = 100;//响应超时时间设定
while(DHT22_IO_READ)//等待50us低电平间隙到来
{
if((waitTime--) > 0)
delay_us(1);
else
return 3;
}
waitTime = 50;//响应超时时间设定
while(!DHT22_IO_READ)//间隙结束,等待数据高电平到来
{
if((waitTime--) > 0)
delay_us(1);
else
return 3;
}
//高电平保持26~28us表示低电平,保持70us表示高电平。
delay_us(30);//这里等待30us,越过28us(但不能大于28+50),直接判断是不是1
if(DHT22_IO_READ)//读取当前总线的状态
{
data <<= 1;//右移1位空出末位
data |= 1;//把1添入末位
}
else
data <<= 1;右移1位空出末位,末位就是0
}
DHT22_IO_OUT();//设为输出
DHT22_IO_HIGH();//拉高,释放总线
return data;
}
/*****************************************
*作 用:获取温湿度传感器的检测值
*参 数:temp:用于获取温度值的变量地址
humi:用于获取湿度值得变量地址
*返回值:返回0成功,非0获取失败
******************************************/
u8 DHT22_GetValue(int* temp,u16* humi)
{
uint64_t data1 = 0;
data1 = DHT22_ReadData();
if(data1 < 0xff)//判断数据接收是否成功,大于0xff代表成功
{
return (u8)data1;//
}
//去掉后24位数据保留16位湿度数据
*humi = (u16)(data1 >> 24) & 0x00ffff;
//去掉前16位湿度数据和后8位校验数据,保留16位温度数据
*temp = (u16)(data1 >> 8) & 0x00ffff;
return 0;
}
响应超时的设定是为了便于调试,若各位不需要可直接删除。
(有不足之处,还请各位老兄不吝赐教)