freertos学习

1.基本概念

一、内核(Kernel)

管理所有任务、分配 CPU 资源、处理中断、提供系统 API(如任务创建 / 延时 / 队列)

  1. 可以实现抢占式,configUSE_PREEMPTION=1 开启
  2. 可裁剪通过 FreeRTOSConfig.h 宏定义开启/关闭,适配不同的mcu

二、任务(Task)

RTOS中最小执行单元,对应独立的、无限循环的C函数,实现一个具体的业务功能

1
2
3
4
5
6
7
void vTaskUART(void *pvParameters)
{
  for(;;)
  {
    
  }
}

多状态切换:任务在运行过程中会被内核切换为不同状态,核心状态有 4 种

  • 运行态:当前正在占用 CPU 执行的任务(同一时间只有一个任务处于运行态);
  • 就绪态:任务已准备好执行,等待 CPU 资源(如你的串口任务被唤醒后,进入就绪态立即抢占 CPU);
  • 阻塞态:任务因等待某个事件而暂停(如vTaskDelay延时、xQueueReceive等待队列数据),不占用 CPU;
  • 挂起态:任务被手动挂起(vTaskSuspend),需手动恢复(vTaskResume),同样不占用 CPU。

三、任务控制块(TCB - Task Control Block)

为每个任务分配一个结构体,存储任务的核心信息,内核通过操作TCB来管理任务(创建、调度、切换、删除)

1
2
3
4
5
6
typedef struct tskTaskControlBlock { 
	StackType_t *pxTopOfStack; // 任务栈的栈顶指针(核心,任务切换的关键) 
	ListItem_t xStateListItem; // 任务状态链表项(用于将任务加入就绪/阻塞/挂起链表)          UBaseType_t uxPriority; // 任务的优先级(0~configMAX_PRIORITIES-1) 
	char pcTaskName[ configMAX_TASK_NAME_LEN ]; // 任务名称(如你的"LED_Task") 
	// 其他:栈大小、任务编号、队列/信号量等待信息等 
} tskTCB;

核心作用

  1. 存储任务状态:通过xStateListItem将任务挂载到内核的就绪链表 / 阻塞链表 / 挂起链表,调度器只需遍历链表即可找到待执行的任务;
  2. 记录运行环境pxTopOfStack保存任务栈的栈顶地址,任务切换的核心就是保存 / 恢复栈顶指针(CPU 的寄存器值会压入任务栈,栈顶指针记录压栈位置);
  3. 标识任务属性:优先级、任务名称、栈大小等,为调度器的调度决策提供依据。

四:栈(STACK)

为每一个任务分配独立的RAM空间,存储局部变量、CPU寄存器值、函数调用返回地址

实现任务切换:这是栈最核心的作用!当高优先级任务抢占低优先级任务时,内核会将当前 CPU 的所有寄存器值(如 PC、R0-R15)压入被抢占任务的栈中,并将栈顶指针更新到 TCB 的pxTopOfStack;当被抢占任务再次执行时,内核会从栈中恢复所有寄存器值,让任务从被打断的位置继续执行,实现 “无缝切换”。

五、优先级(Priority)

FreeRTOS 优先级的核心规则

  1. 抢占式调度核心当一个高优先级任务进入就绪态时,调度器会立即暂停当前正在执行的低优先级任务,将 CPU 切换给高优先级任务(这就是你代码中串口任务能打断数据处理 / LED 任务的根本原因);
  2. 同优先级任务调度:若多个任务优先级相同,FreeRTOS 会采用时间片轮转调度(需开启configUSE_TIME_SLICING=1),每个任务分配固定的 CPU 时间片,轮流执行;
  3. 优先级范围:由FreeRTOSConfig.hconfigMAX_PRIORITIES定义,建议按实际需求配置(无需配置过大,否则会占用更多内核 RAM);
  4. 空闲任务优先级:FreeRTOS 会自动创建一个空闲任务(idle task),优先级为 0(最低),当系统中所有任务都处于阻塞 / 挂起态时,调度器会执行空闲任务(防止 CPU 空转)。

六、调度器(scheduler)

根据任务的优先级和TCB状态来决定哪个任务获得CPU执行权

调度器的类型(FreeRTOS 支持)

  1. 抢占式调度器configUSE_PREEMPTION=1开启,是嵌入式实时开发的主流选择,高优先级任务可随时抢占低优先级任务,保证实时性;
  2. 协作式调度器configUSE_PREEMPTION=0开启,任务不会被主动抢占,需任务主动调用taskYIELD()让出 CPU,实时性差,适合对实时性要求低的场景。

2. 常用函数

函数名参数
xTaskCreate()xTaskCreate(Func, "name", stack, pvParameters, priority, Handle);
vTaskStartSchedulervTaskStartScheduler()
vTaskDeletevTaskDelete(Handle)
vTaskSuspendvTaskSuspend(Handle)
vTaskResumevTaskResume(Handle)
xTaskGetHandlexTaskGetHandle(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.标准流程

  1. 中断里在执行完代码后立即按照任务优先级执行:
1
2
3
4
5
6
	// 典型用法 
BaseType_t xHigherPriorityTaskWoken = pdFALSE; 
	// 初始化为“未唤醒高优先级任务” 
	// 在ISR中释放信号量,函数会修改 xHigherPriorityTaskWoken 的值 xSemaphoreGiveFromISR(Handle, &xHigherPriorityTaskWoken); 
	// 根据标记判断是否需要立即切换任务 
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);

4.工程步骤

划分任务(按功能 + 优先级)→ 确定同步 / 通信方式 → 分配栈大小和优先级 → 编写业务逻辑 → 调试排错。

  1. 整理FreeRTOS 核心知识框架

    plaintext

    1
    2
    3
    4
    5
    
    FreeRTOS核心
    ├─ 任务管理:创建/删除/挂起/恢复 + 调度器(抢占式/时间片)
    ├─ 通信同步:队列(数据传输)、信号量(同步/计数)、互斥量(互斥+优先级继承)、事件组(多条件同步)
    ├─ 时间管理:vTaskDelay()/vTaskDelayUntil()、软件定时器
    └─ 中断管理:FROM_ISR API、中断优先级配置、portYIELD_FROM_ISR()
    
专注嵌入式开发,记录技术成长
使用 Hugo 构建
主题 StackJimmy 设计