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

STM32F030上xTaskCreate()任务调度异常,osThreadNew()正常的原因排查

问题:STM32F030上xTaskCreate与osThreadNew创建FreeRTOS任务的调度差异

问题现象

在STM32F030开发板上,基于STM32CubeMX配置的CMSIS-RTOS v2环境下,使用FreeRTOS原生API xTaskCreate() 创建LibmodbusServerTask和AHT20Task时出现调度异常:程序启动仅执行一次osThreadNew()创建的默认任务,之后持续运行LibmodbusServerTask,AHT20Task从未被调度;改用CMSIS-RTOS v2的osThreadNew()创建这两个任务后,任务间能正常切换调度。

使用xTaskCreate创建任务的代码

xTaskCreate(
        LibmodbusServerTask,
        "LibmodbusServerTask",
        512,
        NULL,
        osPriorityNormal,
        NULL
    );
xTaskCreate(
        AHT20Task,
        "AHT20Task",
        512,
        NULL,
        osPriorityNormal,
        NULL
    );

默认任务创建代码

osThreadId_t defaultTaskHandle;
const osThreadAttr_t defaultTask_attributes = {
  .name = "defaultTask",
  .stack_size = 128 * 4,
  .priority = (osPriority_t) osPriorityNormal,
};
defaultTaskHandle = osThreadNew(StartDefaultTask, NULL, &defaultTask_attributes);

三个任务的实现代码

void AHT20Task(void *pvParameters)
{
    while (1)
    {
            // 此处为AHT20相关操作
            vTaskDelay(100);
    }   
}

void LibmodbusServerTask( void *pvParameters )
{
    // 变量定义、Modbus初始化、建立连接
    for (;;) {
        do {
            rc = modbus_receive(ctx, query);
        } while (rc == 0);
        /* 对于无需回复的错误(如RTU模式下的CRC错误),不关闭连接 */
        if (rc == -1 && errno != EMBBADCRC) {
            /* 跳过当前循环 */
            continue;
        }
        rc = modbus_reply(ctx, query, rc, mb_mapping);
        if (rc == -1) {
            // break;
        }
    }
    // 关闭Modbus连接(代码无法执行到此处)
    vTaskDelete(NULL);
}

void StartDefaultTask(void *argument)
{
  /* USER CODE BEGIN StartDefaultTask */
    /* 无限循环 */
    for(;;)
    {   
        vTaskDelay(500);
    }
  /* USER CODE END StartDefaultTask */
}

改用osThreadNew创建任务的代码

osThreadId_t libmodbusTaskHandle;
const osThreadAttr_t libmodbusTask_attributes = {
  .name = "libmodbusTask",
  .stack_size = 128 * 4,
  .priority = (osPriority_t) osPriorityNormal,
};

osThreadId_t aht20TaskHandle;
const osThreadAttr_t aht20Task_attributes = {
  .name = "aht20HandleTask",
  .stack_size = 128 * 4,
  .priority = (osPriority_t) osPriorityNormal,
};

libmodbusTaskHandle = osThreadNew(LibmodbusServerTask, NULL, &libmodbusTask_attributes);
aht20TaskHandle = osThreadNew(AHT20Task, NULL, &aht20Task_attributes);

差异原因分析

1. 优先级映射不匹配

CMSIS-RTOS v2对FreeRTOS的优先级做了封装,osPriorityNormal是CMSIS定义的枚举值,而xTaskCreate的优先级参数需要直接传入FreeRTOS原生的优先级数值(如tskNORMAL_PRIORITY)。两者的数值可能存在差异,导致用xTaskCreate创建的任务实际优先级高于其他任务,抢占了CPU资源。

2. 栈大小单位不同

xTaskCreate的栈大小参数单位是FreeRTOS栈项(通常为4字节,对应一个32位寄存器),而osThreadNew的.stack_size字段单位是字节。你用xTaskCreate时指定了512个栈项(即2048字节),远大于osThreadNew配置的512字节,虽然栈大小足够不会直接导致调度问题,但如果FreeRTOS的栈溢出检测未开启,可能隐藏其他潜在问题。

3. 任务管理机制差异

CMSIS-RTOS v2的osThreadNew()会将任务纳入CMSIS的任务管理体系,与osKernelStart()的调度流程兼容;直接调用xTaskCreate绕过了CMSIS的封装,可能导致任务在调度器初始化的时机不正确,或未被正确加入FreeRTOS的调度链表,引发调度异常。

4. Libmodbus任务的阻塞行为

modbus_receive()在RTU模式下,如果底层串口驱动未基于FreeRTOS的阻塞API(如队列、信号量)实现,会进入忙等待状态,持续占用CPU,不触发任务调度。而osThreadNew()创建的任务可能在CMSIS的封装下,确保串口驱动正确使用了FreeRTOS的阻塞机制,让任务在无数据时进入阻塞态,释放CPU给其他任务。

验证建议

  • 检查优先级映射:查看CubeMX生成代码中osPriorityNormal的定义,对比FreeRTOS原生tskNORMAL_PRIORITY的数值,确保两者一致;或在xTaskCreate中直接使用tskNORMAL_PRIORITY作为优先级参数。
  • 统一栈大小配置:将xTaskCreate的栈大小改为128(对应512字节,与osThreadNew配置一致),排除栈大小影响。
  • 检查Libmodbus底层驱动:确保Modbus RTU的串口接收基于FreeRTOS队列实现,避免忙等待,让任务在无数据时进入阻塞态。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 07:35:04