You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何FreeRTOS在Raspberry Pi Pico(RP2040)中无法抢占任务?

问题

在Raspberry Pi Pico(RP2040)上使用FreeRTOS编写了如下双任务测试程序:

#include "FreeRTOS.h"
#include "task.h"
#include "timers.h"
#include "pico/stdlib.h"
#include <stdio.h>

void Task1(void* nothing)
{
    while(1)
    {
        printf("Task1\n");
        sleep_ms(1000);                             // 不允许抢占
        //vTaskDelay(1 * configTICK_RATE_HZ );      // 允许抢占
    }
}

void Task2(void* nothing)
{
    sleep_ms(500);
    while(1)
    {
        printf("Task2\n");
        sleep_ms(1000);                             // 不允许抢占
        //vTaskDelay(1 * configTICK_RATE_HZ );      // 允许抢占
    }
}


void main()
{
    stdio_init_all();
    sleep_ms(2000);
    printf("\n\n\n\nHello\n\n");

    TaskHandle_t xTask1Handle = NULL;
    TaskHandle_t xTask2Handle = NULL;

    BaseType_t ret1 = xTaskCreate(Task1, "Task1", 256, 0, 10, &xTask1Handle);
    BaseType_t ret2 = xTaskCreate(Task2, "Task2", 256, 0, 10, &xTask2Handle);

    if (ret1 == pdPASS) printf("Task 1 created OK\n");
    else                printf("Task 1 failed\n");

    if (ret2 == pdPASS) printf("Task 2 created OK\n");
    else                printf("Task 2 failed\n");

    vTaskStartScheduler();

    while(1)
    {
    }
}

程序运行时发现:用sleep_ms()时只有一个任务输出,换成vTaskDelay()则两个任务都能正常运行,看起来FreeRTOS没执行任务抢占。

已经在FreeRTOSConfig.h中开启了抢占配置:

#define configUSE_PREEMPTION                    1
#define configUSE_TIME_SLICING                  1

请问还需要做哪些设置才能启用任务抢占?

解决方法

  • 替换裸机阻塞函数,改用FreeRTOS调度接口
    pico/stdlib.h中的sleep_ms()是裸机休眠函数,执行期间不会触发FreeRTOS调度器——它直接让CPU进入低功耗状态,同优先级任务无法通过时间片轮转切换,高优先级任务虽能抢占,但你的两个任务优先级相同,所以会出现单任务独占的情况。而vTaskDelay()是FreeRTOS专属延迟函数,会让当前任务进入阻塞态主动让出CPU,触发调度器切换到其他就绪任务。

  • 检查FreeRTOS时钟节拍核心配置
    在FreeRTOSConfig.h中确认以下宏的配置:

    // 启用SysTick作为FreeRTOS时钟节拍源(RP2040默认依赖此)
    #define configUSE_SYSTICK                      1
    // 设置时钟节拍频率,通常为1000Hz(对应每1ms一个tick)
    #define configTICK_RATE_HZ                     ( ( TickType_t ) 1000 )
    

    若未开启SysTick,FreeRTOS无法生成定时中断触发抢占调度,时间片轮转也无法生效。

  • 确认移植层中断配置正确性
    确保RP2040的FreeRTOS移植包正确实现了SysTick中断和PendSV中断(用于任务上下文切换)。部分自定义移植需手动配置中断优先级,要保证FreeRTOS相关中断的优先级高于普通裸机中断,但低于硬件不可屏蔽中断。

  • 禁止在任务中使用裸机忙等/阻塞函数
    除sleep_ms外,busy_wait_ms这类忙等函数也会持续占用CPU,不会触发调度。任务中所有延迟、阻塞操作都应使用FreeRTOS提供的vTaskDelay()、vTaskDelayUntil()等接口,让调度器有机会切换任务。

内容的提问来源于stack exchange,提问作者Rocketmagnet

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 04:53:15