嵌入式学习 day61 DHT11、I2C
一、DHT111、介绍DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器。它应用专用的数字模块采集技术和温湿度传感技术。传感器包括一 个电容式感湿元件和一个NTC 测温元件并与一个8位单片机相连接。2、产品参数3、串行通信说明单线双向1单总线说明DHT11器件采用简化的单总线通信。单总线即只有一根数据线系统中的数据交换、控制均由单总线 完成。设备主机或从机通过一个漏枀开路或三态端口连至该数据线以允许设备在不发送数据时能够 释放总线而让其它设备使用总线单总线通常要求外接一个约 4.7kΩ 的上拉电阻这样当总线闲置时 其状态为高电平。由于它们是主从结极只有主机呼叫从机时从机才能应答因此主机访问器件都必须 严格遵循单总线序列如果出现序列混乱器件将不响应主机。2单总线传送数据位8bit 湿度整数数据 8bit湿度小数数据 8bit温度整数数据 8bit温度小数数据 8bit校验位3通信时序①DHT11上电后DHT11上电后要等待 1S 以越过不稳定状态在此期间不能发送任何指令测试环境 温湿度数据并记录数据同时 DHT11的DATA数据线由上拉电阻拉高一直保持高电平此时 DHT11的 DATA 引脚处于输入状态时刻检测外部信号。②微处理器的I/O设置为输出同时输出低电平且低电平保持时间不能小于18ms最大不得超过30ms 然后微处理器的I/O设置为输入状态由于上拉电阻微处理器的I/O即DHT11的DATA数据线也随之变 高等待DHT11作出回答信号发送信号如图所示③DHT11的DATA引脚检测到外部信号有低电平时等待外部信号低电平结束延迟后DHT11的DATA 引脚处于输出状态输出 83微秒的低电平作为应答信号紧接着输出 87 微秒的高电平通知外设准备接 收数据微处理器的 I/O 此时处于输入状态检测到 I/O 有低电平DHT11回应信号后等待87微秒 的高电平后的数据接收发送信号如图所示④由DHT11的DATA引脚输出40位数据微处理器根据I/O电平的变化接收40位数据位数据“0” 的格式为 54 微秒的低电平和 23-27 微秒的高电平位数据“1”的格式为 54 微秒的低电平加68-74 微秒的高电平。位数据“0”、“1”格式信号如图所示⑤发送结束信号4代码①设备树节点②驱动代码#include linux/init.h #include linux/fs.h #include linux/cdev.h #include linux/module.h #include asm/io.h #include asm/uaccess.h #include linux/device.h #include linux/mutex.h #include linux/miscdevice.h #include linux/of.h #include linux/of_gpio.h #include linux/gpio.h #include linux/platform_device.h #include linux/delay.h static int dht11stat 0; static int dht11gpio 0; static struct mutex lock; static ssize_t dht11_read(struct file *fp, char __user *puser, size_t n, loff_t *off); static ssize_t dht11_write(struct file *fp, const char __user *puser, size_t n, loff_t *off); static int dht11_open(struct inode *node, struct file *fp); static int dht11_release(struct inode *node, struct file *fp); static ssize_t dht11_show(struct device *dev, struct device_attribute *attr, char *buf); static ssize_t dht11_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); extern void __iomem *of_iomap(struct device_node *np, int index); struct device_attribute attr __ATTR(attr, 0664, dht11_show, dht11_store); static struct file_operations fops { .owner THIS_MODULE, .open dht11_open, .release dht11_release, .read dht11_read, .write dht11_write, }; static struct miscdevice misc { .name misc_dht11, .minor MISC_DYNAMIC_MINOR, .fops fops, }; //从DHT11获取一位数据的函数 static int dht11_get_bit(void) { int num 0; while(0 gpio_get_value(dht11gpio)); num 0; while(gpio_get_value(dht11gpio)) { udelay(10); num; } if(num 5) { return 0; } else if(num 5) { return 1; } } //获取一个字节的函数 static char dht11_get_char(void) { char dat 0; int bit 0; int i 0; for(i0;i 8;i) { bit dht11_get_bit(); dat (dat 1) | bit; } return dat; } //将获得的数据校验成功后发向应用层 static ssize_t dht11_read(struct file *fp, char __user *puser, size_t n, loff_t *off) { int i 0; int nret 0; char dat[5] {0}; int num 0; gpio_set_value(dht11gpio,0); msleep(22); gpio_set_value(dht11gpio,1); udelay(40); gpio_direction_input(dht11gpio); while(0 gpio_get_value(dht11gpio)) { if(num 20){ pr_info(dht11gpio_get_bit 1 failed\n); return -1; } udelay(10); num; } num 0; while(gpio_get_value(dht11gpio)) { if(num 20){ pr_info(dht11gpio_get_bit 2 failed\n); return -1; } udelay(10); num; } for(i 0;i 5;i) { dat[i] dht11_get_char(); } gpio_direction_output(dht11gpio,1); gpio_set_value(dht11gpio,1); pr_info(dht11 read success!\n); if(((dat[0] dat[1] dat[2] dat[3]) 0xff) dat[4]){ nret copy_to_user(puser,dat,sizeof(dat)); if (nret) { pr_info(copy_to_user failed\n); return -1; } return sizeof(dat); } else{ pr_info(data failed\n); return 0; } return 0; } static ssize_t dht11_write(struct file *fp, const char __user *puser, size_t n, loff_t *off) { pr_info(dht11 write success!\n); return 0; } static int dht11_open(struct inode *node, struct file *fp) { pr_info(dht11 open success!\n); return 0; } static int dht11_release(struct inode *node, struct file *fp) { pr_info(dht11 close success!\n); return 0; } static ssize_t dht11_show(struct device *dev, struct device_attribute *attr, char *buf) { return 0; } static ssize_t dht11_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { return 0; } //platform总线匹配成功后的操作 static int dht11_probe(struct platform_device *pdevice) { int ret 0; struct device_node *pdht11node NULL; //注册混杂设备 ret misc_register(misc); if (ret) { pr_info(misc_register failed\n); return -1; } //通过路径查找设备树节点 pdht11node of_find_node_by_path(/putedht11); if (NULL pdht11node) { pr_info(of_find_node_by_path failed\n); return -1; } //从设备树节点中解析并获取指定GPIO硬件编号 dht11gpio of_get_named_gpio(pdht11node, gpio-dht11, 0); if (dht11gpio 0) { pr_info(of_get_named_gpio failed\n); return -1; } //申请GPIO资源 ret gpio_request(dht11gpio, pute_dht11_drv); if (ret) { pr_info(gpio_request failed\n); return -1; } //将GPIO引脚设置为输出模式 ret gpio_direction_output(dht11gpio, 1); if (ret) { pr_info(gpio_direction_output failed\n); return -1; } //将该gpio引脚拉高 gpio_set_value(dht11gpio,1); dht11stat 0; mutex_init(lock); //在sys系统设备目录下创建文件 ret device_create_file(misc.this_device, attr); if (ret) { pr_info(device_create_file failed); return -1; } pr_info(probe success!\n); return 0; } static int dht11_remove(struct platform_device *pdevice) { int ret 0; //释放GPIO资源 gpio_free(dht11gpio); //在sys系统设备目录下删除文件 device_remove_file(misc.this_device, attr); mutex_destroy(lock); //注销混杂设备 ret misc_deregister(misc); if (ret) { pr_info(misc_register failed\n); return -1; } pr_info(remove success\n); return 0; } static struct platform_device_id id_table[] { {.name putedht11}, {}, }; static struct of_device_id dht11_of_match_table[] { {.compatible pute,putedht11}, {}, }; static struct platform_driver dht11_driver { .probe dht11_probe, .remove dht11_remove, .driver { .name putedht11, .of_match_table dht11_of_match_table, }, .id_table id_table, }; module_platform_driver(dht11_driver); MODULE_LICENSE(GPL); MODULE_AUTHOR(pute);③应用层#include stdio.h #include string.h #include stdlib.h #include sys/types.h #include sys/stat.h #include fcntl.h #include unistd.h int main() { int fd; char buf[5] {0}; int ret; fd open(/dev/misc_dht11, O_RDONLY); if (fd 0) { perror(open /dev/misc_dht11 failed); return -1; } while(1) { sleep(3); ret read(fd, buf, sizeof(buf)); if (ret sizeof(buf)) { printf(RH:%d.%d \n, buf[0], buf[1]); printf(temp:%d.%d\n, buf[2], buf[3]); } else { printf(read failed (ret: %d)\n, ret); } } close(fd); return 0; }二、I2C1、通信特点通信方式串行、同步、半双工2、应用场景同一硬件平台不同外设之间的通信注1i2c与spi的区别①12c半双工、SPI全双工②I2c硬件设计更加简洁、SPI因为有CS线所以占用更过硬件资源③I2c通信速率100k、400k、3.4MSPI通信速率1M-十几M之间④I2c一般用于传感器采集接口、SPI屏幕TFT-LCD、存储设备FLASH接口3、I2C组成4、i2c硬件接线需要注意事项:需要接入上拉电阻5、I2C分类1软件I2C用gpio模拟I2C时序2硬件I2C用I2C控制器来生成I2C时序6、I2C总线结构7、I2C典型通信8、I2C结构9、I2C框架流程10、I2C驱动编写LM751配置设备树2编写驱动①驱动层#include linux/init.h #include linux/cdev.h #include linux/fs.h #include linux/module.h #include linux/miscdevice.h #include asm/uaccess.h #include linux/of.h #include asm/io.h #include linux/gpio.h #include linux/of_gpio.h #include linux/interrupt.h #include linux/irqreturn.h #include linux/sched.h #include linux/workqueue.h #include linux/timer.h #include linux/poll.h #include linux/input.h #include linux/of_irq.h #include linux/platform_device.h #include linux/i2c.h static struct i2c_client *plm75client NULL; static ssize_t lm75_read(struct file *fp, char __user *puser, size_t n, loff_t *off) { struct i2c_msg msg; int ret 0; long nret 0; unsigned char data[2] {0}; /*发送0x00到lm75中*/ data[0] 0x00; msg.addr plm75client-addr; msg.flags 0; msg.len 1; msg.buf data; ret plm75client-adapter-algo-master_xfer(plm75client-adapter,msg,1); if(ret 0){ pr_info(master_xfer failed\n); return -1; } /*从lm75读两个字节*/ msg.addr plm75client-addr; msg.flags I2C_M_RD; msg.len 2; msg.buf data; ret plm75client-adapter-algo-master_xfer(plm75client-adapter,msg,1); if(ret 0){ pr_info(master_xfer failed\n); return -1; } nret copy_to_user(puser,data,2); if(nret){ pr_info(copy_to_user failed); return -1; } return 2; } static struct file_operations fops { .owner THIS_MODULE, .read lm75_read, }; static struct miscdevice misc_lm75 { .minor MISC_DYNAMIC_MINOR, .name misc_lm75, .fops fops, }; int lm75_probe(struct i2c_client *pclient, const struct i2c_device_id *devid) { int ret 0; plm75client pclient; //注册混杂设备 ret misc_register(misc_lm75); if(ret){ pr_info(misc_register failed\n); return -1; } pr_info(lm75 probe ok\n); return 0; } int lm75_remove(struct i2c_client *pclient) { int ret 0; ret misc_deregister(misc_lm75); if(ret){ pr_info(misc_deregister failed\n); return -1; } pr_info(lm75 remove ok\n); return 0; } static struct i2c_device_id lm75_id_table[] { {.name putelm75}, }; static struct of_device_id lm75_of_match_table[] { {.compatible pute,putelm75}, {}, }; struct i2c_driver lm75_diver { .probe lm75_probe, .remove lm75_remove, .driver { .name putelm75, .of_match_table lm75_of_match_table, }, .id_table lm75_id_table, }; static int __init lm75_init(void) { //注册I2C设备 int ret 0; ret i2c_register_driver(THIS_MODULE,lm75_diver); if(ret){ pr_info(i2c_register_driver failed\n); return -1; } return 0; } static void __exit lm75_exit(void) { i2c_del_driver(lm75_diver); return; } module_init(lm75_init); module_exit(lm75_exit); MODULE_LICENSE(GPL); MODULE_AUTHOR(pute);②应用层#include stdio.h #include sys/types.h #include sys/stat.h #include fcntl.h #include unistd.h #include signal.h #include sys/select.h #include linux/input.h int main(void) { int fd 0; unsigned char data[2] {0}; fd open(/dev/misc_lm75, O_RDWR); if (-1 fd) { perror(fail to open); return -1; } while (1) { read(fd, data, sizeof(data)); printf(temp:%.2lf\n, (((data[0] 8) | data[1]) 7) * 0.5); sleep(1); } close(fd); return 0; }

