STM32F030上xTaskCreate()任务调度异常,osThreadNew()正常的原因排查
问题现象
在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

