news 2026/1/10 18:59:31

中断下半部:延迟工作实验

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
中断下半部:延迟工作实验

一、该驱动程序的功能

这个驱动程序是基于 Linux 中断下半部的 “延迟工作” 机制,实现按键中断的消抖处理:当按键触发中断时,不会立即处理按键事件,而是调度一个 “延迟工作”(延迟指定时间,避开按键抖动的窗口期),待延迟时间结束后,再执行工作函数,以此过滤按键抖动导致的多次误触发,保证按键事件的有效识别。

二、实验完整步骤(含代码)

步骤 1:准备实验环境
  1. 确保已安装 Linux 内核源码(需与开发板内核版本一致)。
  2. 准备交叉编译工具链(适配开发板架构,如 ARM 架构的arm-linux-gnueabihf-)。
  3. 开发板端确保已开启 GPIO 中断支持(内核配置中启用对应 GPIO 子系统、工作队列子系统)。
步骤 2:编写驱动代码(文件名:interrupt.c
#include <linux/init.h> #include <linux/module.h> #include <linux/gpio.h> #include <linux/interrupt.h> #include <linux/workqueue.h> #include <linux/delay.h> // 定义工作队列、延迟工作 struct workqueue_struct *test_workqueue; struct delayed_work test_workqueue_work; // 1. 延迟工作对应的工作函数(中断下半部,延迟后执行) void test_work(struct work_struct *work) { msleep(100); // 模拟实际按键处理(如读取GPIO状态) printk("This is test_work (按键抖动已过滤,执行有效处理)\n"); } // 2. 中断处理函数(中断上半部,快速响应) irqreturn_t test_interrupt(int irq, void *args) { printk("This is test_interrupt (按键触发中断,调度延迟工作)\n"); // 调度延迟工作:在自定义工作队列上,延迟3秒(3*HZ,HZ是内核时钟节拍,默认1000) queue_delayed_work(test_workqueue, &test_workqueue_work, 3 * HZ); return IRQ_HANDLED; } static int irq; // 中断号 // 3. 驱动初始化函数 static int __init interrupt_irq_init(void) { int ret; // (1)将GPIO4转换为对应的中断号(假设按键接在GPIO4) irq = gpio_to_irq(4); printk("irq is %d\n", irq); // (2)申请中断 ret = request_irq(irq, test_interrupt, IRQF_TRIGGER_RISING, "test", NULL); if (ret < 0) { printk("request_irq is error\n"); return -1; } // (3)创建自定义工作队列 test_workqueue = create_workqueue("test_workqueue"); // (4)初始化延迟工作(绑定工作函数test_work) INIT_DELAYED_WORK(&test_workqueue_work, test_work); printk("interrupt_irq_init success\n"); return 0; } // 4. 驱动退出函数 static void __exit interrupt_irq_exit(void) { // (1)释放中断 free_irq(irq, NULL); // (2)同步取消延迟工作(确保工作函数执行完毕) cancel_delayed_work_sync(&test_workqueue_work); // (3)销毁工作队列 destroy_workqueue(test_workqueue); printk("bye bye\n"); } module_init(interrupt_irq_init); module_exit(interrupt_irq_exit); MODULE_LICENSE("GPL");
步骤 3:编写 Makefile(文件名:Makefile

makefile

obj-m += interrupt.o KERNELDIR ?= /path/to/your/kernel/source # 替换为你的内核源码路径 PWD := $(shell pwd) all: make -C $(KERNELDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- # 适配开发板架构 clean: make -C $(KERNELDIR) M=$(PWD) clean
步骤 4:编译驱动模块

在主机端执行命令:

make

编译完成后,会生成interrupt.ko驱动模块文件。

步骤 5:加载驱动到开发板
  1. interrupt.ko通过 U 盘、SSH 等方式传到开发板。
  2. 开发板端执行加载命令:
insmod interrupt.ko
  1. 查看驱动加载状态(可选):
lsmod | grep interrupt
步骤 6:测试驱动功能
  1. 按下与 GPIO4 连接的按键,触发中断。
  2. 查看内核打印信息(开发板端执行):
dmesg -w
  • 会先打印This is test_interrupt (按键触发中断,调度延迟工作)(中断上半部)。
  • 延迟 3 秒后,打印This is test_work (按键抖动已过滤,执行有效处理)(延迟工作的下半部)。
步骤 7:卸载驱动模块

测试完成后,开发板端执行卸载命令:

rmmod interrupt

同时通过dmesg可查看退出打印的bye bye

我以RK3568 开发板为例,带你完成 “按键 + 延迟工作” 的完整实验,从硬件接线到软件验证一步到位:

一、先确认:开发板 GPIO 引脚对应(以 RK3568 为例)

RK3568 的 GPIO 编号规则是:编号 = 组索引*32 + 子组索引*8 + 引脚号,常用按键实验引脚(以 “GPIO0_A4” 为例):

开发板引脚丝印内核 GPIO 编号说明
GPIO0_A44对应内核中gpio=4

二、硬件接线(按键部分)

只需要 1 个按键 + 杜邦线:

  1. 按键的一端接开发板的GPIO0_A4引脚;
  2. 按键的另一端接开发板的GND引脚(接地);
  3. (可选)若开发板 GPIO 无内部上拉,需在GPIO0_A43.3V之间接一个 10KΩ 上拉电阻(大部分 RK 开发板 GPIO 默认内部上拉,可省略)。

三、实验步骤(分硬件验证→驱动修改→编译测试)

步骤 1:先验证按键硬件是否正常(用户空间临时测试)

先通过sysfs确认 GPIO 能识别按键状态,避免硬件问题:

  1. 开发板终端执行(导出 GPIO4):
    echo 4 > /sys/class/gpio/export
  2. 配置 GPIO4 为输入模式:
    echo in > /sys/class/gpio/gpio4/direction
  3. 读取 GPIO4 电平(未按按键时,内部上拉应为1;按下按键时变为0):
    cat /sys/class/gpio/gpio4/value
    → 按下按键再执行cat,若 value 从10,说明硬件接线正常。
步骤 2:完善驱动代码(补充 GPIO 申请逻辑)

之前的驱动缺少 GPIO 申请步骤,需修改interrupt.c(确保 GPIO 资源不冲突):

#include <linux/init.h> #include <linux/module.h> #include <linux/gpio.h> #include <linux/interrupt.h> #include <linux/workqueue.h> #include <linux/delay.h> struct workqueue_struct *test_workqueue; struct delayed_work test_workqueue_work; int gpio_num = 4; // 对应GPIO0_A4 int irq; // 延迟工作函数 void test_work(struct work_struct *work) { int key_val = gpio_get_value(gpio_num); // 读取按键电平 printk("按键当前电平:%d(已过滤抖动)\n", key_val); } // 中断处理函数 irqreturn_t test_interrupt(int irq, void *args) { printk("按键触发中断,调度延迟工作(3秒后执行)\n"); // 调度延迟工作(延迟3秒,避开按键抖动) queue_delayed_work(test_workqueue, &test_workqueue_work, 3 * HZ); return IRQ_HANDLED; } static int __init interrupt_irq_init(void) { int ret; // 1. 申请GPIO if (gpio_request(gpio_num, "key_gpio") < 0) { printk("GPIO%d申请失败\n", gpio_num); return -EBUSY; } // 2. 配置GPIO为输入 if (gpio_direction_input(gpio_num) < 0) { printk("GPIO%d配置输入失败\n", gpio_num); gpio_free(gpio_num); return -EINVAL; } // 3. 获取GPIO对应的中断号 irq = gpio_to_irq(gpio_num); printk("按键对应的中断号:%d\n", irq); // 4. 申请中断(触发方式:下降沿,对应按键按下时电平从1→0) ret = request_irq(irq, test_interrupt, IRQF_TRIGGER_FALLING, "key_irq", NULL); if (ret < 0) { printk("中断申请失败\n"); gpio_free(gpio_num); return -1; } // 5. 创建工作队列+初始化延迟工作 test_workqueue = create_workqueue("test_workqueue"); INIT_DELAYED_WORK(&test_workqueue_work, test_work); printk("驱动加载成功\n"); return 0; } static void __exit interrupt_irq_exit(void) { free_irq(irq, NULL); cancel_delayed_work_sync(&test_workqueue_work); destroy_workqueue(test_workqueue); gpio_free(gpio_num); // 释放GPIO printk("驱动卸载成功\n"); } module_init(interrupt_irq_init); module_exit(interrupt_irq_exit); MODULE_LICENSE("GPL");
步骤 3:编译驱动(同之前的 Makefile)

确保 Makefile 中KERNELDIR是你的 RK3568 内核源码路径,执行编译:

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-

生成interrupt.ko文件。

步骤 4:加载驱动并测试
  1. interrupt.ko传到开发板,执行加载:
    insmod interrupt.ko
  2. 查看内核日志(实时监控):
    dmesg -w
  3. 按下开发板上的按键,日志会输出:
    • 先打印:按键触发中断,调度延迟工作(3秒后执行)
    • 3 秒后打印:按键当前电平:0(已过滤抖动)(说明延迟工作执行,成功消抖)
步骤 5:卸载驱动(测试完成后)
rmmod interrupt

常见问题排查

  • 若中断不触发:检查 GPIO 引脚是否接错、中断触发方式是否匹配(比如改为IRQF_TRIGGER_RISING);
  • 若延迟工作不执行:确认工作队列是否成功创建(通过cat /proc/workqueue查看)。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/1/6 22:18:36

【无标题】人工智能

序号类型任务提示词生成的图像1人物摄影生成婚礼上的新娘和伴娘示例&#xff1a;梦幻般的婚礼殿堂内&#xff0c;新娘身着洁白的婚纱&#xff0c;宛如雪天中的仙子&#xff0c;眼眸中闪烁着幸福的泪光。她的笑容温柔而灿烂&#xff0c;每一步都散发着优雅与喜悦。伴娘们环绕在新…

作者头像 李华
网站建设 2026/1/9 22:52:14

操作指南:ST7789V驱动在树莓派Pico上的移植步骤

手把手教你把ST7789V彩屏“点亮”在树莓派Pico上你有没有试过&#xff0c;手里的小屏幕死活不亮&#xff1f;明明接线没错、代码也抄了&#xff0c;可屏幕就是全白、花屏&#xff0c;甚至毫无反应。如果你正在用树莓派Pico驱动一块常见的1.3英寸或1.69英寸彩色TFT屏——那大概率…

作者头像 李华
网站建设 2026/1/10 12:26:39

PaddlePaddle + GPU算力:释放大规模模型训练潜能

PaddlePaddle GPU算力&#xff1a;释放大规模模型训练潜能 在当今AI工业化浪潮中&#xff0c;一个现实问题反复浮现&#xff1a;如何在有限时间内完成对中文场景的高精度建模&#xff1f;比如银行票据识别、政务文档语义理解或电商评论情感分析。这些任务不仅要求模型具备强大…

作者头像 李华
网站建设 2026/1/8 1:13:03

Windows系统安装配置Miniconda

从官网下载安装Miniconda配置环境变量”此电脑“右击”属性“->”高级系统设置“->”高级“->”环境变量“->”系统变量“->”Path“->”编辑“”新建“->添加”路径\miniconda3“”新建“->添加”路径\miniconda3\Scripts“”新建“->添加”路径\m…

作者头像 李华
网站建设 2026/1/2 0:00:51

新手教程:树莓派插针定义与基本连接操作指南

树莓派入门必修课&#xff1a;40个插针怎么用&#xff1f;一文讲透GPIO接线与实战技巧 你有没有过这样的经历——手里的树莓派刚通电&#xff0c;杜邦线七七八八连了一堆&#xff0c;结果LED不亮、屏幕没反应&#xff0c;甚至主板发烫重启&#xff1f;别急&#xff0c;90%的新手…

作者头像 李华
网站建设 2026/1/10 8:18:53

PaddlePaddle数据隐私保护:GDPR与等保合规设计

PaddlePaddle数据隐私保护&#xff1a;GDPR与等保合规设计 在金融、医疗和政务领域&#xff0c;AI系统的每一次模型训练都可能涉及成千上万条个人敏感信息。当这些数据被用于构建智能客服、身份识别或风险评估系统时&#xff0c;一个不容忽视的问题浮现出来&#xff1a;我们如何…

作者头像 李华