DTH11 温湿度模块

news2024/11/23 11:19:59

文章目录

  • 前言
  • 一、DTH11 模块介绍
  • 二、设备树设置
  • 三、驱动程序
  • 四、测试程序
  • 五、上机测试及效果
  • 总结


前言

DHT11 是一款可测量 温度 和 湿度 的传感器。比如市面上一些空气加湿器,会测量空气中湿度,再根据测量结果决定是否继续加湿。


一、DTH11 模块介绍

在这里插入图片描述

  1. DHT11通信过程:
    主机通过一条数据线与DH11连接,主机通过这条线发命令给DHT11,DHT11再通过这条线把数据发送给主机。
    当主机没有与DHT11通信时,总线处于空闲状态,此时总线电平由于上拉电阻的作用处于高电平。
  • 主机将对应的GPIO管脚配置为输出,准备向DHT11发送数据;
  • 主机发送一个开始信号:
    开始信号 = 一个低脉冲 + 一个高脉冲。低脉冲至少持续18ms,高脉冲持续20-40us。
  • 主机将对应的GPIO管脚配置为输入,准备接受DHT11传来的数据,这时信号由上拉电阻拉高;
  • DHT11发出响应信号:
    响应信号 = 一个低脉冲 + 一个高脉冲。低脉冲持续80us,高脉冲持续80us。
  • DHT11发出数据信号:
    数据为0的一位信号 = 一个低脉冲 + 一个高脉冲。低脉冲持续50us,高脉冲持续26~28us。
    数据为1的一位信号 = 一个低脉冲 + 一个高脉冲。低脉冲持续50us,高脉冲持续70us。
    DHT11发出结束信号:
  • 最后1bit数据传送完毕后,DHT11拉低总线50us,然后释放总线,总线由上拉电阻拉高进入空闲状态。
    在这里插入图片描述
  1. 数据格式:
    8 bit 湿度整数数据 + 8 bit 湿度小数数据 + 8 bit 温度整数数据 + 8 bit 温度小数数据 + 8 bit 校验和。(5 字节数据,共 40 位 )
    数据传送正确时,校验和等于“8bit湿度整数数据+8bit湿度小数数据+8bi温度整数数据+8bit温度小数数据”所得结果的末8位。

二、设备树设置

设备树 中 compatible 与 驱动程序 进行匹配。
将模块分别接到 开发板的 gpio4-19引脚。每一组 GPIO 有 32 个引脚。

配置设备树需要对 GPIO 引脚 以及相关的 pincontrol 配置。由于本实验是使用 DTH11 模块,所以不需要配置 pincontrol 。
在这里插入图片描述

三、驱动程序

  1. 根据框架编写基本驱动程序:

首先要 定义一个file_operations 结构体,在入口函数里对其 注册,在 出口函数里卸载。 实现辅助信息,使用 class_create 创建类 , device_create 创建设备节点。

定义一个 platform_driver。也是在入口函数里对其 注册,在 出口函数里卸载。
这些基本代码的详细实现可以参考我之前的文章 :SR501人体红外模块

  1. 实现 probe 函数。
    总线处于空闲状态,此时总线电平由于上拉电阻的作用处于高电平。
static int dht11_probe(struct platform_device *pdev)
{
	/* 获取引脚信息,将其设置为输出引脚高电平 */
	dht11_data_pin = gpiod_get(&pdev->dev, NULL, GPIOD_OUT_HIGH);
	if (IS_ERR(dht11_data_pin))
	{
		printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	}
	/* 创建设备节点 */
	device_create(dht11_class, NULL, MKDEV(major, 0), NULL, "mydht11");
	return 0;
}
  1. 首先将 gpio 引脚设置为 输出引脚,准备向 DTH11 发送数据。
static void dht11_reset(void)
{
	gpiod_direction_output(dht11_data_pin, 1);
}
  1. 然后主机发送一个开始信号。
    发送开始 信号完毕,将 引脚设置为 输入引脚,等待 DHT11 发送数据,准备接收数据。
static void dht11_start(void)
{
	mdelay(30);
	gpiod_set_value(dht11_data_pin, 0);
	mdelay(20);
	gpiod_set_value(dht11_data_pin, 1);
	udelay(40);	
	gpiod_direction_input(dht11_data_pin);		
	udelay(2);	
}
  1. DHT11 发出响应信号,之后发送数据。
