当前位置:首页 > 行业动态 > 正文

如何在 Linux 系统中处理按键中断?

linux 按键中断通常通过捕获键盘事件来实现,可以使用如 read() 函数读取终端输入,或者使用更高级的库如 ncurses 来处理。

Linux 按键中断

如何在 Linux 系统中处理按键中断?  第1张

背景与简介

在Linux操作系统中,中断是一种重要的机制,用于处理硬件事件,当外部设备(如键盘、鼠标等)触发中断时,CPU会暂停当前正在执行的程序,转而执行预先定义的中断处理程序,本文将详细介绍如何在Linux环境下实现按键中断功能,包括获取中断号、申请中断以及编写中断处理函数。

按键中断代码实现

获取中断号

需要获取按键对应的中断号,以下是示例代码:

#include <linux/interrupt.h>
int gpio_to_irq(unsigned gpio);

申请中断

使用request_irq函数申请中断,该函数原型如下:

int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
                const char *name, void *dev_id);

irq: 中断编号。

handler: 中断服务函数指针。

flags: 中断的标志,用来描述中断的基本特征。

name: 中断名字。

dev_id: 传递给中断服务函数的参数。

示例代码:

int request_irq(gpio_to_irq(GPIO_PIN), key_irq_handler, IRQF_TRIGGER_RISING, "key_irq", &key_dev);

实现中断处理函数

中断处理函数的原型如下:

typedef irqreturn_t (*irq_handler_t)(int, void *);

示例代码:

static irqreturn_t key_irq_handler(int irq, void *dev_id) {
    struct key_dev *key_dev = (struct key_dev *)dev_id;
    int value = gpio_get_value(key_dev->gpio_number);
    if (value == 0) { // 按键按下
        printk("KEY Pressed!
");
    } else { // 按键释放
        printk("KEY Released!
");
    }
    return IRQ_HANDLED;
}

完整代码示例

以下是一个完整的按键中断驱动程序示例:

#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 // 无效的按键值
struct key_dev {
    int gpio_number;        // IO编号
    int interrupt_number;   // 中断号
    unsigned char value;    // 键值
    unsigned char name[50]; // 按键名字
    irqreturn_t (*handler)(int, void*); // 中断处理函数
};
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_num", &(dev->key[i].gpio_number));
        if (ret < 0) {
            printk("can't get gpio
");
            goto read_gpio_failed;
        }
        /* 3. 申请中断 */
        ret = request_irq(gpio_to_irq(dev->key[i].gpio_number), key0_irq_handler, IRQF_TRIGGER_RISING, IRQ_NAME, &dev->key[i]);
        if (ret) {
            printk("Failed to request IRQ %d
", gpio_to_irq(dev->key[i].gpio_number));
            goto request_irq_failed;
        }
        /* 4. 注册中断处理函数 */
        dev->key[i].handler = key0_irq_handler;
    }
    return ret;
read_gpio_failed:
request_irq_failed:
find_dev_node:
    return -ENODEV;
}

归纳与FAQs

常见问题解答(FAQs)

1. 如何申请和释放中断?

申请中断使用request_irq函数,释放中断使用free_irq函数,示例如下:

int request_irq(unsigned int irq, flags, irq_handler_t handler, const char *name, void *dev);
void free_irq(unsigned int irq, flags, void *dev);

2. 如何处理按键消抖?

可以使用定时器或工作队列来实现按键消抖,使用tasklet或workqueue来延迟处理按键事件。

到此,以上就是小编对于“linux 按键中断”的问题就介绍到这了,希望介绍的几点解答对大家有用,有任何问题和不懂的,欢迎各位朋友在评论区讨论,给我留言。

0