一、获取FreeRTOS(熟悉)
1.1 源码获取:
- FreeRTOS官网:https://www.freertos.org/,本人所使用的例程为FreeRTOS的V10.4.6版本。
- 进入后点击下载FreeRTOS,选择“FreeRTOS 202112.00”文件,下载完成后解压到指定目录。
名称 | 描述 |
FreeRTOS | FreeRTOS内核 |
FreeRTOS-Plus | FreeRTOS组件 |
tools | 工具 |
GitHub-FreeRTOS-Home | FreeRTOS的GitHub仓库链接 |
Quick_Start_Guide | 快速入门指南官方文档链接 |
Upgrading-to-FreeRTOS-xxx | 升级到指定FreeRTOS版本官方文档链接 |
History.txt | FreeRTOS历史更新记录 |
其他 | 其他 |
我们主要掌握 FreeRTOS内核就 可以了,内核里面有以下文件
名称 | 描述 |
Demo | FreeRTOS演示例程 |
License | FreeRTOS相关许可 |
Source | FreeRTOS源码 |
Test | 公用以及移植层测试代码 |
我们主要掌握demo以及source即可
Demo文件夹
Demo文件夹里面就是FreeRTOS的演示例程,如下所示:我们主要看就就是这两个STM32相关的
可以看出FreeRTOS 支持多种芯片架构,支持多种不同型号芯片,对于入门学习FreeRTOS是十分有帮助的,在学习移植FreeRTOS的过程中可以参考这些演示工程。
Source文件夹
就是FreeRTOS源码
名称 | 描述 |
include | 内包含了FreeRTOS的头文件 |
portable | 内包含了FreeRTOS的移植文件 |
croutine.c | 协程相关文件 |
event_groups.c | 事件相关文件 |
list.c | 列表相关文件 |
queue.c | 队列相关文件 |
stream_buffer.c | 流式缓冲区相关文件 |
tasks.c | 任务相关文件 |
timers.c | 软件定时器相关文件 |
portable文件夹
FreeRTOS操作系统归根到底是一个软件层面的东西,那FreeRTOS是如何跟硬件联系在一起的呢?
portable文件夹里面的东西就是连接桥梁
由于我们使用MDK开发,因此这里只重点介绍其中的部分移植文件
名称 | 描述 |
Keil | 指向RVDS文件夹 |
RVDS | 不同内核芯片的移植文件 |
MemMang | 内存管理文件 |
二、FreeRTOS手把手移植(掌握)
2.1 目的:实现正点原子开发板的FreeRTOS移植
2.2 移植准备:
①FreeRTOS源码
②使用HAL库版本的《内存管理的实验》为基础工程进行FreeRTOS的移植。(有需要可以留言或者私信)
2.3 移植步骤:
2.3.1 添加FreeRTOS源码
详见FreeRTOS操作指南V1.5(后期会免费提供给大家,如需可留言或者私信)
将所有FreeRTOS相关的所需文件添加到工程后,如下图 所示:
2.3.2添加FreeRTOSConfig.h文件,添加至user路径下
FreeRTOSConfig.h是 FreeRTOS操作系统的配置文件, FreeRTOS操作系统是可裁剪的,用户可以根据需求对 FreeRTOS进行裁剪,裁剪掉不需要用到的 FreeRTOS功能,以此来节约 MCU中寸土寸金的内存资源。那么 FreeRTOSConfig.h文件从哪里来呢?主要有三个途径:
- 自己编写(新手不推荐)
- 演示demo
- 参考的项目
2.3.3修改SYSTEM文件
SYSTEM文件夹中的文件一开始是针对 μC/OS编写的,因此使用 FreeRTOS的话,就需要作相应的修改。SYSTEM文件夹中一共需要修改三个文件,分别是 sys.h、 usart.c、 delay.c。
- sys.h文件 :sys.h文件的修改很简单, 在 sys.h文件中使用了宏 SYS_SUPPORT_OS来定义是否支持 OS因为要支持 FreeRTOS,因此应当将宏 SYS_SUPPORT_OS定义为 1,具体修改如下 所示
- usart.c文件:usart.c文件的修改也很简单,一共有两个地方需要修改, 首先就是串口的中断服务函数,原本在使用 μC/OS的时候,进入和退出中断需要添加 OSIntEnter()和 OSIntExit()两个函数,这是 μC/OS对于中断 的相关处理机制,而 FreeRTOS中并没有这种机制,因此 将这两行代码删除,修改后串口的中断服务函数如下 所示
一个 是 添加 FreeRTOS.h头 文件,默认 是添加的 UCOS中 的 includes.h头文件,修改以后如下:
- 修改 delay.c文件:接下来修改SYSTEM文件夹中的最后一个文件 delay.c delay.c文件需要改动的地方就比较多了,大致可分为三个步骤:删除适用于 μC/OS但不适用于 FreeRTOS的相关代码、添加FreeRTOS的相关代码、修改部分 内容 。
(1) 删除适用于 μC/OS但不适用于 FreeRTOS的相关代码: 一共需要删除1个 全局变量、 6个宏定义、 3个函数 ,这些要删除的代码在使用 μC/OS的时候会使用到,但是在使用 FreeRTOS的时候无需使用 ,需要删除的代码如下所示:
/* 定义g_fac_ms变量, 表示ms延时的倍乘数,
* 代表每个节拍的ms数, (仅在使能os的时候,需要用到)
*/
static uint16_t g_fac_ms = 0;
/*
* 当delay_us/delay_ms需要支持OS的时候需要三个与OS相关的宏定义和函数来支持
* 首先是3个宏定义:
* delay_osrunning :用于表示OS当前是否正在运行,以决定是否可以使用相关函数
* delay_ostickspersec :用于表示OS设定的时钟节拍,
* delay_init将根据这个参数来初始化systick
* delay_osintnesting :用于表示OS中断嵌套级别,因为中断里面不可以调度,
* delay_ms使用该参数来决定如何运行
* 然后是3个函数:
* delay_osschedlock :用于锁定OS任务调度,禁止调度
* delay_osschedunlock :用于解锁OS任务调度,重新开启调度
* delay_ostimedly :用于OS延时,可以引起任务调度.
*
* 本例程仅作UCOSII和UCOSIII的支持,其他OS,请自行参考着移植 */
/* 支持UCOSII */
#ifdef OS_CRITICAL_METHOD /* OS_CRITICAL_METHOD定义了,说明要支持UCOSII */
#define delay_osrunning OSRunning /* OS是否运行标记,0,不运行;1,在运行 */
#define delay_ostickspersec OS_TICKS_PER_SEC /* OS时钟节拍,即每秒调度次数 */
#define delay_osintnesting OSIntNesting /* 中断嵌套级别,即中断嵌套次数 */
#endif
/* 支持UCOSIII */
#ifdef CPU_CFG_CRITICAL_METHOD /* CPU_CFG_CRITICAL_METHOD定义了,说明要支持UCOSIII */
#define delay_osrunning OSRunning /* OS是否运行标记,0,不运行;1,在运行 */
#define delay_ostickspersec OSCfg_TickRate_Hz /* OS时钟节拍,即每秒调度次数 */
#define delay_osintnesting OSIntNestingCtr /* 中断嵌套级别,即中断嵌套次数 */
#endif
/**
* @brief us级延时时,关闭任务调度(防止打断us级延迟)
* @param 无
* @retval 无
*/
void delay_osschedlock(void)
{
#ifdef CPU_CFG_CRITICAL_METHOD /* 使用UCOSIII */
OS_ERR err;
OSSchedLock(&err); /* UCOSIII的方式,禁止调度,防止打断us延时 */
#else /* 否则UCOSII */
OSSchedLock(); /* UCOSII的方式,禁止调度,防止打断us延时 */
#endif
}
/**
* @brief us级延时时,恢复任务调度
* @param 无
* @retval 无
*/
void delay_osschedunlock(void)
{
#ifdef CPU_CFG_CRITICAL_METHOD /* 使用UCOSIII */
OS_ERR err;
OSSchedUnlock(&err); /* UCOSIII的方式,恢复调度 */
#else /* 否则UCOSII */
OSSchedUnlock(); /* UCOSII的方式,恢复调度 */
#endif
}
/**
* @brief us级延时时,恢复任务调度
* @param ticks : 延时的节拍数
* @retval 无
*/
void delay_ostimedly(uint32_t ticks)
{
#ifdef CPU_CFG_CRITICAL_METHOD
OS_ERR err;
OSTimeDly(ticks, OS_OPT_TIME_PERIODIC, &err); /* UCOSIII延时采用周期模式 */
#else
OSTimeDly(ticks); /* UCOSII延时 */
#endif
}
(2) 添加 FreeRTOS的相关代码:只需要在delay.c文件中使用 extern关键字导入一个 FreeRTOS函数xPortSysTickHandler()即可,这个函数是 用于处理 FreeRTOS系统时钟节拍的,本教程是使用
SysTick作为 FreeRTOS操作系统的心跳,因此需要在 SysTick的中断服务函数中调用这个函数,因此将代码添加到 SysTick中断服务函数之前,代码修改如下:
extern void xPortSysTickHandler(void);
/**
* @brief systick中断服务函数,使用OS时用到
* @param ticks: 延时的节拍数
* @retval 无
*/
void SysTick_Handler(void)
{
/*代码省略*/
}
(3) 修改部分内容最后要修改的内容包括两个,分别是包含头文件和4个函数。首先来看需要修改的4个函数,分别是 SysTick_Handler()、 delay_init()、 delay_us()和delay_ms()。
(a)SysTick_Handler()这个函数是SysTick的中断服务函数,需要在这个函数中重复调用上 个步骤中导入的函数xPortSysTickHand(),xPortSysTickHandler(),代码修改后如下所示
/**
* @brief systick中断服务函数,使用OS时用到
* @param ticks: 延时的节拍数
* @retval 无
*/
//systick中断服务函数,使用ucos时用到
void SysTick_Handler(void)
{
HAL_IncTick();
/* OS开始跑了,才执行正常的调度处理 */
if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)//系统已经运行
{
xPortSysTickHandler();
}
}
(b) delay_init() 函数delay_init()主要用于初始化 SysTick。这里要说明的是, 在后续调用函数
vTaskStartScheduler()这个函数在下文中讲解到 FreeRTOS任务调度器的时候会具体分析)的
时候, FreeRTOS会按照 FreeRTOSConfig.h文件的配置对 SysTick进行初始化,因此 delay_init()函数初始化的 SysTick主要使用在 FreeRTOS开始任务调度之前。函数 delay_init()要修改的部分
主要为 SysTick的重装载值以及删除不用的代码,代码修改如下:
//初始化延迟函数
//SYSTICK的时钟固定为AHB时钟,基础例程里面SYSTICK时钟频率为AHB/8
//这里为了兼容FreeRTOS,所以将SYSTICK的时钟频率改为AHB的频率!
//SYSCLK:系统时钟频率
void delay_init()
{
u32 reload;
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);//选择外部时钟 HCLK
fac_us=SystemCoreClock/1000000; //不论是否使用OS,fac_us都需要使用
reload=SystemCoreClock/1000000; //每秒钟的计数次数 单位为M
reload*=1000000/configTICK_RATE_HZ; //根据configTICK_RATE_HZ设定溢出时间
//reload为24位寄存器,最大值:16777216,在72M下,约合0.233s左右
fac_ms=1000/configTICK_RATE_HZ; //代表OS可以延时的最少单位
SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk; //开启SYSTICK中断
SysTick->LOAD=reload; //每1/configTICK_RATE_HZ秒中断一次
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; //开启SYSTICK
}
(c) delay_us()函数
delay_us()用于微秒级的 CPU忙延时 ,原本的函数 delay_us()延时的前后加入了自定义函数 delay_osschedlock()和 delay_osschedunlock()用于锁定和解锁 μC/OS的任务调度器,以此来
让延时更加准确。在 FreeRTOS中可以不用加入这两个函数,但是要注意的是,这会让函数
delay_us()的微秒级延时的精度有所下降, 函数 delay_us()修改后的代码如下所示:
//延时nus
//nus:要延时的us数.
//nus:0~204522252(最大值即2^32/fac_us@fac_us=168)
void delay_us(u32 nus)
{
u32 ticks;
u32 told,tnow,tcnt=0;
u32 reload=SysTick->LOAD; //LOAD的值
/* 删除适用于μC/OS用于锁定任务调度器的自定义函数 */
ticks=nus*fac_us; //需要的节拍数
told=SysTick->VAL; //刚进入时的计数器值
while(1)
{
tnow=SysTick->VAL;
if(tnow!=told)
{
if(tnow<told)tcnt+=told-tnow; //这里注意一下SYSTICK是一个递减的计数器就可以了.
else tcnt+=reload-tnow+told;
told=tnow;
if(tcnt>=ticks)break; //时间超过/等于要延迟的时间,则退出.
}
};
}
(d) delay_ms()函数
delay_ms()用于毫秒级的 CPU忙延时,原本的函数 delay_ms()会判断 μC/OS是否运
行,如果 μC/OS正在运行的话,就使用 μC/OS的 OS延时进行毫秒级的延时,否则就调用函数
delay_us()进行毫秒级的 CPU忙延时。在 FreeRTOS中,可以将函数 delay_ms()定义为只进行
CPU忙延时,当需要 OS延时的时候,调用 FreeRTOS提供的 OS延时函数 vTaskDelay()(在下
文讲解 FreeRTOS时间管理的时候会对此函数进行分析)进行系统节拍级延时,函数 delay_ms()修改后的代码如下所示:
//延时nms
//nms:要延时的ms数
//nms:0~65535
void delay_ms(u32 nms)
{
if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)//系统已经运行
{
if(nms>=fac_ms) //延时的时间大于OS的最少时间周期
{
vTaskDelay(nms/fac_ms); //FreeRTOS延时
}
nms%=fac_ms; //OS已经无法提供这么小的延时了,采用普通方式延时
}
delay_us((u32)(nms*1000)); //普通方式延时
}
(e) 包含头文件 根据上述步骤的修改,delay.c文件中使用到了 FreeRTOS的相关函数,因此就需要在 delay.c文件中包含 FreeRTOS的相关头文件,并且移除掉原本存在的 μC/OS相关头文件。先看一下修改前 delay.c文件中包含的 μC/OS相关的头文件:
至此,SYSTEM文件夹针对 FreeRTOS的修改就完成了。
2.3.4 修改中断相应文件
在FreeRTOS的移植过程中会这几到三个重要的中断,分别是 FreeRTOS系统时基定时器的中断( SysTick中断)、 SVC中断、 PendSV中断( SVC中断和 PendSV中断在下文讲解 FreeRTOS中断和 FreeRTOS任务切换的时候会具体分析),这三个中断的中断服务函数在 HAL库提供的文件中都有定义。
其中,SysTick的中断服务函数在 delay.c文件中已经定义了,并且 FreeRTOS也提供了 SVC和 PendSV的中断服务函数,因此需要将 提供的这三个中断服务函数注释掉,修改后的代码如下所示:
最后,也是移植FreeRTOS要修改的最后一个地方 FreeRTOSConfig.h文件中有如下定义,改成如下

