简介

FreeRTOS的配置都是在FreeRTOSConfig.h,这个文件我们在移植FreeRTOS之后是肯定存在我们工程下的。通过修改FreeRTOSConfig.h的值,我们就可以定制FreeRTOS。这个文件里基本都是宏定义,只要修改宏定义的值,FreeRTOS就完成了配置。

  • INCLUDE_开始的宏:使用INCLUDE_开头的宏用来表示使能或除能 FreeRTOS 中相应的 API 函数,作用就 是用来配置 FreeRTOS 中的可选 API 函数的。
  • config开始的宏:这些宏主要是为了使能FreeRTOS的一些功能了。

    config宏介绍

configAPPLICATION_ALLOCATED_HEAP介绍

configAPPLICATION_ALLOCATED_HEAP(堆内存分配选择宏)默认情况下FreeRTOS的堆内存是由编译器来分配的,将宏configAPPLICATION_ALLOCATED_HEAP定义为 1 的话堆内存可以由用户自行设置,堆内存在 heap_1.cheap_2.cheap_3.cheap_4.cheap_5.c 中有定义,具体在哪个文件取决于用户的选择哪种内存管理方式。

configASSERT介绍

configASSERT(断言配置)断言,类似 C 标准库中的 assert()函数,调试代码的时候可以检查传入的参数是否合理,FreeRTOS 内核中的关键点都会调用configASSERT(x),当 x 为 0 的时候说明有错误发生,使用断言的话会导致开销加大,一般在调试阶段使用。configASSERT()需要在FreeRTOSConfig.h文件中定义,如下实例:

  1. #define configASSERT((x)) if((x)==0) vAssertCalled(__FILE_,__LINE__);

这里的vAssertCalled()由用户定义,可以配置出错时打印到串口、也可以配置出错时在LCD上显示 例如:

  1. #define vAssertCalled(char,int) printf("Error:%s,%d\r\n",char,int)
  2. #define configASSERT(x) if((x)==0) vAssertCalled(__FILE__,__LINE__)

configCHECK_FOR_STACK_OVERFLOW介绍

configCHECK_FOR_STACK_OVERFLOW(堆栈溢出检测)设置堆栈溢出检测,每个任务都有一个任务堆栈,堆栈溢出是导致应用程序不稳定的主要因素,FreeRTOS 提供了两种可选的机制来帮助检测和调试堆栈溢出,不管使用哪种机制都要设置宏 configCHECK_FOR_STACK_OVERFLOW。如果使能了堆栈检测功能的话,即宏 configCHECK_FOR_STACK_OVERFLOW不为 0,那么用户必须提供一个钩子函数(回调函数),当内核检测到堆栈溢出以后就会调用这个钩子函数,此钩子函数原型如下:

  1. void vApplicationStackOverflowHook( TaskHandle_t xTask, char * pcTaskName );

参数xTask是任务句柄,pcTaskName是任务名字,要注意的是堆栈溢出太严重的话可能会损毁这两个参数,如果发生这种情况的话可以直接查看变量pxCurrentTCB来确定哪个任务发生了堆栈溢出。

  • configCHECK_FOR_STACK_OVERFLOW==1,使用堆栈溢出检测方法 1。上下文切换的时候需要保存现场,现场是保存在堆栈中的,这个时候任务堆栈使用率很可能达到最大值,方法一就是不断的检测任务堆栈指针是否指向有效空间,如果指向了无效空间的话就会调用钩子函数。方法一的优点就是快!但是缺点就是不能检测所有的堆栈溢出。
  • configCHECK_FOR_STACK_OVERFLOW==2,使用堆栈溢出检测方法 2。使用方法二的话在创建任务的时候会向任务堆栈填充一个已知的标记值,方法二会一直检测堆栈后面的几个 bytes(标记值)是否被改写,如果被改写的话就会调用堆栈溢出钩子函数,方法二也会使用方法一中的机制!方法二比方法一要慢一些,但是对用户而言还是很快的!方法二能检测到几乎所有的堆栈溢出,但是也有一些情况检测不到,比如溢出值和标记值相同的时候。

    configCPU_CLOCK_HZ介绍

    configCPU_CLOCK_HZ(CPU频率)设置 CPU 的频率。

    configSUPPORT_DYNAMIC_ALLOCATION介绍

    configSUPPORT_DYNAMIC_ALLOCATION(动态内存分配)定义为1的话在创建FreeRTOS的内核对象的时候所需要的 RAM 就会从 FreeRTOS 的堆中动态的获取内存,如果定义为 0 的话所需的 RAM 就需要用户自行提供,默认情况下宏configSUPPORT_DYNAMIC_ALLOCATION 为 1。

    configENABLE_BACKWARD_COMPATIBILITY介绍

    configENABLE_BACKWARD_COMPATIBILITY(数据类型重定义)
    02.配置 - 图1
    在 V8.0.0 之前的 FreeRTOS 中会使用到这些数据类型,这些宏保证了你的代码从V8.0.0之前的版本升级到最新版本的时候不需要做出修改 , 默认情况下宏configENABLE_BACKWARD_COMPATIBILITY为 1。

