DHT11时序讲解(很详细):
https://blog.csdn.net/qq_21990661/article/details/81043121
时序对应代码:
首先小熊派给DHT11发送启动时序,如图,拉低大于18ms后再拉高即可。
启动时序对应代码如下所示:
GpioInit();//初始化
IoSetFunc(WIFI_IOT_IO_NAME_GPIO_13,WIFI_IOT_IO_FUNC_GPIO_13_GPIO);
IoSetPull(WIFI_IOT_IO_NAME_GPIO_13, WIFI_IOT_IO_PULL_UP);
GpioSetDir(WIFI_IOT_GPIO_IDX_13,WIFI_IOT_GPIO_DIR_OUT);
GpioSetOutputVal(WIFI_IOT_GPIO_IDX_13,0);//拉低并延时 大于18ms
osDelay(2U);//貌似100U = 1s
GpioSetOutputVal(WIFI_IOT_GPIO_IDX_13,1);//拉高
delay_us(30); //拉高20~40us
若DHT11正确接收到启动信号,会拉低总线80us后,再拉高80us,通知接收数据。
小熊派接收DHT11响应代码:
/*等待低电平的到来*/
GpioSetDir(WIFI_IOT_GPIO_IDX_13,WIFI_IOT_GPIO_DIR_IN);
GpioGetInputVal(WIFI_IOT_GPIO_IDX_13,&inputdata);
int num=0;
while(inputdata&&num<=100)
{
num++;
GpioGetInputVal(WIFI_IOT_GPIO_IDX_13,&inputdata);
}
if(num>100)return 0;//大于100表示DHT11未启动成功
/*接收80us低电平*/
while(!inputdata&&timer<=100)
{
timer++;
delay_us(1);
GpioGetInputVal(WIFI_IOT_GPIO_IDX_13,&inputdata);
}
if (timer>100 || timer<20) //判断响应时间
{
return 0;
}
/*接收80us高电平*/
timer = 0;
while(inputdata&&timer<=100)
{
timer++;
GpioGetInputVal(WIFI_IOT_GPIO_IDX_13,&inputdata);
delay_us(1);
}
if (timer>100 || timer<20) //检测响应信号之后的高电平
{
return 0;
}
return 1;//成功启动
成功接收DHT11响应信号后,DHT11开始按照高位在前的顺序,将数据一位一位传给主机。
可以看到数据“0”和数据“1”的差别在于高电平的持续时间,可以通过高电平持续时间内变量累计次数来确定数据“0”,“1”。
上述链接文章详细描述了数据格式。数据共40位,分5次接收,一次接收一字节,即8位。
读取一字节的代码如下所示:
for (i=0; i<8; i++)
{
GpioGetInputVal(WIFI_IOT_GPIO_IDX_13,&inputdata);
int num=0;
while (inputdata&&num<=100) //等待低电平,数据位前都有50us低电平时隙
{
GpioGetInputVal(WIFI_IOT_GPIO_IDX_13,&inputdata);
num++;
}
num=0;
while (!inputdata&&num<=100) //等待高电平,开始传输数据位
{
GpioGetInputVal(WIFI_IOT_GPIO_IDX_13,&inputdata);
num++;
}
num=0;
while(inputdata&&num<=80)
{
GpioGetInputVal(WIFI_IOT_GPIO_IDX_13,&inputdata);
num++;
}
byt <<= 1; //因高位在前,所以左移byt,最低位补0
if (num>30) //将总线电平值读取到byt最低位中
{
byt |= 0x01;
}
}
读取所有数据:首先检测DHT11是否能正常响应,后读取5字节即40位数据,读完后,按照数据格式进行校验。
if (DHT11RstAndCheck()) //检测响应信号
{
for(i=0;i<5;i++) //读取40位数据
{
buf[i]=DHT11ReadByte(); //读取1字节数据
}
if(buf[0]+buf[1]+buf[2]+buf[3] == buf[4]) //校验成功
{
*Humi = buf[0]; //保存湿度整数部分数据
*Temp = buf[2]; //保存温度整数部分数据
}
sta = 1;
}
else //响应失败返回-1
{
*Humi = 0xFF; //响应失败返回255
*Temp = 0xFF; //响应失败返回255
sta = -1;
}
总代码:
DHT11.h、
#ifndef _DHT11_H
#define _DHT11_H
#include "utils_config.h"
#define DHT11_OUT PC_OUT(13)
#define DHT11_IN PC_IN(13)
int DHT11Init(void);
int DHT11ReadData(int *Humi,int *Temp);
int DHT11RstAndCheck(void);
void delay_us(int num);
#endif
DHT11.c、
#include "dht11.h"
#include "wifiiot_gpio.h"
#include "wifiiot_gpio_ex.h"
#include "wifiiot_adc.h"
#include <stdio.h>
#include "cmsis_os2.h"
#include <ohos_init.h>
#include <unistd.h>
#include <time.h>
/*DHT11复位和检测响应函数,返回值:1-检测到响应信号;0-未检测到响应信号*/
WifiIotGpioValue inputdata={0};
WifiIotGpioValue outputdata={0};
int DHT11RstAndCheck(void)
{
int timer = 0;
GpioInit();
IoSetFunc(WIFI_IOT_IO_NAME_GPIO_13,WIFI_IOT_IO_FUNC_GPIO_13_GPIO);
IoSetPull(WIFI_IOT_IO_NAME_GPIO_13, WIFI_IOT_IO_PULL_UP);
GpioSetDir(WIFI_IOT_GPIO_IDX_13,WIFI_IOT_GPIO_DIR_OUT);
GpioSetOutputVal(WIFI_IOT_GPIO_IDX_13,0);
osDelay(2U);
GpioSetOutputVal(WIFI_IOT_GPIO_IDX_13,1);
delay_us(30); //拉高20~40us
GpioSetDir(WIFI_IOT_GPIO_IDX_13,WIFI_IOT_GPIO_DIR_IN);
GpioGetInputVal(WIFI_IOT_GPIO_IDX_13,&inputdata);
int num=0;
while(inputdata&&num<=100)
{
num++;
GpioGetInputVal(WIFI_IOT_GPIO_IDX_13,&inputdata);
}
if(num>100)return 0;
while(!inputdata&&timer<=100)
{
timer++;
delay_us(1);
GpioGetInputVal(WIFI_IOT_GPIO_IDX_13,&inputdata);
}
if (timer>100 || timer<20) //判断响应时间
{
return 0;
}
timer = 0;
while(inputdata&&timer<=100)
{
timer++;
GpioGetInputVal(WIFI_IOT_GPIO_IDX_13,&inputdata);
delay_us(1);
}
if (timer>100 || timer<20) //检测响应信号之后的高电平
{
return 0;
}
return 1;
}
// /*读取一字节数据,返回值-读到的数据*/
int DHT11ReadByte(void)
{
uint8_t i;
int byt = 0;
for (i=0; i<8; i++)
{
GpioGetInputVal(WIFI_IOT_GPIO_IDX_13,&inputdata);
int num=0;
while (inputdata&&num<=100) //等待低电平,数据位前都有50us低电平时隙
{
GpioGetInputVal(WIFI_IOT_GPIO_IDX_13,&inputdata);
num++;
}
num=0;
while (!inputdata&&num<=100) //等待高电平,开始传输数据位
{
GpioGetInputVal(WIFI_IOT_GPIO_IDX_13,&inputdata);
num++;
}
num=0;
while(inputdata&&num<=80)
{
GpioGetInputVal(WIFI_IOT_GPIO_IDX_13,&inputdata);
num++;
}
byt <<= 1; //因高位在前,所以左移byt,最低位补0
if (num>30) //将总线电平值读取到byt最低位中
{
byt |= 0x01;
}
}
return byt;
}
// /*读取一次数据,返回值:Humi-湿度整数部分数据,Temp-温度整数部分数据;返回值: -1-失败,1-成功*/
int DHT11ReadData(int *Humi, int *Temp)
{
//printf("access\n");
int sta = 0;
uint8_t i;
int buf[5];
if (DHT11RstAndCheck()) //检测响应信号
{
for(i=0;i<5;i++) //读取40位数据
{
buf[i]=DHT11ReadByte(); //读取1字节数据
}
if(buf[0]+buf[1]+buf[2]+buf[3] == buf[4]) //校验成功
{
*Humi = buf[0]; //保存湿度整数部分数据
*Temp = buf[2]; //保存温度整数部分数据
}
sta = 1;
}
else //响应失败返回-1
{
*Humi = 0xFF; //响应失败返回255
*Temp = 0xFF; //响应失败返回255
sta = -1;
}
return sta;
}
//应该延时了1us吧
void delay_us(int num)
{
while(num--)
{
for(int i=0;i<25;i++){}
}
}