中断概念
中断(Interrupt)是计算机硬件和操作系统中的一个重要概念,它能够使CPU在执行任务时暂停当前的运行,切换上下文从而响应硬件事件,处理输入输出数据或者承担其它任务,随后重新回到原来的上下文继续执行。这种机制使得计算机能够响应外部事件,并根据特定情况实时做出相应处理,是操作系统和应用程序正常运行的基础。
举一个实际的例子,比如当你在电脑上运行程序时,CPU在执行程序的指令,但是你突然按下了一个键盘上的按键,这时就会触发键盘对的中断信号,使得CPU暂停执行程序,切换上下文,去处理按键的输入信号,并通知对应的程序按键的具体信息,然后CPU会重新回到原来的上下文,结合应用程序运行状态继续执行指令。这个过程就是一个典型的中断流程,通过中断机制,计算机能够响应丰富多样的事件,从而控制设备的输入/输出、自动化控制、数据处理和通信等等。
简单说明一下,中断就是让计算机在做事情时候,停下来做其他事情,就叫中断。
查看中断情况
这里用xshell在Linux环境下演示
输入指令:cat /proc/interrupts
gpio中断
GPIO中断(GPIO Interrupt)是指在嵌入式系统中,通过将硬件中断与GPIO(通用输入/输出)引脚连接起来,使得在GPIO引脚发生电平变化时,能够触发相应的中断处理。这种机制使得系统能够对GPIO引脚的状态变化做出实时响应,从而实现对硬件设备的控制和数据采集等功能。
例如,在树莓派(Raspberry Pi)中,可以使用GPIO引脚来连接外部设备,如按键、传感器、显示屏等等。通过配置GPIO引脚为输入模式,并将其与中断连接,可以实现对外部设备的状态进行实时监测,一旦设备状态发生变化,就能够触发中断,通知系统进行相应处理。例如,当按键被按下时,GPIO引脚的电平会发生变化,从而触发中断,系统就可以在中断处理函数中执行相应的操作,如启动计时器、记录事件等等。
gpio中断的四种模式
在硬件中断处理中,不同的触发方式描述了外部信号引起中断的具体时机和条件。下面是四种常见的触发方式的区别:
- 上升沿触发(IRQF_TRIGGER_RISING):当外部信号从低电平(0)变为高电平(1)时触发中断。适用于需要在信号从低电平变为高电平时进行处理的情况。
- 下降沿触发(IRQF_TRIGGER_FALLING):当外部信号从高电平(1)变为低电平(0)时触发中断。适用于需要在信号从高电平变为低电平时进行处理的情况。
- 高电平触发(IRQF_TRIGGER_HIGH):当外部信号保持在高电平时触发中断。适用于需要当信号保持在高电平时进行处理的情况。
- 低电平触发(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功能
- 再看按键按的时候触发了没有