configGENERATE_RUN_TIME_STATS介绍

configGENERATE_RUN_TIME_STATS(时间统计功能)设置为1开启时间统计功能,相应的 API 函数会被编译,为 0时关闭时间统计功能。如果宏configGENERATE_RUN_TIME_STATS为1的话还需要定义如下的宏:

描述
portCONFIGURE_TIMER_FOR_RUN_TIME_STATS 此宏用来初始化一个外设来作为时间统计的基准时钟。
portGET_RUN_TIME_COUNTER_VALUE 此宏用来返回当前基准时钟的时钟值
portALT_GET_RUN_TIME_COUNTER_VALUE(Time) 此宏用来返回当前基准时钟的时钟值

configIDLE_SHOULD_YIELD介绍

configIDLE_SHOULD_YIELD(空闲任务的调度)此宏定义了与空闲任务(idle Task)处于同等优先级的其他用户任务的行为,当为 0 的时候空闲任务不会为其他处于同优先级的任务让出 CPU 使用权。当为 1 的时候空闲任务就会为处于同等优先级的用户任务让出 CPU 使用权,除非没有就绪的用户任务,这样花费在空闲任务上的时间就会很少
02.配置 - 图2
有三个用户任务:A、B、C,还有一个空闲任务 I,用户任务和空闲任务处于同一优先级,任务切换发生在 T0和T7 时刻。T0 到T1之间的时间为一个时间片,从图中可以看出一开始任务 B、C 都执行了一个完成的时间片,在 T2 时刻空闲任务 I 开始执行,I 任务运行了一段时间以后被 A 任务抢走了 CPU 使用权,A 任务运行到 T3 时刻发生任务切换,B 任务开始运行。可以看出其实任务 I 和任务 A 一起使用了一个时间片,所以任务 A 运行的时间就比其他任务少!一般建议关闭这个功能,毕竟空闲任务用不了多少时间,而且现在的 MCU 性能都很强!

configMAX_CO_ROUTINE_PRIORITIES介绍

configMAX_CO_ROUTINE_PRIORITIES(协程的最大优先级)设置可以分配给协程的最大优先级,也就是协程的优先级数。设置号以后协程的优先级可以从0到configMAX_CO_ROUTINE_PRIORITIES-1,其中0是最低的优先级,configMAX_CO_ROUTINE_PRIORITIES-1为最高的优先级

configMAX_PRIORITIES介绍

configMAX_PRIORITIES(任务最大优先级)设置任务的优先级数量,设置好以后任务就可以使用从0到 configMAX_PRIORITIES-1的优先级,其中0是最低优先级configMAX_PRIORITIES-1是最高优先级

注意和UCOS的区别,UCOS中0是最高优先级!

configMAX_TASK_NAME_LEN介绍

configMAX_TASK_NAME_LEN(设置任务名最大长度)设置任务名最大长度

configMINIMAL_STACK_SIZE介绍

configMINIMAL_STACK_SIZE(设置空闲任务的最小任务堆栈大小)设置空闲任务的最小任务堆栈大小,以字为单位,不是字节。比如在 STM32 上设置为 100的话,那么真正的堆栈大小就是 100*4=400 字节。

configNUM_THREAD_LOCAL_STORAGE_POINTERS介绍

configNUM_THREAD_LOCAL_STORAGE_POINTERS(任务的本地存储指针数组大小)设置每个任务的本地存储指针数组大小,任务控制块中有本地存储数组指针,用户应用程序可以在这些本地存储中存入一些数据

configQUEUE_REGISTRY_SIZE介绍

