首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >FreeRTOS多任务执行原理详解 - 第二部分

FreeRTOS多任务执行原理详解 - 第二部分

作者头像
云深无际
发布2026-01-07 12:50:17
发布2026-01-07 12:50:17
2320
举报
文章被收录于专栏:云深之无迹云深之无迹

FreeRTOS多任务切换底层原理详解

6. 任务状态转换

6.1 状态转换图

代码语言:javascript
复制
     创建          就绪队列         CPU执行
  [NEW] -----> [READY] -----> [RUNNING]
                 ↑  ↓              ↓
                 ↑  ↓         [时间片用完]
                 ↑  ↓              ↓
              [等待事件]     [BLOCKED]
              [延时等待]    [SUSPENDED]

6.2 状态转换条件

转换

触发条件

说明

NEW → READY

任务创建完成

任务进入就绪队列

READY → RUNNING

调度器选择

成为当前运行任务

RUNNING → READY

时间片用完/高优先级任务就绪

被抢占或主动让出

RUNNING → BLOCKED

等待事件/延时

主动阻塞等待

BLOCKED → READY

事件发生/延时到期

等待条件满足

RUNNING → SUSPENDED

被挂起

明确的挂起操作

SUSPENDED → READY

被恢复

明确的恢复操作

任意状态 → DELETED

任务删除

任务生命周期结束

6.3 状态转换实现

代码语言:javascript
复制
/**
 * @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();
    }
}

7. 实际执行示例

7.1 示例场景设置

假设有一个简单的嵌入式系统,包含以下任务:

代码语言:javascript
复制
/**
 * @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);
}

7.2 任务实现代码

代码语言:javascript
复制
/**
 * @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);
        }
    }
}

7.3 执行时序分析

代码语言:javascript
复制
时间轴: 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执行一次检测
- 串口任务仅在接收到数据时执行(事件驱动)
- 空闲任务在所有其他任务都阻塞时执行

7.4 内存使用分析

代码语言:javascript
复制
/**
 * @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字节 */

8. 性能分析与优化

8.1 任务切换性能分析

代码语言:javascript
复制
/**
 * @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% */

8.2 性能优化建议

8.2.1 调度器优化
代码语言:javascript
复制
/**
 * @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    /* 保留栈溢出检测 */
8.2.2 内存优化
代码语言:javascript
复制
/**
 * @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   /* 空闲任务栈 */
8.2.3 中断优化
代码语言:javascript
复制
/**
 * @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)

8.3 性能测量工具

代码语言:javascript
复制
/**
 * @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));
}

9. 配置要点

9.1 基础配置

代码语言:javascript
复制
/**
 * @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      /* 任务名长度 */

9.2 内存管理配置

代码语言:javascript
复制
/**
 * @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堆大小 */

9.3 安全性配置

代码语言:javascript
复制
/**
 * @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       /* 递归互斥量 */

9.4 调试配置

代码语言:javascript
复制
/**
 * @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       /* 内存分配失败钩子 */

10. 总结

10.1 FreeRTOS多任务执行核心要点

时间分片本质:单核MCU通过快速任务切换实现"伪并行"

硬件依赖:依靠SysTick定时器和PendSV异常实现任务调度

调度算法:基于优先级的抢占式调度,支持硬件优化

状态管理:通过TCB和多个链表管理任务状态转换

10.2 为什么用户感觉是"并行"的?

首先是切换速度极快,任务切换只需几十个CPU周期(微秒级)

时间片很小:通常1ms,人眼无法察觉

连续性好:每个任务都在持续获得CPU时间;响应及时高优先级任务可以立即抢占低优先级任务

10.3 适用场景

场景

推荐配置

说明

资源受限设备

静态分配 + heap_1

内存使用可预测

通用应用

混合分配 + heap_4

平衡性能和灵活性

安全关键应用

启用MPU + 栈检测

最高安全等级

高性能应用

硬件优化调度

最低调度延迟

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-09-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 云深之无迹 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 6. 任务状态转换
    • 6.1 状态转换图
    • 6.2 状态转换条件
    • 6.3 状态转换实现
  • 7. 实际执行示例
    • 7.1 示例场景设置
    • 7.2 任务实现代码
    • 7.3 执行时序分析
    • 7.4 内存使用分析
  • 8. 性能分析与优化
    • 8.1 任务切换性能分析
    • 8.2 性能优化建议
      • 8.2.1 调度器优化
      • 8.2.2 内存优化
      • 8.2.3 中断优化
    • 8.3 性能测量工具
  • 9. 配置要点
    • 9.1 基础配置
    • 9.2 内存管理配置
    • 9.3 安全性配置
    • 9.4 调试配置
  • 10. 总结
    • 10.1 FreeRTOS多任务执行核心要点
    • 10.2 为什么用户感觉是"并行"的?
    • 10.3 适用场景
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档