Linux内核驱动——DTH11温湿度传感器
一、DHT11 传感器基础DHT11 采用单总线串行通信方式仅需一根数据线即可完成温湿度数据的双向传输无需额外的时钟线硬件连接简单。其通信逻辑由主机MCU / 开发板主动发起从机DHT11响应并返回 40 位数据。数据格式为8 位湿度整数 8 位湿度小数 8 位温度整数 8 位温度小数 8 位校验和其中 DHT11 的湿度小数和温度小数位始终为 0实际有效数据为湿度整数和温度整数二、DHT11原理图1.电路原理图DHT11 温湿度传感器的单总线连接电路DATA 引脚通过 4.7K 上拉电阻接 VCC确保总线空闲时为高电平VCC 和 GND 分别接电源正负极。2.通信时许主机起始主机将数据线拉低至少 18ms再拉高 20~40us向 DHT11 发送起始指令从机响应DHT11 检测到起始信号后会将数据线拉低 80us再拉高 80us完成响应3.读取0和1的时序从机通过数据线高低电平的持续时间表示二进制位低电平 50us 后高电平 26~28us 表示 0依次传输 40 位数据。从机通过数据线高低电平的持续时间表示二进制位低电平 50us 后高电平 70us 表示 1依次传输 40 位数据。三、驱动代码核心实现解析3.1 宏定义与全局变量#define DEV_NAME dht11 static int dht11_gpio;定义设备名dht11作为杂项设备和平台驱动的标识全局变量dht11_gpio存储从设备树解析到的 DHT11 数据线对应的 GPIO 编号实现 GPIO 资源的动态获取。3.2 核心时序操作函数3.2.1 起始信号函数dht11_startstatic void dht11_start(void) { gpio_direction_output(dht11_gpio, 1); mdelay(2); gpio_set_value(dht11_gpio, 0); msleep(20); gpio_set_value(dht11_gpio, 1); udelay(20); }该函数实现主机向 DHT11 发送起始信号严格遵循 DHT11 时序要求先将 GPIO 配置为输出模式并拉高 2ms保证数据线初始状态稳定拉低数据线 20ms满足至少 18ms 的要求发送起始指令拉高数据线 20us等待 DHT11 的响应信号。3.2.2 响应等待函数dht11_wait_responstatic int dht11_wait_respon(void) { int time 0; gpio_direction_input(dht11_gpio); // 等待数据线拉低 time 30; while(gpio_get_value(dht11_gpio) time--) { udelay(1); } if(time 0) return -1; // 等待从机响应低电平结束 time 100; while((!gpio_get_value(dht11_gpio)) time--) { udelay(1); } if(time 0) return -2; // 等待从机响应高电平结束 time 100; while(gpio_get_value(dht11_gpio) time--) { udelay(1); } if(time 0) return -3; return 0; }主机发送起始信号后将 GPIO 配置为输入模式等待 DHT11 的响应信号通过超时计数避免死循环等待 DHT11 将数据线拉低超时 30us 返回错误等待 DHT11 响应的 80us 低电平结束超时 100us 返回错误等待 DHT11 响应的 80us 高电平结束超时 100us 返回错误无超时则返回 0表示响应成功。3.2.3 位数据读取函数dht11_get_bitstatic char dht11_get_bit(void) { int time 60; while(gpio_get_value(dht11_gpio) time--) { udelay(1); } if(time 0) return -4; time 80; while((!gpio_get_value(dht11_gpio)) time--) { udelay(1); } if(time 0) return -5; udelay(35); if(!gpio_get_value(dht11_gpio)) return 0; time 50; while(gpio_get_value(dht11_gpio) time--) { udelay(1); } if(time 0) return -6; return 1; }该函数实现单个二进制位的读取基于 DHT11 的位时序特征先等待数据位的起始低电平结束超时则返回错误延时 35us 后检测数据线电平若为低表示该位为 0若为高表示该位为 1对高电平做超时判断避免总线异常导致的死循环。3.2.4 完整数据读取函数dht11_read_datastatic int dht11_read_data(unsigned char * data) { int i 0; int j 0; for(j 0; j 5; j) { for(i 0; i 8; i) { char bit dht11_get_bit(); if(bit 0) return bit; data[j] 1; data[j] | bit; } } return 5; }循环读取 40 位5 个字节数据通过位运算将读取到的二进制位拼接为完整的字节数据外层循环遍历 5 个字节湿度整、湿度小、温度整、温度小、校验和内层循环遍历每个字节的 8 位通过左移和或运算拼接位数据若位读取失败立即返回错误码读取成功返回 5表示获取到 5 个字节有效数据。3.3 文件操作接口实现static int open(struct inode * inode, struct file * file) { printk(dht11 open\n); return 0; } static ssize_t read(struct file * file, char __user * buf, size_t size, loff_t * loff) { int ret 0; unsigned char data[5]; dht11_start(); ret dht11_wait_respon(); if(ret 0) return ret; ret dht11_read_data(data); if(ret 0) return ret; ret copy_to_user(buf, data, sizeof(data)); printk(dht11 read\n); return 5; } static ssize_t write(struct file * file, const char __user * buf, size_t size, loff_t * loff) { printk(dht11 write\n); return 0; } static int close(struct inode * inode, struct file * file) { printk(dht11 close\n); return 0; } static struct file_operations fops { .owner THIS_MODULE, .open open, .read read, .write write, .release close };read核心接口用户态调用read函数读取设备文件时触发该接口依次执行起始信号、响应等待、数据读取通过copy_to_user将内核态的 5 字节温湿度数据拷贝到用户态缓冲区数据传输成功后返回 5表示读取到 5 个字节数据。3.4 杂项设备注册static struct miscdevice misc_dev { .minor MISC_DYNAMIC_MINOR, // 动态分配次设备号 .name DEV_NAME, // 设备名对应/dev/dht11 .fops fops // 绑定文件操作接口 };在平台驱动的probe函数中通过misc_register(misc_dev)完成注册驱动卸载时通过misc_deregister(misc_dev)注销。3.5.1 设备树匹配与 probe/remove 函数static int probe(struct platform_device * pdev) { struct device_node * pdts; int ret misc_register(misc_dev); if(ret) goto err_misc_register; // 解析设备树节点 pdts of_find_node_by_path(/dht11); if(NULL pdts) { ret PTR_ERR(pdts); goto err_of_find; } // 获取GPIO编号 dht11_gpio of_get_named_gpio(pdts, ptdht11-gpio, 0); if(dht11_gpio 0) { ret dht11_gpio; goto err_of_find; } // 申请GPIO资源 ret gpio_request(dht11_gpio, dht11); if(ret 0) goto err_gpio_request; gpio_direction_output(dht11_gpio, 1); printk(######################### dht11_driver probe\n); return 0; // 错误处理流程 err_gpio_request: err_of_find: misc_deregister(misc_dev); err_misc_register: printk(######################### dht11_driver misc register ret %d\n, ret); return ret; } static int remove(struct platform_device * pdev) { gpio_free(dht11_gpio); misc_deregister(misc_dev); printk(######################### dht11_driver remove\n); return 0; } // 设备树匹配表 static struct of_device_id dht11_table[] { {.compatible pt-dht11}, {} }; // 平台驱动结构体 static struct platform_driver pdrv { .probe probe, .remove remove, .driver { .name DEV_NAME, .of_match_table dht11_table } };probe 函数平台驱动匹配成功后执行的核心函数完成设备初始化remove 函数驱动卸载时执行释放 GPIO 资源并注销杂项设备避免资源泄漏。设备树匹配表通过compatible属性pt-dht11与设备树中的设备节点匹配实现驱动的自动加载。3.5.2 模块入口与出口static int __init dht11_driver_init(void) { int ret platform_driver_register(pdrv); if(ret) goto err_platform_driver_register; printk(dht11 platform_driver_register success\n); return 0; err_platform_driver_register: printk(dht11 platform_driver_register failed\n); return ret; } static void __exit dht11_driver_exit(void) { platform_driver_unregister(pdrv); printk(dht11 platofrm_driver_unregister\n); } module_init(dht11_driver_init); module_exit(dht11_driver_exit); MODULE_LICENSE(GPL);模块入口dht11_driver_init注册平台驱动驱动加载时执行模块出口dht11_driver_exit注销平台驱动驱动卸载时执行MODULE_LICENSE(GPL)声明模块遵循 GPL 协议避免内核加载时的版权警告。四、应用层程序int main(int argc, const char* argv[]) { // 1. 打开驱动生成的设备节点 int fd open(/dev/dht11, O_RDONLY); if (fd 0) { perror(open dht11 failed); return 1; } unsigned char data[5] { 0 }; while (1) { // 2. 读取 5 字节数据 if (read(fd, data, sizeof(data)) 5) { // data[0]: 湿度整数, data[1]: 湿度小数 // data[2]: 温度整数, data[3]: 温度小数 float h data[0] data[1] * 0.1; float t data[2] data[3] * 0.1; printf(Humidity %.1f %%, Temperature %.1f C\n, h, t); } else { printf(Read error or checksum failed\n); } // 3. 每 3 秒读一次DHT11 硬件限制不能读太快 sleep(3); } close(fd); return 0; }五、总结DHT11 温湿度传感器的单总线接口电路DHT11 的 VCC 和 GND 分别接电源正负极为传感器供电。DATA 引脚通过 4.7K 上拉电阻接 VCC保证总线空闲时为高电平并通过接口 P2 与 MCU 通信。整个电路实现了单总线双向通信用于 MCU 采集温湿度数据。

