news 2026/10/14 15:37:56

嵌入式学习 day66:中断下半部、工作队列与内核定时器

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
嵌入式学习 day66:中断下半部、工作队列与内核定时器

一、中断上下半部

1. 为什么需要上下半部

中断处理函数不能做耗时操作,否则会阻塞其他中断和进程。所以 Linux 把中断处理分成两部分:

部分作用特点
上半部(顶半部)紧急的硬件操作不可被打断,要快
下半部(底半部)耗时的操作可被打断,可以慢

上半部:在中断处理函数里,只做最紧急的事(比如记录中断、唤醒进程)。
下半部:把耗时的操作放到下半部执行。

2. 下半部的实现方式

Linux 有 4 种下半部实现方式:

方式执行上下文能否睡眠
软中断中断上下文❌
tasklet中断上下文❌
工作队列进程上下文✅
线程化 IRQ进程上下文✅

tasklet 和 工作队列最常用。

二、tasklet

1. 特点

  • 基于软中断实现。

  • 执行在中断上下文,不能睡眠。

  • 适合短小、不睡眠的耗时操作。

2. 代码示例

c

#include <linux/interrupt.h> static void mytasklet_func(unsigned long data) { pr_info("tasklet running\n"); } static DECLARE_TASKLET(mytasklet, mytasklet_func, 0); static irqreturn_t key_isr(int irqno, void *pdev) { tasklet_schedule(&mytasklet); // 调度 tasklet return IRQ_HANDLED; }
函数/宏作用
DECLARE_TASKLET定义并初始化 tasklet
tasklet_schedule调度 tasklet(在中断里调用)
mytasklet_functasklet 执行函数

中断触发 →tasklet_schedule调度 → 内核在合适时机执行mytasklet_func。

三、工作队列

1. 特点

  • 执行在进程上下文,可以睡眠。

  • 适合耗时、可能睡眠的操作(比如msleep、I2C 读写)。

2. 代码示例

c

#include <linux/workqueue.h> static struct work_struct workqueue; static void key_workqueue_func(struct work_struct *work) { msleep(10); // 可以睡眠 pr_info("key pressed\n"); } static irqreturn_t key_handler(int irqno, void *pdev) { schedule_work(&workqueue); // 调度工作队列 return IRQ_HANDLED; } // probe 里初始化 INIT_WORK(&workqueue, key_workqueue_func);
函数/宏作用
INIT_WORK初始化工作队列
schedule_work调度工作队列(在中断里调用)
key_workqueue_func工作队列执行函数

中断触发 →schedule_work调度 → 内核线程执行key_workqueue_func。

3. tasklet vs 工作队列

项目tasklet工作队列
执行上下文中断上下文进程上下文
能否睡眠❌✅
适合短小操作耗时操作
调度函数tasklet_scheduleschedule_work

关键:需要在中断下半部睡眠(比如msleep),必须用工作队列。

四、input 子系统

1. 什么是 input 子系统

Linux 把输入设备(键盘、鼠标、触摸屏、按键)统一管理,称为input 子系统。

应用程序通过/dev/input/eventX读取输入事件,不用自己写驱动接口。

2. input 驱动的流程

c

// 1. 申请 input 设备 pkey_dev = input_allocate_device(); // 2. 说明设备能力(支持什么事件) input_set_capability(pkey_dev, EV_KEY, KEY_0); // 3. 注册 input 设备 input_register_device(pkey_dev); // 4. 上报事件 input_event(pkey_dev, EV_KEY, KEY_0, 1); // 按下 input_sync(pkey_dev); input_event(pkey_dev, EV_KEY, KEY_0, 0); // 松开 input_sync(pkey_dev);
函数作用
input_allocate_device申请 input 设备
input_set_capability说明设备支持的事件类型
input_register_device注册 input 设备
input_event上报事件
input_sync同步事件

3. 事件类型

类型含义
EV_KEY按键事件
EV_REL相对坐标(鼠标)
EV_ABS绝对坐标(触摸屏)

4. input 驱动 + tasklet

c

