驱动开发day8
编写LED灯的驱动,使用GPIO子系统,里面添加按键的中断处理
1.应用程序发送指令控制LED亮灭
2.按键1 按下,led1电位反转 按键2按下,led2电位反转 按键3 按下,led3电位反转
驱动程序
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/device.h>
#include "head.h"
struct device_node *dev_key;
unsigned int irqno_key1;
unsigned int irqno_key2;
unsigned int irqno_key3;struct device_node *dev_led;
struct gpio_desc *gpiono_led1;
struct gpio_desc *gpiono_led2;
struct gpio_desc *gpiono_led3;int major;
struct class *cls;
struct device *dev;
// 中断处理函数
irqreturn_t myirq_handler_key1(int irq, void *dev)
{gpiod_set_value(gpiono_led1,!gpiod_get_value(gpiono_led1));return IRQ_HANDLED;
}
irqreturn_t myirq_handler_key2(int irq, void *dev)
{gpiod_set_value(gpiono_led2,!gpiod_get_value(gpiono_led2));return IRQ_HANDLED;
}
irqreturn_t myirq_handler_key3(int irq, void *dev)
{gpiod_set_value(gpiono_led3,!gpiod_get_value(gpiono_led3));return IRQ_HANDLED;
}
long mycdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{switch (cmd){case LED_ON:switch (arg){case 1: // LED1gpiod_set_value(gpiono_led1,1);; // LED1开灯break;case 2: // LED2gpiod_set_value(gpiono_led2,1); // LED2开灯break;case 3: // LED3gpiod_set_value(gpiono_led3,1); // LED3开灯break;}break;case LED_OFF:switch (arg){case 1:gpiod_set_value(gpiono_led1,0);break;case 2:gpiod_set_value(gpiono_led2,0);break;case 3:gpiod_set_value(gpiono_led3,0);break;}break;}return 0;
}
struct file_operations fops = {.unlocked_ioctl = mycdev_ioctl,};
static int __init mycdev_init(void)
{int i;// 字符设备驱动注册major = register_chrdev(0, "mychrdev", &fops);if (major < 0){printk("字符设备驱动注册失败\n");return major;}printk("字符设备驱动注册成功:major=%d\n", major);// 向上提交目录cls = class_create(THIS_MODULE, "myled");if (IS_ERR(cls)){printk("向上提交目录失败\n");return -PTR_ERR(cls);}printk("向上提交目录信息成功\n");// 向上提交设备节点信息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");int ret;// 解析按键的设备树节点dev_key = of_find_node_by_path("/myirq");if (dev_key == NULL){printk("解析设备树节点失败\n");return -EFAULT;}printk("解析设备树节点成功\n");// 根据设备树节点解析出软中断号irqno_key1 = irq_of_parse_and_map(dev_key, 0); // 按键1索引号为0if (!irqno_key1){printk("解析软中断号失败\n");return -ENXIO;}printk("key1解析软中断号成功 irqno=%d\n", irqno_key1);irqno_key2 = irq_of_parse_and_map(dev_key, 1); // 按键1索引号为0if (!irqno_key2){printk("解析软中断号失败\n");return -ENXIO;}printk("key2解析软中断号成功 irqno=%d\n", irqno_key2);irqno_key3 = irq_of_parse_and_map(dev_key, 2); // 按键1索引号为0if (!irqno_key3){printk("解析软中断号失败\n");return -ENXIO;}printk("key3解析软中断号成功 irqno=%d\n", irqno_key3);// 注册中断ret = request_irq(irqno_key1, myirq_handler_key1, IRQF_TRIGGER_FALLING, "key1", NULL);if (ret){printk("注册中断失败\n");return ret;}printk("key1注册中断成功\n");ret = request_irq(irqno_key2, myirq_handler_key2, IRQF_TRIGGER_FALLING, "key2", NULL);if (ret){printk("注册中断失败\n");return ret;}printk("key2注册中断成功\n");ret = request_irq(irqno_key3, myirq_handler_key3, IRQF_TRIGGER_FALLING, "key3", NULL);if (ret){printk("注册中断失败\n");return ret;}printk("key3注册中断成功\n");// 根据设备树节点的路径解析设备树信息dev_led = of_find_node_by_path("/leds");if (dev_led == NULL){printk("解析设备树节点失败\n");return -EFAULT;}printk("解析设备树节点成功\n");// 申请gpio_desc对象并设置输出为低电平gpiono_led1 = gpiod_get_from_of_node(dev_led, "led1-gpios", 0, GPIOD_OUT_LOW, NULL);if (IS_ERR(gpiono_led1)){printk("申请gpio对象失败\n");return -PTR_ERR(gpiono_led1);}printk("申请gpio_led1对象成功\n");gpiono_led2 = gpiod_get_from_of_node(dev_led, "led2-gpios", 0, GPIOD_OUT_LOW, NULL);if (IS_ERR(gpiono_led2)){printk("申请gpio对象失败\n");return -PTR_ERR(gpiono_led2);}printk("申请gpio_led1对象成功\n");gpiono_led3 = gpiod_get_from_of_node(dev_led, "led3-gpios", 0, GPIOD_OUT_LOW, NULL);if (IS_ERR(gpiono_led3)){printk("申请gpio对象失败\n");return -PTR_ERR(gpiono_led3);}printk("申请gpio_led1对象成功\n");return 0;
}
static void __exit mycdev_exit(void)
{// 注销中断free_irq(irqno_key1, NULL);free_irq(irqno_key2, NULL);free_irq(irqno_key3, NULL);// 灭灯gpiod_set_value(gpiono_led1, 0);// 释放gpio编号gpiod_put(gpiono_led1);// 灭灯gpiod_set_value(gpiono_led2, 0);// 释放gpio编号gpiod_put(gpiono_led2);// 灭灯gpiod_set_value(gpiono_led3, 0);// 释放gpio编号gpiod_put(gpiono_led3);int i;for (i = 0; i < 3; i++){device_destroy(cls, MKDEV(major, i));}// 销毁目录信息class_destroy(cls);// 注销字符设备驱动unregister_chrdev(major, "mychrdev");
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");
应用程序
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include "head.h"int main(int argc, char const *argv[])
{int a, b;char buf[128] = {0};int fd0 = open("/dev/mycdev0", O_RDWR);if (fd0 < 0){printf("打开设备文件失败\n");exit(-1);}int fd1 = open("/dev/mycdev1", O_RDWR);if (fd1 < 0){printf("打开设备文件失败\n");exit(-1);}int fd2 = open("/dev/mycdev2", O_RDWR);if (fd2 < 0){printf("打开设备文件失败\n");exit(-1);}while (1){// 从终端读取printf("请输入指令\n");printf("0(关灯) 1(开灯)\n");printf("请输入>");scanf("%d", &a);printf("请输入要控制的灯 1(LED1) 2(LED2) 3(LED3)>");scanf("%d", &b);switch (b){case 1:switch (a){case 1:ioctl(fd0, LED_ON); // 开灯break;case 0:ioctl(fd0, LED_OFF);break;}break;case 2:switch (a){case 1:ioctl(fd1, LED_ON); // 开灯break;case 0:ioctl(fd1, LED_OFF);break;}break;case 3:switch (a){case 1:ioctl(fd2, LED_ON); // 开灯break;case 0:ioctl(fd2, LED_OFF);break;}break;}}close(fd0);close(fd1);close(fd2);return 0;
}
相关文章:
驱动开发day8
编写LED灯的驱动,使用GPIO子系统,里面添加按键的中断处理 1.应用程序发送指令控制LED亮灭 2.按键1 按下,led1电位反转 按键2按下,led2电位反转 按键3 按下,led3电位反转 驱动程序 #include <linux/init.h> #i…...

CAS 机制
问题分析与思考: CAS 是 Java 中 Unsafe 类里面的方法,它的全称是 CompareAndSwap,比较并交换 的意思。 它的主要功能是能够保证在多线程环境下,对于共享变量的修改的原子性。 举个例子,比如说有这样一个场景ÿ…...
#P1003. [NOIP2009普及组] 道路游戏
题目描述 小新正在玩一个简单的电脑游戏。 游戏中有一条环形马路,马路上有 nn 个机器人工厂,两个相邻机器人工厂之间由一小段马路连接。小新以某个机器人工厂为起点,按顺时针顺序依次将这 nn 个机器人工厂编号为 1\sim n1∼n,因…...

python-网络爬虫.regular
regular 正则表达式 (regular expression) 正则表达式(regular expression)描述了一种字符串匹配的模式 (pattern), 可以用来检查一个串是否含有某种子串、将匹配的子串替换或者从某个串 中取出符合某个条件的子串等。 正则表达式是由普通…...

手动搭建gateway,项目集成gateway实现Token效果
目录 背景步骤1、首先创建springboot项目2、引入依赖3、配置文件!!!!!(超级重要!!!根据自己的需要进行配置)4、相关类我们在服务中进行的白名单中接口的操作如…...
linux下SVN服务器搭建
在本教程中,我们将介绍如何在Linux系统下搭建Subversion(SVN)服务器。Subversion是一种流行的版本控制系统,它允许多个人在同一项目上进行协作,同时避免了他们各自的更改发生冲突。 安装SVN 在大多数Linux发行版中&am…...

技术等级 TRL 定义
“不同环境、不同目标下TRL表述不一样” 技术等级 TRL 定义 TRL1 基本原理提出和发现 TRL2 技术应用研究 TRL3 完成概念验证,如叶栅试验、燃烧室头部试验等 TRL4 完成模拟部件试验.如压气机性能试验,燃烧室扇形试验 TRL5 完…...

DHorse v1.3.0 发布,基于k8s的发布平台
综述 DHorse是一个简单易用、以应用为中心的云原生DevOps系统,具有持续集成、持续部署、微服务治理等功能,无需安装依赖Docker、Maven、Node等环境即可发布Java、Vue、React应用,主要特点:部署简单、操作简洁、功能快速。 新增特…...

Redis - 缓存的双写一致性
概念: 当修改了数据库的数据也要同时更新缓存的数据,缓存和数据库的数据要保持一致 那为什么会有不一致的情况呢? 如果不追求一致性,正常有两种做法 先修改数据库 后删除旧的缓存先删除旧的缓存 再修改数据库 我们以先删除旧的…...
opencv03-Mat矩阵API的使用
opencv03-Mat矩阵API的使用 构造方法(具体介绍看API文档) int main() {Mat m1 Mat(200, 100, CV_8UC1);imshow("o1", m1);Mat m2 Mat(Size(100, 200), CV_8UC1);imshow("o2", m2);Mat m3 Mat(200, 100, CV_8UC3, Scalar(255, 0, 0));imshow("o3&…...

2023届浙江大学MPA提面A资格经验总结分享
本人是去年报考的浙大MPA项目,并通过提面获得了A资格,新一年浙大MPA项目提前批面试已经开始了,受达立易考周老师邀请来分享下我的提面经验,希望我的经验能对还在迷茫中的小伙伴有所帮助。 点开提面通知,首先看到…...

BugKu CTF(杂项篇MISC)—想要种子吗
BugKu CTF(杂项篇MISC)—想要种子吗 提 示: 描 述:flag{} 题目下载后是一张图片,打开如下。 一、工具 十六进制编辑器010 editor kali系统文件分离工具binwalk或者foremost 维吉尼亚密码 STEGHIDE图片隐写工具 文章所需的软件下载地址 ARCHPR压缩包密码破解…...

类之间的关系
1、类关系 继承、实现、依赖、组合、聚合 继承:一个类继承另一个类; 实现:一个类实现另一个接口; 依赖:一个类作为另一个的局部变量,方法的参数,临时对象等; 组合:一个类…...

【蓝图】p40-p43对象引用、变量有效性、实现键盘控制物体自转、简单点名系统
p40-p43对象引用、变量有效性、实现键盘控制物体自转、简单点名系统 p40对象引用、变量有效性p41实现键盘控制物体自转创建bool值控制旋转实现通过键盘控制自转 p42p43简单点名系统Get All Actors Of Class(获得场景中所有该类的actor演员)getFor Each L…...

vscode设置远程登录和免密登录
首先,我们去官网下载VScode 安装过程比较简单,大家自行安装即可,注意建议安装在除C盘外的其他盘中。 安装完成后,打开我们下载好的VScode,点击左侧的Extensions选项,搜索Remote,Install第一项R…...

今日头条面试真题及答案,软件测试工程师面试秘籍
试题1.在浏览器地址栏里输入一个网址,接下来会发生什么? 答案:发生的操作如下。 (1)浏览器查找该网址的IP地址。 (2)浏览器根据解析得到的IP地址向Web服务器发送一个HTTP请求。 &am…...
JavaScript Windows 浏览器对象模型
Window 对象 BOM 的核心就是 window 对象所有浏览器都支持 window 对象。它表示浏览器窗口。所有 JavaScript 全局对象、函数以及变量均自动成为 window 对象的成员。全局变量是 window 对象的属性。全局函数是 window 对象的方法。HTML DOM 的 document 也是 window 对象的属…...
【uniapp 获取缓存及清除缓存】
小程序及H5 获取缓存: 使用uniapp中的wx.getStorageInfoSync()方法可以获取当前小程序或H5应用的本地缓存信息,如下所示: let storageInfo uni.getStorageInfoSync() console.log(storageInfo)其中,storageInfo是一个对象&…...
【vim 学习系列文章 2 - vim 常用插件配置】
文章目录 1.1 vim 常用插件1.1.1 vim 插件 Pathogen 管理1.1.2 vim 常用插件推荐1.1.3 vim Leaderf1.1.4 vim ripgrep 工具1.1.5 vim Leaderf 配合 rg1.1.6 vim autocmd 配置 1.2 其它类型文件 vimrc 配置1.2.1 System Verilog vimrc 配置 上篇文章:vim 学习系列文章…...

【外卖系统】修改菜品
需求分析 在菜品管理列表页面点击修改按钮,跳转到修改页面,在修改页面回显菜品相关信息并进行修改,在最后点击确定按钮完成修改操作 代码设计 页面发送ajax请求,请求服务端获取分类数据,用于菜品分类下拉框中数据显…...

Spark 之 入门讲解详细版(1)
1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室(Algorithms, Machines, and People Lab)开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目,8个月后成为Apache顶级项目,速度之快足见过人之处&…...
k8s从入门到放弃之Ingress七层负载
k8s从入门到放弃之Ingress七层负载 在Kubernetes(简称K8s)中,Ingress是一个API对象,它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress,你可…...

YSYX学习记录(八)
C语言,练习0: 先创建一个文件夹,我用的是物理机: 安装build-essential 练习1: 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件,随机修改或删除一部分,之后…...

Psychopy音频的使用
Psychopy音频的使用 本文主要解决以下问题: 指定音频引擎与设备;播放音频文件 本文所使用的环境: Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...

【7色560页】职场可视化逻辑图高级数据分析PPT模版
7种色调职场工作汇报PPT,橙蓝、黑红、红蓝、蓝橙灰、浅蓝、浅绿、深蓝七种色调模版 【7色560页】职场可视化逻辑图高级数据分析PPT模版:职场可视化逻辑图分析PPT模版https://pan.quark.cn/s/78aeabbd92d1...

基于 TAPD 进行项目管理
起因 自己写了个小工具,仓库用的Github。之前在用markdown进行需求管理,现在随着功能的增加,感觉有点难以管理了,所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD,需要提供一个企业名新建一个项目&#…...
IP如何挑?2025年海外专线IP如何购买?
你花了时间和预算买了IP,结果IP质量不佳,项目效率低下不说,还可能带来莫名的网络问题,是不是太闹心了?尤其是在面对海外专线IP时,到底怎么才能买到适合自己的呢?所以,挑IP绝对是个技…...
Java编程之桥接模式
定义 桥接模式(Bridge Pattern)属于结构型设计模式,它的核心意图是将抽象部分与实现部分分离,使它们可以独立地变化。这种模式通过组合关系来替代继承关系,从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...
GitHub 趋势日报 (2025年06月06日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 590 cognee 551 onlook 399 project-based-learning 348 build-your-own-x 320 ne…...

Scrapy-Redis分布式爬虫架构的可扩展性与容错性增强:基于微服务与容器化的解决方案
在大数据时代,海量数据的采集与处理成为企业和研究机构获取信息的关键环节。Scrapy-Redis作为一种经典的分布式爬虫架构,在处理大规模数据抓取任务时展现出强大的能力。然而,随着业务规模的不断扩大和数据抓取需求的日益复杂,传统…...