【香橙派+DHT11】香橙派(全志H616)+ DHT11温湿度传感器的驱动教程

news/2024/12/1 8:53:27/

目录

    • 一、前言
        • 产品概述
        • 特点
        • 数据传送逻辑
        • DHT11通信时序
    • 二、代码
        • GPIO初始化
        • 起始信号
        • 读取数据
        • 整体代码
        • 执行结果

一、前言

最近写DHT11的代码到香橙派(全志H616)上,发现网上案例基本上都是树莓派+DHT11的居多,香橙派的少,少数找得到的代码跑起来也是不稳定或者数据相对不太准确,于是这里自己写了一篇,供大家参考和批评指正

产品概述


DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器,应用领域:暖通 空调;汽车;消费品;气象站;湿度调节器;除湿器;家电;医疗;自动控制
在这里插入图片描述

特点

  • 相对湿度和温度测量
  • 全部校准,数字输出
  • 长期稳定性
  • 超长的信号传输距离:20米
  • 超低能耗:休眠
  • 4 引脚安装:可以买封装好的
  • 完全互换 : 直接出结果,不用转化

数据传送逻辑

只有一根数据线DATA,主控MCU发送序列指令给DHT11模块,模块一次完整的数据传输为40bit,高位先出

数据格式

8bit湿度整数数据+8bit湿度小数数据+8bi温度整数数据+8bit温度小数数据+8bit校验和

关于校验:假设接收到的40位数据为:
在这里插入图片描述

计算:
0011 0101 + 0000 0000 + 0001 1000 + 0000 0100 = 0101 0001(校验位)


DHT11通信时序

在这里插入图片描述

(1)主机发送起始信号
首先单片机将连接DHT11 DATA引脚的GPIO口输出低电平,且低电平保持时间不能小于18ms (t1)最大不能超多30ms,然后拉高数据线20~40us (t2) ,等待读取DHT11的响应信号。

(2)检测从机应答信号
DHT11的DATA引脚检测到外部信号有低电平(t1),并等待外部低电平信号结束(t2),延迟后DHT11的DATA引脚处于输出状态,之后DHT11开始输出80 us (t3)的低电平作为应答信号,紧接着输出80us(t4)的高电平通知主机准备接收数据。
主机的I/O此时处于输入状态,检测I/O有低电平(DHT11应答信号)后,等待80us的高电平后接受数据。

(3)数据传输
由DHT11的DATA引脚输出40位数据,采用高位优先方式(MSB),微处理器根据I/0电平的变化接收40位数据。
位数据“0”的格式为:50微秒的低电平和26-28us的高电平。
位数据“1”的格式为:50微秒的低电平加70us的高电平。


二、代码


主体代码主要是利用多线程,用户每发送一次数据读取请求,创建一个线程用于读取数据;利于提高代码的健壮性和扩展性;

同时引入一个blockFlag的标志位,避免子线程代码跑飞无法退出的问题;

并且在测试过程中发现有偶尔测试出温度明显错误的数据;考虑到可能是由于环境、传感器、延时误差等原因导致的数据不准确问题,所以程序中会将超过50°C的数据视为无效数据,自行重新测试,最多自行重试5次

GPIO初始化

因为发送给DHT11的起始信号是先拉低电平,所以拉低电平前先维持一个稳定的高电平状态

void GPIO_init(int gpio_pin)
{pinMode(gpio_pin, OUTPUT); // set mode to outputdigitalWrite(gpio_pin, 1); // output a high leveldelay(1000);
}

起始信号

因为DHT11的触发是单次的,即每发送一次起始信号,才会检查一次温湿度,所以发送起始信号的代码必然是要多次复用,所以这里也封装成一个函数

void DHT11_Start_Sig()
{pinMode(pinNumber,OUTPUT);	//让GPIO为输出模式digitalWrite(pinNumber,HIGH);digitalWrite(pinNumber,LOW);delay(25);	//维持25ms的低电平digitalWrite(pinNumber,HIGH);	//转化为高电平,等待DHT11的响应信号pinMode(pinNumber,INPUT);//响应信号为80us电平与80us的准备信号pullUpDnControl(pinNumber,PUD_UP);	//进行上拉,增加稳定性,非必选delayMicroseconds(35);	//维持35微秒
}

读取数据