相关新闻

今日头条互动率严重虚高----只有50%是真实的

今日头条互动率严重虚高----只有50%是真实的

有一半的评价都是豆包在回复:1/32/63/105/127/15看吧只有50%互动是真实的,而且其他人,还有一部分也是机器人。-----------------------------本次互动数量:150,所以也有75个互动

2026/8/7 19:35:16 阅读更多 →
沉降变形观测方案设计:从基准构建到预警体系的工程实践

沉降变形观测方案设计:从基准构建到预警体系的工程实践

1. 项目概述:沉降变形观测,远不止“看个读数”那么简单 在工程建设和运维领域,沉降变形观测是一个听起来专业、做起来更需严谨的活儿。很多人,包括一些刚入行的朋友,可能会觉得这活儿不就是定期拿个水准仪去测几个点&a…

2026/8/7 19:35:16 阅读更多 →
CMake目标链接高级用法:example_exec与JSONUtils库的无缝集成

CMake目标链接高级用法:example_exec与JSONUtils库的无缝集成

CMake目标链接高级用法:example_exec与JSONUtils库的无缝集成 【免费下载链接】modern-cmake-sample Example library that shows best practices and proper usage of CMake by using targets 项目地址: https://gitcode.com/gh_mirrors/mo/modern-cmake-sample …

