gpio中断

本文详细解释了中断在计算机硬件和操作系统中的作用,介绍了中断的概念、中断流程,特别关注了GPIO中断在嵌入式系统中的应用,包括中断触发模式和驱动实现。通过实例展示了如何观察和处理中断,以及如何在Linux环境中检查中断情况。
摘要由CSDN通过智能技术生成

中断概念

中断(Interrupt)是计算机硬件和操作系统中的一个重要概念,它能够使CPU在执行任务时暂停当前的运行,切换上下文从而响应硬件事件,处理输入输出数据或者承担其它任务,随后重新回到原来的上下文继续执行。这种机制使得计算机能够响应外部事件,并根据特定情况实时做出相应处理,是操作系统和应用程序正常运行的基础。

举一个实际的例子,比如当你在电脑上运行程序时,CPU在执行程序的指令,但是你突然按下了一个键盘上的按键,这时就会触发键盘对的中断信号,使得CPU暂停执行程序,切换上下文,去处理按键的输入信号,并通知对应的程序按键的具体信息,然后CPU会重新回到原来的上下文,结合应用程序运行状态继续执行指令。这个过程就是一个典型的中断流程,通过中断机制,计算机能够响应丰富多样的事件,从而控制设备的输入/输出、自动化控制、数据处理和通信等等。

简单说明一下,中断就是让计算机在做事情时候,停下来做其他事情,就叫中断。

查看中断情况

这里用xshell在Linux环境下演示

输入指令:cat /proc/interrupts

gpio中断

GPIO中断(GPIO Interrupt)是指在嵌入式系统中,通过将硬件中断与GPIO(通用输入/输出)引脚连接起来,使得在GPIO引脚发生电平变化时,能够触发相应的中断处理。这种机制使得系统能够对GPIO引脚的状态变化做出实时响应,从而实现对硬件设备的控制和数据采集等功能。

例如,在树莓派(Raspberry Pi)中,可以使用GPIO引脚来连接外部设备,如按键、传感器、显示屏等等。通过配置GPIO引脚为输入模式,并将其与中断连接,可以实现对外部设备的状态进行实时监测,一旦设备状态发生变化,就能够触发中断,通知系统进行相应处理。例如,当按键被按下时,GPIO引脚的电平会发生变化,从而触发中断,系统就可以在中断处理函数中执行相应的操作,如启动计时器、记录事件等等。

gpio中断的四种模式

在硬件中断处理中,不同的触发方式描述了外部信号引起中断的具体时机和条件。下面是四种常见的触发方式的区别:

  1.  上升沿触发(IRQF_TRIGGER_RISING):当外部信号从低电平(0)变为高电平(1)时触发中断。适用于需要在信号从低电平变为高电平时进行处理的情况。
  2.  下降沿触发(IRQF_TRIGGER_FALLING):当外部信号从高电平(1)变为低电平(0)时触发中断。适用于需要在信号从高电平变为低电平时进行处理的情况。
  3.  高电平触发(IRQF_TRIGGER_HIGH):当外部信号保持在高电平时触发中断。适用于需要当信号保持在高电平时进行处理的情况。
  4.  低电平触发(IRQF_TRIGGER_LOW):当外部信号保持在低电平时触发中断。适用于需要当信号保持在低电平时进行处理的情况。

根据实际情况和外部信号变化的时机,可以选择适合的触发方式来实现对中断的响应和处理。

驱动实现gpio中断

//添加头文件
#include <linux/init.h>
#include <linux/module.h>
#include <linux/gpio.h>
#include <linux/uaccess.h>
#include <linux/interrupt.h>

/*确定gpio的号*/
#define GPIO_PIN_49 45    

static int interrupt_major;
static int ret = 0;
static int irq1;

static struct class *interrupt_cls;

struct work_struct key_work_0;

/*中断下半部*/
void key_do_work_0(struct work_struct *work)
{
	printk(KERN_CRIT "key1 dowm irq headler!\n");
}

/*中断上半部*/
static irqreturn_t key1_irq_handler(int irqe, void *dev_id)
{
	printk(KERN_CRIT "key1 irq handler!\n");
	//唤起key_work工作队列
	schedule_work(&key_work_0);
	return IRQ_HANDLED;
}

const struct file_operations interrupt_fops = {};

