FreeRTOS学习记录——持续更新

发布于:2024-09-18 ⋅ 阅读:(119) ⋅ 点赞:(0)

目录

入门知识:

裸机与FreeRTOS:

裸机:

RTOS系统:

堆栈相关的简单概念

堆(Heap)

栈(Stack)

API(Application Programming Interface,应用程序编程接口)

基础知识:

任务调度:

分类:

时间片调度:

任务状态(四种):

四种状态图片:

FreeRTOS的源码内容:

(1)原所有文件

(2)FreeRTOS文件

FreeRTOS的移植:

系统配置文件:FreeRTOSConfig.h 文件

(a)“config”配置项

(1)基础配置项

(2)内存分配相关定义

(3)钩子函数相关定义

(4)运行时间和任务状态统计相关定义

注意(重要注意事项)

(5)协程相关定义

(6)软件定时器相关定义

(7)中断嵌套行为配置

(8)断言

(9)FreeRTOS MPU 特殊定义

(b)“INCLUDE”配置项

(c)其他配置项

任务创建和删除的API函数介绍:

BaseType_t xTaskCreate( ):

void vTaskDelete( xHandle );

taskEXIT_CRITICAL()与taskENTER_CRITICAL()【临界区】

taskENTER_CRITICAL()

taskEXIT_CRITICAL()

注意事项

动态任务创建示例:

freertos_demo.c(例程入口函数)

main.c

FREERTOSConfig.c


入门知识:

裸机与FreeRTOS:

裸机:

又称前后台系统,前台系统指的中断服务函数,后台系统指的大循环,即应程序

RTOS系统:

全称为:Real Time OS,就是实时操作系统,强调的是:实时性

堆栈:存放断点的数据,以便继续执行 

(1)中断是可以打断任意任务的

(2)任务可以同等优先级

最后一点:软件优先级是没有任何限制的,硬件优先级是有限制的,如stm32为32位,硬件优先级为0到31(ISR中断请求寄存器位数)

堆栈相关的简单概念

堆(Heap)

定义与特性

  • 堆是一种特殊的树形数据结构,通常用来实现优先队列。在计算机内存中,堆主要指的是由程序员分配和释放的一块内存区域,其大小可以在运行时动态变化。
  • 堆中的数据元素通常是无序的,但可以通过特定的算法(如堆排序算法)实现有序。在数据结构中,堆常用来表示完全二叉树,特别是最大堆和最小堆,其中节点的值与其子节点的值有一定的关系(最大堆中父节点的值大于等于子节点的值,最小堆中父节点的值小于等于子节点的值)。
  • 堆的分配方式是由程序员控制的,通常使用malloc(C语言)或new(C++)等函数或操作符来申请空间,并使用freedelete来释放空间。如果不及时释放,可能会导致内存泄漏。
  • 堆的生长方向是向上的,即内存地址由低到高。堆的大小受限于计算机系统中有效的虚拟内存大小。

应用场景

  • 堆常用于需要动态分配大量内存的场景,如大型数据结构的存储、动态数组、链表等。
  • 在某些算法中,如堆排序、优先队列等,堆也是关键的数据结构。

栈(Stack)

定义与特性

  • 栈是一种遵循后进先出(LIFO, Last In First Out)原则的有序集合。在计算机内存中,栈是自动分配和释放的一块内存区域,通常用于存储函数的参数值、局部变量等。
  • 栈的操作仅限于栈顶,包括入栈(Push)、出栈(Pop)、查看栈顶元素(Peek/Top)等。入栈操作是将新元素放到栈顶,出栈操作则是移除栈顶元素。
  • 栈的分配方式分为静态分配和动态分配。静态分配是由操作系统完成的,如局部变量的分配;动态分配则是由alloca等函数(注意,alloca并不是标准C/C++的一部分,且在某些环境下并不支持)进行,但栈的动态分配和释放是由操作系统自动管理的,无需程序员手动控制。
  • 栈的生长方向是向下的,即内存地址由高到低。栈的大小在程序编译时就已确定,通常是有限的,超出限制时会导致栈溢出错误。

应用场景

  • 栈在函数调用过程中起着至关重要的作用,用于保存函数的返回地址、参数、局部变量等。
  • 栈还常用于表达式求值、括号匹配、编辑器撤销操作、浏览器的前进后退功能等场景。

API(Application Programming Interface,应用程序编程接口)

        是一组定义、程序及协议的集合,通过它可以构建软件应用程序,使得这些软件应用程序能够与操作系统、其他软件应用程序或硬件进行交互。简而言之,API 是一种软件中介,允许不同的软件应用程序“交谈”或共享数据。

API 的主要特点和用途:

  1. 抽象化:API 提供了一个抽象层,隐藏了底层系统的复杂性。开发者不需要了解系统内部如何工作,只需要按照 API 提供的规范进行编程即可。

  2. 复用性:通过 API,软件开发者可以重用现有的功能,而不必从头开始编写代码。这大大提高了开发效率,减少了代码量,并降低了出错的可能性。

  3. 模块化:API 促进了软件的模块化设计,使得各个模块之间可以独立开发、测试和更新,而不会影响其他模块。

  4. 跨平台:许多 API 是跨平台的,意味着它们可以在不同的操作系统和硬件上工作。这有助于开发跨平台的应用程序和服务。

  5. 集成:API 使得不同的软件应用程序可以轻松地集成在一起,共同工作。例如,社交媒体平台可以通过 API 允许其他应用程序访问其数据或功能。

基础知识:

任务调度:

使用相关调度算法来决定当前需要执行的哪个任务

分类:

  1. 抢占式调度(Preemptive Scheduling)
    • 这是FreeRTOS默认的调度方式。在这种方式下,调度器始终运行优先级最高且可运行的RTOS任务。如果某个更高优先级的任务变为就绪状态(例如,由于等待的事件发生或延时结束),则当前运行的任务将被抢占,高优先级任务将立即获得CPU控制权并开始执行。这种调度方式确保了系统对紧急任务的快速响应。

1.数值越大优先级就越高

2.高优先级任务不停止,低优先级任务就无法执行