2026/8/7 19:35:16 阅读更多 →

最新新闻

DPark集群配置最佳实践:Mesos集成与Nginx加速Shuffle

DPark集群配置最佳实践:Mesos集成与Nginx加速Shuffle

DPark集群配置最佳实践:Mesos集成与Nginx加速Shuffle 【免费下载链接】dpark Python clone of Spark, a MapReduce alike framework in Python 项目地址: https://gitcode.com/gh_mirrors/dp/dpark DPark作为Python实现的分布式计算框架,提供了类…

2026/8/7 20:38:41 阅读更多 →
微信公众号开发避坑指南:基于 wechat-php-sdk 的常见问题解决方案

微信公众号开发避坑指南:基于 wechat-php-sdk 的常见问题解决方案

微信公众号开发避坑指南:基于 wechat-php-sdk 的常见问题解决方案 【免费下载链接】wechat-php-sdk 微信公众平台 PHP SDK 项目地址: https://gitcode.com/gh_mirrors/wec/wechat-php-sdk 微信公众号开发过程中,开发者常常会遇到各种棘手问题&…

2026/8/7 20:38:41 阅读更多 →
Test PatchTST全面解析:时间序列预测的革命性预训练模型

Test PatchTST全面解析:时间序列预测的革命性预训练模型