相关新闻

无需编程快速搭建专业SaaS网站:3大节省价值与零代码定制指南

无需编程快速搭建专业SaaS网站:3大节省价值与零代码定制指南

无需编程快速搭建专业SaaS网站:3大节省价值与零代码定制指南 【免费下载链接】saas-landingpage https://map.sistilli.dev/public/coding/SaaSBoilerplate 项目地址: https://gitcode.com/GitHub_Trending/sa/saas-landingpage 作为技术创业者,你…

2026/5/17 4:15:58 阅读更多 →
3秒获取无损歌词:163MusicLyrics让音乐体验升维

3秒获取无损歌词:163MusicLyrics让音乐体验升维

3秒获取无损歌词:163MusicLyrics让音乐体验升维 【免费下载链接】163MusicLyrics Windows 云音乐歌词获取【网易云、QQ音乐】 项目地址: https://gitcode.com/GitHub_Trending/16/163MusicLyrics 还在为找不到匹配歌词而烦恼?163MusicLyrics提供网…

2026/7/3 19:30:45 阅读更多 →
一文了解PowerShell 基础指令和高级用法

一文了解PowerShell 基础指令和高级用法

很多人一听到“PowerShell”就头疼,觉得它是程序员、系统管理员的专属,满屏代码看着就劝退。但其实现在Windows 10/11预装的PowerShell 5.1及以上版本,早已不是专业人士的专利,支持语法高亮、Tab键自动补全,普通人跟着抄代码就能用,甚至比CMD简单10倍。 今天从基础入门到…

