创建 就绪队列 CPU执行
[NEW] -----> [READY] -----> [RUNNING]
↑ ↓ ↓
↑ ↓ [时间片用完]
↑ ↓ ↓
[等待事件] [BLOCKED]
[延时等待] [SUSPENDED]
转换 | 触发条件 | 说明 |
|---|---|---|
NEW → READY | 任务创建完成 | 任务进入就绪队列 |
READY → RUNNING | 调度器选择 | 成为当前运行任务 |
RUNNING → READY | 时间片用完/高优先级任务就绪 | 被抢占或主动让出 |
RUNNING → BLOCKED | 等待事件/延时 | 主动阻塞等待 |
BLOCKED → READY | 事件发生/延时到期 | 等待条件满足 |
RUNNING → SUSPENDED | 被挂起 | 明确的挂起操作 |
SUSPENDED → READY | 被恢复 | 明确的恢复操作 |
任意状态 → DELETED | 任务删除 | 任务生命周期结束 |
/**
* @brief 任务状态转换的关键函数
*/
/* 将任务添加到就绪列表 */
static void prvAddTaskToReadyList( TCB_t * const pxTCB )
{
taskRECORD_READY_PRIORITY( pxTCB->uxPriority );
vListInsertEnd( &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xStateListItem ) );
}
/* 从就绪列表移除任务 */
static UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove )
{
List_t * const pxList = pxItemToRemove->pxContainer;
pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;
pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;
if( pxList->pxIndex == pxItemToRemove )
{
pxList->pxIndex = pxItemToRemove->pxPrevious;
}
pxItemToRemove->pxContainer = NULL;
( pxList->uxNumberOfItems )--;
return pxList->uxNumberOfItems;
}
/* 任务延时实现 */
void vTaskDelay( const TickType_t xTicksToDelay )
{
if( xTicksToDelay > ( TickType_t ) 0U )
{
taskENTER_CRITICAL();
{
/* 将任务添加到延时列表 */
prvAddCurrentTaskToDelayedList( xTicksToDelay, pdFALSE );
}
taskEXIT_CRITICAL();
/* 强制进行一次任务切换 */
portYIELD_WITHIN_API();
}
}
假设有一个简单的嵌入式系统,包含以下任务:
/**
* @brief 示例任务定义
*/
/* 任务优先级定义 */
#define TASK_PRIORITY_HIGH 3 /* LED控制任务 */
#define TASK_PRIORITY_MEDIUM 2 /* 按键检测任务 */
#define TASK_PRIORITY_LOW 1 /* 串口通信任务 */
#define TASK_PRIORITY_IDLE 0 /* 空闲任务 */
/* 任务句柄 */
TaskHandle_t xTaskLED = NULL;
TaskHandle_t xTaskButton = NULL;
TaskHandle_t xTaskUART = NULL;
/* 任务创建 */
void CreateTasks(void)
{
xTaskCreate(TaskLED, "LED", 128, NULL, TASK_PRIORITY_HIGH, &xTaskLED);
xTaskCreate(TaskButton, "Button", 128, NULL, TASK_PRIORITY_MEDIUM, &xTaskButton);
xTaskCreate(TaskUART, "UART", 256, NULL, TASK_PRIORITY_LOW, &xTaskUART);
}
/**
* @brief LED控制任务
*/
void TaskLED(void *pvParameters)
{
TickType_t xLastWakeTime = xTaskGetTickCount();
const TickType_t xFrequency = pdMS_TO_TICKS(500); /* 500ms周期 */
for (;;)
{
/* 切换LED状态 */
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
/* 延时到下一个周期 */
vTaskDelayUntil(&xLastWakeTime, xFrequency);
}
}
/**
* @brief 按键检测任务
*/
void TaskButton(void *pvParameters)
{
for (;;)
{
/* 检测按键状态 */
if (HAL_GPIO_ReadPin(BUTTON_GPIO_Port, BUTTON_Pin) == GPIO_PIN_RESET)
{
/* 按键按下,发送事件 */
xEventGroupSetBits(xEventGroup, BUTTON_PRESSED_BIT);
}
/* 10ms检测间隔 */
vTaskDelay(pdMS_TO_TICKS(10));
}
}
/**
* @brief 串口通信任务
*/
void TaskUART(void *pvParameters)
{
char rxBuffer[64];
for (;;)
{
/* 等待串口数据(无限等待) */
if (xQueueReceive(xUARTQueue, rxBuffer, portMAX_DELAY) == pdPASS)
{
/* 处理接收到的数据 */
ProcessUARTData(rxBuffer);
/* 发送响应 */
HAL_UART_Transmit(&huart1, (uint8_t*)"OK\r\n", 4, HAL_MAX_DELAY);
}
}
}
时间轴: 0ms 1ms 2ms 3ms 4ms 5ms 6ms 7ms 8ms 9ms 10ms
任务执行: [LED] [BTN] [LED] [UART][LED] [BTN] [LED] [BTN] [LED] [UART][LED]
事件: ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑
Sys Sys Sys Que Sys Sys Sys Sys Sys Que Sys
Tick Tick Tick Recv Tick Tick Tick Tick Tick Recv Tick
说明:
- LED任务优先级最高,每次SysTick都会检查是否需要执行
- 按键任务每10ms执行一次检测
- 串口任务仅在接收到数据时执行(事件驱动)
- 空闲任务在所有其他任务都阻塞时执行
/**
* @brief 内存使用情况分析
*/
/* 任务栈大小计算 */
#define LED_TASK_STACK_SIZE 128 /* 128 * 4 = 512字节 */
#define BUTTON_TASK_STACK_SIZE 128 /* 128 * 4 = 512字节 */
#define UART_TASK_STACK_SIZE 256 /* 256 * 4 = 1024字节 */
#define IDLE_TASK_STACK_SIZE 64 /* 64 * 4 = 256字节 */
/* TCB大小(大约100-200字节每个任务) */
#define TCB_SIZE 150 /* 每个TCB约150字节 */
/* 总内存使用量估算 */
#define TOTAL_STACK_MEMORY (512 + 512 + 1024 + 256) /* 2304字节 */
#define TOTAL_TCB_MEMORY (4 * 150) /* 600字节 */
#define TOTAL_TASK_MEMORY (TOTAL_STACK_MEMORY + TOTAL_TCB_MEMORY) /* 2904字节 */
/**
* @brief 任务切换性能数据(ARM Cortex-M4 @ 100MHz)
*/
/* 任务切换时间组成 */
#define SYSTICK_ISR_TIME 5 /* SysTick中断处理:约5微秒 */
#define PENDSV_CONTEXT_SAVE 15 /* 上下文保存:约15微秒 */
#define SCHEDULER_TIME 8 /* 调度器选择:约8微秒 */
#define PENDSV_CONTEXT_RESTORE 15 /* 上下文恢复:约15微秒 */
#define TOTAL_SWITCH_TIME 43 /* 总切换时间:约43微秒 */
/* 时间片利用率 */
#define TIME_SLICE_LENGTH 1000 /* 时间片长度:1000微秒(1ms) */
#define SWITCH_OVERHEAD_PERCENT 4.3 /* 切换开销:4.3% */
#define USEFUL_CPU_PERCENT 95.7 /* 有效CPU使用率:95.7% */
/**
* @brief 启用硬件优化的任务选择
*/
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 /* 启用CLZ指令优化 */
#define configMAX_PRIORITIES 8 /* 减少优先级数量 */
/**
* @brief 减少不必要的功能开销
*/
#define configGENERATE_RUN_TIME_STATS 0 /* 关闭运行时统计 */
#define configUSE_TRACE_FACILITY 0 /* 关闭跟踪功能 */
#define configCHECK_FOR_STACK_OVERFLOW 1 /* 保留栈溢出检测 */
/**
* @brief 内存优化配置
*/
#define configSUPPORT_STATIC_ALLOCATION 1 /* 启用静态分配 */
#define configSUPPORT_DYNAMIC_ALLOCATION 0 /* 关闭动态分配 */
#define configTOTAL_HEAP_SIZE 0 /* 不使用堆内存 */
/**
* @brief 任务栈大小优化
*/
#define configMINIMAL_STACK_SIZE 64 /* 最小栈大小 */
#define configIDLE_TASK_STACK_SIZE 64 /* 空闲任务栈 */
/**
* @brief 中断优先级配置
*/
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15 /* 最低中断优先级 */
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5 /* 系统调用最高优先级 */
#define configKERNEL_INTERRUPT_PRIORITY (configLIBRARY_LOWEST_INTERRUPT_PRIORITY << 4)
#define configMAX_SYSCALL_INTERRUPT_PRIORITY (configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << 4)
/**
* @brief 性能测量函数
*/
/* 任务运行时间统计 */
void GetTaskStats(void)
{
TaskStatus_t *pxTaskStatusArray;
volatile UBaseType_t uxArraySize, x;
configRUN_TIME_COUNTER_TYPE ulTotalTime, ulStatsAsPercentage;
/* 获取任务数量 */
uxArraySize = uxTaskGetNumberOfTasks();
/* 分配内存 */
pxTaskStatusArray = pvPortMalloc( uxArraySize * sizeof( TaskStatus_t ) );
if( pxTaskStatusArray != NULL )
{
/* 获取任务信息 */
uxArraySize = uxTaskGetSystemState( pxTaskStatusArray, uxArraySize, &ulTotalTime );
/* 计算每个任务的CPU使用率 */
for( x = 0; x < uxArraySize; x++ )
{
ulStatsAsPercentage = pxTaskStatusArray[ x ].ulRunTimeCounter / (ulTotalTime / 100UL);
printf("Task: %s, CPU: %lu%%\r\n",
pxTaskStatusArray[ x ].pcTaskName,
ulStatsAsPercentage);
}
vPortFree( pxTaskStatusArray );
}
}
/* 栈使用情况检查 */
void CheckStackUsage(void)
{
printf("LED Task Stack High Water Mark: %u\r\n",
uxTaskGetStackHighWaterMark(xTaskLED));
printf("Button Task Stack High Water Mark: %u\r\n",
uxTaskGetStackHighWaterMark(xTaskButton));
printf("UART Task Stack High Water Mark: %u\r\n",
uxTaskGetStackHighWaterMark(xTaskUART));
}
/**
* @brief FreeRTOSConfig.h 关键配置项
*/
/* 基础系统配置 */
#define configUSE_PREEMPTION 1 /* 启用抢占式调度 */
#define configUSE_TIME_SLICING 1 /* 启用时间片轮转 */
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 /* 启用硬件优化 */
#define configUSE_TICKLESS_IDLE 0 /* 关闭无节拍空闲模式 */
#define configCPU_CLOCK_HZ 100000000 /* CPU时钟频率 */
#define configTICK_RATE_HZ 1000 /* 系统节拍频率 */
#define configMAX_PRIORITIES 8 /* 最大优先级数 */
#define configMINIMAL_STACK_SIZE 64 /* 最小栈大小 */
#define configMAX_TASK_NAME_LEN 16 /* 任务名长度 */
/**
* @brief 内存管理策略选择
*/
/* 方案1:静态分配(推荐用于资源受限系统) */
#define configSUPPORT_STATIC_ALLOCATION 1
#define configSUPPORT_DYNAMIC_ALLOCATION 0
#define configTOTAL_HEAP_SIZE 0
/* 方案2:动态分配(推荐用于资源充足系统) */
#define configSUPPORT_STATIC_ALLOCATION 0
#define configSUPPORT_DYNAMIC_ALLOCATION 1
#define configTOTAL_HEAP_SIZE 4096 /* 4KB堆大小 */
/* 方案3:混合分配(灵活性最高) */
#define configSUPPORT_STATIC_ALLOCATION 1
#define configSUPPORT_DYNAMIC_ALLOCATION 1
#define configTOTAL_HEAP_SIZE 2048 /* 2KB堆大小 */
/**
* @brief 安全相关配置
*/
/* 栈溢出检测 */
#define configCHECK_FOR_STACK_OVERFLOW 2 /* 方法2:检查栈底标记 */
/* MPU支持 */
#define configENABLE_MPU 1 /* 启用MPU */
#define configENABLE_FPU 1 /* 启用FPU */
#define configENABLE_TRUSTZONE 0 /* TrustZone支持 */
/* 优先级继承 */
#define configUSE_MUTEXES 1 /* 启用互斥量 */
#define configUSE_RECURSIVE_MUTEXES 1 /* 递归互斥量 */
/**
* @brief 调试相关配置
*/
/* 运行时统计 */
#define configGENERATE_RUN_TIME_STATS 1 /* 启用运行时统计 */
#define configUSE_TRACE_FACILITY 1 /* 启用跟踪功能 */
#define configUSE_STATS_FORMATTING_FUNCTIONS 1 /* 格式化输出 */
/* 断言支持 */
#define configASSERT( x ) if( ( x ) == 0 ) { taskDISABLE_INTERRUPTS(); for( ;; ); }
/* 钩子函数 */
#define configUSE_IDLE_HOOK 1 /* 空闲钩子 */
#define configUSE_TICK_HOOK 1 /* 节拍钩子 */
#define configUSE_MALLOC_FAILED_HOOK 1 /* 内存分配失败钩子 */
时间分片本质:单核MCU通过快速任务切换实现"伪并行"
硬件依赖:依靠SysTick定时器和PendSV异常实现任务调度
调度算法:基于优先级的抢占式调度,支持硬件优化
状态管理:通过TCB和多个链表管理任务状态转换
首先是切换速度极快,任务切换只需几十个CPU周期(微秒级)
时间片很小:通常1ms,人眼无法察觉
连续性好:每个任务都在持续获得CPU时间;响应及时高优先级任务可以立即抢占低优先级任务
场景 | 推荐配置 | 说明 |
|---|---|---|
资源受限设备 | 静态分配 + heap_1 | 内存使用可预测 |
通用应用 | 混合分配 + heap_4 | 平衡性能和灵活性 |
安全关键应用 | 启用MPU + 栈检测 | 最高安全等级 |
高性能应用 | 硬件优化调度 | 最低调度延迟 |