static void mytasklet_func(unsigned long data) { input_event(pkey_dev, EV_KEY, KEY_0, 1); // 按下 input_sync(pkey_dev); input_event(pkey_dev, EV_KEY, KEY_0, 0); // 松开 input_sync(pkey_dev); } static irqreturn_t key_isr(int irqno, void *pdev) { tasklet_schedule(&mytasklet); // 中断里调度 tasklet return IRQ_HANDLED; }

中断触发 → tasklet 上报按键事件 → 应用程序从/dev/input/eventX读到事件。

5. 应用程序读取 input 事件

c

#include <linux/input.h> int fd = open("/dev/input/event1", O_RDONLY); struct input_event ev; while (1) { read(fd, &ev, sizeof(ev)); if (ev.type == EV_KEY && ev.code == KEY_0) { if (ev.value == 1) { printf("key pressed\n"); } else if (ev.value == 0) { printf("key released\n"); } } }

/dev/input/eventX由 input 子系统自动创建,应用程序直接读。

五、内核定时器

1. 概念

内核定时器:在指定的时间之后,执行一个函数(超时函数)。

  • 节拍(jiffies):内核的系统时钟,每毫秒增加一次(HZ = 100)。

  • 定时时间:jiffies + msecs_to_jiffies(100)表示 100ms 后。

2. 代码示例

c

#include <linux/timer.h> static void timeout(unsigned long data) { pr_info("timeout ok!\n"); } static DEFINE_TIMER(mtimer, timeout, 0, 0); static int __init kernel_timer_init(void) { init_timer(&mtimer); // 初始化定时器 add_timer(&mtimer); // 添加定时器 mod_timer(&mtimer, jiffies + msecs_to_jiffies(100)); // 设置超时时间 return 0; } static void __exit kernel_timer_exit(void) { del_timer(&mtimer); // 删除定时器 return 0; }

3. 关键函数

函数作用
DEFINE_TIMER定义并初始化定时器
init_timer初始化定时器
add_timer激活定时器
mod_timer修改超时时间
del_timer删除定时器

4. 时间转换

函数作用
msecs_to_jiffies毫秒转节拍
usecs_to_jiffies微秒转节拍
jiffies_to_msecs节拍转毫秒

5. 用法

c

mod_timer(&mtimer, jiffies + msecs_to_jiffies(100)); // 100ms 后超时

超时后,内核自动调用timeout函数。

六、三种下半部方式对比

方式上下文能否睡眠适合场景
tasklet中断上下文❌短小操作
工作队列进程上下文✅耗时操作
内核定时器中断上下文❌延时执行

七、总结

知识点内容
上下半部上半部快,下半部慢
tasklet中断上下文,不能睡眠
工作队列进程上下文,可以睡眠
input 子系统统一管理输入设备,上报事件
内核定时器延时执行函数

核心思想:中断处理函数要快,耗时操作放到下半部。tasklet 用于短小操作,工作队列用于耗时操作,input 子系统用于输入设备,内核定时器用于延时执行。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/14 15:37:42

Java五子棋对战系统源码详解:AI算法与Socket网络对战实现

简介&#xff1a;一份基于Java实现的五子棋对战系统课程设计源码&#xff0c;适合需要完成课设或希望借助完整项目进阶Java开发的读者&#xff0c;覆盖棋盘绘制、落子交互、胜负判断等核心功能。资源包共290个文件&#xff0c;约18.26MB&#xff0c;以265个GIF图像和17个Java源…

作者头像 李华
网站建设 2026/10/14 15:37:15

学术图表绘制困境,硕词 AI 科研图表生成实操路径

图表是科研成果可视化表达的载体&#xff0c;图表质量直接影响论文可读性。很多研究生写作中遭遇图表难题&#xff1a;统计图表格式混乱&#xff0c;坐标轴、图例、图注不符合学术规范&#xff1b;机理示意图、工程原理图手绘效果差&#xff0c;配色杂乱&#xff1b;图表与正文…

作者头像 李华
网站建设 2026/10/14 15:37:10

STM32+SR8201F通用驱动包:百兆以太网PHY移植与调试指南

简介&#xff1a;针对SR8201F物联网芯片在STM32平台上的通用驱动代码&#xff0c;面向嵌入式开发与物联网终端设计工程师&#xff0c;解决SR8201F以太网控制器在STM32平台上的底层适配与快速移植问题。压缩包内共2个文件&#xff0c;采用1个头文件加1个源文件的精简结构&#x…

作者头像 李华
网站建设 2026/10/14 15:36:58

SSM框架图书借阅管理系统毕业设计全流程解析

简介&#xff1a;基于Java的图书馆借阅管理系统毕业设计资源&#xff0c;采用SSM框架&#xff0c;主要面向计算机专业毕业生、课程设计学习者&#xff0c;可完整解决图书借阅管理系统的需求分析、数据库设计与功能实现等问题&#xff0c;并配套毕业论文设计与答辩素材。压缩包共…

作者头像 李华