Test PatchTST全面解析:时间序列预测的革命性预训练模型 【免费下载链接】test-patchtst 项目地址: https://ai.gitcode.com/hf_mirrors/ibm-research/test-patchtst Test PatchTST是一款基于预训练技术的时间序列预测模型,属于IBM Research开发…

2026/8/7 20:38:41 阅读更多 →
5个技巧掌握Path of Building:流放之路Build规划完全指南

5个技巧掌握Path of Building:流放之路Build规划完全指南

5个技巧掌握Path of Building:流放之路Build规划完全指南 【免费下载链接】PathOfBuilding Offline build planner for Path of Exile. 项目地址: https://gitcode.com/GitHub_Trending/pa/PathOfBuilding Path of Building(简称PoB)是…

2026/8/7 20:38:41 阅读更多 →
X-VLA模型输入输出详解:多视图图像、状态信息与连续动作的处理流程

X-VLA模型输入输出详解:多视图图像、状态信息与连续动作的处理流程

X-VLA模型输入输出详解:多视图图像、状态信息与连续动作的处理流程 【免费下载链接】xvla-libero 项目地址: https://ai.gitcode.com/hf_mirrors/lerobot/xvla-libero X-VLA(LeRobot)是一个视觉-语言-动作基础模型,它使用…

2026/8/7 20:38:40 阅读更多 →
掌握AliceUI工具链:spm、nico与Peaches高效协作指南

