FreeRTOS学习(1)-- FreeRTOS任务创建、调度、任务间通信
文章目录
前言
初学FreeRTOS, 记录一下自己记的笔记。
参考文章:
1) freeRTOS任务调度及其通信 - 知乎 (zhihu.com)
2) FreeRTOS源码探析之——任务调度相关 - 知乎 (zhihu.com)
3) 4、FreeRTOS的任务创建和启动流程 - 孤情剑客 - 博客园 (cnblogs.com)
一、 FreeRTOS任务状态
在裸机系统中, 系统的主体就是 main 函数里面顺序执行的无限循环,这个无限循环里面 CPU 按照顺序完成各种事情。在多任务系统中,我们根据功能的不同,把整个系统分割成一个个独立的无限循环
且不带返回值
的 C 函数,这个函数我们称为任务
。
FreeRTOS的任务被动态创建或者静态创建后,若不进行删除,则一共有四个状态分别为:
Running态
、Ready态
、Blocked态
、Suspended态(挂起)
。
二、FreeRTOS任务创建
FreeRTOS调用xTaskCreate(动态创建)或者 xTaskCreateStatic(静态创建)API进行任务的创建。
1.静态创建任务流程【ref.3】
1) 任务函数。
要点:任务一般都是死循环并且无返回值的,所以实际功能通常都实现在一个死循环中。
任务里面的延时函数必须使用 FreeRTOS 里面提供的延时函数vTaskDelay(),FreeRTOS 里面的延时是阻塞延时,调用 vTaskDelay()
函数的时候,当前任务会被挂起,调度器会切换到其它就绪的任务,从而实现多任务。
安全起见,为了防止程序由于异常执行到死循环外,可在循环外添加删除当前任务语句vTaskDelete( NULL )
;
2) 任务栈。
要点:在多任务系统中,每个任务都是独立的,互不干扰的,所以要为每个任务都分配独立的栈空间
,这个栈空间通常是一个预先定义好的全局数组(静态), 也可以是动态分配的一段内存空间(动态),但它们都存在于 RAM
中。
3) 任务控制块。
要点:在 C 代码上,任务控制块就是一个结构体,里面有非常多的成员,这些成员共同描述了任务的全部信息,类似于任务的身份证
4) 静态任务创建函数 xTaskCreateStatic()
代码如下(示例):
参数说明:
(1)任务函数,即任务函数的名称,需要我们自己定义并且实现。
(2)任务名字,字符串形式, 最大长度由FreeRTOSConfig.h 中定义的configMAX_TASK_NAME_LEN 宏指定其默认为16,多余部分会被自动截掉,这里任务名字最好要与任务函数入口名字一致,方便进行调试。
(3)任务堆栈大小,单位为字,在 32 位的处理器下(STM32),一个字等于4个字节,那么任务大小就为 128*4 字节。
(4)指向任务函数参数的指针,不用的时候配置为0或者NULL即可。
(5)任务的优先级。优先级范围根据 FreeRTOSConfig.h 中的宏configMAX_PRIORITIES 决定,如果使能 configUSE_PORT_OPTIMISED_TASK_SELECTION这个宏定义,则最多支持 32 个优先级。在 FreeRTOS 中,数值越大优先级越高,0 代表最低优先级。
(6)任务栈指针,指向起始地址,只有在使用静态内存的时候才需要提供,在使用动态内存的时候会根据提供的任务栈大小自动创建。
(7)任务控制块指针,在使用静态内存的时候,需要给任务初始化函数 xTaskCreateStatic()传递预先定义好的任务控制块的指针。在使用动态内存的时候,任务创建函数 xTaskCreate()会返回一个指针指向任务控制块。
2.动态创建任务【ref.3】
区别于静态
:
1) 任务使用的栈和任务控制块是在创建任务的时候FreeRTOS 动态分配的,并不是预先定义好的全局变量。
2) 任务创建函数会返回一个指针,用于指向任务控制块,所以要预先为任务栈定义一个任务控制块指针,也是我们常说的任务句柄。
代码如下(示例):
3. FreeRTOS任务调度流程【ref.1、2】
当任务创建好后,是处于任务就绪等待任务调度器启动。任务调度器只启动一次,之后就不会再次执行了, FreeRTOS 中启动任务调度器的函数是 vTaskStartScheduler()
,并且启动任务调度器的时候就不会返回,从此任务管理都由FreeRTOS 管理,此时才是真正进入实时操作系统中的第一步。在任一时刻,CPU只能处理某一个任务。
vTaskStartScheduler
函数内部操作流程:
调度器的工作模式:
FreeRTOS中提供的任务调度器是基于优先级的抢占式调度
:在系统中除了中断处理函数、调度器上锁部分的代码和禁止中断的代码是不可抢占的之外,系统的其他部分都是可以抢占的。
调度器就是使用相关的调度算法来决定当前需要执行的任务。
- 调度器可以区分就
绪态任务
和挂起态任务
(由于延迟,信号量等待,事件组等待等原因而使得任务被挂起)。 - 调度器可以选择
就绪态
中的一个任务,然后激活
它(通过执行这个任务)使其成为运行态的任务。
FreeRTOS 主要有两种调度方式:
抢占式调度
:每个任务都有不同的优先级
,任务会一直运行直到被高优先级任务抢占或者遇到阻塞式
的 API 函数,如 vTaskDelay。时间片调度
:每个任务都有相同的优先级
,任务会运行固定的时间片
个数或者遇到阻塞式的 API 函数,比如vTaskDelay,才会执行同优先级任务之间的任务切换
。
Tips: vTaskDelay()的延时参数是以tick
为单位的,而tick一下具体是多少是在配置里写好的,当然也可以修改。
4. FreeRTOS任务间通信
FreeRTOS具有一般操作系统都具备的几种任务之间的通信方式,提供给用户的常用的通信方式有:消息队列、信号量、互斥锁(互斥信号量)、事件标志组以及任务通知等。
参考:
FreeRTOS消息队列_不秃也很强的博客-CSDN博客_freertos 消息队列
累了。。。。。下次再整理