2026/5/17 4:15:53 阅读更多 →

最新新闻

5分钟掌握AMD Ryzen处理器调试工具:从新手到调优专家

5分钟掌握AMD Ryzen处理器调试工具:从新手到调优专家

5分钟掌握AMD Ryzen处理器调试工具:从新手到调优专家 【免费下载链接】SMUDebugTool A dedicated tool to help write/read various parameters of Ryzen-based systems, such as manual overclock, SMU, PCI, CPUID, MSR and Power Table. 项目地址: https://git…

2026/7/6 4:22:18 阅读更多 →
LTC6904与PIC24FV16KA304实现精密脉冲控制方案

LTC6904与PIC24FV16KA304实现精密脉冲控制方案

1. 项目背景与核心价值在嵌入式系统开发中,精确的时序控制往往是最具挑战性的环节之一。无论是工业自动化中的电机控制、医疗设备中的信号同步,还是科研实验中的精密测量,对脉冲信号的精度要求常常达到微秒甚至纳秒级。传统方案通常采用分立元…

2026/7/6 4:20:18 阅读更多 →
Python抖音机器人开发指南:从零构建智能互动系统

Python抖音机器人开发指南:从零构建智能互动系统

Python抖音机器人开发指南:从零构建智能互动系统 【免费下载链接】Douyin-Bot 😍 Python 抖音机器人,论如何在抖音上找到漂亮小姐姐? 项目地址: https://gitcode.com/gh_mirrors/do/Douyin-Bot 在当今短视频内容爆炸的时代…

2026/7/6 4:20:18 阅读更多 →
LSTM 多步预测实战:从单步滚动到 Seq2Seq 的 2 种方案详解