void* readSensorData(void *arg)
{uint8 crc; 	uint8 i;	int attempt = 5;	//调用一次最多尝试测5次while(attempt){databuf = 0;	//清空数据存储bufcrc = 0;		//清空校验位数据存储bufDHT11_Start_Sig();	if(digitalRead(pinNumber)==0) //检测DHT11是否应答,应答则继续下一步{while(!digitalRead(pinNumber)); //wait to high//读取4个数据,合计32位for(i=0;i<32;i++){while(digitalRead(pinNumber)); //data clock startwhile(!digitalRead(pinNumber)); //data startdelayMicroseconds(HIGH_TIME);	//如果32微秒后,仍然检测到是高电平,则该数据位为1databuf*=2;		//移位到buf的更高位if(digitalRead(pinNumber)==1) //1{databuf++;}}//读取校验位for(i=0;i<8;i++){while(digitalRead(pinNumber)); //data clock startwhile(!digitalRead(pinNumber)); //data startdelayMicroseconds(HIGH_TIME);crc*=2;  if(digitalRead(pinNumber)==1) //1{crc++;}}//用于校验数据的准确性,当温度大于50时,视为无效数据if(((databuf>>8)&0xff) > 50){attempt--;delay(500);	//不加这段延迟,下一次传感器来不及响应continue;}	else{//打印数据printf("Congratulations ! Sensor data read ok!\n");printf("RH:%lu.%lu\n",(databuf>>24)&0xff,(databuf>>16)&0xff); printf("TMP:%lu.%lu\n",(databuf>>8)&0xff,databuf&0xff);blockFlag = 0;	//用来避免程序有时候跑飞,卡在此函数中,无法跳出return (void*)1;}}else		//dht not answer{blockFlag = 0;printf("Sorry! Sensor dosent ans!\n");return (void*)0;}}//如果代码执行到这里,则证明尝试读取了5次数据,都是不准确的数据blockFlag = 0;printf("get data fail\n");return (void*)2;
}

整体代码