3.被抢占的任务将会进入就储态

  1. 协作式调度(Cooperative Scheduling)
    • 协作式调度不是FreeRTOS的默认调度方式,但在某些情况下可以使用。在这种方式下,一旦一个任务开始执行,它将持续运行,直到它主动放弃CPU控制权(例如,通过调用特定的函数如taskYIELD()vTaskDelay(),或者进入阻塞状态等待事件或资源)。协作式调度简化了任务间共享资源的管理,但要求每个任务都必须定期放弃CPU控制权,否则可能导致系统响应性能下降。
  2. 时间片轮转调度(Round-Robin Scheduling)
    • 对于具有相同优先级的任务,FreeRTOS采用时间片轮转调度。这意味着这些任务将轮流获得CPU时间片,每个时间片结束后,任务将被挂起,下一个同优先级的任务将获得执行机会。时间片的大小可以通过配置FreeRTOS的tick中断频率和调度器的时间片长度来设置。

时间片调度:

        同等优先级任务轮流地享有相同CPU时间(可设置),叫时间片,在FreeRTOS中,一个时间片就等于SysTick中断周期

        在FreeRTOS中,时间片调度(Time-Slicing)是一种用于管理具有相同优先级的任务执行顺序的机制。当多个任务具有相同的优先级时,它们会轮流获得CPU的使用权,每个任务执行一个预设的时间片长度后,就会让出CPU给下一个同优先级的任务,以此循环。这种调度方式有助于确保系统公平地分配CPU资源给所有同优先级的任务。

时间片调度的关键要素

  1. 时间片长度
    • 时间片长度是指一个任务在不被抢占或中断的情况下能够连续执行的最长时间。在FreeRTOS中,时间片长度通常与系统的时钟节拍(Tick Rate)相关,一个时间片就等于一个SysTick中断周期。
    • 时间片长度可以通过配置FreeRTOS的configTICK_RATE_HZ宏来设置。例如,如果configTICK_RATE_HZ被设置为1000,那么每个时间片的长度就是1毫秒(ms)。
  2. 任务优先级
    • 在FreeRTOS中,任务可以具有不同的优先级。时间片调度主要适用于具有相同优先级的任务。
    • 当存在多个同优先级的任务时,它们会按照时间片轮转的方式获得CPU使用权。
  3. 抢占式调度与合作式调度的结合
    • FreeRTOS支持抢占式调度和合作式调度。在时间片调度中,抢占式调度仍然有效,即如果更高优先级的任务变为就绪状态,它会立即抢占当前正在执行的任务的CPU使用权。
    • 而在同优先级的任务之间,则采用时间片轮转的方式进行调度。

1.同等优先级任务,轮流执行:时间片流转

2.一个时间片大小,取决为滴答定时器中断周期

3.注意没有用完时间片不会再使用,下次任务Task3得到执行还是按照一个时间片的时钟节拍运行

任务状态(四种):

  1. 运行状态(Running)
    • 当任务正在占用CPU资源并实际执行时,该任务处于运行状态。在单核处理器系统中,同一时间只能有一个任务处于运行状态。
    • 运行状态的任务可以因为各种原因(如时间片结束、更高优先级任务就绪、任务主动让出CPU等)而转换为其他状态。
  2. 就绪状态(Ready)
    • 任务已经准备好执行,但因为某些原因(如当前CPU正在被其他任务占用或更高优先级的任务正在运行)而暂时未获得CPU使用权。
    • 就绪状态的任务会排入相应的就绪列表中,等待调度器根据优先级或时间片策略进行调度。
    • 当任务从阻塞状态或挂起状态恢复时,也会进入就绪状态。
  3. 阻塞状态(Blocked)
    • 任务因等待某个事件(如信号量、消息队列、延时等)而无法继续执行时,会进入阻塞状态。
    • 阻塞状态的任务会排入相应的阻塞列表中,直到等待的事件发生或超时后才会被唤醒并转换为就绪状态。
    • 阻塞是任务调度中常见的一种状态转换,用于实现任务间的同步和通信。
  4. 挂起状态(Suspended)
    • 任务被明确挂起后,将不再参与调度,即不会获得CPU使用权。
    • 挂起状态的任务需要通过特定的恢复函数(如vTaskResume())来唤醒并重新加入就绪列表。
    • 挂起状态通常用于临时停止任务执行,以便进行调试、更新或重新配置等操作

四种状态图片:

FreeRTOS的源码内容:

(1)原所有文件

官网下载链接:Download FreeRTOS - FreeRTOS™

FreeRTOS(文件名称)才与我们使用的密切相关

FreeRTOS组件一般使用第三方组件

(2)FreeRTOS文件

使用的位demo和Source文件夹

portable里面就是FreeRTOS和stm32交流的桥梁文件

FreeRTOS是一个软件操作系统

对于MDK所需的文件为

FreeRTOS的移植:

视频:第7讲 FreeRTOS移植_哔哩哔哩_bilibili

系统配置文件:FreeRTOSConfig.h 文件

        FreeRTOSConfig.h 文件中有几十 个配置项,这使得用户能够很好地配置和裁剪 FreeRTOS。

        FreeRTOSConfig.h 文件中的配置项可分为三大类:“config”配置项、“INCLUDE”配置项其他配置项。

(a)“config”配置项

        “config”配置项按照配置的功能分类,可分为十类,分别为基础配置项、内存分配相关定 义、钩子函数相关定义、运行时间和任务状态统计相关定义、协程相关定义、软件定时器相关 定义、中断嵌套行为配置、断言、FreeRTOS MPU 特殊定义和 ARMv8-M 安全侧端口相关定义。

(1)基础配置项

/* 基础配置项 */
#define configUSE_PREEMPTION                            1                       /* 1: 抢占式调度器, 0: 协程式调度器, 无默认需定义 */
#define configUSE_PORT_OPTIMISED_TASK_SELECTION         1                       /* 1: 使用硬件计算下一个要运行的任务(硬件为0到31,一共32), 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 */

引用自:正点原子FreeRTOS开发指南

需要什么看什么

