1. RTOS 基础概念:任务、调度器、内核对象概述
在深入 RTOS 串口驱动与中断优先级设计之前,必须建立对 RTOS 核心抽象层的清晰认知。实时操作系统(RTOS)的本质是一个确定性任务调度器,它通过内核对象协调多个并发执行流对共享资源(如串口外设)的访问。本节将逐一拆解任务、调度器、信号量、队列与互斥量这五个基础概念,为后续中断服务函数(ISR)与多任务互斥的讨论奠定理论基础。
1.1 任务(Task)—— 并发执行的基本单元
任务是 RTOS 中独立调度的执行线程,每个任务拥有独立的栈空间、优先级和任务控制块(TCB)。与裸机中的超级循环不同,RTOS 任务在逻辑上“同时”运行,由调度器决定哪个任务在哪个时刻获得 CPU 使用权。
关键特征:
- 优先级: 0~255 级(常见配置),数值越小优先级越高(或相反,取决于内核实现)。
- 状态机: 运行态、就绪态、阻塞态、挂起态。
- 上下文切换: 保存/恢复 CPU 寄存器、栈指针,切换时间通常在微秒级。
1.2 调度器(Scheduler)—— 决定“谁运行”的核心引擎
调度器是 RTOS 内核的心脏,它根据预设的调度策略从就绪任务列表中选择下一个要运行的任务。在嵌入式实时系统中,最常用的调度算法是基于固定优先级的抢占式调度。
| 调度策略 | 特点 | 适用场景 |
|---|---|---|
| 抢占式优先级调度 | 高优先级任务就绪时立即抢占低优先级任务 | 硬实时系统,如串口响应、电机控制 |
| 时间片轮转(Round-Robin) | 同优先级任务轮流获得固定时间片 | 非实时或软实时,如人机界面 |
| 协作式调度 | 任务主动让出 CPU,无抢占 | 极简系统,无中断密集型场景 |
串口驱动中的调度要点: 串口 ISR 通常运行在最高优先级(硬件优先级),但 ISR 中不应调用阻塞型 API。正确的做法是 ISR 释放信号量或向队列发送数据,让高优先级任务在任务上下文中处理数据,从而避免 ISR 长时间占用 CPU。
1.3 内核对象:信号量、队列与互斥量
内核对象是 RTOS 提供的同步与通信机制,用于解决多任务访问共享资源(如串口 TX/RX 缓冲区)时的竞态条件。以下逐一分析三种核心对象。
1.3.1 信号量(Semaphore)—— 事件通知与资源计数
信号量是一个非负整数计数器,支持 take(P 操作)和 give(V 操作)两种原子操作。在串口驱动中,二值信号量常用于 ISR 通知任务“数据已到达”。
// 伪代码:串口 ISR 中释放信号量
void UART_ISR(void) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xSemaphoreGiveFromISR(xRxSemaphore, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
// 任务中等待信号量
void RxTask(void *pvParameters) {
while (1) {
xSemaphoreTake(xRxSemaphore, portMAX_DELAY);
// 处理接收到的数据
UART_ReadBuffer(rxBuf, len);
}
}
1.3.2 队列(Queue)—— 结构化数据传递
队列是 RTOS 中最常用的任务间通信方式,支持多个生产者和消费者。队列内部维护一个环形缓冲区,通过拷贝或引用传递数据。在串口驱动中,队列用于将 ISR 接收到的字节传递给处理任务。
| 特性 | 信号量 | 队列 |
|---|---|---|
| 传递数据 | 仅通知事件,不携带数据 | 携带完整数据帧 |
| ISR 安全 API | xSemaphoreGiveFromISR |
xQueueSendFromISR |
| 典型用法 | 通知任务“有数据可读” | 将接收字节直接送入任务缓冲区 |
| 多生产者支持 | 是(计数信号量) | 是(多个 ISR 或任务可发送) |
1.3.3 互斥量(Mutex)—— 保护共享资源的“锁”
互斥量是信号量的特例,专用于解决优先级反转问题。它支持优先级继承协议:当低优先级任务持有互斥量时,若高优先级任务请求同一互斥量,低优先级任务会临时继承高优先级任务的优先级,从而避免被中等优先级任务无限抢占。
串口驱动中的互斥量陷阱: 不要在 ISR 中使用互斥量!互斥量的释放操作必须在任务上下文中完成,且持有互斥量的任务不能进入阻塞态。串口驱动中,互斥量通常用于保护共享的打印缓冲区或配置寄存器,而非用于 ISR 与任务之间的同步。
1.4 三种内核对象在串口驱动中的典型分工
| 场景 | 推荐对象 | 原因 |
|---|---|---|
| ISR 通知任务“收到一个字节” | 二值信号量 | 轻量级,仅传递事件,不拷贝数据 |
| ISR 向任务传递多个字节 | 队列 | 数据缓冲,支持多个生产者(如 DMA 半满/全满中断) |
| 多任务共享串口打印 | 互斥量 | 防止打印内容交错,支持优先级继承 |
| 计数资源(如空闲缓冲区数量) | 计数信号量 | 管理有限数量的缓冲区 |
1.5 小结:从概念到串口驱动设计的映射
理解任务、调度器与内核对象是设计可靠 RTOS 串口驱动的前提:
- 任务 负责在任务上下文中处理串口数据,避免在 ISR 中执行耗时操作。
- 调度器 确保高优先级任务(如串口数据处理任务)在数据到达时立即获得 CPU。
- 信号量 作为 ISR 与任务之间的“门铃”,实现事件驱动。
- 队列 作为数据管道,解耦 ISR 的生产速度与任务的消费速度。
- 互斥量 保护串口配置寄存器或共享打印缓冲区,防止竞态条件。