#include <wiringPi.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include "contrlDevices.h"typedef unsigned char uint8;
typedef unsigned int  uint16;
typedef unsigned long uint32;#define HIGH_TIME 32int pinNumber = 6;  //use gpio1 to read data
uint32 databuf;
int blockFlag;void GPIO_init(int gpio_pin)
{pinMode(gpio_pin, OUTPUT); // set mode to outputdigitalWrite(gpio_pin, 1); // output a high leveldelay(1000);//return;
}void DHT11_Start_Sig()
{pinMode(pinNumber,OUTPUT);digitalWrite(pinNumber,HIGH);digitalWrite(pinNumber,LOW);delay(25);digitalWrite(pinNumber,HIGH);pinMode(pinNumber,INPUT);//响应信号为80us电平与80us的准备信号pullUpDnControl(pinNumber,PUD_UP);delayMicroseconds(35);
}void* readSensorData(void *arg)
{uint8 crc; 	uint8 i;	int attempt = 5;	//调用一次最多尝试测5次while(attempt){databuf = 0;	//清空数据存储bufcrc = 0;		//清空校验位数据存储bufDHT11_Start_Sig();	if(digitalRead(pinNumber)==0) //检测DHT11是否应答,应答则继续下一步{while(!digitalRead(pinNumber)); //wait to high//读取4个数据,合计32位for(i=0;i<32;i++){while(digitalRead(pinNumber)); //data clock startwhile(!digitalRead(pinNumber)); //data startdelayMicroseconds(HIGH_TIME);	//如果32微秒后,仍然检测到是高电平,则该数据位为1databuf*=2;		//移位到buf的更高位if(digitalRead(pinNumber)==1) //1{databuf++;}}//读取校验位for(i=0;i<8;i++){while(digitalRead(pinNumber)); //data clock startwhile(!digitalRead(pinNumber)); //data startdelayMicroseconds(HIGH_TIME);crc*=2;  if(digitalRead(pinNumber)==1) //1{crc++;}}//用于校验数据的准确性,当温度大于50时,视为无效数据if(((databuf>>8)&0xff) > 50){attempt--;delay(500);	//不加这段延迟,下一次传感器来不及响应continue;}	else{//打印数据printf("Congratulations ! Sensor data read ok!\n");printf("RH:%lu.%lu\n",(databuf>>24)&0xff,(databuf>>16)&0xff); printf("TMP:%lu.%lu\n",(databuf>>8)&0xff,databuf&0xff);blockFlag = 0;	//用来避免程序有时候跑飞,卡在此函数中,无法跳出return (void*)1;}}else		//dht not answer{blockFlag = 0;printf("Sorry! Sensor dosent ans!\n");return (void*)0;}}//如果代码执行到这里,则证明尝试读取了5次数据,都是不准确的数据blockFlag = 0;printf("get data fail\n");return (void*)2;
}int main ()
{pthread_t tid;int waitTimes = 10;char cmd[5] = {'\0'};if (wiringPiSetup() == -1) {printf("Setup wiringPi failed!");return 1;}printf("Enter OS-------\n");while(1){waitTimes = 10;		blockFlag = 1;delay(1000);printf("input y\n");scanf("%s",cmd);getchar();if(strcmp(cmd,"y") == 0){//创建一个线程用于读取传感器数据;//严谨来说此处的tid并发时有bug;读者可以自行优化,可以用互斥锁或者tid设为数组等都行//就当作留给读者的一个小作业吧if (pthread_create(&tid, NULL, readSensorData, NULL) != 0){printf("thread create fail!\n");return -1;}//等待数据读取线程10s钟,如果10后blockFlag未置0,则说明读数据时跑飞卡住了while(waitTimes && blockFlag){delay(1000);waitTimes--;}//强行结束跑飞的线程if(blockFlag == 1){pthread_cancel(tid);printf("线程超时退出.....\n");}}else{printf("go on\n");continue;}}return 0;
}

执行结果

在这里插入图片描述


参考文章:
STM32一线协议-DHT11温湿度传感器采样实现


http://www.ppmy.cn/news/52276.html

相关文章

dknit增量编译

原文 knit中的新功能 我一直在写叫Knit的构建工具(我在此写了篇关于它的博客文章). 在Knitv1.1.0中,有个叫"动态省略任务"的新功能,它允许如果试运行任务,确定未改变时,Knit会跳过构建步骤. 这要归功于Knit支持基于哈希,来检测修改文件(如果禁止它,则无法实现). 下…

对话庄表伟老师-文字实录

我内心有一套价值观&#xff0c;有一套世界观&#xff0c;它是一个完整的整体&#xff0c;无论我做任何的事情&#xff0c;工作也好、生活也好、学习也好、去做社区也好、或者是结识朋友也好、去聊天也好&#xff0c;背后的价值观在内心都是一整套的&#xff0c;互相之间是不会…

RK3399平台开发系列讲解(调试篇)断言的使用

🚀返回专栏总目录 文章目录 一、什么是断言二、静态断言三、运行时断言沉淀、分享、成长,让自己和他人都能有所收获!😄 📢断言为我们提供了一种可以静态或动态地检查程序在目标平台上整体状态的能力,与它相关的接口由头文件 assert.h 提供。 一、什么是断言 在编程中…

中国电子学会2023年03月青少年软件编程Scratch图形化等级考试试卷二级真题(含答案)

中国电子学会2023年03月青少年软件编程Scratch图形化等级考试试卷二级 1.小猫的程序如图所示&#xff0c;积木块的颜色与球的颜色一致。点击绿旗执行程序后&#xff0c;下列说法正确的是&#xff1f;&#xff08;C&#xff09;&#xff08;2分&#xff09; A.小猫一直在左右移…

【两个月算法速成】day02

目录 977. 有序数组的平方 题目链接 思路&#xff1a; 代码 &#xff1a; 209. 长度最小的子数组 题目链接 思路 代码 59. 螺旋矩阵 II 题目链接 思路 代码 总结 977. 有序数组的平方 题目链接 ​​​​​​力扣 思路&#xff1a; 双指针法 因为数组是非递减的…

Invalid bound statement (not found)的原因以及解决方法

相信我们在学习Mybatis的时候都出现过 Invalid bound statement (not found) 这个错误&#xff0c;一般由以下几种可能导致这个错误 一&#xff1a;mapper方法名 和 mapper.xml id名不对应 例如&#xff1a; mapper&#xff1a; 对应的mapper.xml 这里建议小伙伴们下载一个插…

【HDCTF2023】wp

【HDCTF2023】wp 文章目录 【HDCTF2023】wpwebWelcome To HDCTF 2023SearchMasterYamiYamiLoginMaster mischardMiscMasterMiscExtremeMiscSuperMisc web Welcome To HDCTF 2023 在源码的 game.js中找到了flag 在控制台输出 console.log(seeeeeeeecret)得flag SearchMaster …

java的社区养老服务系统 ssm空巢老人

创新点&#xff1a; 1、根据时间、类型统计用户下单记录&#xff0c;形成可视化图形&#xff08;饼状图&#xff09; 2、根据用户爱好推荐项目 包含模块&#xff1a;关于我们、联系我们、外链信息、资讯类型、服务资讯、服务类型、服务项目、案例类型、服务案例、讨论类型、讨论…