LSTM 多步预测实战:从单步滚动到 Seq2Seq 的 2 种方案详解

LSTM多步预测实战:从递归滚动到Seq2Seq的深度对比与优化1. 多步预测的核心挑战与解决方案全景当我们面对"用前30天数据预测后10天"这类多步预测任务时,传统单步预测方法会遇到三个本质性挑战:误差累积问题:递归预测中每…

2026/7/6 4:18:18 阅读更多 →
太原考公考编线下班口碑红黑榜:2026学员真实评价背后的选班避坑指南

太原考公考编线下班口碑红黑榜:2026学员真实评价背后的选班避坑指南

一边是动辄数万元的协议班,一边是朋友圈里满天飞的“上岸喜报”,在太原,选一家靠谱的考公考编线下班,正在变成一场信息战。我们花了三周时间,深度整理了太原及周边学员在社交平台、备考群、公开评价里的真实反馈&#…

2026/7/6 4:18:18 阅读更多 →
HTTP协议及其POST与GET操作差异  C#中如何使用POST、GET等

HTTP协议及其POST与GET操作差异 C#中如何使用POST、GET等

HTTP协议我想任何IT人士都耳熟能详了,大家都能说出个所以然来。但是如果我问你HTTP协议的请求方法有哪些?POST与GET的差异?GET或POST传送数据量的大小有限制吗?HTTP响应的状态有哪些?以及在C#中你如何使用?…

2026/7/6 4:16:17 阅读更多 →

日新闻

H2 与 MySQL 单元测试兼容性:5 个关键 SQL 语句差异与规避方案

H2 与 MySQL 单元测试兼容性:5 个关键 SQL 语句差异与规避方案

H2与MySQL单元测试兼容性:5个关键SQL语句差异与规避方案1. 单元测试中的数据库兼容性挑战在Java开发领域,单元测试是保证代码质量的重要环节。当应用涉及数据库操作时,测试环境的搭建往往成为开发者的痛点。H2数据库因其轻量级、内存模式和快…

2026/7/6 0:01:17 阅读更多 →
Windows任务栏终极清理指南:用RBTray一键隐藏窗口到系统托盘

Windows任务栏终极清理指南:用RBTray一键隐藏窗口到系统托盘

Windows任务栏终极清理指南:用RBTray一键隐藏窗口到系统托盘 【免费下载链接】rbtray A fork of RBTray from http://sourceforge.net/p/rbtray/code/. 项目地址: https://gitcode.com/gh_mirrors/rb/rbtray 你是否厌倦了Windows任务栏上密密麻麻的图标&…

2026/7/6 0:01:17 阅读更多 →
Visual C++ 运行时库一键安装终极指南:告别DLL缺失烦恼

Visual C++ 运行时库一键安装终极指南:告别DLL缺失烦恼

Visual C 运行时库一键安装终极指南:告别DLL缺失烦恼 【免费下载链接】vcredist AIO Repack for latest Microsoft Visual C Redistributable Runtimes 项目地址: https://gitcode.com/gh_mirrors/vc/vcredist 你是否曾经遇到过这样的情况:下载了…

2026/7/6 0:05:19 阅读更多 →

周新闻

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容 【免费下载链接】BiliTools A cross-platform bilibili toolbox. 跨平台哔哩哔哩工具箱,支持下载视频、番剧等等各类资源 项目地址: https://gitcode.com/GitHub_Trending/bilit/BiliTools …

2026/7/5 0:03:34 阅读更多 →
威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型的陌生现状在忙碌疲惫的一天里,参与了关于混合后量子密码学的讨论,应付端点攻击找茬的人,还参与留言板讨论后,发现“威胁模型”对多数人仍是陌生概念,且多被当作时髦用语。有趣的相关画作有一幅由 Embyr 创作的…

2026/7/5 0:03:34 阅读更多 →
渗透测试入门指南:从零基础到实战环境搭建

渗透测试入门指南:从零基础到实战环境搭建

1. 从“看热闹”到“入门”:我理解的渗透测试到底是什么?每次看到新闻里说某个大公司的数据被“黑”了,或者某个网站被攻击导致服务瘫痪,你是不是和我一样,心里会冒出两个念头:一是“这黑客真厉害”&#x…

2026/7/5 0:07:38 阅读更多 →

月新闻