驱动开发5 阻塞IO实例、IO多路复用
1 阻塞IO
进程1
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>int main(int argc, char const *argv[])
{char buf[128] = {0};int a,b;int fd = open("/dev/myled0",O_RDWR);if(fd < 0){printf("打开设备文件失败\n");exit(-1);}while(1){memset(buf,0,sizeof(buf));read(fd,buf,sizeof(buf));printf("buf:%s\n",buf);}
}
进程2
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>int main(int argc, char const *argv[])
{char buf[128] = "hello world";int a,b;int fd = open("/dev/myled0",O_RDWR);if(fd < 0){printf("打开设备文件失败\n");exit(-1);}write(fd,buf,sizeof(buf));
}
驱动程序
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/device.h>
#include <linux/wait.h>
#include <linux/uaccess.h>int major;
char kbuf[128] = {0};unsigned int *vir_rcc;
struct class *cls;
struct device *dev;
//定义等待队列
wait_queue_head_t wq_head;
unsigned int condition=0;
int mycdev_open(struct inode *inode, struct file *file)
{printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);return 0;
}ssize_t mycdev_read(struct file *file, char *ubuf, size_t size,loff_t *lof)
{printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);if(file->f_flags&O_NONBLOCK)//用户程序以非阻塞读写数据{}else{wait_event_interruptible(wq_head,condition);//判断condition的值,为假则进程休眠}//将获取到的硬件数据拷贝到用户int ret = copy_to_user(ubuf,kbuf,size);if(ret){printk("copy_to_user filed\n");return -EIO;}condition = 0; //表示下一次数据没有准备就绪return 0;
}
ssize_t mycdev_write(struct file *file, const char *ubuf, size_t size,loff_t *lof)
{printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);int ret;ret = copy_from_user(kbuf,ubuf,size);if (ret){printk("copy_from_user filed\n");return -EIO;}condition = 1;//表示硬件数据就绪wake_up_interruptible(&wq_head);//唤醒休眠的进程return 0;
}
int mycdev_close(struct inode *inode, struct file *file)
{printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);return 0;
}//定义操作方法结构体变量并赋值
struct file_operations fops={.open = mycdev_open,.read = mycdev_read,.write = mycdev_write,.release = mycdev_close,
};
static int __init mycdev_init(void)
{//初始化等待队列init_waitqueue_head(&wq_head);//字符设备驱动major = register_chrdev(0,"mychrdev",&fops);if(major < 0){printk("字符设备驱动注册失败\n");return major;}printk("字符设备驱动注册成功:major=%d\n",major);//向上提交目录 class_createcls = class_create(THIS_MODULE,"mychrdev");if(IS_ERR(cls)){printk("向上提交目录失败\n");return -PTR_ERR(cls);}printk("向上提交目录成功\n");//向上提交设备节点信息 device_createint i;for(i=0;i<3;i++){dev = device_create(cls,NULL,MKDEV(major,i),NULL,"myled%d",i);if(IS_ERR(dev)){printk("向上提交设备节点失败\n");return -PTR_ERR(dev);}}printk("向上提交设备节点信息成功\n");return 0;
}
static void __exit mycdev_exit(void)
{//1.销毁设备节点信息int i;for(i=0;i<3;i++){device_destroy(cls,MKDEV(major,i));}//2.销毁目录class_destroy(cls);//3.注销字符设备驱动unregister_chrdev(major,"mychrdev");
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");
Makefile
modname ?= demo
arch ?= arm
ifeq ($(arch),arm) #通过命令行传过来的架构决定怎么编译
#KERBELDIR保存开发板内核源码路径
KERNELDIR := /home/ubuntu/FSMP1A/linux-stm32mp-5.10.61-stm32mp-r2-r0/linux-5.10.61
else
#保存UBUNTU内核源码路径
KERNELDIR := /lib/modules/$(shell uname -r)/build
endif#PWD保存当前内核模块的路径
PWD := $(shell pwd)
all:
#make modules是模块化编译命令
#make -C $(KERNLEDIR) 执行make之前先切换到KERNELDIR对应的路径
#M=$(PWD)表示进行模块化编译的路径是PWD保存的路径make -C $(KERNELDIR) M=$(PWD) modules
clean:
#编译清除make -C $(KERNELDIR) M=$(PWD) clean
#将obj-m保存的文件单独链接为内核模块
obj-m := $(modname).o
效果演示
2 IO多路复用
驱动程序
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/device.h>
#include <linux/wait.h>
#include <linux/uaccess.h>
#include <linux/poll.h>int major;
char kbuf[128] = {0};unsigned int *vir_rcc;
struct class *cls;
struct device *dev;
//定义等待队列
wait_queue_head_t wq_head;
unsigned int condition=0;
int mycdev_open(struct inode *inode, struct file *file)
{printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);return 0;
}ssize_t mycdev_read(struct file *file, char *ubuf, size_t size,loff_t *lof)
{printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);if(file->f_flags&O_NONBLOCK)//用户程序以非阻塞读写数据{}else{// wait_event_interruptible(wq_head,condition);//判断condition的值,为假则进程休眠}//将获取到的硬件数据拷贝到用户int ret = copy_to_user(ubuf,kbuf,size);if(ret){printk("copy_to_user filed\n");return -EIO;}condition = 0; //表示下一次数据没有准备就绪return 0;
}__poll_t mycdev_poll(struct file *file, struct poll_table_struct *wait)
{__poll_t mask = 0;// 向上提交等待队列队头poll_wait(file, &wq_head, wait);// 根据数据是否就绪给定一个合适的返回值if (condition)mask = POLLIN;return mask;
}
ssize_t mycdev_write(struct file *file, const char *ubuf, size_t size,loff_t *lof)
{printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);int ret = copy_from_user(kbuf,ubuf,size);if (ret){printk("copy_from_user filed\n");return -EIO;}condition = 1;//表示硬件数据就绪wake_up_interruptible(&wq_head);//唤醒休眠的进程return 0;
}
int mycdev_close(struct inode *inode, struct file *file)
{printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);return 0;
}//定义操作方法结构体变量并赋值
struct file_operations fops={.open = mycdev_open,.read = mycdev_read,.write = mycdev_write,.poll = mycdev_poll,.release = mycdev_close,
};static int __init mycdev_init(void)
{//初始化等待队列init_waitqueue_head(&wq_head);//字符设备驱动major = register_chrdev(0,"mychrdev",&fops);if(major < 0){printk("字符设备驱动注册失败\n");return major;}printk("字符设备驱动注册成功:major=%d\n",major);//向上提交目录 class_createcls = class_create(THIS_MODULE,"mychrdev");if(IS_ERR(cls)){printk("向上提交目录失败\n");return -PTR_ERR(cls);}printk("向上提交目录成功\n");//向上提交设备节点信息 device_createint i;for(i=0;i<3;i++){dev = device_create(cls,NULL,MKDEV(major,i),NULL,"myled%d",i);if(IS_ERR(dev)){printk("向上提交设备节点失败\n");return -PTR_ERR(dev);}}printk("向上提交设备节点信息成功\n");return 0;
}
static void __exit mycdev_exit(void)
{//1.销毁设备节点信息int i;for(i=0;i<3;i++){device_destroy(cls,MKDEV(major,i));}//2.销毁目录class_destroy(cls);//3.注销字符设备驱动unregister_chrdev(major,"mychrdev");
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");
进程1:监听多个事件
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/select.h>
#include <sys/time.h>int main(int argc, char const *argv[])
{char buf[128] = {0};int fd1,fd2;fd1 = open("/dev/input/mouse0",O_RDWR);if(fd1 < 0){printf("打开鼠标设备失败\n");return -1;}fd2 = open("/dev/myled0",O_RDWR);if(fd2 < 0){printf("打开设备失败\n");return -1;}// 定义读事件集合fd_set readfds;while(1){// 清空集合FD_ZERO(&readfds);// 将要监听的事件添加进集合FD_SET(fd1, &readfds);FD_SET(fd2, &readfds); // 阻塞监听事件int ret;ret = select(fd2 + 1, &readfds, NULL, NULL, NULL);if(ret < 0){printf("select 调用失败\n");return -1;}// 判断事件是否发生if(FD_ISSET(fd1, &readfds));{memset(buf, 0, sizeof(buf));read(fd1, buf, sizeof(buf));printf("鼠标事件发生buf:%s\n", buf);}if(FD_ISSET(fd2, &readfds)){memset(buf,0,sizeof(buf));read(fd2,buf,sizeof(buf));printf("事件发生buf:%s\n",buf);}}// 关闭文件描述符close(fd1);close(fd2);return 0;
}
进程2:模拟自定义事件就绪
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>int main(int argc, char const *argv[])
{char buf[128] = "hello world";int a,b;int fd = open("/dev/myled0",O_RDWR);if(fd < 0){printf("打开设备文件失败\n");exit(-1);}write(fd,buf,sizeof(buf));
}
效果演示
相关文章:

驱动开发5 阻塞IO实例、IO多路复用
1 阻塞IO 进程1 #include <stdlib.h> #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/ioctl.h> #include <fcntl.h> #include <unistd.h> #include <string.h>int main(int argc, char co…...

ElasticSearch:实现高效数据搜索与分析的利器!项目中如何应用落地,让我带你实操指南。
1.难点解答 收集到几个问题: elasticsearch是单独建一个项目,作为全文搜索使用,还是直接在项目中直接用? ES 服务器是要单独部署的,你可以把 ES 理解为 Redis。 新增数据时,插入到mysql中,需不…...

2023了,是时候使用pnpm了!
2023了,是时候使用pnpm了! Excerpt 2023了,是时候使用pnpm了! 什么是pnpm pnpm代表performant npm(高性能的npm),同npm和Yarn,都属于Javascript包管理安装工具,它较npm和…...

asp.net文档管理系统VS开发sqlserver数据库web结构c#编程Microsoft Visual Studio
一、源码特点 asp.net文档管理系统是一套完善的web设计管理系统,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。开发环境为vs2010,数据库为sqlserver2008,使用c#语言开发 asp.net文档管理系统 二、功能介绍 (1…...

Parallels Client for Mac:改变您远程控制体验的革命性软件
在当今数字化的世界中,远程控制软件已经成为我们日常生活和工作中不可或缺的一部分。在众多远程控制软件中,Parallels Client for Mac以其独特的功能和出色的性能脱颖而出,让远程控制变得更加简单、高效和灵活。 Parallels Client for Mac是…...
Julia数组详解
文章目录 向量数列矩阵特殊数组数组函数 Julia系列:编程初步 向量 Julia中有两种向量,一种是类型统一的,另一种则可包含不同类型的变量,例如下面两个向量都是允许存在的 aNum [1,2,3] # 类型为 3-element Vector{Int64} aAny…...
用事务代码查看视图的函数
文章目录 1 Introduction2 Code 1 Introduction If we continue to see view with T-code. We can use the function for it . 2 Code REPORT z_websrv_con.CALL FUNCTION VIEW_MAINTENANCE_CALLEXPORTINGaction U "操作类型:U修改…...
LuatOS-SOC接口文档(air780E)--libcoap - coap数据处理
libcoap.new(code, uri, headers, payload) 创建一个coap数据包 参数 传入值类型 解释 int coap的code, 例如libcoap.GET/libcoap.POST/libcoap.PUT/libcoap.DELETE string 目标URI,必须填写, 不需要加上/开头 table 请求头,类似于http的headers,可选 string 请求体…...
js控制checkbox单选,获取checkbox的值,选中checkbox
声明:网上的资料杂七杂八的搞得我一个不熟悉前端的后端开发者弄起来贼难受,现在将实现了的做一个整合,希望能给你们带来点帮助(主要还是帮助我自己(●ˇ∀ˇ●),防止丢失) html代码组件示例 <div styl…...

MYSQL(事务+锁+MVCC+SQL执行流程)理解(2)
一)MYSQL中的锁(知识补充) 可以通过In_use字段来进行判断是否针对于表进行加了锁 1)对于undo log日志来说:新增类型的,在事务提交之后就可以清除掉了,修改类型的,事务提交之后不能立即清除掉这些日志会用于mvcc只有当没有事务用到该版本信息时…...