三、系统配置文件说明(熟悉)
3.1 系统配置文件详解
FreeRTOSConfig.h配置文件的作用:对FreeRTOS进行功能配置和裁剪,以及API函数的使能。
配置:FreeRTOS的调度器算法有三种:抢占式,协作式,时间片,也可以通过FreeRTOSConfig.h来配置。
裁剪:很多不用的功能我们便可以将其裁剪掉,FreeRTOSConfig.h的宏定义便可实现这个功能。
相关宏大致可分为三类:
- “INCLUDE”:配置FreeRTOS中可选的API函数,通过控制这类宏还选择使能还是失能。使用“ INCLUDE”配置项对部分 API函数进行条件编译,当“ INCLUDE”配置项被定义为 1时,其对应的 API函数则会加入编译。对于用不到的 API函数,用户则可以将其对应的“ INCLUDE”配置项设置为 0,那么这个 API函数就不会加入编译,以减少不必要的系统开销。“
- “config”:完成FreeRTOS的功能配置和裁剪,“config”配置项按照配置的 功能分类,可分为 十类,分别为基础配置项、内存分配相关定义、钩子函数相关定义、运行时间和任务状态统计相关定义、协 程相关定义、软件定时器相关定义、中断嵌套行为配置、断言、 FreeRTOS MPU特殊定义和 ARMv8-M 安全侧端口相关定义。
- 其他配置项:PendSV宏定义、SVC宏定义,这两个宏为PendSV和 SVC的中断服务函数,主要用于 FreeRTOS操作系统的任务切换,有关 FreeRTOS操作系统中任务切换的相关内容。
具体如下:
/* 基础配置项 */
#define configUSE_PREEMPTION 1 /* 1: 抢占式调度器, 0: 协程式调度器, 无默认需定义 */
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 /* 1: 使用硬件计算下一个要运行的任务, 0: 使用软件算法计算下一个要运行的任务, 默认: 0 */
#define configUSE_TICKLESS_IDLE 0 /* 1: 使能tickless低功耗模式, 默认: 0 */
#define configCPU_CLOCK_HZ SystemCoreClock /* 定义CPU主频, 单位: Hz, 无默认需定义 */
//#define configSYSTICK_CLOCK_HZ (configCPU_CLOCK_HZ / 8)/* 定义SysTick时钟频率,当SysTick时钟频率与内核时钟频率不同时才可以定义, 单位: Hz, 默认: 不定义 */
#define configTICK_RATE_HZ 1000 /* 定义系统时钟节拍频率, 单位: Hz, 无默认需定义 */
#define configMAX_PRIORITIES 32 /* 定义最大优先级数, 最大优先级=configMAX_PRIORITIES-1, 无默认需定义 */
#define configMINIMAL_STACK_SIZE 128 /* 定义空闲任务的栈空间大小, 单位: Word, 无默认需定义 */
#define configMAX_TASK_NAME_LEN 16 /* 定义任务名最大字符数, 默认: 16 */
#define configUSE_16_BIT_TICKS 0 /* 1: 定义系统时钟节拍计数器的数据类型为16位无符号数, 无默认需定义 */
#define configIDLE_SHOULD_YIELD 1 /* 1: 使能在抢占式调度下,同优先级的任务能抢占空闲任务, 默认: 1 */
#define configUSE_TASK_NOTIFICATIONS 1 /* 1: 使能任务间直接的消息传递,包括信号量、事件标志组和消息邮箱, 默认: 1 */
#define configTASK_NOTIFICATION_ARRAY_ENTRIES 1 /* 定义任务通知数组的大小, 默认: 1 */
#define configUSE_MUTEXES 1 /* 1: 使能互斥信号量, 默认: 0 */
#define configUSE_RECURSIVE_MUTEXES 1 /* 1: 使能递归互斥信号量, 默认: 0 */
#define configUSE_COUNTING_SEMAPHORES 1 /* 1: 使能计数信号量, 默认: 0 */
#define configUSE_ALTERNATIVE_API 0 /* 已弃用!!! */
#define configQUEUE_REGISTRY_SIZE 8 /* 定义可以注册的信号量和消息队列的个数, 默认: 0 */
#define configUSE_QUEUE_SETS 1 /* 1: 使能队列集, 默认: 0 */
#define configUSE_TIME_SLICING 1 /* 1: 使能时间片调度, 默认: 1 */
#define configUSE_NEWLIB_REENTRANT 0 /* 1: 任务创建时分配Newlib的重入结构体, 默认: 0 */
#define configENABLE_BACKWARD_COMPATIBILITY 0 /* 1: 使能兼容老版本, 默认: 1 */
#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 0 /* 定义线程本地存储指针的个数, 默认: 0 */
#define configSTACK_DEPTH_TYPE uint16_t /* 定义任务堆栈深度的数据类型, 默认: uint16_t */
#define configMESSAGE_BUFFER_LENGTH_TYPE size_t /* 定义消息缓冲区中消息长度的数据类型, 默认: size_t */
/* 内存分配相关定义 */
#define configSUPPORT_STATIC_ALLOCATION 0 /* 1: 支持静态申请内存, 默认: 0 */
#define configSUPPORT_DYNAMIC_ALLOCATION 1 /* 1: 支持动态申请内存, 默认: 1 */
#define configTOTAL_HEAP_SIZE ((size_t)(10 * 1024)) /* FreeRTOS堆中可用的RAM总量, 单位: Byte, 无默认需定义 */
#define configAPPLICATION_ALLOCATED_HEAP 0 /* 1: 用户手动分配FreeRTOS内存堆(ucHeap), 默认: 0 */
#define configSTACK_ALLOCATION_FROM_SEPARATE_HEAP 0 /* 1: 用户自行实现任务创建时使用的内存申请与释放函数, 默认: 0 */
/* 钩子函数相关定义 */
#define configUSE_IDLE_HOOK 0 /* 1: 使能空闲任务钩子函数, 无默认需定义 */
#define configUSE_TICK_HOOK 0 /* 1: 使能系统时钟节拍中断钩子函数, 无默认需定义 */
#define configCHECK_FOR_STACK_OVERFLOW 0 /* 1: 使能栈溢出检测方法1, 2: 使能栈溢出检测方法2, 默认: 0 */
#define configUSE_MALLOC_FAILED_HOOK 0 /* 1: 使能动态内存申请失败钩子函数, 默认: 0 */
#define configUSE_DAEMON_TASK_STARTUP_HOOK 0 /* 1: 使能定时器服务任务首次执行前的钩子函数, 默认: 0 */
/* 运行时间和任务状态统计相关定义 */
#define configGENERATE_RUN_TIME_STATS 0 /* 1: 使能任务运行时间统计功能, 默认: 0 */
#if configGENERATE_RUN_TIME_STATS
#include "./BSP/TIMER/btim.h"
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() ConfigureTimeForRunTimeStats()
extern uint32_t FreeRTOSRunTimeTicks;
#define portGET_RUN_TIME_COUNTER_VALUE() FreeRTOSRunTimeTicks
#endif
#define configUSE_TRACE_FACILITY 1 /* 1: 使能可视化跟踪调试, 默认: 0 */
#define configUSE_STATS_FORMATTING_FUNCTIONS 1 /* 1: configUSE_TRACE_FACILITY为1时,会编译vTaskList()和vTaskGetRunTimeStats()函数, 默认: 0 */
/* 协程相关定义 */
#define configUSE_CO_ROUTINES 0 /* 1: 启用协程, 默认: 0 */
#define configMAX_CO_ROUTINE_PRIORITIES 2 /* 定义协程的最大优先级, 最大优先级=configMAX_CO_ROUTINE_PRIORITIES-1, 无默认configUSE_CO_ROUTINES为1时需定义 */
/* 软件定时器相关定义 */
#define configUSE_TIMERS 1 /* 1: 使能软件定时器, 默认: 0 */
#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) /* 定义软件定时器任务的优先级, 无默认configUSE_TIMERS为1时需定义 */
#define configTIMER_QUEUE_LENGTH 5 /* 定义软件定时器命令队列的长度, 无默认configUSE_TIMERS为1时需定义 */
#define configTIMER_TASK_STACK_DEPTH ( configMINIMAL_STACK_SIZE * 2) /* 定义软件定时器任务的栈空间大小, 无默认configUSE_TIMERS为1时需定义 */
/* 可选函数, 1: 使能 */
#define INCLUDE_vTaskPrioritySet 1 /* 设置任务优先级 */
#define INCLUDE_uxTaskPriorityGet 1 /* 获取任务优先级 */
#define INCLUDE_vTaskDelete 1 /* 删除任务 */
#define INCLUDE_vTaskSuspend 1 /* 挂起任务 */
#define INCLUDE_xResumeFromISR 1 /* 恢复在中断中挂起的任务 */
#define INCLUDE_vTaskDelayUntil 1 /* 任务绝对延时 */
#define INCLUDE_vTaskDelay 1 /* 任务延时 */
#define INCLUDE_xTaskGetSchedulerState 1 /* 获取任务调度器状态 */
#define INCLUDE_xTaskGetCurrentTaskHandle 1 /* 获取当前任务的任务句柄 */
#define INCLUDE_uxTaskGetStackHighWaterMark 1 /* 获取任务堆栈历史剩余最小值 */
#define INCLUDE_xTaskGetIdleTaskHandle 1 /* 获取空闲任务的任务句柄 */
#define INCLUDE_eTaskGetState 1 /* 获取任务状态 */
#define INCLUDE_xEventGroupSetBitFromISR 1 /* 在中断中设置事件标志位 */
#define INCLUDE_xTimerPendFunctionCall 1 /* 将函数的执行挂到定时器服务任务 */
#define INCLUDE_xTaskAbortDelay 1 /* 中断任务延时 */
#define INCLUDE_xTaskGetHandle 1 /* 通过任务名获取任务句柄 */
#define INCLUDE_xTaskResumeFromISR 1 /* 恢复在中断中挂起的任务 */
/* 中断嵌套行为配置 */
#ifdef __NVIC_PRIO_BITS
#define configPRIO_BITS __NVIC_PRIO_BITS
#else
#define configPRIO_BITS 4
#endif
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15 /* 中断最低优先级 */
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5 /* FreeRTOS可管理的最高中断优先级 */
#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
#define configMAX_API_CALL_INTERRUPT_PRIORITY configMAX_SYSCALL_INTERRUPT_PRIORITY
/* FreeRTOS中断服务函数相关定义 */
#define xPortPendSVHandler PendSV_Handler
#define vPortSVCHandler SVC_Handler