前言
和DHT11一样,都是单总线,通过判断电平变化时间来确定0,1。只需要在dht22.h中修改dht_IO和dht_gpio即可。
详细资料参考微雪电子官网https://www.waveshare.net/wiki/DHT22_Temperature-Humidity_Sensor
一、dht22单总线通信时序
废话不多说,我们对着参考手册来写简单的驱动代码
二、使用步骤
步骤一:
发送我们的主机信号,告诉传感器该上班了。
对应上面的时序图应该显而易见,先将SDA拉低保持1ms,再释放SDA保持20us,但是我们参考表6,还是保持30us好。
void dht22_start()
{
dht22_gpio_Init_out();
GPIO_ResetBits(dht_IO,dht_gpio);
delay_ms(1);
GPIO_SetBits(dht_IO,dht_gpio);
delay_us(30);
}
步骤二:
主机已经喊了,那传感器总要应答。不能让别人单方面付
那么我们怎么判断收没收到呢,厂家规定了,先检测80us低电平如果之后的80us是高电平那说明是应答信号
下面的代码也不难理解,如果是低电平那么就进入判断,如果不是低电平说明一开始的80us低电平都不满足那就直接返回错误。
进入条件之后 我们每1us就让cnt++,参考表6最大值是85,那我们设置成85也没关系嘛,反正在范围里面,然后大家也可以试试其他的数,看看有没有影响。如果大于85说明也是需要返回错误。那么我们的第一个条件80us就判断完毕了,那么就判断第二个条件80us的高电平,所以在此之前将cnt清0。同样的道理,这里就不说了
uint8_t dht22_Recive_Ack()
{
uint8_t cnt = 0;
dht22_gpio_Init_in();
if(GPIO_ReadInputDataBit(dht_IO,dht_gpio) == Bit_RESET) //如果检测80us低电平之后80us高电平,那么说明是应答信号
{
while( (cnt<=85) && ( !GPIO_ReadInputDataBit(dht_IO,dht_gpio) ))
{
cnt++;
delay_us(1);
}
if(cnt > 85) {return 0;}
else {cnt = 0;}
while(GPIO_ReadInputDataBit(dht_IO,dht_gpio) && (cnt<= 85 ))
{
cnt++;
delay_us(1);
}
if(cnt > 85) {return 0;}
else {cnt = 0;return 1;}
}
else
{
return 0;
}
}
步骤三:
那我主机和传感器已经双向奔赴了,就要开始干一点正事了吧,那么主机怎么知道传感器发送的是0还是1呢
可以看到表6已经给出了解释,0,1的低电平时间都是50,那我50+26 那说明我是0,我50+70说明我是1。那既然0,1已经知道怎么区分了,那我们来看看读取
因为我们dht11和dht22一样,总共传输40位,其中温度整数、小数、湿度整数、小数,校验五个,所以每一个都是8位数据。
然后就开始判断嘛,首先给45us的低电平,为什么是45s的低电平呢,因为可以看到0的高电平最大为30,1的高电平最大为75,朋友们可以在中间取一个数值当做判断条件,看看会不会影响。
如果大于45之后还是高电平那说明就是1,我们等待电平结束,然后就数据每次左移1位。
如果大于45之后不是高电平那说明是0,我们也让数据左移,再取反,因为我们低电平要的是0。
朋友们也可以试着用其他方法写,下面是我提供的另一个写法,会不会看起来简洁一点。
for(i =0;i<8;i++)
{
dht22_byte <<= 1;
while(!GPIO_ReadInputDataBit(dht_IO,dht_gpio));
Delay_us(45);
GPIO_ReadInputDataBit(dht_IO,dht_gpio) ? (dht22_byte |= 0x01) : (dht22_byte &=~0x01);
while(GPIO_ReadInputDataBit(dht_IO,dht_gpio));
}
uint8_t dht22_read_byte()
{
uint8_t i,dht22_byte;
for(i = 0;i<8;i++)
{
while(GPIO_ReadInputDataBit(dht_IO,dht_gpio) == 0);
delay_us(45);
if(GPIO_ReadInputDataBit(dht_IO,dht_gpio) == 1)
{
while(GPIO_ReadInputDataBit(dht_IO,dht_gpio) == 1);
dht22_byte |= (uint8_t)(0x01<<(7-i)); // 1
}
else
{
dht22_byte &= (uint8_t)~(0x01 << (7-i)); // 0
}
}
return dht22_byte;
}
步骤四:
最后一步也是我们说的40位需要5次读取
uint8_t dht22_read_data()
{
dht22_start();
if(dht22_Recive_Ack() == 1)
{
dht22_data[0] = dht22_read_byte();
dht22_data[1] = dht22_read_byte();
dht22_data[2] = dht22_read_byte();
dht22_data[3] = dht22_read_byte();
dht22_data[4] = dht22_read_byte();
}
dht22_gpio_Init_out();
GPIO_SetBits(dht_IO,dht_gpio);
if(dht22_data[4] == (uint8_t)(dht22_data[0] + dht22_data[1] + dht22_data[2] + dht22_data[3]))
{
humi = (float)((256*dht22_data[0]+dht22_data[1] )/ 10);
tem = (float)((256*dht22_data[2]+dht22_data[3] )/ 10);
return 1;
}
else return 0;
}
注:一定要注意在协议中调试会不会影响时序
.c和.h文件,修改端口和引脚即可食用
#include "stm32f4xx.h" // Device header
#include "dht22.h"
#include "delay.h"
#include "usart.h"
uint8_t dht22_data[5];
float tem,humi;
void dht22_gpio_Init_out()
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitSturcture;
GPIO_InitSturcture.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitSturcture.GPIO_OType = GPIO_OType_PP;
GPIO_InitSturcture.GPIO_Pin = dht_gpio;
GPIO_InitSturcture.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitSturcture.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(dht_IO,&GPIO_InitSturcture);
}
void dht22_gpio_Init_in()
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitSturcture;
GPIO_InitSturcture.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitSturcture.GPIO_Pin = dht_gpio;
GPIO_InitSturcture.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitSturcture.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(dht_IO,&GPIO_InitSturcture);
}
void dht22_start()
{
dht22_gpio_Init_out();
GPIO_ResetBits(dht_IO,dht_gpio);
delay_ms(1);
GPIO_SetBits(dht_IO,dht_gpio);
delay_us(30);
}
uint8_t dht22_Recive_Ack()
{
uint8_t cnt = 0;
dht22_gpio_Init_in();
if(GPIO_ReadInputDataBit(dht_IO,dht_gpio) == Bit_RESET) //如果检测80us低电平之后80us高电平,那么说明是应答信号
{
while( (cnt<=85) && ( !GPIO_ReadInputDataBit(dht_IO,dht_gpio) ))
{
cnt++;
delay_us(1);
}
if(cnt > 85) {return 0;}
else {cnt = 0;}
while(GPIO_ReadInputDataBit(dht_IO,dht_gpio) && (cnt<= 85 ))
{
cnt++;
delay_us(1);
}
if(cnt > 85) {return 0;}
else {cnt = 0;return 1;}
}
else
{
return 0;
}
}
uint8_t dht22_read_byte()
{
uint8_t i,dht22_byte;
for(i = 0;i<8;i++)
{
while(GPIO_ReadInputDataBit(dht_IO,dht_gpio) == 0);
delay_us(40);
if(GPIO_ReadInputDataBit(dht_IO,dht_gpio) == 1)
{
while(GPIO_ReadInputDataBit(dht_IO,dht_gpio) == 1);
dht22_byte |= (uint8_t)(0x01<<(7-i)); // 1
}
else
{
dht22_byte &= (uint8_t)~(0x01 << (7-i)); // 0
}
}
return dht22_byte;
}
uint8_t dht22_read_data()
{
dht22_start();
if(dht22_Recive_Ack() == 1)
{
dht22_data[0] = dht22_read_byte();
dht22_data[1] = dht22_read_byte();
dht22_data[2] = dht22_read_byte();
dht22_data[3] = dht22_read_byte();
dht22_data[4] = dht22_read_byte();
}
dht22_gpio_Init_out();
GPIO_SetBits(dht_IO,dht_gpio);
//printf("%d,%d,%d,%d---%d\r\n",dht22_data[0],dht22_data[1],dht22_data[2],dht22_data[3],dht22_data[4]);
if(dht22_data[4] == (uint8_t)(dht22_data[0] + dht22_data[1] + dht22_data[2] + dht22_data[3]))
{
humi = (float)((256*dht22_data[0]+dht22_data[1] )/ 10);
tem = (float)((256*dht22_data[2]+dht22_data[3] )/ 10);
printf("humi:%f,tem:%f\r\n",humi,tem);
return 1;
}
else return 0;
}
#ifndef __DHT22_H
#define __DHT22_H
#define dht_IO GPIOA
#define dht_gpio GPIO_Pin_6
void dht22_gpio_Init_out();
void dht22_gpio_Init_in();
void dht22_start();
uint8_t dht22_Recive_Ack();
uint8_t dht22_read_byte();
uint8_t dht22_read_data();
#endif
总结
dht22模块驱动和dht11模块驱动相差不大,大家也可以学习完dht11之后根据提供的数据手册自行编写驱动
然后一定要注意!!!!一定要注意!!!!一定要注意!!!!在函数中打印数据调试的前提是不会影响到时序!!!!