【LV15 day14 中断处理:按键驱动程序编写】

一、什么是中断

一种硬件上的通知机制,用来通知CPU发生了某种需要立即处理的事件

分为:

  1. 内部中断 CPU执行程序的过程中,发生的一些硬件出错、运算出错事件(如分母为0、溢出等等),不可屏蔽
  2. 外部中断 外设发生某种情况,通过一个引脚的高、低电平变化来通知CPU (如外设产生了数据、某种处理完毕等等)

二、中断处理原理

任何一种中断产生,CPU都会暂停当前执行的程序,跳转到内存固定位置执行一段程序,该程序被称为总的中断服务程序,在该程序中区分中断源,然后进一步调用该中断源对应的处理函数。

中断源对应的处理函数被称为分中断处理程序,一般每一个分中断处理程序对应一个外设产生的中断

写驱动时,如果外设有中断,则需要编写一个函数(分中断处理程序)来处理这种中断

三、中断接口

3.1 中断申请

int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,const char *name, void *dev)
/*
参数:
    irq:所申请的中断号
    handler:该中断号对应的中断处理函数
    flags:中断触发方式或处理方式 
        触发方式:IRQF_TRIGGER_NONE      //无触发
                 IRQF_TRIGGER_RISING    //上升沿触发
                 IRQF_TRIGGER_FALLING  //下降沿触发
                IRQF_TRIGGER_HIGH   //高电平触发
                IRQF_TRIGGER_LOW        //低电平触发
        处理方式:
               IRQF_DISABLED        //用于快速中断,处理中屏蔽所有中断
                IRQF_SHARED       //共享中断
        name:中断名 /proc/interrupts
        dev:传递给中断例程的参数,共享中断时用于区分那个设备,一般为对应设备的结构体地址,无共享中断时写NULL
返回值:成功:0 失败:错误码
*/

3.2 中断释放

void free_irq(unsigned int irq, void *dev_id)/*
功能:释放中断号
参数:
    irq:设备号
    dev_id:共享中断时用于区分那个设备一般强转成设备号,无共享中断时写NULL
*/

3.3 中断处理函数原型

typedef irqreturn_t (*irq_handler_t)(int, void *);
/*
参数:
    int:中断号
    void*:对应的申请中断时的dev_id
返回值:
    typedef enum irqreturn irqreturn_t; //中断返回值类型
    enum irqreturn {
        IRQ_NONE    = (0 << 0),
        IRQ_HANDLED = (1 << 0),
        IRQ_WAKE_THREAD = (1 << 1),
    };
    返回IRQ_HANDLED表示处理完了,返回IRQ_NONE在共享中断表示不处理
*/

四、按键驱动

按键原理图:
在这里插入图片描述

exynos4412-fs4412.dts中增加节点

mykey2_node {
    compatible = "mykey2,key2";
    key2-gpio = <&gpx1 1 0>;//gpx1-1
    interrupt-parent = <&gpx1>;
    interrupts = <1 3>;//组内第二个<0 25 0> // 3 ->11 上升沿触发以及下降沿触发
};

首先初始化其中包括设备号分配,pnode指向设备节点,gpio口绑定,中断号分配
中断申请,等待队列初始化。

int __init fs4412key2_init(void)
{
	int ret = 0;
	dev_t devno = MKDEV(major,minor);
	struct device_node *pnode=NULL;
	pnode=of_find_node_by_path("/mykey2_node");
	if(NULL==pnode)
	{
		printk("find node failed.\n");
		return -1;
	}
	pgmydev=(struct fs4412key2_dev *)kmalloc(sizeof(struct fs4412key2_dev),GFP_KERNEL);
	if(NULL==pgmydev)
	{
		printk("kmalloc fs4412key2 pgmydev failed.\n");
		return -1;
	}
	pgmydev->gpio=of_get_named_gpio(pnode,"key2-gpio",0);
	pgmydev->irqno=irq_of_parse_and_map(pnode,0);
	/*申请设备号*/
	ret = register_chrdev_region(devno,fs4412key2_num,"fs4412key2");
	if(ret)
	{
		ret = alloc_chrdev_region(&devno,minor,fs4412key2_num,"fs4412key2");
		if(ret)
		{
			printk("get devno failed\n");
			kfree(pgmydev);
			return -1;
		}
		major = MAJOR(devno);//容易遗漏,注意
	}


		/*给struct cdev对象指定操作函数集*/	
		cdev_init(&pgmydev->mydev,&myops);

		/*将struct cdev对象添加到内核对应的数据结构里*/
		pgmydev->mydev.owner = THIS_MODULE;
		cdev_add(&pgmydev->mydev,devno,1);

	init_waitqueue_head(&pgmydev->rq);

	spin_lock_init(&pgmydev->lock);
	
	ret=request_irq(pgmydev->irqno,key2_irq_handle,IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING,"fs4412key2",pgmydev);
	if(ret)
	{
	printk("request_irq failed.\n");
	kfree(pgmydev);
	pgmydev=NULL;
	return -1;
	}
	return 0;
}