static int dht11_wait_for_ready(void)
{
	int timeout_us = 20000;					//设置超时时间

	/* 等待低电平 */
	while (gpiod_get_value(dht11_data_pin) && --timeout_us)
	{
		udelay(1);
	}
	if (!timeout_us)
	{
		printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
		return -1;
	}

	/* 现在是低电平,等待高电平 */
	timeout_us = 200;
	
	while (!gpiod_get_value(dht11_data_pin) && --timeout_us)
	{
		udelay(1);
	}
	
	if (!timeout_us)
	{
		printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
		return -1;
	}

	/*  现在是高电平,等待低电平 */
	timeout_us = 200;
	while (gpiod_get_value(dht11_data_pin) && --timeout_us)
	{
		udelay(1);
	}
	if (!timeout_us)
	{
		printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
		return -1;
	}
	return 0;	
}
  1. 读一字节的数据。
    每字节八位数据,按位读取。
    怎么判断读出的数据是 0 还是 1 呢?
    通过判断高电平的持续时间可 得出写入的数据。当 高电平 持续26~28us,表示输出 0 。高脉冲持续70us,表明数据是 1 .
    在这里插入图片描述
static int dht11_read_byte(unsigned char *buf)
{
	int i;
	unsigned char data = 0;
	int timeout_us = 200;
	
	for (i = 0; i <8; i++)
	{
		/* 现在是低电平 */
		/* 等待高电平 */
		timeout_us = 400;
		while (!gpiod_get_value(dht11_data_pin) && --timeout_us)
		{
			udelay(1);
		}
		if (!timeout_us)
		{
			printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
			return -1;
		}

		/* 现在是高电平 */
		/* 等待低电平,累加高电平的时间 */
		timeout_us = 20000000;
		
		udelay(40);

		if (gpiod_get_value(dht11_data_pin))
		{
			/* get bit 1 */
			data = (data << 1) | 1;

			/* 当前位的高电平未结束, 等待 */
			timeout_us = 400;
			while (gpiod_get_value(dht11_data_pin) && --timeout_us)
			{
				udelay(1);
			}
			if (!timeout_us)
			{
				printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
				return -1;
			}
			
		}
		else
		{
			/* get bit 0 */
			data = (data << 1) | 0;
		}
	}
	*buf = data;
	return 0;
}
  1. 读五字节数据。
    将 读出的数据放入数组中,传递给应用程序。
static ssize_t dht11_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{
	unsigned long flags;
	int i,err;
	unsigned char data[5];

	if (size != 4)
		return -EINVAL;
	
	local_irq_save(flags);	  // 关中断

	/* 1. 发送高脉冲启动DHT11 */
	dht11_reset();
	dht11_start();

	/* 2. 等待DHT11就绪 */
	if (dht11_wait_for_ready())
	{
		local_irq_restore(flags); // 恢复中断
		printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
		return -EAGAIN;
	}

	/* 3. 读5字节数据 */
	for (i = 0; i < 5; i++)
	{
		if (dht11_read_byte(&data[i]))
		{
			local_irq_restore(flags); // 恢复中断
			printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
			return -EAGAIN;
		}
	}

	dht11_reset();
	local_irq_restore(flags); // 恢复中断

	/* 4. 根据校验码验证数据 */
	if (data[4] != (data[0] + data[1] + data[2] + data[3]))
	{
		printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
		//return -1;
	}
	
	/* 5. copy_to_user */	
	/* data[0]/data[1] : 湿度 */
	/* data[2]/data[3] : 温度 */
	err = copy_to_user(buf, data, 4);
	return 4;
}

四、测试程序

判断参数,打开文件,read 函数读出 测出的温度,湿度。

	if (argc != 2) 
	{
		printf("Usage: %s <dev>\n", argv[0]);
		return -1;
	}
	fd = open(argv[1], O_RDWR);			
	if (fd == -1)
	{
		printf("can not open file %s\n", argv[1]);
		return -1;
	}


	while (1)
	{
		if (read(fd, data, 4) == 4)
		{
			printf("get humidity  : %d.%d\n", data[0], data[1]);
			printf("get temprature: %d.%d\n", data[2], data[3]);
		}
		else 
		{
			printf("get humidity/temprature: -1\n");
		}
		sleep(5);				// 等待 5 秒
	}
	close(fd);