configQUEUE_REGISTRY_SIZE(可以注册的队列和信号量的最大数量)设置可以注册的队列和信号量的最大数量,在使用内核调试器查看信号量和队列的时候需要设置此宏,而且要先将消息队列和信号量进行注册,只有注册了的队列和信号量才会再内核调试器中看到,如果不使用内核调试器的话此宏设置为 0 即可。

configSUPPORT_STATIC_ALLOCATION介绍

configSUPPORT_STATIC_ALLOCATION(静态内存支持)当此宏定义为 1,在创建一些内核对象的时候需要用户指定 RAM,当为 0 的时候就会自使用 heap.c 中的动态内存管理函数来自动的申请 RAM。

configTICK_RATE_HZ介绍

configTICK_RATE_HZ(系统时钟节拍频率)设置 FreeRTOS 的系统时钟节拍频率,单位为 HZ,此频率就是滴答定时器的中断频率,需要使用此宏来配置滴答定时器的中断。

configTIMER_QUEUE_LENGTH介绍

configTIMER_QUEUE_LENGTH(软件定时器的命令队列长度)配置 FreeRTOS 软件定时器的,FreeRTOS 的软件定时器 API 函数会通过命令队列向软件定时器任务发送消息,此宏用来设置这个软件定时器的命令队列长度。

configTIMER_TASK_PRIORITY介绍

configTIMER_TASK_PRIORITY(软件定时器任务的任务优先级)设置软件定时器任务的任务优先级。

configTIMER_TASK_STACK_DEPTH介绍

configTIMER_TASK_STACK_DEPTH(定时器服务任务的任务堆栈大小)设置定时器服务任务的任务堆栈大小。

configTOTAL_HEAP_SIZE介绍

configTOTAL_HEAP_SIZE(堆大小)设置堆大小,如果使用了动态内存管理的话,FreeRTOS 在创建任务、信号量、队列等的时候就会使用heap_x.c(x 为 1~5) 中的内存申请函数来申请内存。 这些内存就是从堆ucHeap[configTOTAL_HEAP_SIZE]中申请的,堆的大小由configTOTAL_HEAP_SIZE来定义。

configUSE_16_BIT_TICKS介绍

configUSE_16_BIT_TICKS(系统节拍计数器变量数据类型)设置系统节拍计数器变量数据类型,系统节拍计数器变量类型为TickType_t,当configUSE_16_BIT_TICKS为1的时候TickType_t就是16位的,当 configUSE_16_BIT_TICKS为0的话TickType_t就是32位的。

configUSE_APPLICATION_TASK_TAG介绍

configUSE_APPLICATION_TASK_TAG(设置任务标签)此宏设置为1的话函数configUSE_APPLICATION_TASK_TAGF()xTaskCallApplicationTaskHook()就会被编译。

configUSE_CO_ROUTINES介绍

configUSE_CO_ROUTINES(启用协程)此宏为1的时候启用协程,协程可以节省开销,但是功能有限,现在的 MCU 性能已经非常强大了,建议关闭协程。

configUSE_COUNTING_SEMAPHORES介绍

configUSE_COUNTING_SEMAPHORES(打开计数信号量)设置为1的时候启用计数型信号量,相关的API函数会被编译。

configUSE_DAEMON_TASK_STARTUP_HOOK介绍

configUSE_DAEMON_TASK_STARTUP_HOOK(计时任务钩子函数)当宏configUSE_TIMERSconfigUSE_DAEMON_TASK_STARTUP_HOOK都为1的时需要定义函数vApplicationDaemonTaskStartupHook(),函数原型如下:

  1. void vApplicationDaemonTaskStartupHook( void )

configUSE_IDLE_HOOK介绍

configUSE_IDLE_HOOK(空闲任务钩子函数)为1时使用空闲任务钩子函数,用户需要实现空闲任务钩子函数,函数的原型如下:

  1. void vApplicationIdleHook( void )

configUSE_MALLOC_FAILED_HOOK介绍

configUSE_MALLOC_FAILED_HOOK(内存分配失败钩子函数)为1时使用内存分配失败钩子函数,用户需要实现内存分配失败钩子函数,函数原型如下;

  1. void vApplicationMallocFailedHook( void )

configUSE_MUTEXES介绍

configUSE_MUTEXES(互斥信号量)为 1 时使用互斥信号量,相关的 API 函数会被编译。

