[驱动开发]gpio子系统及中断实现led亮灭

编写LED灯的驱动,使用GPIO子系统,里面添加按键的中断处理

1.应用程序发送指令控制发光二极管亮灭

2.按键1按下,led1电位反转;按键2按下,led2电位反转;按键3按下,led3电位反转 
 

//头文件
#ifndef __LED_H__
#define __LED_H__//功能码
#define LED_ON _IOW('l',1,int)
#define LED_OFF _IOW('l',0,int)
#endif
//应用程序实现LED的亮灭
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include "led.h"
int main(int argc, const char *argv[])
{int a,b;while(1){int fd_led = open("/dev/myled0",O_RDWR);	if(fd_led < 0){printf("打开设备文件失败\n");exit(-1);}printf("请输入要控制的灯:1 2 3>>");scanf("%d",&b);printf("输入控制命令:0熄灭 1开灯>>>");scanf("%d",&a);switch(a){case 1:ioctl(fd_led,LED_ON,&b);break;case 0:ioctl(fd_led,LED_OFF,&b);break;}close(fd_led);}return 0;
}
//驱动程序
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/io.h>
#include<linux/of_irq.h>
#include<linux/interrupt.h>
#include "led.h"
/*  leds{led1-gpios=<&gpioe 10 0>;//10表示引脚编号  0表示默认led2-gpios=<&gpiof 10 0>;led3-gpios=<&gpioe 8 0>;};*/
struct device_node *dnode1;
struct device_node *dnode2;
struct gpio_desc *gpiono1;
struct gpio_desc *gpiono2;
struct gpio_desc *gpiono3;
struct cdev *cdev;
int major=168;
int minor=0;
struct class *cls;
struct device *dev;
dev_t devno;
int i;
unsigned int irqno[3];      //软中断号//中断处理函数
irqreturn_t myirq_handler(int irqno, void *dev_id)
{unsigned int id=(unsigned int)dev_id;switch(id){case 0:printk("KEY1_INTERRUPT\n");gpiod_set_value(gpiono1,!gpiod_get_value(gpiono1));break;case 1:printk("KEY2_INTERRUPT\n");gpiod_set_value(gpiono2,!gpiod_get_value(gpiono2));break;case 2:printk("KEY3_INTERRUPT\n");gpiod_set_value(gpiono3,!gpiod_get_value(gpiono3));break;}return IRQ_HANDLED;
}
/*********************封装操作方法***************************/
int mycdev_open(struct inode *inode, struct file *file)
{//printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);return 0;
}long mycdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{int which;copy_from_user(&which,(void *)arg,4);switch(cmd){case LED_ON:         // 亮灯switch(which){case 1:   gpiod_set_value(gpiono1, 1);break;case 2:gpiod_set_value(gpiono2, 1);break;case 3:gpiod_set_value(gpiono3, 1);break;}break;case LED_OFF:switch(which){case 1:gpiod_set_value(gpiono1, 0);break;case 2:gpiod_set_value(gpiono2, 0);break;case 3:gpiod_set_value(gpiono3, 0);}break;}//printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);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,.release =  mycdev_close,.unlocked_ioctl = mycdev_ioctl,
};
static int __init mycdev_init(void)
{int ret,i;//1.申请对象空间 cdev_alloccdev = cdev_alloc();if(cdev == NULL){printk("申请对象空间失败\n");ret=-EFAULT;goto out1;}printk("申请对象空间成功\n");//2.初始化对象 cdev_initcdev_init(cdev,&fops);printk("初始化对象成功\n");//3.申请设备号 register_chrdev_region()或clloc_chrdev_region()if(major != 0)  //静态申请{ret=register_chrdev_region(MKDEV(major,minor),3,"myled");if(ret){printk("申请静态设备号失败\n");goto out2;}printk("申请静态设备号成功major=%d\n",major);}else    //动态申请{ret=alloc_chrdev_region(&devno,minor,3,"myled");if(ret){printk("申请动态设备号失败\n");goto out2;}major=MAJOR(devno);minor=MINOR(devno);printk("申请动态设备号成功major=%d\n",major);}//4.注册驱动对象 cdev_add()ret=cdev_add(cdev,MKDEV(major,minor),3);if(ret){printk("注册驱动对象失败\n");goto out3;}printk("注册驱动对象成功\n");//5.向上提交目录 class_create()cls=class_create(THIS_MODULE,"myled");if(IS_ERR(cls)){printk("向上提交目录失败\n");ret = -PTR_ERR(cls);goto out4;}printk("向上提交目录成功\n");//6.向上提交设备信息 device_create()for(i=0;i<3;i++){dev=device_create(cls,NULL,MKDEV(major,i),NULL,"myled%d",i);if(IS_ERR(dev)){printk("向上提交设备节点失败\n");ret = -PTR_ERR(dev);goto out5;}}printk("向上提交设备信息成功\n");// 根据设备树节点的路径解析设备树信息dnode1 = of_find_node_by_path("/leds");if (dnode1 == NULL){printk("解析设备树节点led失败\n");return -EFAULT;}printk("解析设备树节点led成功\n");// 申请gpio_desc对象并设置输出为低电平gpiono1 = gpiod_get_from_of_node(dnode1, "led1-gpios", 0, GPIOD_OUT_LOW, NULL);if (IS_ERR(gpiono1)){printk("申请gpio1对象失败\n");return -PTR_ERR(gpiono1);}printk("申请gpio1对象成功\n");gpiono2 = gpiod_get_from_of_node(dnode1, "led2-gpios", 0, GPIOD_OUT_LOW, NULL);if (IS_ERR(gpiono2)){printk("申请gpio2对象失败\n");return -PTR_ERR(gpiono2);}printk("申请gpio2对象成功\n");gpiono3 = gpiod_get_from_of_node(dnode1, "led3-gpios", 0, GPIOD_OUT_LOW, NULL);if (IS_ERR(gpiono3)){printk("申请gpio3对象失败\n");return -PTR_ERR(gpiono3);}printk("申请gpio3对象成功\n");// 根据设备树节点的路径解析设备树信息dnode2 = of_find_node_by_path("/myirq");if (dnode2 == NULL){printk("解析设备树节点myirq失败\n");return -EFAULT;}printk("解析设备树节点myirq成功\n");for(i=0;i<3;i++){//获取软中断号irqno[i]=irq_of_parse_and_map(dnode2,i);if(!irqno[i]){printk("软中断号irqno[%d]获取失败\n",i);return -ENXIO;}printk("软中断号获取成功irqno[%d]=%d\n",i,irqno[i]);//注册中断ret=request_irq(irqno[i],myirq_handler,IRQF_TRIGGER_FALLING,"key",(void *)i);if(ret){printk("注册驱动失败\n");return ret;}printk("key%d中断注册成功\n",i);}return 0;
out5:for(--i;i>=0;i--){//销毁上面提交的设备信息device_destroy(cls,MKDEV(major,i));}class_destroy(cls);
out4:cdev_del(cdev);
out3:unregister_chrdev_region(MKDEV(major,minor),3);
out2:kfree(cdev);
out1:return ret;
}
static void __exit mycdev_exit(void)
{// 灭灯gpiod_set_value(gpiono1, 0);gpiod_set_value(gpiono2, 0);gpiod_set_value(gpiono3, 0);// 释放gpio编号gpiod_put(gpiono1);gpiod_put(gpiono2);gpiod_put(gpiono3);//注销中断for(i=0;i<3;i++){free_irq(irqno[i],NULL);}
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

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

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

相关文章

PHP并发处理详解

在今天的网络世界中&#xff0c;高并发是一个无法避免的问题。随着用户的增加和业务的复杂性&#xff0c;我们的应用可能会面临大量的并发请求。这时&#xff0c;如果我们不能很好地处理并发&#xff0c;就可能会导致应用的性能下降&#xff0c;甚至崩溃。在很多情况下&#xf…

想做上位机,学C#还是QT?

学习C#还是Qt&#xff0c;取决于你的具体需求和偏好。 如果你计划开发跨平台的桌面应用程序&#xff0c;并且希望使用一种更轻量级、直观的界面框架&#xff0c;那么Qt可能是一个不错的选择。Qt是一个功能丰富且成熟的跨平台框架&#xff0c;支持多种开发语言&#xff08;包括…

flask用DBUtils实现数据库连接池

flask用DBUtils实现数据库连接池 在 Flask 中&#xff0c;DBUtils 是一种实现数据库连接池的方案。DBUtils 提供了持久性&#xff08;persistent&#xff09;和透明的&#xff08;transient&#xff09;两种连接池类型。 首先你需要安装 DBUtils 和你需要的数据库驱动。例如&…

springboot 入门

前提是已安装java环境&#xff0c;分为三部分 一、项目构建 二、项目组成 三、常用注解 Demo源码 spring-demo: springboot 入门项目 一、springboot-stater 使用IDEA快速构建springboot项目 1、新建项目 2、选择maven&#xff0c;在选择next 3、填写好项目信息 4、pom…

分布式应用:ELK企业级日志分析系统

目录 一、理论 1.ELK 2.ELK场景 3.完整日志系统基本特征 4.ELK 的工作原理 5.ELK集群准备 6.Elasticsearch部署&#xff08;在Node1、Node2节点上操作&#xff09; 7.Logstash 部署&#xff08;在 Apache 节点上操作&#xff09; 8.Kiabana 部署&#xff08;在 Node1 节点…

maven安装(windows)

环境 maven&#xff1a;Apache Maven 3.5.2 jdk环境&#xff1a;jdk 1.8.0_192 系统版本&#xff1a;win10 一、安装 apache官网下载需要的版本&#xff0c;然后解压缩&#xff0c;解压路径尽量不要有空格和中文 官网下载地址 https://maven.apache.org/download.cgihttps:…

SpringBoot基础认识

创建SpringBoot模块 首先需要引设置maven并引用maven环境 1.打开项目结构&#xff0c;new module&#xff0c;选择Spring Initializr&#xff0c;URL选默认&#xff1a; group填写分组如com.kdy &#xff0c; Artifact起个模块名如springboot_quickstart&#xff0c;Type选择M…

k8s概念-DaemonSet

回到目录 参考链接https://v1-23.docs.kubernetes.io/zh/docs/concepts/workloads/controllers/daemonset/ DaemonSet 确保全部&#xff08;或者某些&#xff09;节点上运行一个 Pod 的副本 当节点加入到K8S集群中&#xff0c;pod会被&#xff08;DaemonSet&#xff09;调度到…

【AI】《动手学-深度学习-PyTorch版》笔记(九):从零开始实现线性回归的训练

AI学习目录汇总 1、生成数据 在深度学习中,用来训练的数据集通过标注来实现。 咱们在这一步使用函数来生成一组数据集 1.1 定义数据生成函数 定义数据生成函数:synthetic_data %matplotlib inline import random import torch from d2l import torch as d2l def synthet…

【开源源码学习】

C 迷你高尔夫 一款打高尔夫的游戏。亮点是碰撞反应和关卡设计。 GitHub - mgerdes/Open-Golf: A cross-platform minigolf game written in C. TypeScript 俄罗斯方块 复刻经典的俄罗斯方块&#xff0c;项目采用ReactReduxImmutable的技术栈。 GitHub - chvin/react-tetr…

使用Canvas制作画板

使用Canvas制作画板 在本篇技术博客中&#xff0c;我们将使用JavaScript和Canvas技术来创建一个简单的画板应用程序。这个画板将允许用户在一个画布上绘制线条&#xff0c;使用橡皮擦擦除绘制的内容&#xff0c;更改线条的颜色和宽度&#xff0c;并支持撤销和重做功能。 准备…

go interface和nil可以比较吗?

2个 interface 比较 Go语言中&#xff0c;interface的内部实现包含了 2 个字段&#xff0c;类型 T 和 值V&#xff0c;interface 可以使用 或 ! 进行比较。 2 个 interface 相等有以下两种情况&#xff1a; 两个 interface 均等于 nil &#xff08;此时 V 和 T 都处于 unse…

检查 CPU 的上下文切换

一.什么是cpu上下文切换 CPU 上下文切换是操作系统在多任务环境下管理进程的一项关键任务。在现代计算机系统中&#xff0c;有多个进程同时运行&#xff0c;每个进程都需要一定的 CPU 时间来执行其任务。由于 CPU 在某一时刻只能执行一个进程的指令&#xff0c;因此操作系统需…

MySQL内置函数使用说明

MySQL函数使用说明 MySQL 是一个流行的关系型数据库管理系统&#xff0c;它提供了许多内置函数来处理和操作数据。这些函数可以简化数据库查询和操作的过程&#xff0c;提高代码的可读性和效率。以下是一些常见的 MySQL 内置函数及其使用说明和示例。 数值函数 ABS() 函数原…

静态资源导入探究

静态资源可以在哪里找呢&#xff1f;我们看看源码 从这个类进去 里面有个静态类 WebMvcAutoConfigurationAdapter 有个配置类&#xff0c;将这个类的对象创建并导入IOC容器里 这个静态类下有个方法 addResourceHandlers(ResourceHandlerRegistry registry)静态资源处理器 若自…

[软件工程] 架构映射战略设计方案模板

3 系统上下文 结合全局分析阶段获得的价值需求&#xff08;利益相关者、系统愿景、系统范围&#xff09;确定系统上下文&#xff0c;体现用户、目标系统与伴生系统之间的关系。 3.1 概述 绘制系统上下文图&#xff0c;明确解空间的系统边界。 3.2 系统协作业务流程1…n 根据全局…

从零实现深度学习框架——Transformer从菜鸟到高手(一)

引言 &#x1f4a1;本文为&#x1f517;[从零实现深度学习框架]系列文章内部限免文章&#xff0c;更多限免文章见 &#x1f517;专栏目录。 本着“凡我不能创造的&#xff0c;我就不能理解”的思想&#xff0c;系列文章会基于纯Python和NumPy从零创建自己的类PyTorch深度学习框…

【环境配置】Windows下WSL将ubuntu挪位置-系统盘清理

问题–垃圾太多&#xff0c;系统盘空间占用太大 最近 C 盘空间暴涨&#xff0c;用工具 WinDirStat-强烈推荐的工具 查看发现 WSL 子系统占用了6个多 G 的空间&#xff0c;遂想办法挪个位置&#xff1b; 【关键字】将 Windows 里的子系统挪到非系统盘 D 盘&#xff1b; 解决 打…

Redis 序列化器和持久化

Redis 序列化器 针对数据的序列化/反序列化提供了多种可选择策略 比如RedisSerializer&#xff0c;接下来我们详细看看 1、JdkSerializationRedisSerializer 用于 POJO 对象的存取场景&#xff0c;使用 JDK 本身序列化机制&#xff0c;将 pojo 类通过ObjectInputStream/Object…

生产服务器突然本机无法访问本机IP的端口

生产服务器突然本机无法访问本机IP的端口 一、现象描述 生产服务器突然无法访问自己本机IP地址的端口&#xff0c;通过localhost或者127.0.0.1都可以正常访问 二、问题分析 服务器是搭建在虚拟机上面&#xff0c;起初由于服务器内存不足的原因&#xff0c;导致了服务器故障无…