FreeRTOS 任务管理

【基于cortex-M3 内核的任务管理,栈是向下增长的。

 

这里看代码有个原则:

1. 被 #if #endif 控制的,代码不看,这里的代码可以理解为独立的功能;

2. 被 #if #else #endif 控制的,一定要搞清楚走哪一个分支。

通常看代码的 if 也可以采用这种方式,可以快速理清主代码流程。】

1. 任务概念介绍

        在裸机系统中,系统的主体就是main 函数里的死循环,在这个循环里,CPU按照顺序依次执行各种事情;

        在多任务系统中,我们根据功能的不同,把整个系统分割成多个任务,每个任务都有自己的执行环境(运行栈,TCB),且业务上也是相对独立的。Freertos 就是一个实时且免费的多任务系统,调度的最小单位就是任务,这里可以理解为就是进程,没有线程的概念。任务的具体定义就是:独立且无法返回的函数,大概形式如下:

2. 任务创建

        每个任务都运行在自己的环境中,这里的环境包括栈和TCB,所以任务创建的时候,需要知道任务栈的地址和大小(统称栈空间),还有TCB的地址(统称TCB空间,TCB的大小是固定的,等于 sizeof(TCB_t))。

        任务创建分为动态创建和静态创建,所谓的动态创建,就是任务栈空间和TCB空间都是从Freertos 管理的堆空间申请来的,当任务被删除时,也可以从堆空间释放对应的空间;所谓的静态创建,就是任务栈空间和TCB空间都是写死的,也就是声明一个栈变量和TCB变量,由系统启动时,在内存中给定具体地址,但是有个问题,当任务被删除时,这里的栈空间和TCB空间就浪费了。所以,综上所述,再加上实际项目经验,一般使用动态创建的方式,下面说下动态创建流程

2.1 任务创建大体流程

1)申请栈空间

2)申请TCB空间

3)TCB的栈指针(pxStack)指向栈空间

4)初始化TCB结构体的成员

5)初始化栈空间

6)初始化任务相关的链表,包括就绪链表,延时链表,挂起链表和删除链表

7)将任务插入到就绪链表中

2.2 任务创建流程图

3. 任务启动

3.1 任务启动大体流程

1)创建idle 任务

2)如果需要使用定时器的话,创建定时器任务

3)关闭 Freertos 管理的中断

4)设置 pendsv 和 svc 的中断优先级为最低

5)打开不受 Freertos管理的中断

6)触发svc 中断

7) 在svc 中断中,加载任务栈中的内容到CPU寄存器(只加载 r4 – r11),并且打开Freertos 管理的中断,与3)对应,最后设置中断退出进入用户模式,所以当中断退出后,系统会从任务栈空间加载剩余栈内容到寄存器(r0, r1, r2, r3, r12, r14, r15, xPSR)。

3.2 任务启动流程图

4. 任务切换

4.1 任务切换大体流程

        触发场景:systick 定时器中断中触发、事件响应触发(比如任务B读取一个空队列,任务A给此队列发送了一个消息,此时需要执行一个任务切换,让任务B开始运行)。

       怎么触发:通过触发pendsv 中断,在中断处理流程中完成任务切换。

       具体流程:

                1) 保存任务A的运行信息

                2)找到下一个要运行的任务B

                3)将任务B的栈信息加载到寄存器中

4.2 任务切换代码讲解

在调用“vTaskSwitchContext” 之前, 将 R3 和 R14 寄存器压入主堆栈,原因是:

R3 指向的是 pxCurrentTCB , 在调用函数过程中 R0 - R3  的值随时都可能改变,为了之后不在重新指向 pxCurrentTCB,所以保存下来

R14 的值是在离开任务后,将R14 的值赋值为0xFFFFFFFd, 表示从应用进入的中断,所以等到中断处理完成后,需要返回到应用中,而在 调用vTaskSwitchContext时,会修改R14的值(返回地址),所以将R14的值写入主堆栈,用来在退出中断后返回到应用。

5. 任务状态迁移

5.1 状态迁移

5.2 状态解释

【说明】除了运行态之外,其他3个均有一个链表和其对应,也就是说任务挂在哪个链表上,那么这个任务就是处于什么态。运行态就是任务正在使用CPU,不用链表维护,也可以说不属于这3个状态就是运行态,下面对上图做个解释

1)任务创建之后,加入就绪列表,就是就绪态。

2)获得了CPU权限之后就是运行态。

3)当时间片到了后,需要切换下一个任务,此时任务又回到就绪态。

4)当运行态的任务需要读取一个空队列的时候,就会将任务挂到阻塞链表,就是阻塞态(这里只是举例,其他情况下也会发生阻塞的情况)。

5)当队列中有消息之后,将阻塞任务加入到就绪链表,变成就绪态(对应上面的举例)。

6)7)8)处于任何状态下的任务都可以直接进入到挂起态,进入挂起态这个动作不是系统调度的动作,是一个主动调用的过程。

9)挂起的任务要恢复,都是先恢复到就绪态,有一个特殊的挂起所有任务,并不是将任务全部挂到挂起链表,而是直接挂起调度器。

6. 任务相关API

函数名

功能描述

uxTaskPriorityGet()

查询某个任务的优先级

vTaskPrioritySet()

改变某个任务的优先级

uxTaskGetSystemState()

获取系统中任务状态

vTaskGetInfo()

获取某个任务信息

xTaskGetCurrentTaskHandle()

获取当前正在运行任务的任务句柄

xTaskGetHandle()

根据任务名字查找某个任务的句柄

xTaskGetIdleTaskHandle()

获取空闲任务的句柄

uxTaskGetStackHighWaterMark()

获取任务的堆栈的历史剩余最小值,也叫高水位线(可以用来判断栈深度是否合理)

pcTaskGetName()

获取某个任务的任务名字

xTaskGetTickCount()

获取系统时间计数器值

xTaskGetTickCountFromISR()

在中断服务函数中获取时间计数器值

xTaskGetSchedulerState()

获取任务调度器的状态,开启或未开启

uxTaskGetNumberOfTask()

获取当前系统中存在的任务数量

vTaskList()

以表格的形式输出当前系统中所有任务的详细信息

vTaskGetRunTimeStats()

获取每个任务的运行时间

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值