码云项目:https://gitee.com/bigvan_tech/FreeRTOS_STM32Project.git
FreeRTOS_STM32Project
基于STM32的FreeRTOS工程,硬件平台基于启明IMT407G(V3.1)开发板,使用STM32CubeMX进行时钟和外围设备的初始化配置,但不使用STM32CubeMX的FreeRTOS中间件,FreeRTOS代码仍采用手动移植,使用MDK-ARM集成开发环境,使用SystemView作为可视化分析工具。
本文介绍了FreeRTOS创建任务和删除任务,并借助SystemView进行可视化分析。
主要参考资料(排名不分先后):
《FreeRTOS中文实用教程》
《FreeRTOS Kernel Developer Guide》
《FreeRTOS Kernel Reference Manual》
《安富莱 STM32-V5开发板_FreeRTOS教程(V1.0)》
《正点原子 STM32F407 FreeRTOS开发手册V1.1》
本文为经验之谈,若有不对的地方还望指正!
一、使用到的API函数
---------------------------------------------------------------------------------------------------
++ vTaskSuspend()
挂起一个任务。
---------------------------------------------------------------------------------------------------
#include "FreeRTOS.h"
#include "task.h"
void vTaskSuspend(TaskHandle_t pxTaskToSuspend);
---------------------------------------------------------------------------------------------------
函数 vTaskSuspend 用于实现 FreeRTOS 操作系统的任务挂起。
● 第 1 个参数填要挂起任务的句柄
使用这个函数要注意以下问题:
1、使用此函数需要在 FreeRTOSConfig.h 配置文件中配置如下宏定义为 1
#define INCLUDE_vTaskSuspend 1
2、如果用往此函数里面填的任务 ID 是 NULL,即数值 0 的话,那么挂起的就是当前正在执行的任务,
此任务被挂起后,FreeRTOS 会切换到任务就绪列表里面下一个要执行的高优先级任务。
3、多次调用此函数的话,只需调用一次 vTaskResume 即可将任务从挂起态恢复。
---------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------
++ vTaskResume()
恢复一个任务的运行。
---------------------------------------------------------------------------------------------------
#include "FreeRTOS.h"
#include "task.h"
void vTaskResume(TaskHandle_t pxTaskToResume);
---------------------------------------------------------------------------------------------------
函数 vTaskResume 用于实现 FreeRTOS 操作系统的任务恢复
● 第 1 个参数填要恢复任务的句柄
使用这个函数要注意以下问题:
1、使用此函数需要在 FreeRTOSConfig.h 配置文件中配置如下宏定义为 1
#define INCLUDE_vTaskSuspend 1
2、多次调用函数 vTaskSuspend 的话,只需调用一次 vTaskResume 即可将任务从挂起态恢复。
3、此函数是用于任务代码中调用的,故不可以在中断服务程序中调用此函数,中断服务程序中使用的
xTaskResumeFromISR(),以后缀 FromISR 结尾。
---------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------
++ xTaskResumeFromISR()
中断服务函数中恢复一个任务的运行。
---------------------------------------------------------------------------------------------------
#include "FreeRTOS.h"
#include "task.h"
BaseType_t xTaskResumeFromISR(TaskHandle_t pxTaskToResume);
---------------------------------------------------------------------------------------------------
函数 vTaskResumeFromISR 用于实现 FreeRTOS 操作系统的任务恢复。
● 第 1 个参数填要恢复任务的句柄
使用这个函数要注意以下问题:
1、使用此函数需要在 FreeRTOSConfig.h 配置文件中配置如下宏定义为 1
#define INCLUDE_xResumeFromISR 1
2、多次调用函数 vTaskSuspend 的话,只需调用一次 vTaskResumeFromISR 即可将任务从挂起态恢复。
3、如果用户打算采用这个函数实现中断与任务的同步,要注意一种情况,如果此函数的调用优先于函数
vTaskSuspend 被调用,那么此次同步会丢失,这种情况下建议使用信号量来实现同步。
4、此函数是用于中断服务程序中调用的,故不可以在任务中使用此函数,任务中使用的是 vTaskResume。
---------------------------------------------------------------------------------------------------
二、工程描述
创建任务Task1在优先级3上,创建任务Task0A、Task0B在优先级2上,创建任务Task2A、Task2B在优先级4上。
进入任务Task0A、Task0B、Task2A、Task2B后,各自挂起自己(Suspend)。
进入任务Task1后恢复(Resume)Task0A和Task2A。
通过按键KEY0和按键KEY2,按键中断恢复(ResumeFromISR)Task0B和Task2B。
延时使用vTaskDelay()以让任务Task1在延迟期间保持在阻塞态。
具体代码见码云代码托管平台:https://gitee.com/bigvan_tech/FreeRTOS_STM32Project/tree/master/Project02
三、分析
从contexts看,Task1工作于优先级3,Task0A,Task0B工作于优先级2,Task2A,Task2B工作于优先级4。
借助SystemView中Events栏,可以进行细节分析。
第一种情况,不在中断中恢复任务:
上图为进入任务Task1后恢复(Resume)Task0A和Task2A:
3845、Task1开始运行。
3846、Task1中恢复Task0A。
3847、Task0A进入就绪态,但是Task0A优先级低于Task1,Task1继续运行。
3848、Task1中恢复Task2A。
3849、Task2A进入就绪态,Task2A优先级高于Task1。
3850、Task2A开始运行。
3851、Task2A挂起自己。
3852、Task2A进入阻塞态。
3853、Task1开始运行。
3854、Task1执行延迟函数。
3855、调度器使Task1进入阻塞态。
3856、因为Task1进入阻塞态,Task0A得以执行。
3857、Task0A挂起自己。
3858、Task0A进入阻塞态。
3859、进入空闲任务。
第二种情况,中断中恢复任务:
上两图为中断恢复(ResumeFromISR)Task2B:
21302、中断中恢复Task2B。
21303、Task2B进入就绪态。
22149、由于Task2B优先级高于Task1,因此调度器使Task2B开始运行。
22150、Task2B挂起自己。
22151、Task2B进入阻塞态。
22152、Task1开始运行。
22153 ~ 22166、同第一种情况。
上两图为中断恢复(ResumeFromISR)Task0B:
10076、中断中恢复Task0B。
10077、Task0B进入就绪态。
10959、由于Task0B优先级低于Task1,因此调度器使Task1开始运行。
10960、Task1中恢复Task0A。
10961、Task0A进入就绪态,但是Task0A优先级低于Task1,Task1继续运行。
10962、Task1中恢复Task2A。
10963、Task2A进入就绪态,Task2A优先级高于Task1。
10964、Task2A开始运行。
10965、Task2A挂起自己。
10966、Task2A进入阻塞态。
10967、Task1开始运行。
10968、Task1执行延迟函数。
10969、调度器使Task1进入阻塞态。
10970、因为Task1进入阻塞态,Task0B比Task0A早进入就绪态,因此Task0B得以执行。
10971、Task0B挂起自己。
10972、Task0B进入阻塞态。
10973、Task0A挂起自己。
10974、Task0A进入阻塞态。
10975、进入空闲任务。
四、小结:
1、Task1(优先级3)中恢复Task0A,由于Task0A优先级低于Task1,Task0A并不会立即执行,恢复Task2A后,Task2A具有高优先级,所以会立即得到执行。执行完Task2A,Task1继续执行,当执行到延迟函数,Task1进入阻塞态,Task0A才会执行。
2、中断中恢复Task0B和Task2B,Task0B和Task2B进入就绪态,但Task0B和Task2B并不会立即执行,等到下一个调度(Scheduler)时刻到来后,Task0B和Task2B才会运行,其中由于Task2B具有高优先级,所以调度(Scheduler)时刻到来后会立即执行Task2B,由于Task0B具有低优先级,只有等到Task1进入阻塞态,Task0B才会运行。