read()
函数读取终端输入,或者使用更高级的库如 ncurses 来处理。Linux 按键中断
背景与简介
在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 按键中断”的问题就介绍到这了,希望介绍的几点解答对大家有用,有任何问题和不懂的,欢迎各位朋友在评论区讨论,给我留言。
原创文章,作者:未希,如若转载,请注明出处:https://www.kdun.com/ask/1311952.html
本网站发布或转载的文章及图片均来自网络,其原创性以及文中表达的观点和判断不代表本网站。如有问题,请联系客服处理。
发表回复