void __exit fs4412key2_exit(void)
{
	dev_t devno = MKDEV(major,minor);
	free_irq(pgmydev->irqno,pgmydev);
	cdev_del(&pgmydev->mydev);	
	unregister_chrdev_region(devno,fs4412key2_num);
}

定义结构体
注意一个case:这里编译时一直报错int前面少写了;
检查后发现是fs4412_key2.h结构体后面少了一个;

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/of.h>
#include <linux/interrupt.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/mutex.h>
#include <linux/poll.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/irq.h>
#include "fs4412_key.h"
int major = 11;
int minor = 0;
int fs4412key2_num= 1;

struct fs4412key2_dev
{
	struct cdev mydev;
	int gpio;
	int irqno;
	int newflag;//用于判断是否有数据可以读取//
	wait_queue_head_t rq;
	struct keyvalue data;
	spinlock_t lock;
};
struct fs4412key2_dev *pgmydev=NULL;

int fs4412key2_open(struct inode *pnode,struct file *pfile)
{
	pfile->private_data =(void *) (container_of(pnode->i_cdev,struct fs4412key2_dev,mydev));
	printk("fs4412key2_open is called\n");
	return 0;
}

int fs4412key2_close(struct inode *pnode,struct file *pfile)
{

	return 0;
}
//编写read函数//
ssize_t fs4412key2_read(struct file *pfile,char __user *puser,size_t count,loff_t *p_pos)
{
	struct fs4412key2_dev *pmydev = (struct fs4412key2_dev *)pfile->private_data;
	int size = 0;
	int ret = 0;
	spin_lock(&pmydev->lock);
	if(!pmydev->newflag)
	{

		if(pfile->f_flags & O_NONBLOCK)
		{//非阻塞

			spin_unlock(&pmydev->lock);
			printk("O_NONBLOCK No Data Read\n");
			return -1;
		}
		else
		{//阻塞

			spin_unlock(&pmydev->lock);
			ret = wait_event_interruptible(pmydev->rq,pmydev->newflag==1);
			if(ret)
			{
				printk("Wake up by signal\n");
				return -ERESTARTSYS;
			}
			spin_lock(&pmydev->lock);
		}
	}
	
	if(count > sizeof(struct keyvalue))
	{
		size = sizeof(struct keyvalue);
	}
	else
	{
		size = count;
	}
	
	ret = copy_to_user(puser,&pmydev->data,size);
	if(ret)
	{
		
		spin_unlock(&pmydev->lock);
		printk("copy_to_user failed\n");
		return -1;
	}
	pmydev->newflag= 0;
	spin_unlock(&pmydev->lock);
	return size;
}

unsigned int fs4412key2_poll(struct file *pfile, poll_table *ptb)
{
	struct fs4412key2_dev *pmydev = (struct fs4412key2_dev *)pfile->private_data;
	unsigned int mask=0;
	
	poll_wait(pfile,&pmydev->rq,ptb);
	spin_lock(&pmydev->lock);
	if(pmydev->newflag)
	{
	mask |= POLLIN | POLLRDNORM;
	}
	spin_unlock(&pmydev->lock);
	return mask;
}
struct file_operations myops = {
	.owner = THIS_MODULE,
	.open = fs4412key2_open,
	.release = fs4412key2_close,
	.read = fs4412key2_read,
	.poll=fs4412key2_poll,
};