五、上机测试及效果

执行 insmod 命令可以将 .ko 文件加载到内核中,再 执行测试程序。(rmmod命令可以卸载已加载的模块,lsmod 命令 可以观察已加载到内核的文件。)
在这里插入图片描述
/dev/mydht11 是 驱动程序中创建的设备节点( device_create )。在这里插入图片描述


总结

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/795505.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

VS下c++解析pcap文件

一、pcap文件格式 https://www.cnblogs.com/Chary/articles/15716063.html 接口协议&#xff08;四&#xff09;&#xff1a;以太网&#xff08;Ethernet&#xff09;学习&#xff08;一&#xff09;&#xff1a;协议_以太网协议_QNee的博客-CSDN博客 二、代码 pcapParser.h #…

向npm注册中心发布包(下)

目录 1、在package.json文件中指定dependencies和devDependencies 1.1 将依赖项添加到 package.json 文件 1.2 从命令行中 将依赖项添加到 package.json 文件 1.3 手动编辑 package.json 文件 2、关于语义版本控制 2.1 在已发布的包中增加语义版本 2.2 使用语义版本控制…

CentOS7系统Nvidia Docker容器基于TensorFlow2.12测试GPU

CentOS7系统Nvidia Docker容器基于TensorFlow1.15测试GPU 参考我的另一篇博客 1. 安装NVIDIA-Docker的Tensorflow2.12.0版本 1. 版本依赖对应关系&#xff1a;从源代码构建 | TensorFlow GPU 版本Python 版本编译器构建工具cuDNNCUDAtensorflow-2.6.03.6-3.9GCC 7.3.1Ba…

Linux设置密码复杂度

在etc目录下pam.d目录下&#xff0c;存在system-auth文件 先将文件备份下&#xff0c;然后在system-auth中插入下面行 password requisite pam_pwquality.so try_first_pass local_users_only retry3 authtok_type minlen8 lcredit-1 ucredit-1 dcredit-1 ocredi…

OpenCV 4.0+Python机器学习与计算机视觉实战

&#x1f482; 个人网站:【办公神器】【游戏大全】【神级源码资源网】&#x1f91f; 前端学习课程&#xff1a;&#x1f449;【28个案例趣学前端】【400个JS面试题】&#x1f485; 寻找学习交流、摸鱼划水的小伙伴&#xff0c;请点击【摸鱼学习交流群】 目录 前言第一部分&…

Shell脚本学习-变量子串

变量子串&#xff1a; man bash&#xff0c;然后搜索&#xff1a;Parameter Expansion。 参数拓展 $字符引进、提出了参数拓展、命令替换和数字替换。变量名或标识被大括号包围才能够被拓展。 我们可以记住一个表&#xff1a; 序号表达式说明1${parameter}返回变量$paramete…

东南大学齿轮箱故障诊断(Python代码,CNN结合LSTM模型)

运行代码要求&#xff1a; 代码运行环境要求&#xff1a;Keras版本>2.4.0&#xff0c;python版本>3.6.0 1.东南大学采集数据平台&#xff1a; 数据 该数据集包含2个子数据集&#xff0c;包括轴承数据和齿轮数据&#xff0c;这两个子数据集都是在传动系动力学模拟器&am…

PVS-Studio Crack,重新编译后的自动分析

PVS-Studio Crack,重新编译后的自动分析 PVS Studio执行静态代码分析并生成报告&#xff0c;帮助程序员查找和修复错误。PVS Studio执行广泛的代码检查&#xff0c;搜索印刷错误和复制粘贴错误也很有用。此类错误的示例&#xff1a;V501、V517、V522、V523、V3001。 静态分析的…

常常会用到的截取字符串substr()、substring()、slice()方法详解

常常会用到的截取字符串substr()、substring()、slice()方法详解 slice() 定义&#xff1a;接受一个或者两个参数&#xff0c;第一个参数指定子字符串的开始位置。第二个参数表示子字符串的结束位置&#xff08;不包括结束位置的那个字符&#xff09;&#xff0c;如果没有传递…

Linux用户权限问题详解