1. configUSE_PREEMPTION

        此宏用于设置系统的调度方式。当宏 configUSE_PREEMPTION 设置为 1 时,系统使用抢占式调度;当宏 configUSE_PREEMPTION 设置为 0 时,系统使用协程式调度。抢占式调度和 协程式调度的区别在于,协程式调度是正在运行的任务主动释放 CPU 后才能切换到下一个任 务,任务切换的时机完全取决于正在运行的任务。协程式的优点在于可以节省开销,但是功能 比较有限,现在的 MCU 性能都比较强大,建议使用抢占式调度。

2. configUSE_PORT_OPTIMISED_TASK_SELECTION

        FreeRTOS 支持两种方法来选择下一个要执行的任务,分别为通用方法和特殊方法。 当宏 configUSE_PORT_OPTIMISED_TASK_SELECTION 设置为 0 时,使用通用方法。通 用方法是完全使用 C 实现的软件算法,因此支持所用硬件,并且不限制任务优先级的最大值, 但效率相较于特殊方法低。 当宏 configUSE_PORT_OPTIMISED_TASK_SELECTION 设置为 1 时,使用特殊方法。特 殊方法的效率相较于通用方法高,但是特殊方法依赖于一个或多个特定架构的汇编指令(一般 是类似计算前导零[CLZ]的指令),因此特殊方法并不支持所有硬件,并且对任务优先级的最大 值一般也有限制,通常为 32。

3. configUSE_TICKLESS_IDLE

        当宏 configUSE_TICKLESS_IDLE 设置为 1 时,使能 tickless 低功耗模式;设置为 0 时, tick 中断则会移植运行。tickless 低功耗模式并不适用于所有硬件。

4. configCPU_CLOCK_HZ

        此宏应设置为 CPU 的内核时钟频率,单位为 Hz。

5. configSYSTICK_CLOCK_HZ

        此宏应设置为 SysTick 的时钟频率,当 SysTick 的时钟源频率与内核时钟频率不同时才可 以定义,单位为 Hz。

6. configTICK_RATE_HZ

        此宏用于设置 FreeRTOS 系统节拍的中断频率,单位为 Hz。

7. configMAX_PRIORITIES

        此 宏 用 于 定 义 系 统 支 持 的 最 大 任 务 优 先 级 数 量 , 最 大 任 务 优 先 级 数 值 为 configMAX_PRIORITIES-1。

 8. configMINIMAL_STACK_SIZE

        此宏用于设置空闲任务的栈空间大小,单位为 word。

9. configMAX_TASK_NAME_LEN

        此宏用于设置任务名的最大字符数。

10. configUSE_16_BIT_TICKS

        此宏用于定义系统节拍计数器的数据类型,当宏 configUSE_16_BIT_TICKS 设置为 1 时, 系统节拍计数器的数据类型为 16 位无符号整形;当宏 configUSE_16_BIT_TICKS 设置为 0 时, 系统节拍计数器的数据类型为 32 为无符号整型。(STM32为32位所以设置为0)

11. configIDLE_SHOULD_YIELD

        当宏 configIDLE_SHOULD_YIELD 设置为 1 时,在抢占调度下,同等优先级的任务可抢占 空闲任务,并延用空闲任务剩余的时间片。

12. configUSE_TASK_NOTIFICATIONS

        当宏 configUSE_TASK_NOTIFICATIONS 设置为 1 时,开启任务通知功能。当开启任务通 知功能后,每个任务将多占用 8 字节的内存空间。

13. configTASK_NOTIFICATION_ARRAY_ENTRIES

        此宏用于定义任务通知数组的大小。

14. configUSE_MUTEXES

        此宏用于使能互斥信号量,当宏 configUSE_MUTEXS 设置为 1 时,使能互斥信号量;当宏 configUSE_MUTEXS 设置为 0 时,则不使能互斥信号量。

15. configUSE_RECURSIVE_MUTEXES

         此宏用于使能递归互斥信号量,当宏 configUSE_RECURSIVE_MUTEXES 设置为 1 时,使 能递归互斥信号量;当宏 configUSE_RECURSIVE_MUTEXES 设置为 0 时,则不使能递归互斥 信号量。

16. configUSE_COUNTING_SEMAPHORES

         此宏用于使能计数型信号量,当宏 configUSE_COUNTING_SEMAPHORES 设置为 1 时, 使能计数型信号量;当宏 configUSE_COUNTING_SEMAPHORES 设置为 0 时,则不使能计数 型信号量。

17. configUSE_ALTERNATIVE_API

        此宏在 FreeRTOS V9.0.0 之后已弃用。

18. configQUEUE_REGISTRY_SIZE

        此宏用于定义可以注册的队列和信号量的最大数量。此宏定义仅用于调试使用。

19. configUSE_QUEUE_SETS

        此宏用于使能队列集,当宏 configUSE_QUEUE_SETS 设置为 1 时,使能队列集;当宏 configUSE_QUEUE_SETS 设置为 0 时,则不使能队列集。

20. configUSE_TIME_SLICING

        此宏用于使能时间片调度,当宏 configUSE_TIMER_SLICING 设置为 1 且使用抢占式调度 时,使能时间片调度;当宏 configUSE_TIMER_SLICING 设置为 0 时,则不使能时间片调度。

21. configUSE_NEWLIB_REENTRANT

        此 宏 用 于 为 每 个 任 务 分 配 一 个 NewLib 重 入 结 构 体 , 当 宏configUSE_NEWLIB_REENTRANT 设置为 1 时,FreeRTOS 将为每个创建的任务的任务控制块中分配一个 NewLib 重入结构体。

22. configENABLE_BACKWARD_COMPATIBILITY

        此宏用于兼容 FreeRTOS 老版本的 API 函数。

23. configNUM_THREAD_LOCAL_STORAGE_POINTERS

        此宏用于在任务控制块中分配一个线程本地存储指着数组,当此宏被定义为大于 0 时, configNUM_THREAD_LOCAL_STORAGE_POINTERS 为线程本地存储指针数组的元素个数; 当宏 configNUM_THREAD_LOCAL_STORAGE_POINTERS 为 0 时,则禁用线程本地存储指针 数组。

