FreeRTOS简单使用

FreeRTOS简单使用
xucanxxFreeRTOS简单使用
迁移
迁移真的遇到好多坑,最多的还是中断优先级的问题,优先级太高的中断会破坏FreeRTOS的调度,所以与FreeRTOS调度相关的中断优先级必须高于其他中断
配置
在 Cortex-M 架构中,优先级数值越小,优先级越高。
FreeRTOS的配置主要集中在FreeRTOSConfig.h文件中,但是感觉最重要的配置是
1 | /* configKERNEL_INTERRUPT_PRIORITY sets the priority of the tick and context |
configKERNEL_INTERRUPT_PRIORITY
configKERNEL_INTERRUPT_PRIORITY 用于设置 FreeRTOS 内核相关中断(如系统时钟节拍和上下文切换)的优先级。
在 Cortex-M 架构中,优先级数值越小,优先级越高。这里的 (15 << 4) 表示将优先级设置为最低(数值最大),左移 4 位是因为优先级寄存器只使用高 4 位。
该参数决定了 FreeRTOS 内部使用的中断优先级,确保这些中断不会被更高优先级的中断抢占,从而保证内核调度的正常进行。
一般建议将 configKERNEL_INTERRUPT_PRIORITY 设置为最低优先级,以避免与其他高优先级中断冲突,提升系统的稳定性和可靠性。
configMAX_SYSCALL_INTERRUPT_PRIORITY
configMAX_SYSCALL_INTERRUPT_PRIORITY 用于设置允许调用 FreeRTOS API 的中断的最高优先级。
高于该优先级5(数值更小)的中断不能调用 FreeRTOS 的 API(如队列、信号量、任务通知等),否则可能导致系统崩溃或不可预期的行为。
这是因为 FreeRTOS 在临界区会屏蔽低优先级中断,但不会屏蔽高优先级中断。只有优先级等于或低于 configMAX_SYSCALL_INTERRUPT_PRIORITY 的中断,才能安全地与 FreeRTOS 内核交互。
正确配置该参数有助于保证 RTOS 的调度和资源管理的稳定性,避免高优先级中断打断内核关键操作。
实际使用时,建议查阅芯片手册和 FreeRTOS 官方文档,确保优先级配置符合硬件和应用需求。
使用
1 |
|
创建任务
1 | if (xTaskCreate(taskFunc, "taskFunc", configMINIMAL_STACK_SIZE, NULL, 3, &TaskHandle) != pdPASS) { |
传入参数
taskFunc
任务函数指针。这个函数就是任务的入口点,任务调度器会周期性地调用它。“taskFunc”
任务名称。用于调试和跟踪,通常是一个字符串。configMINIMAL_STACK_SIZE
任务栈大小。以字(不是字节)为单位,决定该任务可用的栈空间。NULL
任务参数。传递给任务函数的参数,如果不需要可以填 NULL,由taskFunc方法中的msg接收。3
任务优先级。数值越大优先级越高,决定任务调度的优先顺序。&TaskHandle
任务句柄指针。用于保存任务的句柄,可以后续用于操作该任务(如删除、挂起等)。
如果创建任务失败(返回值不是 pdPASS),会输出错误信息。
等待
vTaskDelay
vTaskDelay 是 FreeRTOS 中用于让任务延时(挂起)一段时间的 API。它的作用是让当前任务进入阻塞状态,直到指定的时间周期过去后再恢复运行。
基本用法
参数是以 tick 为单位的延时时间。tick 是 FreeRTOS 的时钟节拍,具体时长取决于系统配置(比如 1 tick = 1ms)。
延时期间,任务不会占用 CPU,调度器可以运行其他任务。
常用于任务周期性执行或等待某些事件。
注意事项
vTaskDelay 只能用于任务函数内部,不能在中断服务程序中调用。
如果需要精确的周期性执行,建议使用 vTaskDelayUntil。
vTaskDelayUntil
vTaskDelayUntil 是 FreeRTOS 中用于让任务延时到下一个周期的 API。它与 vTaskDelay 的区别在于,vTaskDelayUntil 可以确保任务以固定的时间间隔执行。
1 | void vTaskDelayUntil(TickType_t *pxPreviousWakeTime, TickType_t xTimeIncrement); |
基本用法
- 第一个参数是一个指向上次唤醒时间的变量,通常是一个静态变量或全局变量。
- 第二个参数是以 tick 为单位的周期
- 任务会在每个周期结束时自动唤醒,确保任务以固定的时间间隔执行。
注意事项
- vTaskDelayUntil 只能在任务函数中使用,不能在中断服务程序中使用
- 需要在任务开始时初始化上次唤醒时间,通常使用 xTaskGetTickCount() 获取当前 tick 值。
- 如果任务执行时间超过周期时间,可能会导致任务错过下一个周期的唤醒,因此需要确保任务执行时间小于周期时间。
事件通知
事件通知是 FreeRTOS 中用于任务间通信的一种机制,允许一个任务向另一个任务发送信号或数据。它比信号量和消息队列更轻量级,适用于简单的任务间同步和通知。
发送通知
非中断中发送通知
1 | xTaskNotify(TaskHandle, value, eSetValueWithOverwrite); |
- TaskHandle:目标任务的句柄。
- value:要发送的值,可以是任意整数。
- eSetValueWithOverwrite:通知方式,表示如果目标任务已经有通知值,则覆盖它。
中断中发送通知
1 | void callTaskFuncFromISR(uint32_t value ){ |
- TaskHandle:目标任务的句柄。
- value:要发送的值,可以是任意整数。
- eSetValueWithOverwrite:通知方式,表示如果目标任务已经有通知值,则覆盖它。
- xHigherPriorityTaskWoken:指向一个 BaseType_t 变量的指针,用于判断是否需要进行任务切换。如果发送通知后,目标任务的优先级高于当前任务,则会设置该变量为 pdTRUE,表示需要进行任务切换。如果为pdFALSE,则不需要切换任务。
- portYIELD_FROM_ISR(xHigherPriorityTaskWoken):如果 xHigherPriorityTaskWoken 被设置为 pdTRUE,则会触发任务切换,确保高优先级任务能够立即运行。如果为pdFALSE,则不会进行任务切换,当前中断服务程序将继续执行。
结束任务
结束任务可以使用 vTaskDelete() 函数。该函数会将指定的任务从调度器中删除,并释放其占用的资源。
1 | void vTaskDelete(TaskHandle_t xTaskToDelete); |
- xTaskToDelete:要删除的任务句柄。如果传入 NULL,则会删除当前任务。
动态内存分配
pvPortMalloc 与 vPortFree
用法与 malloc与free类似,但是使用的是 FreeRTOS 的内存管理函数。由于 FreeRTOS 的内存管理是基于堆的,因此需要在 FreeRTOSConfig.h 中配置堆的大小和类型。
1 | //分配20KB的堆内存 |
后记
- 在通过串口通讯进行异步操作时,例如发送串口消息,串口消息返回触发中断的模式,需要在串口信息发送完成后进行一小段时间的vTaskDelay操作,以切出当前调度,开始接收中断。因为为了保护FreeRTOS的内部调度,系统中断的优先级都设定的比FreeRTOS的调度中断的等级低。只有手动进行delay操作才能更加实时的接收中断信息