Linux用户权限问题详解 【一】Linux权限的概念&#xff08;1&#xff09;用户类型&#xff08;2&#xff09;如何切换用户&#xff08;3&#xff09;用户相关的一些命令 【二】Linux文件权限管理&#xff08;1&#xff09;文件访问者的分类&#xff08;2&#xff09;文件类型和…

激光点云数据如何在客户端进行管理、查看及分享?

四维轻云是一款地理空间数据在线管理平台&#xff0c;具有地理空间数据的在线管理、查看及分享等功能。在四维轻云平台中&#xff0c;用户可以不受时间地点限制&#xff0c;随时随地上传数字高程模型、激光点云、倾斜摄影模型、正射影像等地理空间数据。 现在&#xff0c;小编…

算法(3)

喝汽水 两瓶即可换一瓶 import java.util.*; public class Main {public static void main(String[] args) {//剩2个空瓶子时&#xff0c;可以先找老板借一瓶汽水&#xff0c;喝掉这瓶满的&#xff0c;喝完以后用3个空瓶子换一瓶满的还给老板。 //也就是说2个空瓶子即可换一瓶汽…

vue如何设置网站标题和logo图标

目录 1、在根目录找到项目index.html文件 2、在index.html 的 title标签中修改名称为自己设计的标题 3、在index.html 的 title标签下的link标签中引入图标 ①格式为&#xff1a; ②注意&#xff1a; 1、在根目录找到项目index.html文件 2、在index.html 的 title标签中修改…

Visual Assist X Crack

Visual Assist X Crack Visual Assist X通过Visual Studio中的关键新功能和对现有功能的改进&#xff0c;大大缩短了应用程序开发时间&#xff0c;使您能够&#xff1a;Visual Assist提高了自动化程度&#xff0c;简化了导航&#xff0c;并在开发过程中显示重要信息。这些功能已…

WebDAV之π-Disk派盘+ WinSCP

WinSCP是一个免费的开源文件传输应用程序&#xff0c;它使用文件传输协议&#xff0c;安全外壳文件传输协议和安全复制协议来进行纯文件或安全文件传输。该应用程序旨在与Windows一起使用&#xff0c;并支持常见的Windows桌面功能&#xff0c;例如拖放文件&#xff0c;跳转列表…

Python web实战 | 使用 Django 搭建 Web 应用程序 【干货】

概要 从社交媒体到在线购物&#xff0c;从在线银行到在线医疗&#xff0c;Web 应用程序为人们提供了方便快捷的服务。Web 应用程序已经成为了人们日常生活中不可或缺的一部分。搭建一个高效、稳定、易用的 Web 应用程序并不是一件容易的事情。本文将介绍如何使用 Django 快速搭…

2_Apollo4BlueLite中断控制器NVIC

1.概述 Apollo4BlueLite 的中断控制器是采用 ARM Cortex-M4 内核&#xff0c;并集成了 NVIC&#xff08;Nested Vectored Interrupt Controller&#xff0c;嵌套向量中断控制器&#xff09;作为其中断控制器。 NVIC 是 ARM Cortex-M 系列处理器中常用的中断控制器&#xff0c…

Linux centos7.x系统将/home磁盘分配给/

1.解除挂载并删除/home卷 umount /home如果出现以下报错 &#xff1a; 可以使用以下命令查看哪些进程在占用 fuser -mv /home杀死这些进程就行 kill -9 进程号然后再执行umount /home就可以成功了 &#xff0c; 同时执行以下命令把逻辑卷删除了 lvremove /dev/centos/home…

腾讯云标准型S6/SA3/SR1/S5/SA2服务器CPU处理器大全

腾讯云服务器CVM标准型CPU处理器大全&#xff0c;包括标准型S6、SA3、SR1、S5、S5se、SA2、S4、SN3ne、S3、SA1、S2ne实例CPU处理器型号大全&#xff0c;标准型S6云服务器CPU采用Intel Ice Lake(2.7GHz/3.3GHz)&#xff0c;标准型S5采用Intel Xeon Cascade Lake 8255C/Intel Xe…

Linux C tcp/ip

服务端代码&#xff1a; #include <stdio.h> #include<sys/types.h> #include<sys/socket.h> #include<string.h> #include<netinet/in.h> #include<arpa/inet.h> #include <unistd.h>/* socket bind listen accept send/receive *…