24. configSTACK_DEPTH_TYPE

        此宏用于定义任务堆栈深度的数据类型,默认为 uint16_t。

25. configMESSAGE_BUFFER_LENGTH_TYPE

        此宏用于定义消息缓冲区中消息长度的数据类型,默认为 size_t。

(2)内存分配相关定义

/* 内存分配相关定义 */
#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 */

1. configSUPPORT_STATIC_ALLOCATION

        当宏 configSUPPORT_STSTIC_ALLOCATION 设置为 1 时,FreeRTOS 支持使用静态方式 管理内存,此宏默认设置为 0。如果将 configSUPPORT_STATIC_ALLOCATION 设置为 1,用户 还 需 要 提 供 两 个 回 调 函 数 : vApplicationGetIdleTaskMemory() 和 vApplicationGetTimerTaskMemory(),更详细的内容请参考第六章的“静态创建与删除任务实验”。

2. configSUPPORT_DYNAMIC_ALLOCATION

        当宏 configSUPPORT_DYNAMIC_ALLOCATION 设置为 1 时,FreeRTOS 支持使用动态方 式管理内存,此宏默认设置为 1。

3. configTOTAL_HEAP_SIZE

         此宏用于定义用于 FreeRTOS 动态内存管理的内存大小,即 FreeRTOS 的内存堆,单位为 Byte。

4. configAPPLICATION_ALLOCATED_HEAP

        此宏用于自定义 FreeRTOS 的内存堆,当宏configAPPLICATION_ALLOCATED_HEAP 设 置为 1 时,用户需要自行创建 FreeRTOS 的内存堆,否则 FreeRTOS 的内存堆将由编译器进行分 配。利用此宏定义,可以使用 FreeRTOS 动态管理外扩内存。

5. configSTACK_ALLOCATION_FROM_SEPARATE_HEAP

        此宏用于自定义动态创建和删除任务时,任务栈内存的申请与释放函数pvPortMallocStack() 和vPortFreeStack(),当宏configSTACK_ALLOCATION_FROM_SEPARATE_HEAP 设置为1是, 用户需提供 pvPortMallocStack()和 vPortFreeStack()函数。

(3)钩子函数相关定义

类似为回调函数

/* 钩子函数相关定义 */
#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 */

1. configUSE_IDLE_HOOK

        此宏用于使能使用空闲任务钩子函数,当宏 configUSE_IDLE_HOOK 设置为 1 时,使能使 用空闲任务钩子函数,用户需自定义相关钩子函数;当宏 configUSE_IDLE_HOOK 设置为 0 时, 则不使能使用空闲任务钩子函数。

2. configUSE_TICK_HOOK

        此宏用于使能使用系统时钟节拍中断钩子函数,当宏 configUSE_TICK_HOOK 设置为 1 时, 使 能 使 用 系 统 时 钟 节 拍 中 断 钩 子 函 数 , 用 户 需 自 定 义 相 关 钩 子 函 数 ; 当 宏 configUSE_TICK_HOOK 设置为 0 时,则不使能使用系统时钟节拍中断钩子函数。 3. configCHECK_FOR_STACK_OVERFLOW

        此宏用于使能栈溢出检测,当宏 configCHECK_FOR_STACK_OVERFLOW 设置为 1 时, 使用栈溢出检测方法一;当宏 configCHECK_FOR_STACK_OVERFLOW 设置为 2 时,栈溢出 检测方法二;当宏 configCHECK_FOR_STACK_OVERFLOW 设置为 0 时,不使能栈溢出检测。

4. configUSE_MALLOC_FAILED_HOOK

        此 宏 用 于 使 能 使 用 动 态 内 存 分 配 失 败 钩 子 函 数 , 当 宏 configUSE_MALLOC_FAILED_HOOK 设置为 1 时,使能使用动态内存分配失败钩子函数,用 户需自定义相关钩子函数;当宏 configUSE_MALLOC_FAILED_HOOK 设置为 0 时,则不使能 使用动态内存分配失败钩子函数。

5. configUSE_DAEMON_TASK_STARTUP_HOOK

         此 宏 用 于 使 能 使 用 定 时 器 服 务 任 务 首 次 执 行 前 的 钩 子 函 数 , 当 宏 configUSE_DEAMON_TASK_STARTUP_HOOK 设置为 1 时,使能使用定时器服务任务首次执 行前的钩子函数,此时用户需定义定时器服务任务首次执行的相关钩子函数;当宏 configUSE_DEAMON_TASK_STARTUP_HOOK 设置为 0 时,则不使能使用定时器服务任务首 次执行前的钩子函数。

(4)运行时间和任务状态统计相关定义

注意(重要注意事项)

第61行官网版没有这个宏定义需自行添加:

#define configUSE_STATS_FORMATTING_FUNCTIONS            1                       /* 1: configUSE_TRACE_FACILITY为1时,会编译vTaskList()和vTaskGetRunTimeStats()函数, 默认: 0 */

第60行,官网下载版这个宏定义默认设置为0,需要修改为1(2022版为1)

#define configUSE_TRACE_FACILITY                        1                       /* 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 */

1. configGENERATE_RUN_TIME_STATS

        此宏用于使能任务运行时间统计功能,当宏 configGENERATE_RUN_TIME_STATS 设置为1 时,使能任务运行时间统计功能,此时用户需要提供两个函数,一个是用于配置任务运行时 间统计功能的函数 portCONFIGURE_TIMER_FOR_RUN_TIME_STATS(),一般是完成定时器的 初始化,另一个函数是 portGET_RUN_TIME_COUNTER_VALUE(),该函数用于获取定时器的 计时值;当宏 configGENERATE_RUN_TIME_STATS 设置为 0 时,则不使能任务运行时间统计 功能。

2. configUSE_TRACE_FACILITY

        此宏用于使能可视化跟踪调试,当宏 configUSE_TRACE_FACILITY 设置为 1 时,使能可 视化跟踪调试;当宏 configUSE_TRACE_FACILITY 设置为 0 时,则不使能可视化跟踪调试。