//中断处理函数
irqreturn_t key2_irq_handle(int no,void* arg)
{	
	struct fs4412key2_dev *pmydev = (struct fs4412key2_dev *)arg;
	int status=0;
	int status1=0;
	int status2=0;
	status1=gpio_get_value(pmydev->gpio);
	mdelay(1);
	status2=gpio_get_value(pmydev->gpio);
	if(status1!=status2)
	{
		return IRQ_NONE;
	}//按键防抖//
	status=status1;
	spin_lock(&pmydev->lock);
	if(status==pmydev->data.status)
	{
	spin_unlock(&pmydev->lock);
	return IRQ_NONE;
	}
	pmydev->data.code=KEY2;
	pmydev->data.status=status;
	pmydev->newflag=1;
	spin_unlock(&pmydev->lock);
	wake_up(&pmydev->rq);
	return 0;
}
fs4412_key.h
#ifndef FS4412_KEY_H
#define FS4412_KEY_H
enum KEYCODE
{
	KEY2=1002,
	KEY3,
	KEY4,
};
enum KEYSTATUS
{
	KEY_DOWN=0,
	KEY_UP,
};
struct keyvalue
{
	int code;
	int status;
};
#endif
key2test_app.c
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include "fs4412_key.h"
int main(int argc,char *argv[])
{
	int fd = -1;
	struct keyvalue keydata = {0};
	int ret=0;
	if(argc < 2)
	{
		printf("The argument is too few\n");
		return 1;
	}

	fd = open(argv[1],O_RDWR);
	if(fd < 0)
	{
		printf("open %s failed\n",argv[1]);
		return 2;
	}
	while((ret=read(fd,&keydata,sizeof(keydata)))==sizeof(keydata))
	{
	if(keydata.status==KEY_DOWN)
	{
	printf("key2 is down.\n");
	}
	else
	{
	printf("key2 is up.\n");
	}
	}

	close(fd);
	fd = -1;
	return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

一、SpringBoot3 介绍

本章概要 SpringBoot3 简介系统要求快速入门入门总结 1.1 SpringBoot3 简介 此处使用 SpringBoot 版本&#xff1a;3.0.5 https://docs.spring.io/spring-boot/docs/current/reference/html/getting-started.html 无论使用XML、注解、Java配置类还是他们的混合用法&#xff0…

C语言学习--字符串和整型的转换

目录 整型→字符串 方法1&#xff1a;利用‘0’将单个数字转字符 方法2&#xff1a;利用sprintf函数 方法3&#xff1a;利用itoa函数 字符串→整型 方法1&#xff1a;利用-‘0’直接转换 方法2&#xff1a;利用atoi函数 整型→字符串 整形数据变成字符串&#xff0c;最…

数据结构从入门到精通——归并排序

归并排序 前言一、归并排序的基本思想二、归并排序的特性总结三、归并排序的动画展示四、递归实现归并排序的具体代码展示五、非递归实现归并排序 前言 归并排序是一种分治策略的排序算法。它将一个序列分为两个等长&#xff08;几乎等长&#xff09;的子序列&#xff0c;分别…

百度百科审核不通过全攻略,一看就会!

在撰写百度百科词条时&#xff0c;遇到审核不通过的情况可能会让人感到沮丧。然而&#xff0c;我们并不需要灰心&#xff0c;而是要通过一些方法来改善文章质量&#xff0c;使其符合百度百科的要求。腾轩科技传媒分享百度百科审核不通过全攻略&#xff0c;一看就会&#xff01;…

Docker Stack(堆栈) 部署多服务集群,多服务编排

1、Docker Stack简介 Docker Stack(堆栈) 是在 Swarm 上管理服务堆栈的工具。而在以前文章docker swarm集群搭建 介绍的 Docker Swarm 只能实现对单个服务的简单部署&#xff0c;于是就引出了Docker Stack。 上面我们介绍到 docker-compose&#xff1a;可以在一台机器上使用…

出差补助怎么发放更高效省心?这套攻略快看看

交补、餐补、话补等各类补助场景分散&#xff0c;无法实现一站式统筹管理。不仅如此&#xff0c;补贴核算也总是需要员工提供各类凭证&#xff0c;经过财务反复核实才能发放……出差发放补助原本是为了传递企业关怀&#xff0c;鼓励员工积极出差&#xff0c;由于发放和管理不当…

6 Spring-AOP

文章目录 1&#xff0c;AOP简介1.1 什么是AOP?1.2 AOP作用1.3 AOP核心概念 2&#xff0c;AOP入门案例2.1 需求分析2.2 思路分析2.3 环境准备2.4 AOP实现步骤步骤1:添加依赖步骤2:定义接口与实现类步骤3:定义通知类和通知步骤4:定义切入点步骤5:制作切面步骤6:将通知类配给容器…

新能源电车充电桩运营管理分析

摘要&#xff1a;近年来&#xff0c;我国大力推进新能源公共交通的发展&#xff0c;制定了一系列相关政策法规。作为公共充电设施的新能源充电桩也得到了发展和普及&#xff0c;其在新能源领域发挥着重要的保障作用。在当前&#xff0c;充电桩的管理还存在许多短板&#xff0c;…

MySql实战--全局锁和表锁 :给表加个字段怎么有这么多阻碍

今天我要跟你聊聊MySQL的锁。数据库锁设计的初衷是处理并发问题。作为多用户共享的资源&#xff0c;当出现并发访问的时候&#xff0c;数据库需要合理地控制资源的访问规则。而锁就是用来实现这些访问规则的重要数据结构。 根据加锁的范围&#xff0c;MySQL里面的锁大致可以分成…

开放式耳机性价比高的品牌有哪些呢?五大高性价比选购清单

不入耳开放式蓝牙耳机近两年开始火起来了&#xff0c;因为它佩戴的舒适性和安全性两方面受到了很多人的关注。开放式的设计&#xff0c;就算不放进耳朵里也能听歌&#xff0c;同时加上它独特的空气传导的传声途径&#xff0c;整体的音质还是很不错的。不压耳&#xff0c;不涨耳…

Redis 6.0.8版本下载

简介&#xff1a;Java领域优质创作者楠木 分享Java项目、简历模板、学习资料、面试题库 想必大家在下载redis之前已经逛了很多教程了&#xff0c;可能不尽如意&#xff0c;找不到自己的想要的版本。既然刷到了我的这条博客&#xff0c;说明你是幸运的&#xff01; Redis6.0.8的…

【Godot4自学手册】第二十七节自定义状态机完成看守地宫怪物

本节&#xff0c;我将使用自定义状态机实现看守地宫怪物&#xff0c;完成了基础类State&#xff0c;状态机类StateMachine的编码&#xff0c;实现了怪物的闲置巡逻类、追踪类和攻击类&#xff0c;以及对应动画等。这节代码有点多&#xff0c;不过还好&#xff0c;代码比较简单。…

C语言 汉诺塔问题

目录 1.前言 2.问题描述 3.问题分析 4.定义一个主函数 5.再定义一个hanoi函数 6.所有代码 7.结语 1.前言 汉诺塔问题&#xff0c;是心理学实验研究常用的任务之一。该问题的主要材料包括三根高度相同的柱子和一些大小及颜色不同的圆盘&#xff0c;三根柱子分别为起始柱A…

大数据入门(一)

大数据主要要解决&#xff1a;海量数据的采集&#xff0c;存储&#xff0c;分析计算问题。 大数据的特点&#xff1a;大量&#xff08;数据量大&#xff09;&#xff0c;高速&#xff08;数据量的累积越来越快&#xff09;&#xff0c;多样&#xff08;结构化数据和非结构化数…

基于nodejs+vue医院综合管理系统实现与设计python-flask-django-php

第一&#xff0c;研究分析当下主流的nodejs技术&#xff0c;结合医院日常管理方式&#xff0c;进行医院综合管理系统的数据库设计&#xff0c;设计医院综合管理系统功能&#xff0c;并对每个模块进行说明。 第二&#xff0c;陈列说明该系统实现所采用的架构、系统搭建采用的服务…

【办公类-50-01】20240326判断随机写的“日期”是否是双休日

背景需求&#xff1a; 领导让我做设计本学期的科研培训方案。 我在2-6月随机写每月的培训日期&#xff0c;重新制定了主题 因为科研培训不可能在双休日&#xff0c;因此我希望本次活动的随机写的日期&#xff0c;不能是双休日。 我想用Python判断一下这些预设的日期是否是双休…

SpringBoot—@ConditionalOnBean与@ConditionalOnClass

一、ConditionalOnBean概念 需求场景 比如下面一种场景&#xff0c;我在实例化People对象的时候&#xff0c;需要注入一个City对象。这个时候问题来了&#xff0c;如果city没有实例化&#xff0c;那么下面就会报空指针或者直接报错。 所以这里需求很简单&#xff0c;就是当前c…

JS加密解密之应用如何保存到桌面书签

前言 事情起因是这样的&#xff0c;有个客户解密了一个js&#xff0c;然后又看不懂里边的一些逻辑&#xff0c;想知道它是如何自动拉起谷歌浏览器和如何保存应用到书签的&#xff0c;以及如何下载应用的。继而诞生了这篇文章&#xff0c;讲解一下他的基本原理。 渐进式Web应用…

电源模块 YULIN俞霖科技DC/DC电源模块 直流升压 高压稳压

Features 最低工作电压&#xff1a;0.7V电压隔离&#xff1a;1000VDC /3000VDC 平均无故障时间&#xff1a; > 800,000 小时短路与电弧保护无最低负载要求&#xff1a;可空载工作输入电压&#xff1a;5、12、15、24VDCOutput 100,200、300、400、500 、600、800、 1000、1…

kubernetes-k9s一个基于Linux 终端的集群管理工具

效果预览 下载 github 版本 此文档使用的版本是 v0.32.4&#xff0c;下载地址&#xff1a; https://github.com/derailed/k9s/releases/download/v0.32.4/k9s_linux_amd64.rpm 安装 rpm -ivh k9s_linux_amd64.rpm使用 启动 终端直接执行命令 k9s k9s基本操作 1 选择目…