概述
文章目录
- 前言
- DHT11简介
- 通信流程
- 硬件连接
- 编程实现
- GPIO API简介
- 复位总线
- DHT11应答
- 数据读取
- 效果一览
- 总结
- 目录
前言
此文主要是使用Hi3861的GPIO口,模拟1—Wire时序,获取类单总线协议器件DHT11的温湿度信息,由于小熊派官方的温湿度采集是用的I2C接口的SHT30来实现的,而笔者手头没有这个模块,只有一个DHT11,结合前面的经验,Hi3861的代码逻辑跟STM32差不多,理论上是可以移植的,于是就有了以下写bug的时光。
DHT11简介
DHT11内部包括一个电阻式感湿元件和一个NTC测温元件,并与一个高性能8位单片机相连接,在使用过程中,这个内置的8位单片机会实时采集温湿度并做好转换,等到主机端的起始信号就开始发送40位的数据。学习过单总线的其他器件的同学都知道,单总线的一般通信流程是遵循初始化、ROM、命令功能命令三部曲来实现的,而DHT11由于内部有单片机的存在,所以不需要写入ROM和命令来实现功能,这需要一个起始信号即可实现数据传输。想要深入了解的同学可以参考此文——DHT11使用笔记。这里重点关注下其传输的一帧数据的内容。
数据传送正确时校验和数据等于“ 8bit 湿度整数数据 +8bit 湿度小数数据
+8bi 温度整数数据 +8bit 温度小数数据 ”所得结果的末8位。
通信流程
对于编程,最主要还是要搞清楚通信流程,尤其是这种使用GPIO进行模拟时序的。DHT11的通信流程如下:
1.总线初始化;(主机拉低总线,时长不小于18ms,然后拉高总线,使得总线回到高电平20-40us,等待从机应答)。
2.DHT11应答;(DHT11将总线拉低80us,然后再拉高80us)。
3.输出数据帧(一次完整的数据传输为40bit,高位先出)。
实测波形如下,后面框起来的是应答信号和40位的数据(图片截取自立创EDA的【DHT11温湿度计】)。
有关这个波形的详细讲解可以去看立创EDA的——【DHT11温湿度计】在示波器上的波形!。
硬件连接
由于采用的是模拟1-Wire的时序,所以可以选取任意一个GPIO口来实现,笔者这里使用的是GPIO11,根据芯片手册最好是使用带上拉电阻的模块。
接线如下:
Hi3861开发板 | DHT11引脚 |
---|---|
GPIO11 | OUT |
5V | + |
GND | - |
编程实现
GPIO API简介
弄清楚了上述的通信流程,可以发现,整个过程中,传输数据的GPIO管脚需要进行输入与输出的切换,在产生起始信号时,GPIO需要配置为输出模式,产生高低电平的切换;在检测应答信号及接收数据时,需要配置成浮空输入模式检测总线的高低电平状态。在这个过程中需要使用到Hi3861的GPIO API接口函数。有关GPIO控制的接口函数目录位置为baseiot_hardwareinterfaceskitswifiiot_lite。
wifiiot_gpio.h和wifiiot_gpio_ex.h包含了所有和GPIO操作有关的函数接口。
这里简介一下需要使用到函数,详细用法直接.h的注释吧,和STM32的GPIO类似:
复位总线
在产生起始信号时的配置方法:
首先,GpioInit()初始化GPIO;然后配置为普通IO模式;再然后配置为输出模式,最后根据时序要求配置输出高低电平。
笔者这里GPIO2是用来做运行指示灯的。代码如下:
#define DHT11_GPIO WIFI_IOT_IO_NAME_GPIO_11
IO操作函数
#define DHT11_DQ_OUT_High GpioSetOutputVal(DHT11_GPIO, 1); //设置GPIO输出高电平
#define DHT11_DQ_OUT_Low GpioSetOutputVal(DHT11_GPIO, 0); //设置GPIO输出低电平
/****************************************
设置端口为输出
*****************************************/
void DHT11_IO_OUT(void)
{
//设置GPIO_11为输出模式
GpioSetDir(DHT11_GPIO, WIFI_IOT_GPIO_DIR_OUT);
}
//初始化DHT11的IO口 DQ 同时检测DHT11的存在
//返回1:不存在
//返回0:存在
u8 DHT11_Init(void)
{
//初始化GPIO
GpioInit();
//设置GPIO_2的复用功能为普通GPIO
IoSetFunc(WIFI_IOT_IO_NAME_GPIO_2, WIFI_IOT_IO_FUNC_GPIO_2_GPIO);
//设置GPIO_2为输出模式
GpioSetDir(WIFI_IOT_GPIO_IDX_2, WIFI_IOT_GPIO_DIR_OUT);
//设置GPIO_2输出高电平点亮LED灯
GpioSetOutputVal(WIFI_IOT_GPIO_IDX_2, 1);
//设置GPIO_11的复用功能为普通GPIO
IoSetFunc(DHT11_GPIO, WIFI_IOT_IO_FUNC_GPIO_11_GPIO);
//设置GPIO_11为输出模式
GpioSetDir(DHT11_GPIO, WIFI_IOT_GPIO_DIR_OUT);
//设置GPIO_11输出高电平
GpioSetOutputVal(DHT11_GPIO, 1);
DHT11_Rst(); //复位DHT11
return DHT11_Check();//等待DHT11的回应
}
//复位DHT11
void DHT11_Rst(void)
{
DHT11_IO_OUT(); //SET OUTPUT
DHT11_DQ_OUT_Low; //拉低DQ
hi_udelay(20000);//拉低至少18ms
DHT11_DQ_OUT_High; //DQ=1
hi_udelay(35); //主机拉高20~40us
}
DHT11应答
在等待应答阶段,需要将GPIO口配置为浮空输入模式,并且需要检测GPIO的状态来判断DHT11连接是否正常。
代码流程:
首先将GPIO切换为输入模式,然后检测GPIO状态,判断总线的高低电平状态是否满足应答信号。
代码如下:
//获取GPIO输入状态
u8 GPIOGETINPUT(WifiIotIoName id,WifiIotGpioValue *val)
{
GpioGetInputVal(id,val);
return *val;
}
/****************************************
设置端口为输入
*****************************************/
void DHT11_IO_IN(void)
{
GpioSetDir(DHT11_GPIO, WIFI_IOT_GPIO_DIR_IN);//配置为输入模式
IoSetPull( DHT11_GPIO, WIFI_IOT_IO_PULL_NONE);//配置为浮空输入
}
//等待DHT11的回应
//返回1:未检测到DHT11的存在
//返回0:存在
u8 DHT11_Check(void)
{
u8 retry=0;
DHT11_IO_IN();//SET INPUT
while (GPIOGETINPUT(DHT11_GPIO,&DHT11_DQ_IN)&&retry<100)//DHT11会拉低40~80us
{
retry++;
hi_udelay(1);
};
if(retry>=100)return 1;
else retry=0;
while ((!GPIOGETINPUT(DHT11_GPIO,&DHT11_DQ_IN))&&retry<100)//DHT11拉低后会再次拉高40~80us
{
retry++;
hi_udelay(1);
};
if(retry>=100)return 1;
return 0;
}
数据读取
在检测到DHT11的应答后,DHT11会紧接着发送40位BIT的数据,需要通过固定时间间隔去读取总线状态来获取。
编程流程:
继续配置为输入模式,间隔固定时间去读取总线电平,进而得到数据,最后根据数据格式解析出所需内容。
代码如下:
//从DHT11读取一个位
//返回值:1/0
u8 DHT11_Read_Bit(void)
{
u8 retry=0;
while(GPIOGETINPUT(DHT11_GPIO,&DHT11_DQ_IN)&&retry<100){//等待变为低电平
retry++;
hi_udelay(1);
}
retry=0;
while((!GPIOGETINPUT(DHT11_GPIO,&DHT11_DQ_IN))&&retry<100){//等待变高电平
retry++;
hi_udelay(1);
}
hi_udelay(40);//等待40us //用于判断高低电平,即数据1或0
if(GPIOGETINPUT(DHT11_GPIO,&DHT11_DQ_IN))return 1; else return 0;
}
//从DHT11读取一个字节
//返回值:读到的数据
u8 DHT11_Read_Byte(void)
{
u8 i,dat;
dat=0;
for (i=0;i<8;i++)
{
dat<<=1;
dat|=DHT11_Read_Bit();
}
return dat;
}
//从DHT11读取一次数据
//temp:温度值(范围:0~50°)
//humi:湿度值(范围:20%~90%)
//返回值:0,正常;1,读取失败
u8 DHT11_Read_Data(u8 *temp,u8 *humi)
{
u8 buf[5]={ 0 };
u8 i;
DHT11_Rst();
if(DHT11_Check()==0)
{
for(i=0;i<5;i++)//读取40位数据
{
buf[i]=DHT11_Read_Byte();
}
if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4])//数据校验
{
*humi=buf[0];
*temp=buf[2];
}
}else return 1;
return 0;
}
以上三步对应的示波器实际效果如下图(图片截取自立创EDA):
注:这里的实现需要导入hi_time.h头文件,调用hi_udelay()实现而不能用usleep()函数。
至此就可以通过DHT11获取到温湿度了,上述代码有极少部分缺失,如有需要,私信笔者,建议大家自己试着配配看。
效果一览
总结
本文主要是使用使用Hi3861的GPIO口去模拟单总线的时序,进而读取到DHT11的温湿度值,整体代码可以参考任何一个STM32版本的代码,需要特别注意的是,整个过程中需要使用阻塞式的延时hi_udelay(1),而不能使用非阻塞式的usleep(),非阻塞式的延时会产生任务流转,会影响时序,造成数据读取失败,笔者踩了这个坑,分享给大家避雷用。
目录
OpenHarmony学习笔记——南向开发环境搭建
OpenHarmony学习笔记——编辑器访问Linux服务器进行编译
OpenHarmony学习笔记——点亮你的LED
OpenHarmony学习笔记——多线程的创建
OpenHarmony学习笔记——I2C驱动0.96OLED屏幕
OpenHarmony学习笔记——Hi3861使用DHT11获取温湿度
OpenHarmony学习笔记——Hi3861接入OneNET
手把手教你OneNET数据可视化
OpenHarmony学习笔记——Hi386+ASR-01的语音识别助手
最后
以上就是认真冬天为你收集整理的OpenHarmony学习笔记——Hi3861使用DHT11获取温湿度前言DHT11简介通信流程硬件连接编程实现效果一览总结目录的全部内容,希望文章能够帮你解决OpenHarmony学习笔记——Hi3861使用DHT11获取温湿度前言DHT11简介通信流程硬件连接编程实现效果一览总结目录所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复