3. configUSE_STATS_FORMATTING_FUNCTIONS

        当此宏与 configUSE_TRACE_FACILITY 同时设置为 1 时,将编译函数 vTaskList()和函数 vTaskGetRunTimeStats(),否则将忽略编译函数 vTaskList()和函数 vTaskGetRunTimeStats()。
 

(5)协程相关定义

/* 协程相关定义 */
#define configUSE_CO_ROUTINES                           0                       /* 1: 启用协程, 默认: 0 */
#define configMAX_CO_ROUTINE_PRIORITIES                 2                       /* 定义协程的最大优先级, 最大优先级=configMAX_CO_ROUTINE_PRIORITIES-1, 无默认configUSE_CO_ROUTINES为1时需定义 */

1. configUSE_CO_ROUTINES

        此宏用于启用协程,当宏 configUSE_CO_ROUTINES 设置为 1 时,启用协程;当宏 configUSE_CO_ROUTINES 设置为 0 时,则不启用协程。

2. configMAX_CO_ROUTINE_PRIORITIES

        此 宏 用 于 设 置 协 程 的 最 大 任 务 优 先 级 数 量 , 协 程 的 最 大 任 务 优 先 级 数 值 为 configMAX_CO_ROUTINE_PRIORITIES-1。

(6)软件定时器相关定义

/* 软件定时器相关定义 */
#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. configUSE_TIMERS

         此宏用于启用软件定时器功能,当宏 configUSE_TIMERS 设置为 1 时,启用软件定时器功 能;当宏 configUSE_TIMERS 设置为 0 时,则不启用软件定时器功能。

2. configTIMER_TASK_PRIORITY

        此宏用于设置软件定时器处理任务的优先级,当启用软件定时器功能时,系统会创建一个 用于处理软件定时器的软件定时器处理任务。

3. configTIMER_QUEUE_LENGTH

        此宏用于定义软件定时器队列的长度,软件定时器的开启、停止与销毁等操作都是通过队 列实现的。

4. configTIMER_TASK_STACK_DEPTH

        此宏用于设置软件定时器处理任务的栈空间大小,当启用软件定时器功能时,系统会创建 一个用于处理软件定时器的软件定时器处理任务。

(7)中断嵌套行为配置

/* 中断嵌套行为配置 */
#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

1. configPRIO_BITS

        此宏应定义为 MCU 的 8 位优先级配置寄存器实际使用的位数。

2. configLIBRARY_LOWEST_INTERRUPT_PRIORITY

        此宏应定义为 MCU 的最低中断优先等级,对于 STM32,在使用 FreeRTOS 时,建议将中 断优先级分组设置为组 4,此时中断的最低优先级为 15。此宏定义用于辅助配置宏 configKERNEL_INTERRUPT_PRIORITY。

3. configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY

        此宏定义用于设置 FreeRTOS 可管理中断的最高优先级,当中断的优先级数值小于 configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 时,此中断不受 FreeRTOS 管理。 此宏定义用于辅助配置宏 configMAX_SYSCALL_INTERRUPT_PRIORITY。

4. configKERNEL_INTERRUPT_PRIORITY

        此宏应定义为 MCU 的最低中断优先等级在中断优先级配置寄存器中的值,对于 STM32, 即宏 configLIBRARY_LOWEST_INTERRUPT_PRIORITY 偏移 4bit 的值。

5. configMAX_SYSCALL_INTERRUPT_PRIORITY

        此宏应定义为 FreeRTOS 可管理中断的最高优先等级在中断优先级配置寄存器中的值,对 于 STM32,即宏 configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 偏移 4bit 的值。

6. configMAX_API_CALL_INTERRUPT_PRIORITY

        此宏为宏 configMAX_SYSCALL_INTERRUPT_PRIORITY 的新名称,只被用在 FreeRTOS 官方一些新的移植当中,此宏与宏configMAX_SYSCALL_INTERRUPT_PRIORITY 是等价的。

(8)断言

/* 断言 */
#define vAssertCalled(char, int) printf("Error: %s, %d\r\n", char, int)
#define configASSERT( x ) if( ( x ) == 0 ) vAssertCalled( __FILE__, __LINE__ )

1. vAssertCalled(char, int)

        此宏用于辅助配置宏 configASSERT( x )以通过串口打印相关信息。

2. configASSERT( x )

        此宏为 FreeRTOS 操作系统中的断言,断言会对表达式 x 进行判断,当 x 为假时,断言失 败,表明程序出错,于是使用宏 vAssertCalled(char, int)通过串口打印相关的错误信息。断言常 用于检测程序中的错误,使用断言将增加程序的代码大小和执行时间,因此建议在程序调试通 过后将宏 configASSERT( x )进行注释,以较少额外的开销

(9)FreeRTOS MPU 特殊定义

/* FreeRTOS MPU 特殊定义 */
//#define configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS 0
//#define configTOTAL_MPU_REGIONS                                8
//#define configTEX_S_C_B_FLASH                                  0x07UL
//#define configTEX_S_C_B_SRAM                                   0x07UL
//#define configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY            1
//#define configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS             1

(b)“INCLUDE”配置项

        FreeRTOS 使用“INCLUDE”配置项对部分 API 函数进行条件编译,当“INCLUDE”配置 项被定义为 1 时,其对应的 API 函数则会加入编译。对于用不到的 API 函数,用户则可以将其 对应的“INCLUDE”配置项设置为 0,那么这个 API 函数就不会加入编译,以减少不必要的系 统开销。

/* 可选函数, 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                       /* 恢复在中断中挂起的任务 */

(c)其他配置项

/* FreeRTOS中断服务函数相关定义 */
#define xPortPendSVHandler                              PendSV_Handler
#define vPortSVCHandler                                 SVC_Handler
/* ARMv8-M 安全侧端口相关定义。 */
//#define secureconfigMAX_SECURE_CONTEXTS         5

#endif /* FREERTOS_CONFIG_H */

