目录
API(Application Programming Interface,应用程序编程接口)
BaseType_t xTaskCreateStatic()
taskEXIT_CRITICAL()与taskENTER_CRITICAL()【临界区】
vApplicationGetIdleTaskMemory()与vApplicationGetTimerTaskMemory()
任务挂起函数 vTaskSuspend(TaskHandle_t xTaskToSuspend)
任务恢复函数vTaskResume(TaskHandle_t xTaskToResume)
中断中恢复被挂起函数:BaseType_t xTaskResumeFromISR(TaskHandle_t xTaskResume):
任务切换函数portTIELD_FROM_ISR( [pdTURE或则PDFLASE])
入门知识:
裸机与FreeRTOS:
裸机:
又称前后台系统,前台系统指的中断服务函数,后台系统指的大循环,即应程序
RTOS系统:
全称为:Real Time OS,就是实时操作系统,强调的是:实时性
堆栈:存放断点的数据,以便继续执行
(1)中断是可以打断任意任务的
(2)任务可以同等优先级
最后一点:软件优先级是没有任何限制的,硬件优先级是有限制的,如stm32为32位,硬件优先级为0到31(ISR中断请求寄存器位数)
堆栈相关的简单概念
堆(Heap)
定义与特性:
- 堆是一种特殊的树形数据结构,通常用来实现优先队列。在计算机内存中,堆主要指的是由程序员分配和释放的一块内存区域,其大小可以在运行时动态变化。
- 堆中的数据元素通常是无序的,但可以通过特定的算法(如堆排序算法)实现有序。在数据结构中,堆常用来表示完全二叉树,特别是最大堆和最小堆,其中节点的值与其子节点的值有一定的关系(最大堆中父节点的值大于等于子节点的值,最小堆中父节点的值小于等于子节点的值)。
- 堆的分配方式是由程序员控制的,通常使用
malloc
(C语言)或new
(C++)等函数或操作符来申请空间,并使用free
或delete
来释放空间。如果不及时释放,可能会导致内存泄漏。 - 堆的生长方向是向上的,即内存地址由低到高。堆的大小受限于计算机系统中有效的虚拟内存大小。
应用场景:
- 堆常用于需要动态分配大量内存的场景,如大型数据结构的存储、动态数组、链表等。
- 在某些算法中,如堆排序、优先队列等,堆也是关键的数据结构。
栈(Stack)
定义与特性:
- 栈是一种遵循后进先出(LIFO, Last In First Out)原则的有序集合。在计算机内存中,栈是自动分配和释放的一块内存区域,通常用于存储函数的参数值、局部变量等。
- 栈的操作仅限于栈顶,包括入栈(Push)、出栈(Pop)、查看栈顶元素(Peek/Top)等。入栈操作是将新元素放到栈顶,出栈操作则是移除栈顶元素。
- 栈的分配方式分为静态分配和动态分配。静态分配是由操作系统完成的,如局部变量的分配;动态分配则是由
alloca
等函数(注意,alloca
并不是标准C/C++的一部分,且在某些环境下并不支持)进行,但栈的动态分配和释放是由操作系统自动管理的,无需程序员手动控制。 - 栈的生长方向是向下的,即内存地址由高到低。栈的大小在程序编译时就已确定,通常是有限的,超出限制时会导致栈溢出错误。
应用场景:
- 栈在函数调用过程中起着至关重要的作用,用于保存函数的返回地址、参数、局部变量等。
- 栈还常用于表达式求值、括号匹配、编辑器撤销操作、浏览器的前进后退功能等场景。
API(Application Programming Interface,应用程序编程接口)
是一组定义、程序及协议的集合,通过它可以构建软件应用程序,使得这些软件应用程序能够与操作系统、其他软件应用程序或硬件进行交互。简而言之,API 是一种软件中介,允许不同的软件应用程序“交谈”或共享数据。
API 的主要特点和用途:
-
抽象化:API 提供了一个抽象层,隐藏了底层系统的复杂性。开发者不需要了解系统内部如何工作,只需要按照 API 提供的规范进行编程即可。
-
复用性:通过 API,软件开发者可以重用现有的功能,而不必从头开始编写代码。这大大提高了开发效率,减少了代码量,并降低了出错的可能性。
-
模块化:API 促进了软件的模块化设计,使得各个模块之间可以独立开发、测试和更新,而不会影响其他模块。
-
跨平台:许多 API 是跨平台的,意味着它们可以在不同的操作系统和硬件上工作。这有助于开发跨平台的应用程序和服务。
-
集成:API 使得不同的软件应用程序可以轻松地集成在一起,共同工作。例如,社交媒体平台可以通过 API 允许其他应用程序访问其数据或功能。
基础知识:
任务调度:
使用相关调度算法来决定当前需要执行的哪个任务
分类:
- 抢占式调度(Preemptive Scheduling):
- 这是FreeRTOS默认的调度方式。在这种方式下,调度器始终运行优先级最高且可运行的RTOS任务。如果某个更高优先级的任务变为就绪状态(例如,由于等待的事件发生或延时结束),则当前运行的任务将被抢占,高优先级任务将立即获得CPU控制权并开始执行。这种调度方式确保了系统对紧急任务的快速响应。
1.数值越大优先级就越高
2.高优先级任务不停止,低优先级任务就无法执行
3.被抢占的任务将会进入就储态
- 协作式调度(Cooperative Scheduling):
- 协作式调度不是FreeRTOS的默认调度方式,但在某些情况下可以使用。在这种方式下,一旦一个任务开始执行,它将持续运行,直到它主动放弃CPU控制权(例如,通过调用特定的函数如
taskYIELD()
或vTaskDelay()
,或者进入阻塞状态等待事件或资源)。协作式调度简化了任务间共享资源的管理,但要求每个任务都必须定期放弃CPU控制权,否则可能导致系统响应性能下降。
- 协作式调度不是FreeRTOS的默认调度方式,但在某些情况下可以使用。在这种方式下,一旦一个任务开始执行,它将持续运行,直到它主动放弃CPU控制权(例如,通过调用特定的函数如
- 时间片轮转调度(Round-Robin Scheduling):
- 对于具有相同优先级的任务,FreeRTOS采用时间片轮转调度。这意味着这些任务将轮流获得CPU时间片,每个时间片结束后,任务将被挂起,下一个同优先级的任务将获得执行机会。时间片的大小可以通过配置FreeRTOS的tick中断频率和调度器的时间片长度来设置。
时间片调度:
同等优先级任务轮流地享有相同CPU时间(可设置),叫时间片,在FreeRTOS中,一个时间片就等于SysTick中断周期
在FreeRTOS中,时间片调度(Time-Slicing)是一种用于管理具有相同优先级的任务执行顺序的机制。当多个任务具有相同的优先级时,它们会轮流获得CPU的使用权,每个任务执行一个预设的时间片长度后,就会让出CPU给下一个同优先级的任务,以此循环。这种调度方式有助于确保系统公平地分配CPU资源给所有同优先级的任务。
时间片调度的关键要素
- 时间片长度:
- 时间片长度是指一个任务在不被抢占或中断的情况下能够连续执行的最长时间。在FreeRTOS中,时间片长度通常与系统的时钟节拍(Tick Rate)相关,一个时间片就等于一个SysTick中断周期。
- 时间片长度可以通过配置FreeRTOS的
configTICK_RATE_HZ
宏来设置。例如,如果configTICK_RATE_HZ
被设置为1000,那么每个时间片的长度就是1毫秒(ms)。- 任务优先级:
- 在FreeRTOS中,任务可以具有不同的优先级。时间片调度主要适用于具有相同优先级的任务。
- 当存在多个同优先级的任务时,它们会按照时间片轮转的方式获得CPU使用权。
- 抢占式调度与合作式调度的结合:
- FreeRTOS支持抢占式调度和合作式调度。在时间片调度中,抢占式调度仍然有效,即如果更高优先级的任务变为就绪状态,它会立即抢占当前正在执行的任务的CPU使用权。
- 而在同优先级的任务之间,则采用时间片轮转的方式进行调度。
1.同等优先级任务,轮流执行:时间片流转
2.一个时间片大小,取决为滴答定时器中断周期
3.注意没有用完时间片不会再使用,下次任务Task3得到执行还是按照一个时间片的时钟节拍运行
任务状态(四种):
- 运行状态(Running):
- 当任务正在占用CPU资源并实际执行时,该任务处于运行状态。在单核处理器系统中,同一时间只能有一个任务处于运行状态。
- 运行状态的任务可以因为各种原因(如时间片结束、更高优先级任务就绪、任务主动让出CPU等)而转换为其他状态。
- 就绪状态(Ready):
- 任务已经准备好执行,但因为某些原因(如当前CPU正在被其他任务占用或更高优先级的任务正在运行)而暂时未获得CPU使用权。
- 就绪状态的任务会排入相应的就绪列表中,等待调度器根据优先级或时间片策略进行调度。
- 当任务从阻塞状态或挂起状态恢复时,也会进入就绪状态。
- 阻塞状态(Blocked):
- 任务因等待某个事件(如信号量、消息队列、延时等)而无法继续执行时,会进入阻塞状态。
- 阻塞状态的任务会排入相应的阻塞列表中,直到等待的事件发生或超时后才会被唤醒并转换为就绪状态。
- 阻塞是任务调度中常见的一种状态转换,用于实现任务间的同步和通信。
- 挂起状态(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 时,