1. 中断系统概述:中断、RTOS角色与轮询对比
大家好,我是老李。做嵌入式这行快二十年了,从8位单片机一路干到多核处理器。今天咱们聊聊中断——这个RTOS里最核心、也最容易出坑的话题。
说实话,我见过太多工程师把中断用成了轮询,或者把ISR写得比主任务还长。嗯,这都不对。咱们从头捋一遍。
1.1 什么是中断?
中断,说白了就是CPU正在干一件事,突然被另一件更紧急的事打断。
举个例子:你正在写代码,突然电话响了。你放下键盘接电话,接完再回来继续写。这个电话就是中断。
在硬件层面,中断是这样工作的:
- 外设(比如网卡、串口、定时器)拉高一根中断请求线
- CPU检测到中断信号,暂停当前指令流
- CPU保存现场(PC、寄存器等)到栈里
- CPU跳转到中断向量表,找到对应的ISR入口
- 执行ISR,处理紧急事件
- ISR执行完毕,恢复现场,继续原来的工作
整个过程,硬件自动完成大部分。你只需要写好ISR就行。
关键点:中断是异步事件。CPU不知道它什么时候来,来了就得停下手里的活。
1.2 中断在RTOS中的角色
在VxWorks这样的RTOS里,中断不是可有可无的。它是系统响应的基石。
我个人习惯把RTOS里的中断分成三类:
| 中断类型 | 典型来源 | 响应要求 |
|---|---|---|
| 外部中断 | GPIO、按键、传感器 | 微秒级 |
| 内部中断 | 定时器、DMA、看门狗 | 纳秒级 |
| 异常中断 | 除零、缺页、非法指令 | 立即处理 |
你想想看,如果没有中断,CPU得不停地轮询外设状态。那效率得多低?
在VxWorks里,中断处理有几个特点:
- 中断优先级可配置:VxWorks支持多级中断嵌套,高优先级中断可以打断低优先级ISR
- 中断与任务隔离:ISR运行在中断上下文中,不能调用阻塞API(比如semTake、taskDelay)
- 中断延迟可控:VxWorks通过关中断时间最小化,保证实时性
我的经验:在项目中,我习惯把中断优先级分成三级:紧急(定时器、看门狗)、重要(通信接口)、普通(按键、传感器)。这样嵌套起来不会乱。
1.3 中断 vs 轮询:到底选哪个?
这个问题,我每次带新人都会问。答案其实不复杂,但很多人搞混。
咱们直接对比一下:
| 对比项 | 中断 | 轮询 |
|---|---|---|
| CPU利用率 | 高(无事时CPU干别的) | 低(一直占着CPU问状态) |
| 响应延迟 | 确定(微秒级) | 不确定(取决于轮询周期) |
| 实现复杂度 | 较高(需配置中断控制器、写ISR) | 简单(一个while循环搞定) |
| 适用场景 | 事件驱动、实时性要求高 | 数据量大、实时性要求低 |
说白了,中断适合「等事件」,轮询适合「查数据」。
举个例子:
- 按键按下——用中断。因为按键事件不频繁,但需要立即响应
- ADC连续采样——用轮询。因为数据量大,中断太频繁反而浪费
避坑指南:我曾经在一个项目中,把UART接收用中断处理,结果每来一个字节就触发一次中断。波特率115200时,CPU几乎全耗在ISR里了。后来改成DMA+中断,只在缓冲区满时触发一次,问题解决。
1.4 中断在VxWorks中的特殊之处
VxWorks的中断处理,和Linux、FreeRTOS不太一样。这里说几个关键点:
- 中断栈独立:VxWorks为ISR分配独立的中断栈,不占用任务栈。这避免了栈溢出问题。
- 中断延迟可测量:VxWorks提供
vxTasKDelay和vxTime等工具,可以精确测量中断响应时间。 - 中断嵌套可控:通过
intLock/intUnlock控制中断开关,粒度很细。
嗯,这里要注意:VxWorks的ISR里不能调用semTake、taskDelay这些阻塞函数。为什么?因为ISR运行在中断上下文,没有任务控制块(TCB),调度器管不到它。
核心原则:ISR里只做最紧急的事——读取数据、清除中断标志、通知任务。剩下的交给任务去处理。
1.5 一个简单的例子
咱们看一段VxWorks下的中断注册代码:
/* 中断服务函数 */
void myIsr(void)
{
/* 读取中断状态寄存器 */
UINT32 status = *(volatile UINT32 *)INT_STATUS_REG;
/* 清除中断标志 */
*(volatile UINT32 *)INT_CLEAR_REG = status;
/* 通知任务处理 */
semGive(mySem);
}
/* 中断初始化 */
void initInterrupt(void)
{
/* 注册中断 */
intConnect(INUM_TO_IVEC(INT_NUM), myIsr, 0);
/* 使能中断 */
sysIntEnable(INT_NUM);
}
这段代码很简单,但有几个坑:
intConnect必须在任务上下文中调用,不能在ISR里注册中断semGive是安全的,但semTake不行- 中断标志必须及时清除,否则会一直触发
我的习惯:ISR里只做三件事——读状态、清标志、发信号。剩下的数据处理,全部交给任务。这样ISR执行时间控制在几微秒内,系统响应才快。
1.6 小结
中断是RTOS的命脉。用好了,系统实时性杠杠的;用不好,CPU全耗在ISR里,任务反而跑不起来。
记住几个要点:
- 中断适合事件驱动,轮询适合数据采集
- ISR要短小精悍,别在里面做复杂运算
- VxWorks的ISR不能调用阻塞API
- 中断优先级要合理规划,别让低优先级中断饿死
下一章,咱们聊聊VxWorks的中断向量表和中断控制器配置。到时候我会分享一个实际项目中踩过的坑——中断向量表配置错了,系统直接死机。嗯,那场面,记忆犹新。
公众号:蓝海资料掘金营,微信deep3321