1. ureconfigMAX_SECURE_CONTEXTS

         此宏为 ARMv8-M 安全侧端口的相关配置项,本文暂不涉及 ARMv8-M 安全侧端口的相关 内容,感兴趣的读者可自行查阅相关资料。

2. xPortPendSVHandler 和 vPortSVCHandler

        这两个宏为 PendSV 和 SVC 的中断服务函数,主要用于 FreeRTOS 操作系统的任务切换, 有关 FreeRTOS 操作系统中任务切换的相关内容

任务创建和删除的API函数介绍:

动态创建任务:

                任务的任务控制块以及任务的栈空间所需的内存,均由 FreeRTOS 从 FreeRTOS 管理的堆中分配

静态创建任务:

                任务的任务控制块以及任务的栈空间所需的内存,需用户分配提供

BaseType_t xTaskCreate( ):

        官网函数讲解链接:xTaskCreate - FreeRTOS™

创建一项新任务 并将其添加到准备运行的任务列表中。configSUPPORT_DYNAMIC_ALLOCATION 必须在 FreeRTOSConfig.h 中设置为 1,或处于未定义状态(默认为 1), 才可使用此 RTOS API 函数。

每项任务都需要 RAM 来保存任务状态,并由任务用作其堆栈。如果 使用 xTaskCreate() 创建任务,则所需的 RAM 会自动 从 FreeRTOS 堆分配。如果使用 xTaskCreateStatic() 创建任务, 则 RAM 由应用程序编写者提供,因此可以在编译时静态分配。 有关详细信息,请参阅静态分配与动态分配页面。

如果使用的是 FreeRTOS-MPU,建议 使用 xTaskCreateRestricted(),而不是 xTaskCreate()。

参数:

  • pvTaskCode

    指向任务入口函数的指针(即实现任务的函数名称,请参阅如下示例)。 任务通常以无限循环的形式实现;实现任务的函数 绝不能尝试返回或退出。但是,任务可以 自行删除

  • pcName (电脑名称)

    任务的描述性名称。此参数主要用于方便调试,但也可用于 获取任务句柄。任务名称的最大长度 由 FreeRTOSConfig.h 中的 configMAX_TASK_NAME_LEN 定义。

  • uxStackDepth

    分配用作任务堆栈的字数(不是字节数!)。例如,如果 堆栈宽度为 16 位,uxStackDepth 为 100,则将分配 200 字节用作任务 堆栈。再举一例,如果堆栈宽度为 32 位,uxStackDepth 为 400, 则将分配 1600 字节用作任务堆栈。堆栈深度与堆栈宽度的乘积不得超过 size_t 类型变量所能包含的最大值。请参阅 常见问题:堆栈应该多大?

  • pvParameters

    作为参数传递给所创建任务的值。如果 pvParameters 设置为某变量的地址, 则在创建的任务执行时,该变量必须仍然存在, 因此,不能传递堆栈变量的地址。

  • uxPriority

    创建的任务将以该指定优先级执行。支持 MPU 的系统 可以通过在 uxPriority 中设置 portPRIVILEGE_BIT 位来选择以特权(系统)模式创建任务。 例如,要创建优先级为 2 的特权任务,请将 uxPriority 设置为 ( 2 | portPRIVILEGE_BIT )。应断言优先级 低于 configMAX_PRIORITIES。如果 configASSERT 未定义,则优先级默认上限为 (configMAX_PRIORITIES - 1)。

  • pxCreatedTask 的

    用于将句柄传递至由 xTaskCreate() 函数创建的任务。pxCreatedTask 是可选参数, 可设置为 NULL。

返回:

  • 如果任务创建成功,则返回 pdPASS,
  • 否则返回 errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY。
/*-----------------------------------------------------------
* TASK CREATION API
*----------------------------------------------------------*/

/**
 * task. h
 * @code{c}
 * BaseType_t xTaskCreate(
 *                            TaskFunction_t pxTaskCode,
 *                            const char *pcName,
 *                            configSTACK_DEPTH_TYPE usStackDepth,
 *                            void *pvParameters,
 *                            UBaseType_t uxPriority,
 *                            TaskHandle_t *pxCreatedTask
 *                        );
 * @endcode
 *
 * Create a new task and add it to the list of tasks that are ready to run.
 *
 * Internally, within the FreeRTOS implementation, tasks use two blocks of
 * memory.  The first block is used to hold the task's data structures.  The
 * second block is used by the task as its stack.  If a task is created using
 * xTaskCreate() then both blocks of memory are automatically dynamically
 * allocated inside the xTaskCreate() function.  (see
 * https://www.FreeRTOS.org/a00111.html).  If a task is created using
 * xTaskCreateStatic() then the application writer must provide the required
 * memory.  xTaskCreateStatic() therefore allows a task to be created without
 * using any dynamic memory allocation.
 *
 * See xTaskCreateStatic() for a version that does not use any dynamic memory
 * allocation.
 *
 * xTaskCreate() can only be used to create a task that has unrestricted
 * access to the entire microcontroller memory map.  Systems that include MPU
 * support can alternatively create an MPU constrained task using
 * xTaskCreateRestricted().
 *
 * @param pxTaskCode Pointer to the task entry function.  Tasks
 * must be implemented to never return (i.e. continuous loop).
 *
 * @param pcName A descriptive name for the task.  This is mainly used to
 * facilitate debugging.  Max length defined by configMAX_TASK_NAME_LEN - default
 * is 16.
 *
 * @param usStackDepth The size of the task stack specified as the number of
 * variables the stack can hold - not the number of bytes.  For example, if
 * the stack is 16 bits wide and usStackDepth is defined as 100, 200 bytes
 * will be allocated for stack storage.
 *
 * @param pvParameters Pointer that will be used as the parameter for the task
 * being created.
 *
 * @param uxPriority The priority at which the task should run.  Systems that
 * include MPU support can optionally create tasks in a privileged (system)
 * mode by setting bit portPRIVILEGE_BIT of the priority parameter.  For
 * example, to create a privileged task at priority 2 the uxPriority parameter
 * should be set to ( 2 | portPRIVILEGE_BIT ).
 *
 * @param pxCreatedTask Used to pass back a handle by which the created task
 * can be referenced.
 *
 * @return pdPASS if the task was successfully created and added to a ready
 * list, otherwise an error code defined in the file projdefs.h
 *
 * Example usage:
 * @code{c}
 * // Task to be created.
 * void vTaskCode( void * pvParameters )
 * {
 *   for( ;; )
 *   {
 *       // Task code goes here.
 *   }
 * }
 *
 * // Function that creates a task.
 * void vOtherFunction( void )
 * {
 * static uint8_t ucParameterToPass;
 * TaskHandle_t xHandle = NULL;
 *
 *   // Create the task, storing the handle.  Note that the passed parameter ucParameterToPass
 *   // must exist for the lifetime of the task, so in this case is declared static.  If it was just an
 *   // an automatic stack variable it might no longer exist, or at least have been corrupted, by the time
 *   // the new task attempts to access it.
 *   xTaskCreate( vTaskCode, "NAME", STACK_SIZE, &ucParameterToPass, tskIDLE_PRIORITY, &xHandle );
 *   configASSERT( xHandle );
 *
 *   // Use the handle to delete the task.
 *   if( xHandle != NULL )
 *   {
 *      vTaskDelete( xHandle );
 *   }
 * }
 * @endcode
 * \defgroup xTaskCreate xTaskCreate
 * \ingroup Tasks
 */
