1.基本概念
一、内核(Kernel)
管理所有任务、分配 CPU 资源、处理中断、提供系统 API(如任务创建 / 延时 / 队列)
- 可以实现抢占式,
configUSE_PREEMPTION=1开启 - 可裁剪通过
FreeRTOSConfig.h宏定义开启/关闭,适配不同的mcu
二、任务(Task)
RTOS中最小执行单元,对应独立的、无限循环的C函数,实现一个具体的业务功能
| |
多状态切换:任务在运行过程中会被内核切换为不同状态,核心状态有 4 种
- 运行态:当前正在占用 CPU 执行的任务(同一时间只有一个任务处于运行态);
- 就绪态:任务已准备好执行,等待 CPU 资源(如你的串口任务被唤醒后,进入就绪态立即抢占 CPU);
- 阻塞态:任务因等待某个事件而暂停(如
vTaskDelay延时、xQueueReceive等待队列数据),不占用 CPU; - 挂起态:任务被手动挂起(
vTaskSuspend),需手动恢复(vTaskResume),同样不占用 CPU。
三、任务控制块(TCB - Task Control Block)
为每个任务分配一个结构体,存储任务的核心信息,内核通过操作TCB来管理任务(创建、调度、切换、删除)
| |
核心作用
- 存储任务状态:通过
xStateListItem将任务挂载到内核的就绪链表 / 阻塞链表 / 挂起链表,调度器只需遍历链表即可找到待执行的任务; - 记录运行环境:
pxTopOfStack保存任务栈的栈顶地址,任务切换的核心就是保存 / 恢复栈顶指针(CPU 的寄存器值会压入任务栈,栈顶指针记录压栈位置); - 标识任务属性:优先级、任务名称、栈大小等,为调度器的调度决策提供依据。
四:栈(STACK)
为每一个任务分配独立的RAM空间,存储局部变量、CPU寄存器值、函数调用返回地址
实现任务切换:这是栈最核心的作用!当高优先级任务抢占低优先级任务时,内核会将当前 CPU 的所有寄存器值(如 PC、R0-R15)压入被抢占任务的栈中,并将栈顶指针更新到 TCB 的pxTopOfStack;当被抢占任务再次执行时,内核会从栈中恢复所有寄存器值,让任务从被打断的位置继续执行,实现 “无缝切换”。
五、优先级(Priority)
FreeRTOS 优先级的核心规则
- 抢占式调度核心:当一个高优先级任务进入就绪态时,调度器会立即暂停当前正在执行的低优先级任务,将 CPU 切换给高优先级任务(这就是你代码中串口任务能打断数据处理 / LED 任务的根本原因);
- 同优先级任务调度:若多个任务优先级相同,FreeRTOS 会采用时间片轮转调度(需开启
configUSE_TIME_SLICING=1),每个任务分配固定的 CPU 时间片,轮流执行; - 优先级范围:由
FreeRTOSConfig.h的configMAX_PRIORITIES定义,建议按实际需求配置(无需配置过大,否则会占用更多内核 RAM); - 空闲任务优先级:FreeRTOS 会自动创建一个空闲任务(idle task),优先级为 0(最低),当系统中所有任务都处于阻塞 / 挂起态时,调度器会执行空闲任务(防止 CPU 空转)。
六、调度器(scheduler)
根据任务的优先级和TCB状态来决定哪个任务获得CPU执行权
调度器的类型(FreeRTOS 支持)
- 抢占式调度器:
configUSE_PREEMPTION=1开启,是嵌入式实时开发的主流选择,高优先级任务可随时抢占低优先级任务,保证实时性; - 协作式调度器:
configUSE_PREEMPTION=0开启,任务不会被主动抢占,需任务主动调用taskYIELD()让出 CPU,实时性差,适合对实时性要求低的场景。
2. 常用函数
| 函数名 | 参数 |
|---|---|
xTaskCreate() | xTaskCreate(Func, "name", stack, pvParameters, priority, Handle); |
vTaskStartScheduler | vTaskStartScheduler() |
vTaskDelete | vTaskDelete(Handle) |
vTaskSuspend | vTaskSuspend(Handle) |
vTaskResume | vTaskResume(Handle) |
xTaskGetHandle | xTaskGetHandle(name) |
vTaskDelay() | vTaskDelay(pdMS_TO_TICKS(time)); |
vTaskDelayUntil() | vTaskDelayUntil(&pretime,delaytime); |
xQueueCreate()队列创建 | xADCQueue = xQueueCreate(10, sizeof(float)); |
xQueueSend()队列发送 | xQueueSend(xADCQueue,&voltage,pdMS_TO_TICKS(50)) |
xQueueReceive()队列接收 | xQueueReceive(xADCQueue,&voltage,portMAX_DELAY) |
uxQueueMessagesWaiting()队列数目查询 | uxQueueMessagesWaiting(adc_voltage_queue) |
xSemaphoreCreateBinary二值信号量 | xBinarySemaphore = xSemaphoreCreateBinary();必须手动调用Give函数启用 |
xSemaphoreCreateCounting计数信号量 | |
xSemaphoreTake获取令牌,获取后从1-0 | xSemaphoreTake(句柄,portMAX_DELAY) |
xSemaphoreGive释放令牌,成功后获取后从0-1 | xSemaphoreGive(xBinarySemaphore);//释放 |
xSemaphoreGiveFromISR中断释放令牌 | |
xSemaphoreCreateMutex创建互斥量(获取和释放同上) | xSemaphoreCreateMutex避免优先级反转,自动启用需要手动释放 |
xQueueSendFromISR()中断中队列入队 | |
xSemaphoreGiveFromISR()中断中释放信号量 / 互斥量 | |
portYIELD_FROM_ISR()中断中触发任务调度 | |
xEventGroupCreate()创建事件组 | |
xEventGroupSetBits()设置事件位 | |
xEventGroupWaitBits()等待事件位 | |
xEventGroupClearBits清除事件位 | |
xTimerCreate()创建定时器 | xTimerCreate( "名称", 定时时长, pdTRUE,pvTimerID 回调函数 ; |
xTimerStart()启动定时器 | xTimerStart(名称, 0);第二位0表示立即开始 |
xTimerStop()停止定时器 | |
xTimerReset()重置定时器 | |
vApplicationStackOverflowHook()栈溢出钩子函数 | |
portYIELD_FROM_ISR中断中唤醒高优先级任务 | 一般用于中断处理后加上 xHigherPriorityTaskWoken |
uxTaskGetStackHighWaterMark空闲任务剩余栈大小 | |
xTaskGetTickCount获取当前tick数 |
3.标准流程
- 中断里在执行完代码后立即按照任务优先级执行:
| |
4.工程步骤
划分任务(按功能 + 优先级)→ 确定同步 / 通信方式 → 分配栈大小和优先级 → 编写业务逻辑 → 调试排错。
整理FreeRTOS 核心知识框架:
plaintext
1 2 3 4 5FreeRTOS核心 ├─ 任务管理:创建/删除/挂起/恢复 + 调度器(抢占式/时间片) ├─ 通信同步:队列(数据传输)、信号量(同步/计数)、互斥量(互斥+优先级继承)、事件组(多条件同步) ├─ 时间管理:vTaskDelay()/vTaskDelayUntil()、软件定时器 └─ 中断管理:FROM_ISR API、中断优先级配置、portYIELD_FROM_ISR()