//实现装载入口函数和卸载入口函数
static __init int interrupt_drv_v1_init(void)
{
	printk("----^v^-----interrupt drv v1 init\n");
	//①、申请主设备号
	//参数1----需要的主设备号,>0静态分配, ==0自动分配
	//参数2----设备的描述 信息,体现在cat /proc/devices, 一般自定义
	//参数3----文件描述集合
	//返回值,小于0报错
	interrupt_major = register_chrdev(0, "interrupt_drv_v1", &interrupt_fops);
	if (interrupt_major < 0)
	{
		printk("register chrdev faile!\n");
		return interrupt_major;
	}

	//②、自动创建设备节点
	//创建设备的类别
	//参数1----设备的拥有者,当前模块,直接填THIS_MODULE
	//参数2----设备类别的名字,自定义
	//返回值:类别结构体指针,其实就是分配了一个结构体空间
	interrupt_cls = class_create(THIS_MODULE, "interrupt_class");

	//③、创建设备
	//参数1----设备对应的类别
	//参数2----当前设备的父类,直接填NULL
	//参数3----设备节点关联的设备号
	//参数4----私有数据直接填NULL
	//参数5----设备节点的名字
	device_create(interrupt_cls, NULL, MKDEV(interrupt_major, 0), NULL, "myinterrupt%d", 0);

	//⑤、获取中断号
	irq1 = gpio_to_irq(GPIO_PIN_49);

	printk(" gpio irq1 = %d\n", irq1);

	//⑥、申请中断
	/*
	 * 参数1--中断号码---为哪个中断设置处理方法
	 * 参数2--中断的处理函数
	 * 参数3--中断的触发方式
	 * #define IRQF_TRIGGER_NONE    0x00000000 		无触发中断(采用默认的或之前设置的触发方式)
	 * #define IRQF_TRIGGER_RISING  0x00000001 		指定中断触发类型:上升沿有效
	 * #define IRQF_TRIGGER_FALLING 0x00000002		中断触发类型:下降沿有效
	 * #define IRQF_TRIGGER_HIGH    0x00000004		指定中断触发类型:高电平有效
	 * #define IRQF_TRIGGER_LOW     0x00000008		指定中断触发类型:低电平有效
	 * #define IRQF_TRIGGER_MASK   (IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)
	 * #define IRQF_TRIGGER_PROBE   0x00000010		触发式检测中断
	 * 参数4--中断的描述--自定义
	 * 参数5--传递给中断处理函数的参数
	 * 返回值--出错小于0 正确为0
	 */
	ret = request_irq(irq1, key1_irq_handler, IRQF_TRIGGER_FALLING, "interrupt_key1", NULL);
	if (ret < 0)
	{
		printk("request irq1 fail!\n");
		return ret;
	}

	//在key_work工作队列中添加一个key_do_work任务
	INIT_WORK(&key_work_0, key_do_work_0);
	return 0;
}

//实现装载入口函数和卸载入口函数
static __exit void interrupt_drv_v1_exit(void)
{
	printk("----^v^-----interrupt drv v1 exit\n");

	cancel_work_sync(&key_work_0);

	//释放irq
	free_irq(irq1, NULL);

	//删除设备
	device_destroy(interrupt_cls, MKDEV(interrupt_major, 0));
	//删除类
	class_destroy(interrupt_cls);
	//注销主设备号
	unregister_chrdev(interrupt_major, "interrupt_drv_v1");
}

//申明装载入口函数和卸载入口函数
module_init(interrupt_drv_v1_init);
module_exit(interrupt_drv_v1_exit);

//添加GPL协议
MODULE_LICENSE("GPL");
MODULE_AUTHOR("msxbo");

代码编译一下就可以用了,只需要更改gpio号即可

驱动运行

打开中断情况

中断多了一个,中断号为69,第二个数字1代表已经中断一次。

然后我用米联客的开发板进行gpio中断测试,用一根杜邦线放在gpio49和3.3v上,就会发现

xshell打印出

我们再输入指令看看中断情况

我们可以看到成功中断9次

总结

gpio中断看三步

  • 先看下注册没注册上这个中断
  • 再看复用的对不对,是不是gpio功能
  • 再看按键按的时候触发了没有
  • 24
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值