#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
    BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,
                            const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
                            const configSTACK_DEPTH_TYPE usStackDepth,
                            void * const pvParameters,
                            UBaseType_t uxPriority,
                            TaskHandle_t * const pxCreatedTask ) PRIVILEGED_FUNCTION;
#endif

void vTaskDelete( xHandle );

        FreeRTOS官网函数讲解:vTaskDelete - FreeRTOS™

INCLUDE_vTaskDelete

必须定义为 1,才可使用此函数。有关更多信息,请参阅 RTOS 配置文档 。

从 RTOS 内核管理中移除任务。要删除的任务将从所有就绪、 阻塞、挂起和事件列表中移除。

注意:空闲任务负责释放由 RTOS 内核分配给已删除任务的 内存。因此,如果应用程序调用了

vTaskDelete()

,请务必确保空闲任务获得足够的微控制器处理时间。任务代码分配的内存不会自动释放, 应在任务删除之前手动释放。

请参阅演示应用程序文件 death.c,获取使用

vTaskDelte()

的代码示例。

参数:

  • xTask 任务

    要删除的任务的句柄。如果传递 NULL,会删除调用任务。

void vOtherFunction( void )
{
    TaskHandle_t xHandle = NULL;

    // Create the task, storing the handle.
    xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );

    // Use the handle to delete the task.
    if( xHandle != NULL )
    {
        vTaskDelete( xHandle );
    }
}

taskEXIT_CRITICAL()与taskENTER_CRITICAL()【临界区】

taskENTER_CRITICAL()

        当任务需要进入临界区时,它会调用 taskENTER_CRITICAL() 函数。这个函数的主要作用是禁用中断(在某些配置下)和/或禁用任务调度,以确保在临界区执行期间,没有其他任务或中断可以打断当前任务的执行。这样做可以保护临界区内的代码和数据不被并发访问所破坏。

  • 禁用中断:在某些FreeRTOS配置中,taskENTER_CRITICAL() 可能会禁用中断,但这通常不是默认行为,因为禁用中断会影响系统的实时响应能力。
  • 禁用任务调度:更常见的做法是,taskENTER_CRITICAL() 会通过提高当前任务的优先级(或设置调度器锁定)来阻止其他任务运行,直到 taskEXIT_CRITICAL() 被调用。这通常是通过修改调度器的状态来实现的,而不是直接禁用中断。

taskEXIT_CRITICAL()

        当任务完成临界区的操作后,它应该调用 taskEXIT_CRITICAL() 函数来退出临界区。这个函数的作用是恢复 taskENTER_CRITICAL() 所做的更改,即重新启用中断(如果之前被禁用)和/或重新启用任务调度。

  • 恢复中断和任务调度taskEXIT_CRITICAL() 会将系统状态恢复到调用 taskENTER_CRITICAL() 之前的状态,允许中断和任务调度正常进行。

注意事项

  • 嵌套调用:FreeRTOS的 taskENTER_CRITICAL() 和 taskEXIT_CRITICAL() 支持嵌套调用。这意味着你可以在一个临界区内再次调用 taskENTER_CRITICAL(),但每调用一次 taskENTER_CRITICAL(),都必须对应调用一次 taskEXIT_CRITICAL() 来正确退出临界区。
  • 性能影响:虽然这些函数对于保护临界区至关重要,但它们可能会对系统性能产生负面影响,因为它们可能会阻止中断和任务调度。因此,应该尽量减少临界区的长度,并仅在必要时使用它们。
  • 替代方案:对于某些情况,可能需要考虑使用其他同步机制(如互斥锁、信号量等)来管理对共享资源的访问,而不是使用 taskENTER_CRITICAL() 和 taskEXIT_CRITICAL()。这些机制提供了更细粒度的控制和更好的可移植性。

动态任务创建示例:

freertos_demo.c(例程入口函数)

TaskHandle_t    名称   ;     是句柄的定义方式(void * pvParameters)

 (TaskHandle_t *         )   &task3_handler

优先级越大执行越早

/**
 ****************************************************************************************************
 * @file        freertos.c
 * @author      正点原子团队(ALIENTEK)
 * @version     V1.4
 * @date        2022-01-04
 * @brief       FreeRTOS 移植实验
 * @license     Copyright (c) 2020-2032, 广州市星翼电子科技有限公司
 ****************************************************************************************************
 * @attention
 *
 * 实验平台:正点原子 F407电机开发板
 * 在线视频:www.yuanzige.com
 * 技术论坛:www.openedv.com
 * 公司网址:www.alientek.com
 * 购买地址:openedv.taobao.com
 *
 ****************************************************************************************************
 */

#include "freertos_demo.h"
#include "./SYSTEM/usart/usart.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
/*FreeRTOS*********************************************************************************************/
#include "FreeRTOS.h"
#include "task.h"