ubuntu tools
1 cloc calculate lines of your code sudo apt-get install cloccloc ./file...
LeetCode 155. 掷骰子等于目标和的方法数:动态规划
【LetMeFly】1155.掷骰子等于目标和的方法数:动态规划 力扣题目链接:https://leetcode.cn/problems/number-of-dice-rolls-with-target-sum/ 这里有 n 个一样的骰子,每个骰子上都有 k 个面,分别标号为 1 到 k 。 给定三个整数 …...
PostgreSQL数据库从入门到精通系列之五:安装时序数据库TimescaleDB的详细步骤
PostgreSQL数据库从入门到精通系列之五:安装时序数据库TimescaleDB的详细步骤 一、下载PostgreSQL数据库yum源二、创建TimescaleDB存储库三、更新本地存储库列表四、安装TimescaleDB五、初始化PostgreSQL数据库六、启动Postgresql数据库服务七、以超级用户身份连接到PostgreSQ…...

软件测试(五)自动化 selenium
文章目录 自动化测试单元测试:单元测试:UI自动化 selenium工具定义特点:原理:seleniumjava环境搭建SeleniumAPI获取测试结果:添加等待浏览器操作键盘事件鼠标事件多层框架/窗口定位下拉框处理弹窗处理上传文件操作关闭…...
Android grantUriPermission的使用场景和方式
#grantUriPermission 作用 临时授权。 背景:FileProvider引入后应用之间想访问文件,都需要使用此接口。特别是两个独立的应用之间互通数据的时候。例如我们应用从图库获取文件的uri,显示在应用内的ImageView中。 #grantUriPermission 使用方…...

