在FreeRTOS新创建的任务无法进入


问题现象

在一个有两个任务且能正常运行的FreeRTOS工程中,再次添加一个新任务会出现新的任务无法运行(进入)的现象。如下图所示,

  • 旧任务(可正常运行):OLED任务、LED任务
  • 新添加任务(无法运行):串口测试任务

在这里插入图片描述

一、问题验证

初步怀疑是在创建任务时出现了问题,因此可以利用任务创建函数的返回值,来监控任务创建的情况。返回值xReturn有以下三种类型:

/* FreeRTOS error definitions. */
#define errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY	( -1 ) 
#define errQUEUE_BLOCKED						( -4 ) 
#define errQUEUE_YIELD							( -5 ) 

除上述情况还有pdPASS,代表创建任务成功,实际上任务创建函数只会返回以下两种情况

  • pdPASS(成功)
  • errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY(内存不足)
  • 其他错误码(如errQUEUE_BLOCKED、errQUEUE_YIELD)属于队列操作函数的返回值,与任务创建无关

于是创建一个变量来读取返回值,并在Debug中对该变量进行监控。

volatile BaseType_t UARTtask_Create_status = 0;

UARTtask_Create_status = xTaskCreate((TaskFunction_t )UART_task,                   
                                     (const char*    )"UART_task",                      
                                     (uint16_t       )UART_STK_SIZE,                    
                                     (void*          )NULL,                                 
                                     (UBaseType_t    )UART_TASK_PRIO,                   
                                     (TaskHandle_t*  )&UARTtask_Handler);  

Debug结果如下图:

在这里插入图片描述

可以看到返回值为-1,创建该任务内存不足,接着打开FreeRTOSConfig.h文件。
修改其中的configTOTAL_HEAP_SIZE宏定义。

#define configTOTAL_HEAP_SIZE                    ((size_t)3072)
						||
						\/
#define configTOTAL_HEAP_SIZE                    ((size_t)2*3072)

根据自己的情况来修改,我这个工程只是个Demo,所以我索性翻倍了。实际上需要根据任务、队列等资源需求合理配置,否则会导致内存耗尽

修改后的结果如下:

在这里插入图片描述

二、导致内存不足的原因

该问题主要是因为任务创建的时,任务栈空间设置与FreeRTOS堆空间分配冲突导致的。所有任务及内核变量加在一起所占的大小已经超出了分配的堆空间。

  1. 任务栈(Stack)

    FreeRTOS中 xTaskCreate() 函数的栈大小参数以字(word)为单位,而非字节(byte)。
    对于32位MCU(如STM32):1字 = 4字节
    计算示例
    若栈大小设置为150(单位:字),在不同架构下的内存占用为:
    32位系统: 150字 x 4字节 = 600字节
    16位系统: 150字 x 2字节 = 300字节

  2. 任务控制块(TCB)

    TCB内存占用:
    每个任务的控制块(TCB)是FreeRTOS管理任务的核心数据结构,其大小与具体配置和版本有关。
    典型大小:
    在32位系统中,TCB通常占用约 80~120字节(具体取决于FreeRTOSConfig.h中的配置,如是否启用调试信息)。

  3. 总内存占用计算
    假设一个任务创建时栈大小参数所填150(单位:字),那么这个任务在创建时所占堆空间为:
    总内存占用 = 栈空间 + TCB
    总内存 ≈ 600字节(栈)+100字节(TCB)=700字节

我的任务设置如下:分别包括三个应用任务,栈空间各为150,初始任务200,软件定时任务。需要注意的是初始任务的空间是在创建完所有任务之后才会释放。

在这里插入图片描述

那么总内存大小约为:700*3+900 = 3000字节,而除此之外还有软件定时及其他FreeRTOS内核变量。最开始我配置的堆空间是3072,显然是不够用的,所以就导致了最后一个任务创建失败。

三、其他可能的原因

  • 1、任务优先级冲突: 新任务的优先级设置不当,导致无法被调度。

    高优先级任务阻塞:若新任务优先级与已有高优先级任务相同或更低,且高优先级任务未主动释放CPU(如未调用vTaskDelay或等待信号量),则低优先级任务无法运行。
    空闲任务被占用:若所有任务优先级均高于空闲任务(优先级0),且没有任务主动释放CPU,会导致系统卡死。

  • 2、任务函数实现问题: 任务函数逻辑错误(如死循环未释放CPU、未调用任何阻塞API)。

  • 3、中断优先级冲突: 若新任务涉及中断服务,中断优先级高于configMAX_SYSCALL_INTERRUPT_PRIORITY,会导致任务切换异常。

STM32中使用FreeRTOS(Real-Time Operating System)创建和挂起任务的过程如下: 1. **创建任务**: 创建任务首先需要定义一个函数作为任务的主要执行体。这个函数通常是异步运行的,因为它会在任务上下文中运行。例如: ```c void my_task_function(void *pvParameters) { while(1) { // 任务的具体操作 vTaskDelay(pdMS_TO_TICKS(1000)); // 每隔1秒执行一次 } } ``` `vTaskDelay()` 函数会暂停当前任务,直到指定的时间间隔过去。 2. **初始化任务**: 在主程序中,通过`xTaskCreate()`函数来创建任务实例: ```c static void appTask(void *pvParameters) { xTaskCreate(my_task_function, "My Task", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL); } int main(void) { // 其他初始化步骤... appTask(); // 启动 FreeRTOS vTaskStartScheduler(); // 进入任务循环 // 这里永远不会到达,因为一旦开始调度,程序控制权就会交给RTOS return 0; } ``` `my_task_function` 的第一个参数`pvParameters`在这里是空指针,因为不需要传递额外的信息;`configMINIMAL_STACK_SIZE` 是最小的栈大小;`tskIDLE_PRIORITY + 1` 表示任务优先级比标准空闲任务稍高一些。 3. **挂起任务**: 如果需要暂时停止某个任务,可以使用`vTaskDelayUntil()`或`portYIELD_FROM_ISR()`,前者在给定时间之前不会返回,后者则是在中断上下文中释放控制权。例如: ```c void task_to_pause() { for(;;) { // 执行任务前的操作 portYIELD_FROM_ISR(); // 暂停任务,让其他任务运行 // 任务核心操作 } } ``` 注意,在任务内直接调用`vTaskDelayUntil()`可能导致无限等待,因为它不会在其他任务执行完毕后返回,除非指定的时间到了。 **相关问题--:** 1. 如何在FreeRTOS中查看任务的状态(如已挂起、就绪等)? 2. 如果一个任务永远无法完成,会对系统的性能有何影响? 3. 在STM32中,如何防止阻塞在一个长时间运行的任务上导致其他紧急任务无法及时响应?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值