/******************************************************************************************************/
/*FreeRTOS配置*/

/* START_TASK 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define START_TASK_PRIO         1
#define START_TASK_STACK_SIZE   128
TaskHandle_t    start_task_handler;
void start_task( void * pvParameters );

/* TASK1 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define TASK1_PRIO         2
#define TASK1_STACK_SIZE   128
TaskHandle_t    task1_handler;
void task1( void * pvParameters );

/* TASK2 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define TASK2_PRIO         3
#define TASK2_STACK_SIZE   128
TaskHandle_t    task2_handler;
void task2( void * pvParameters );

/* TASK3 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define TASK3_PRIO         4
#define TASK3_STACK_SIZE   128
TaskHandle_t    task3_handler;
void task3( void * pvParameters );
/******************************************************************************************************/


/**
 * @brief       FreeRTOS例程入口函数
 * @param       无
 * @retval      无
 */
void freertos_demo(void)
{    
    xTaskCreate((TaskFunction_t         )   start_task,
                (char *                 )   "start_task",
                (configSTACK_DEPTH_TYPE )   START_TASK_STACK_SIZE,
                (void *                 )   NULL,
                (UBaseType_t            )   START_TASK_PRIO,
                (TaskHandle_t *         )   &start_task_handler );
    vTaskStartScheduler();
}


void start_task( void * pvParameters )
{
    taskENTER_CRITICAL();               /* 进入临界区 */
    xTaskCreate((TaskFunction_t         )   task1,   							//有一个强制类型转换
                (char *                 )   "task1",
                (configSTACK_DEPTH_TYPE )   TASK1_STACK_SIZE,
                (void *                 )   NULL,
                (UBaseType_t            )   TASK1_PRIO,
                (TaskHandle_t *         )   &task1_handler );
                
    xTaskCreate((TaskFunction_t         )   task2,
                (char *                 )   "task2",
                (configSTACK_DEPTH_TYPE )   TASK2_STACK_SIZE,
                (void *                 )   NULL,
                (UBaseType_t            )   TASK2_PRIO,
                (TaskHandle_t *         )   &task2_handler );
                
    xTaskCreate((TaskFunction_t         )   task3,
                (char *                 )   "task3",
                (configSTACK_DEPTH_TYPE )   TASK3_STACK_SIZE,
                (void *                 )   NULL,
                (UBaseType_t            )   TASK3_PRIO,
                (TaskHandle_t *         )   &task3_handler );
    vTaskDelete(NULL);
    taskEXIT_CRITICAL();                /* 退出临界区 */
}

/* 任务一,实现LED0每500ms翻转一次 */
void task1( void * pvParameters )
{
    while(1)
    {
        printf("task1正在运行!!!\r\n");
        LED0_TOGGLE();
        vTaskDelay(500);
    }
}

/* 任务二,实现LED1每500ms翻转一次 */
void task2( void * pvParameters )
{
    while(1)
    {
        printf("task2正在运行!!!\r\n");
        LED1_TOGGLE();
        vTaskDelay(500);
    }
}

/* 任务三,判断按键KEY0,按下KEY0删除task1 */
void task3( void * pvParameters )
{
    uint8_t key = 0;
    while(1)
    {
        printf("task3正在运行!!!\r\n");
        key = key_scan(0);
        if(key == KEY0_PRES)
        {
            if(task1_handler != NULL)
            {
                printf("删除task1任务\r\n");
                vTaskDelete(task1_handler);
                task1_handler = NULL;
            }

        }
        vTaskDelay(10);
   
main.c
/**
 ****************************************************************************************************
 * @file        main.c
 * @author      正点原子团队(ALIENTEK)
 * @version     V1.0
 * @date        2022-4-20
 * @brief       内存管理 实验
 * @license     Copyright (c) 2020-2032, 广州市星翼电子科技有限公司
 ****************************************************************************************************
 * @attention
 *
 * 实验平台:正点原子 阿波罗 F429开发板
 * 在线视频:www.yuanzige.com
 * 技术论坛:www.openedv.com
 * 公司网址:www.alientek.com
 * 购买地址:openedv.taobao.com
 *
 ****************************************************************************************************
 */

#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
#include "./BSP/SDRAM/sdram.h"
#include "./MALLOC/malloc.h"
#include "freertos_demo.h"

int main(void)
{
    HAL_Init();                                 /* 初始化HAL库 */
    sys_stm32_clock_init(360, 25, 2, 8);        /* 设置时钟,180Mhz */
    delay_init(180);                            /* 延时初始化 */
    usart_init(115200);                         /* 串口初始化为115200 */
    led_init();                                 /* 初始化LED */
    key_init();                                 /* 初始化按键 */
    sdram_init();                               /* SRAM初始化 */
    lcd_init();                                 /* 初始化LCD */

    my_mem_init(SRAMIN);                        /* 初始化内部内存池 */
    my_mem_init(SRAMEX);                        /* 初始化外部内存池 */
    my_mem_init(SRAMCCM);                       /* 初始化CCM内存池 */
    
    freertos_demo();
}
FREERTOSConfig.c
#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H

/* 头文件 */
#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include <stdint.h>

extern uint32_t SystemCoreClock;

/* 基础配置项 */
#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

/* 断言 */
#define vAssertCalled(char, int) printf("Error: %s, %d\r\n", char, int)
#define configASSERT( x ) if( ( x ) == 0 ) vAssertCalled( __FILE__, __LINE__ )

/* FreeRTOS MPU 特殊定义 */
//#define configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS 0
//#define configTOTAL_MPU_REGIONS                                8
//#define configTEX_S_C_B_FLASH                                  0x07UL
//#define configTEX_S_C_B_SRAM                                   0x07UL
//#define configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY            1
//#define configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS             1

/* ARMv8-M 安全侧端口相关定义。 */
//#define secureconfigMAX_SECURE_CONTEXTS         5

#endif /* FREERTOS_CONFIG_H */


网站公告

今日签到

点亮在社区的每一天
去签到