2023高频前端面试题-vue
1. 什么是 M V VM Model-View-ViewModel 模式 Model 层: 数据模型层 通过 Ajax、fetch 等 API 完成客户端和服务端业务模型的同步。 View 层: 视图层 作为视图模板存在,其实 View 就是⼀个动态模板。 ViewModel 层: 视图模型层 负责暴露数据给 View 层&…...

03初始Docker
一、初始Docker 1.什么是Docker 问题 ①大型项目组件复杂,运行环境复杂,部署时依赖复杂,出现兼容性问题。 ②开发,测试,生产环境有差异。不同的环境操作系统不同 解决 ①Docket将应用、依赖、函数库、配置一起打…...
1.1、Python基础-注释、变量声明及命名规则、数据类型
1.1、Python基础 Python基础1、注释2、变量3、数据类型 Python基础 1、注释 注释是给程序员看的,为了让程序员方便阅读代码,解释器会忽略注释。使用自己熟悉的语言,适当的对代 码进行注释说明是一种良好的编码习惯。 注释写法 #我是单行注…...
Python第三方库安装——使用vscode、pycharm安装Python第三方库
[TOC](Python第三方库安装——使用vscode、pycharm安装Python第三方库) # 前言 在这里介绍vscode、Pycharm安装python第三方库的方法。 操作系统:windows10 专业版 环境如下: Pycharm Comunity 2022.3 Visual Studio Code 2019 Python 3.8 pipÿ…...
【vue】组件通选方式
父子传值 props $emit 这是最基本的父子组件通讯方式。通过 props 属性将数据从父组件传递给子组件,而子组件通过触发事件($emit)将数据发送回父组件。 $children $parent 通过 $parent 属性可以访问父组件的实例,通过 $child…...