掌握AliceUI工具链:spm、nico与Peaches高效协作指南

掌握AliceUI工具链:spm、nico与Peaches高效协作指南 【免费下载链接】aliceui.github.io 写样式的一种方式 项目地址: https://gitcode.com/gh_mirrors/al/aliceui.github.io AliceUI是一套基于spm生态圈的样式解决方案,作为Arale的子集&#xff…

2026/8/7 20:37:40 阅读更多 →

日新闻

为什么scrcpy成为Android投屏的终极解决方案:完整实战指南

为什么scrcpy成为Android投屏的终极解决方案:完整实战指南

为什么scrcpy成为Android投屏的终极解决方案:完整实战指南 【免费下载链接】scrcpy Display and control your Android device 项目地址: https://gitcode.com/GitHub_Trending/sc/scrcpy 想要将Android手机屏幕完美投射到电脑上,享受大屏操作的自…

2026/8/7 0:00:19 阅读更多 →
如何在5分钟内掌握Tom Select:打造现代化表单选择器的终极指南

如何在5分钟内掌握Tom Select:打造现代化表单选择器的终极指南

如何在5分钟内掌握Tom Select:打造现代化表单选择器的终极指南 【免费下载链接】tom-select Tom Select is a lightweight (~16kb gzipped) hybrid of a textbox and select box. Forked from selectize.js to provide a framework agnostic autocomplete widget wi…

2026/8/7 0:00:19 阅读更多 →
5分钟快速上手:NSZ压缩工具终极指南,轻松管理Switch游戏文件

5分钟快速上手:NSZ压缩工具终极指南,轻松管理Switch游戏文件

5分钟快速上手:NSZ压缩工具终极指南,轻松管理Switch游戏文件 【免费下载链接】nsz NSZ - Homebrew compatible NSP/XCI compressor/decompressor 项目地址: https://gitcode.com/gh_mirrors/ns/nsz 你是否在为Nintendo Switch游戏文件占用大量存储…

2026/8/7 0:00:19 阅读更多 →

周新闻

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

1. 从水管网络到最大流:一个核心问题的诞生想象一下,你是一个城市供水系统的总工程师。你的城市有多个水源(水库),需要通过一个复杂的地下管道网络,将水输送到各个居民区。每条管道都有其最大通水能力&…

2026/8/6 22:02:27 阅读更多 →
基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台…

2026/8/6 22:02:27 阅读更多 →
MATLAB xcorr函数详解:从互相关原理到四大实战应用

MATLAB xcorr函数详解:从互相关原理到四大实战应用

1. 从一次信号“找茬”说起:为什么我们需要互相关几年前,我在处理一组声学传感器数据时遇到了一个棘手的问题。我有两个麦克风记录了一段相同的音频信号,理论上它们接收到的声音波形应该非常相似,只是由于麦克风位置不同&#xff…

2026/8/6 22:02:27 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/7 17:02:37 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/6 22:02:28 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/7 17:02:36 阅读更多 →