configUSE_PORT_OPTIMISED_TASK_SELECTION介绍

configUSE_PORT_OPTIMISED_TASK_SELECTION(查找下一个任务的方法)FreeRTOS 有两种方法来选择下一个要运行的任务,一个是通用的方法,另外一个是特殊的方法,也就是硬件方法。

  • 通用方法:configUSE_PORT_OPTIMISED_TASK_SELECTION为0
  • 硬件方法:configUSE_PORT_OPTIMISED_TASK_SELECTION为1,且硬件支持计算前导零(CLZ)指令


configUSE_PREEMPTION介绍

configUSE_PREEMPTION(调度器选择)为1时使用抢占式调度器,为0时使用协程。如果使用抢占式调度器的话内核会在每个时钟节拍中断中进行任务切换,当使用协程的话会在如下地方进行任务切换:

  • 一个任务调用了函数 taskYIELD()。
  • 一个任务调用了可以使任务进入阻塞态的 API 函数。
  • 应用程序明确定义了在中断中执行上下文切换。

configUSE_QUEUE_SETS介绍

configUSE_QUEUE_SETS(队列集)为 1 时启用队列集功能。

configUSE_RECURSIVE_MUTEXES介绍

configUSE_RECURSIVE_MUTEXES(递归互斥信号量)为 1 时使用递归互斥信号量,相关的 API 函数会被编译。

configUSE_STATS_FORMATTING_FUNCTIONS介绍

configUSE_STATS_FORMATTING_FUNCTIONS(查询任务状态)宏configUSE_TRACE_FACILITYconfigUSE_STATS_FORMATTING_FUNCTIONS都为1的时候函数vTaskList()vTaskGetRunTimeStats()会被编译。

configUSE_TASK_NOTIFICATIONS介绍

configUSE_TASK_NOTIFICATIONS(任务通知)为1的时候使用任务通知功能,相关的API函数会被编译,开启了此功能的话每个任务会多消耗 8 个字节。

configUSE_TICK_HOOK介绍

configUSE_TICK_HOOK(时间片钩子函数)为1时使能时间片钩子函数,用户需要实现时间片钩子函数,函数的原型如下:

  1. void vApplicationTickHook( void )

configUSE_TICKLESS_IDLE介绍

configUSE_TICKLESS_IDLE(低功耗tickless模式)为1时使能低功耗tickless模式。

configUSE_TIMERS介绍

configUSE_TIMERS(软件定时器)为1时使用软件定时器,相关的 API 函数会被编译,当宏configUSE_TIMERS为1的话,那么宏configTIMER_TASK_PRIORITYconfigTIMER_QUEUE_LENGTHconfigTIMER_TASK_STACK_DEPTH必须定义。

configUSE_TIME_SLICING介绍

configUSE_TIME_SLICING(时间片轮换开关)默认情况下,FreeRTOS 使用抢占式调度器,这意味着调度器永远都在执行已经就绪了的最高优先级任务,优先级相同的任务在时钟节拍中断中进行切换,当宏 configUSE_TIME_SLICING为0的时候不会在时钟节拍中断中执行相同优先级任务的任务切换,默认情况下宏configUSE_TIME_SLICING为1。

configUSE_TRACE_FACILITY介绍

configUSE_TRACE_FACILITY(可视化跟踪调试)为1启用可视化跟踪调试,会增加一些结构体成员和 API 函数。

configPRIO_BITS介绍

configPRIO_BITS(MCU 使用几位优先级)在CORTEX-M芯片上,中断最多有128位是可配置,也就是有利用一个字节表示中断优先级,但各个芯片厂商都会有自己的中断设计,比如STM32只使用了8位中断优先级中的高4位,第四位都为0,因此在开发STM32的时候configPRIO_BITS为4。

configLIBRARY_LOWEST_INTERRUPT_PRIORITY介绍

configLIBRARY_LOWEST_INTERRUPT_PRIORITY(设置最低优先级)此宏是用来设置最低优先级,前面说了,STM32 优先级使用了 4 位,而且 STM32 配置的中断组4,也就是4位都是抢占优先级。因此优先级数就是 16 个,最低优先级那就是 15。所以此宏就是 15。

configKERNEL_INTERRUPT_PRIORITY介绍