【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)
骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术,它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton):由层级结构的骨头组成,类似于人体骨骼蒙皮 (Mesh Skinning):将模型网格顶点绑定到骨骼上,使骨骼移动…...
Java多线程实现之Thread类深度解析
Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...

华为OD机考-机房布局
import java.util.*;public class DemoTest5 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseSystem.out.println(solve(in.nextLine()));}}priv…...

GO协程(Goroutine)问题总结
在使用Go语言来编写代码时,遇到的一些问题总结一下 [参考文档]:https://www.topgoer.com/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/goroutine.html 1. main()函数默认的Goroutine 场景再现: 今天在看到这个教程的时候,在自己的电…...

永磁同步电机无速度算法--基于卡尔曼滤波器的滑模观测器
一、原理介绍 传统滑模观测器采用如下结构: 传统SMO中LPF会带来相位延迟和幅值衰减,并且需要额外的相位补偿。 采用扩展卡尔曼滤波器代替常用低通滤波器(LPF),可以去除高次谐波,并且不用相位补偿就可以获得一个误差较小的转子位…...

C++_哈希表
本篇文章是对C学习的哈希表部分的学习分享 相信一定会对你有所帮助~ 那咱们废话不多说,直接开始吧! 一、基础概念 1. 哈希核心思想: 哈希函数的作用:通过此函数建立一个Key与存储位置之间的映射关系。理想目标:实现…...

结构化文件管理实战:实现目录自动创建与归类
手动操作容易因疲劳或疏忽导致命名错误、路径混乱等问题,进而引发后续程序异常。使用工具进行标准化操作,能有效降低出错概率。 需要快速整理大量文件的技术用户而言,这款工具提供了一种轻便高效的解决方案。程序体积仅有 156KB,…...

工厂方法模式和抽象工厂方法模式的battle
1.案例直接上手 在这个案例里面,我们会实现这个普通的工厂方法,并且对比这个普通工厂方法和我们直接创建对象的差别在哪里,为什么需要一个工厂: 下面的这个是我们的这个案例里面涉及到的接口和对应的实现类: 两个发…...
6.计算机网络核心知识点精要手册
计算机网络核心知识点精要手册 1.协议基础篇 网络协议三要素 语法:数据与控制信息的结构或格式,如同语言中的语法规则语义:控制信息的具体含义和响应方式,规定通信双方"说什么"同步:事件执行的顺序与时序…...

Web APIS Day01
1.声明变量const优先 那为什么一开始前面就不能用const呢,接下来看几个例子: 下面这张为什么可以用const呢?因为复杂数据的引用地址没变,数组还是数组,只是添加了个元素,本质没变,所以可以用con…...