如何正确处理Linux系统中的中断按键事件?

在Linux系统中,可以使用Ctrl+C组合键来中断正在执行的命令或程序。

Linux中断按键

在Linux操作系统中,中断是处理器响应异步事件的一种机制,当某个设备(例如键盘)产生中断时,CPU会暂停当前任务,处理该中断,然后返回继续执行之前的任务,这种机制对于实时系统或需要快速响应的系统尤为重要,本文将详细介绍如何在Linux环境下实现按键中断功能,包括硬件原理、驱动编写和实际应用示例。

如何正确处理Linux系统中的中断按键事件?

一、硬件原理

按键中断通常通过GPIO(通用输入输出)引脚来实现,当按键被按下或释放时,GPIO引脚的电平发生变化,从而触发中断,以正点原子阿尔法开发板为例,其KEY0按键连接到GPIO18引脚,具体过程如下:

1、按键按下:GPIO引脚检测到低电平信号。

2、按键释放:GPIO引脚恢复到高电平信号。

3、中断触发:根据配置的中断类型(上升沿、下降沿或双沿),触发相应的中断。

二、驱动编写

如何正确处理Linux系统中的中断按键事件?

为了处理按键中断,需要在Linux内核中编写相应的驱动程序,以下是一个简单的按键中断驱动程序示例:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#define IRQ_NAME "key_irq"
#define IRQ_CNT 1
#define KEY_NUM 1 
#define KEY0_VALUE 0x01  // key0按键值
#define INVAL_KEY_VALUE 0xFF  // 无效的按键值
/*key按键结构体 */
struct key_dev {
    int gpio_number;        // IO编号
    int interrupt_number;   // 中断号
    unsigned char value;    // 键值
    unsigned char name[50]; // 按键名字
    irqreturn_t (*handler)(int, void*); // 中断处理函数
};
/*imx6ull_irq设备结构体 */
struct irq_dev {
    dev_t devid;  // 主设备号+次设备号
    int major; // 主设备号
    int minor; // 次设备号
    struct cdev cdev;
    struct class* class;
    struct device* device;
    struct device_node *dev_node;// 设备节点
    struct key_dev key[KEY_NUM];
};
struct irq_dev irq;
/* 打开设备函数*/
static int irq_dev_open(struct inode *inode, struct file *filp)
{
    filp->private_data = &irq;
    return 0;
}
ssize_t irq_dev_read(struct file * filp, char __user * buf, size_t count, loff_t * ppos)
{
    return 0;
}
/* 关闭设备函数 */
int irq_dev_close(struct inode * inode, struct file * filp)
{
    return 0;
}
static const struct file_operations irq_fops = {
    .open = irq_dev_open,
    .owner = THIS_MODULE,
    .read = irq_dev_read,
    .release = irq_dev_close, 
};
/* 中断处理函数 */
static irqreturn_t key0_irq_handler(int irq, void *param)
{
    int value = 0;
    struct irq_dev* dev = (struct irq_dev*)param;
    //读取按键值
    value = gpio_get_value(dev->key[0].gpio_number);
    if(value == 0) //按键按下
    {
        printk("KEY0 Press!
");
    }
    else if(value == 1) //按键释放
    {
        printk("KEY0 Release!
");
    }
    return IRQ_HANDLED;
}
/*按键初始化 */
static int key_io_init(struct irq_dev* dev)
{
    int ret = 0;
    int i = 0;
    int n = 0;
    /*1.获取设备节点 */
    dev->dev_node = offind_node_by_path("/key");
    if(NULL == dev->dev_node)
    {
        printk("find dev_node failed!
");
        goto find_dev_node;
    }
    
    /*2.获取IO编号 */
    for(i=0; i< KEY_NUM; i++)
    {   
        ret = off_property_read_u32(dev->dev_node, "gpio", &(dev->key[i].gpio_number)); //获取按键对应的GPIO编号
        if(ret < 0) {
            printk("read irq failed!
");
            goto read_irq;
        }
        dev->key[i].name[0] = '