configKERNEL_INTERRUPT_PRIORITY(内核中断优先级,也用来设置PendSV 和滴答定时器的中断优先级)此宏定义如下:

  1. #define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )

这里就相当于将内核中断优先级设置为最低优先级。

configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY介绍

configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY(内核可管理的最大中断优先级)此宏用来设置 FreeRTOS系统可管理的最大优先级。也就是高于5的优先级(优先级数小于 5)不归 FreeRTOS 管理!

configMAX_SYSCALL_INTERRUPT_PRIORITY介绍

configMAX_SYSCALL_INTERRUPT_PRIORITY此宏是configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY左移4位而来的,原因和宏configKERNEL_INTERRUPT_PRIORITY一样。此宏设置好以后,低于此优先级的中断可以安全的调用FreeRTOSAPI函数,高于此优先级的中断FreeRTOS是不能禁止的,中断服务函数也不能调用FreeRTOS的 API 函数!
02.配置 - 图3
由于高于configMAX_SYSCALL_INTERRUPT_PRIORITY的优先级不会被FreeRTOS内核屏蔽,因此那些对实时性要求严格的任务就可以使用这些优先级。

INCLUDE宏配置

宏配置 描述
INCLUDE_xSemaphoreGetMutexHolder 如果要使用函数 xQueueGetMutexHolder()的话宏 INCLUDE_xSemaphoreGetMutexHolder 必须定义为 1。
INCLUDE_xTaskAbortDelay 如果要使用函数 xTaskAbortDelay()的话将宏 INCLUDE_xTaskAbortDelay 定义为 1。
INCLUDE_vTaskDelay 如果要使用函数 vTaskDelay()的话需要将宏 INCLUDE_vTaskDelay 定义为 1。
INCLUDE_vTaskDelayUntil 如果要使用函数 vTaskDelayUntil()的话需要将宏 INCLUDE_vTaskDelayUntil 定义为 1。
INCLUDE_vTaskDelete 如果要使用函数 vTaskDelete()的话需要将宏 INCLUDE_vTaskDelete 定义为 1。
INCLUDE_xTaskGetCurrentTaskHandle 如果要使用函数 xTaskGetCurentTaskHandle() 的话需要将宏INCLUDE_xTaskGetCurrentTaskHandle 定义为 1。
INCLUDE_xTaskGetHandle 如果要使用函数 xTaskGetHandle()的话需要将宏 INCLUDE_xTaskGetHandle 定义为 1。
INCLUDE_xTaskGetIdleTaskHandle 如 果 要 使 用 函 数 xTaskGetIdleTaskHandle() 的话需要将宏INCLUDE_xTaskGetIdleTaskHandle 定义为 1
INCLUDE_xTaskGetSchedulerState 如果要使用函数 xTaskGetSchedulerState()的话需要将宏 INCLUDE_xTaskGetSchedulerState定义为 1。
INCLUDE_uxTaskGetStackHighWaterMark 如果要使用函数 uxTaskGetStackHighWaterMark() 的话需要将宏INCLUDE_uxTaskGetStackHighWaterMark 定义为 1。
INCLUDE_uxTaskPriorityGet 如果要使用函数 vTaskPrioritySet()的话需要将宏 INCLUDE_vTaskPrioritySet 定义为 1。
INCLUDE_xTaskResumeFromISR 如果要使用函数 xTaskResumeFromISR()的话需要将宏 INCLUDE_xTaskResumeFromISR和INCLUDE_vTaskSuspend 都定义为 1。
INCLUDE_eTaskGetState 如果要使用函数 eTaskGetState()的话需要将宏 INCLUDE_eTaskGetState 定义为 1。
INCLUDE_vTaskSuspend 如 果 要 使 用 函 数 vTaskSuspend() 、 vTaskResume() 、 prvTaskIsTaskSuspended() 、xTaskResumeFromISR()的话宏 INCLUDE_vTaskSuspend 要定义为 1。如 果 要 使 用 函 数 xTaskResumeFromISR() 的话宏 INCLUDE_xTaskResumeFromISR 和INCLUDE_vTaskSuspend 都必须定义为 1。
INCLUDE_xTimerPendFunctionCall 如果要使用函数 xTimerPendFunctionCall()和 xTimerPendFunctionCallFromISR()的话宏INCLUDE_xTimerPendFunctionCall 和 configUSE_TIMERS 都必须定义为 1。