【正点原子FreeRTOS学习笔记】————(7)任务调度

这里写目录标题

  • 一、开启任务调度器(熟悉)
  • 二、启动第一个任务(熟悉)
    • 2.1,prvStartFirstTask () /* 开启第一个任务 */
    • 2.2,vPortSVCHandler () /* SVC中断服务函数 */
  • 三、任务切换(掌握)

一、开启任务调度器(熟悉)

vTaskStartScheduler()
作用:用于启动任务调度器,任务调度器启动后, FreeRTOS 便会开始进行任务调度
该函数内部实现,如下:
1、创建空闲任务
2、如果使能软件定时器,则创建定时器任务
3、关闭中断,防止调度器开启之前或过程中,受中断干扰,会在运行第一个任务时打开中断
4、初始化全局变量,并将任务调度器的运行标志设置为已运行
5、初始化任务运行时间统计功能的时基定时器
6、调用函数 xPortStartScheduler()

xPortStartScheduler()
作用:该函数用于完成启动任务调度器中与硬件架构相关的配置部分,以及启动第一个任务
该函数内部实现,如下:
1、检测用户在 FreeRTOSConfig.h 文件中对中断的相关配置是否有误
2、配置 PendSV 和 SysTick 的中断优先级为最低优先级
3、调用函数 vPortSetupTimerInterrupt()配置 SysTick
4、初始化临界区嵌套计数器为 0
5、调用函数 prvEnableVFP()使能 FPU
6、调用函数 prvStartFirstTask()启动第一个任务

二、启动第一个任务(熟悉)

想象下应该如何启动第一个任务?
假设我们要启动的第一个任务是任务A,那么就需要将任务A的寄存器值恢复到CPU寄存器
任务A的寄存器值,在一开始创建任务时就保存在任务堆栈里边!
注意:
1、中断产生时,硬件自动将xPSR,PC(R15),LR(R14),R12,R3-R0出/入栈;而R4~R11需要手动出/入栈
2、进入中断后硬件会强制使用MSP指针 ,此时LR(R14)的值将会被自动被更新为特殊的EXC_RETURN

2.1,prvStartFirstTask () /* 开启第一个任务 */

用于初始化启动第一个任务前的环境,主要是重新设置MSP 指针,并使能全局中断
1、什么是MSP指针?
程序在运行过程中需要一定的栈空间来保存局部变量等一些信息。当有信息保存到栈中时,MCU 会自动更新 SP 指针,ARM Cortex-M 内核提供了两个栈空间
主堆栈指针(MSP):它由 OS 内核、异常服务例程以及所有需要特权访问的应用程序代码来使用
进程堆栈指针(PSP):用于常规的应用程序代码(不处于异常服务例程中时)
在FreeRTOS中,中断使用MSP(主堆栈),中断以外使用PSP(进程堆栈)

2、为什么是 0xE000ED08?
因为需从 0xE000ED08 获取向量表的偏移,为啥要获得向量表呢?因为向量表的第一个是 MSP 指针!
取 MSP 的初始值的思路是先根据向量表的位置寄存器 VTOR (0xE000ED08) 来获取向量表存储的地址;
再根据向量表存储的地址,来访问第一个元素,也就是初始的 MSP
CM3 允许向量表重定位——从其它地址处开始定位各异常向量 这个就是向量表偏移量寄存器,向量表的起始地址保存的就是主栈指针MSP 的初始值

2.2,vPortSVCHandler () /* SVC中断服务函数 */

注意:SVC中断只在启动第一次任务时会调用一次,以后均不调用
当使能了全局中断,并且手动触发 SVC 中断后,就会进入到 SVC 的中断服务函数中

  1. 通过 pxCurrentTCB 获取优先级最高的就绪态任务的任务栈地址,优先级最高的就绪态任务是系统将要运行的任务
  2. 通过任务的栈顶指针,将任务栈中的内容出栈到 CPU 寄存器中,任务栈中的内容在调用任务创建函数的时候,已初始化,然后设置 PSP 指针 。
  3. 通过往 BASEPRI 寄存器中写 0,允许中断。
  4. R14 是链接寄存器 LR,在 ISR 中(此刻我们在 SVC 的 ISR 中),它记录了异常返回值 EXC_RETURN,而EXC_RETURN 只有 6 个合法的值(M4、M7),如下表所示:
    在这里插入图片描述
    出栈/压栈汇编指令详解
    1、出栈(恢复现场),方向:从下往上(低地址往高地址):假设r0地址为0x04汇编指令示例:
    ldmia r0!, {r4-r6} /* 任务栈r0地址由低到高,将r0存储地址里面的内容手动加载到 CPU寄存器r4、r5、r6 */
    r0地址(0x04)内容加载到r4,此时地址r0 = r0+4 = 0x08
    r0地址(0x08)内容加载到r5,此时地址r0 = r0+4 = 0x0C
    r0地址(0x0C)内容加载到r6,此时地址r0 = r0+4 = 0x10

2、压栈(保存现场),方向:从上往下(高地址往低地址):假设r0地址为0x10汇编指令示例:
stmdb r0!, {r4-r6} } /* r0的存储地址由高到低递减,将r4、r5、r6里的内容存储到r0的任务栈里面。 */
地址:r0 = r0-4 = 0x0C,将r6的内容(寄存器值)存放到r0所指向地址(0x0C)
地址:r0 = r0-4 = 0x08,将r5的内容(寄存器值)存放到r0所指向地址(0x08)
地址:r0 = r0-4 = 0x04,将r4的内容(寄存器值)存放到r0所指向地址(0x04)

三、任务切换(掌握)

任务切换的本质:就是CPU寄存器的切换。
假设当由任务A切换到任务B时,主要分为两步:
第一步:需暂停任务A的执行,并将此时任务A的寄存器保存到任务堆栈,这个过程叫做保存现场;
第二步:将任务B的各个寄存器值(被存于任务堆栈中)恢复到CPU寄存器中,这个过程叫做恢复现场;
对任务A保存现场,对任务B恢复现场,这个整体的过程称之为:上下文切换

注意:任务切换的过程在PendSV中断服务函数里边完成
在这里插入图片描述
PendSV中断是如何触发的?
1、滴答定时器中断调用
2、执行FreeRTOS提供的相关API函数:portYIELD()
本质:通过向中断控制和状态寄存器 ICSR 的bit28 写入 1 挂起 PendSV 来启动 PendSV 中断
在这里插入图片描述
查找最高优先级任务
vTaskSwitchContext( ) /* 查找最高优先级任务 /
taskSELECT_HIGHEST_PRIORITY_TASK( ) /
通过这个函数完成 */

 #define taskSELECT_HIGHEST_PRIORITY_TASK()                                                  			
    {                                                                                          									
        UBaseType_t uxTopPriority;                                                             		 		 
        portGET_HIGHEST_PRIORITY( uxTopPriority, uxTopReadyPriority );         			
        configASSERT( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ uxTopPriority ] ) ) > 0 ); 	
        listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) );   	
    }

前导置零指令

#define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities )        uxTopPriority = ( 31UL - ( uint32_t ) __clz( ( uxReadyPriorities ) ) )

在这里插入图片描述
所谓的前导置零指令,大家可以简单理解为计算一个 32位数,头部 0 的个数
通过前导置零指令获得最高优先级

获取最高优先级任务的任务控制块

#define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList )                                           	
    {                                                                                         							 
        List_t * const pxConstList = ( pxList );                                              					
        ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;                         			
        if( ( void * ) ( pxConstList )->pxIndex == ( void * ) &( ( pxConstList )->xListEnd ) ) 			 
        {                                                                                      							 
            ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;                       			 
        }                                                                                      							 	
        ( pxTCB ) = ( pxConstList )->pxIndex->pvOwner;                                         			 	 
    }

通过该函数获取当前最高优先级任务的任务控制块
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/496436.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【元胞自动机】MATLAB界面聚合的元胞自动机模拟完整实现运行

文末有完整代码分享链接 文件介绍 automain 为元胞自动机主函数 choosedirection 选择方向函数,主函数调用 judgedirection 判断位置函数,主函数调用 neighbor 求每个元胞的邻居函数,主函数调用 surfaceness 求表面粗糙度 porosity 求孔隙率…

开源AI引擎|信息抽取与文本分类项目案例:提升12345政务投诉处理效率

一、实际案例介绍 采集员案件上报流程是城市管理和问题解决的关键环节,涉及对案件类别的选择、案件来源的记录、详细案件描述的填写以及现场图片的上传。这一流程要求采集员准确、详细地提供案件信息,以便系统能够自动解析关键数据并填写相关内容&#…

Python读取PDF文字转txt,解决分栏识别问题,能读两栏

搜索了一下,大致有这些库能将PDF转txt 1. PyPDF/PyPDF2(截止2024.03.28这两个已经合并成了一个)pypdf PyPI 2. pdfplumber GitHub - jsvine/pdfplumber: Plumb a PDF for detailed information about each char, rectangle, line, et cete…

VSCode 如何同步显示网页在手机或者平板上

首先要确保 ①电脑上安装了VsCode ②VsCode安装插件LiveServer 安装成功之后 连续按住 Alt L 、Alt O 会跳转到对应的html页面上 http://127.0.0.1:5500/....... 是这个开头的 然后打开网络 如果桌面有网上邻居的可以直接点桌面的网上邻居 进来找到WLAN这个…

spark核心概念

DAG 所谓DAG就是有向无环图,其实就是个无环的流程,Spark的核心是根据RDD来实现的,Spark Scheduler!则为Spark核心实现的重要一环,其作用就是任务调度。Spark的任务调度就是如何组织任务去处理RDD中每个分区的数据,根据…

AI智能分析网关V4如何使用GB28181注册到EasyCVR平台?具体步骤是什么?

旭帆科技的智能分析网关V4内含近40种智能分析算法,包括人体、车辆、消防、环境卫生、异常检测等等,在消防安全、生产安全、行为检测等场景应用十分广泛。如常见的智慧工地、智慧校园、智慧景区、智慧城管等等,还支持抓拍、记录、告警、语音对…

JavaScript基础练习题之计算数组元素的和与平均值

一、如何使用JavaScript计算数组元素的和与平均值&#xff1f; 二、正确的源程序 <!DOCTYPE html> <html><head><meta charset"UTF-8"><title>计算数组元素的和与平均值</title></head><body><h1>计算数组元…

HarmonyOS 应用开发之AbilityStage组件容器

AbilityStage是一个 Module 级别的组件容器&#xff0c;应用的HAP在首次加载时会创建一个AbilityStage实例&#xff0c;可以对该Module进行初始化等操作。 AbilityStage与Module一一对应&#xff0c;即一个Module拥有一个AbilityStage。 DevEco Studio默认工程中未自动生成Ab…

Linux常见指令解析一

Linux常见指令解析一 常见指令1. ls 指令2.pwd 命令3.cd 命令4.touch 命令5.mkdir 命令6.rmdir指令 && rm 指令7.man 指令8.cp 指令9.cat 命令 && tac 命令10.mv 指令11.more 指令12.less 指令13.head 指令14.tail 指令15.cal 指令 常见指令 1. ls 指令 语法…

包含具有多种类型信息的3D模型

1982年&#xff0c;Gbor Bojr开始使用类似于1975年的建筑描述系统技术来开发建筑信息软件。随后&#xff0c;1984年Bojr发布了用于Apple Lisa操作系统的Graphisoft的Radar CH。该软件技术被称为ArchiCAD于1987年重新推出&#xff0c;这是第一个能够在个人计算机上运行的建筑信息…

【源码分析】一文看透集合容器

一文看透集合容器 一、Mapa. HashMapb.ConcurrentHashMapc.HashTabled. TreeMap 二、Collectiona. ListArrayListLinkedListVectorCopyOnWriteArrayList对比和自身思考思考&#xff1a;为什么都拒绝使用Vector啊&#xff1f;它线程安全诶 b. SetHashSetTreeSetCopyOnWriteArray…

2024年【烟花爆竹产品涉药】免费试题及烟花爆竹产品涉药考试技巧

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年【烟花爆竹产品涉药】免费试题及烟花爆竹产品涉药考试技巧&#xff0c;包含烟花爆竹产品涉药免费试题答案和解析及烟花爆竹产品涉药考试技巧练习。安全生产模拟考试一点通结合国家烟花爆竹产品涉药考试最新大纲…

135.分发糖果

javapublic class Solution {public int candy(int[] ratings) {// 获取孩子人数int len ratings.length;// 初始化一个数组存储每个孩子的糖果数&#xff0c;默认第一个孩子有1颗糖果int[] candyVec new int[len];candyVec[0] 1;// 阶段1&#xff1a;从左到右遍历for (int …

MongoDB内存过高问题分析解决

告警 公司有个3.2.7版本的mongo复制集&#xff0c;最近几天频繁告警内存过高。 服务器配置16C64G内存。mongo备节点内存使用到55G&#xff0c;触发告警。 以下内容基于3.2.7版本&#xff0c;3.2.7版本已经太老&#xff0c;很多后来的命令和配置&#xff0c;3.2.7都没有。 …

C++自主点餐系统

一、 题目 设计一个自助点餐系统&#xff0c;方便顾客自己点餐&#xff0c;并提供对餐厅销售情况的统计和管理功能。 二、 业务流程图 三、 系统功能结构图 四、 类的设计 五、 程序代码与说明 头文件1. SystemMap.h #pragma once #ifndef SYSTEMMAP #define SYSTEMMAP #in…

vue3全局引入element-plus使用Message教程

文章目录 安装引入 Element Plus和组件样式示例注意安装与引入&#xff1a;按需引入&#xff1a;API 使用&#xff1a;样式问题&#xff1a;组件上下文&#xff1a;版本兼容性&#xff1a;错误处理&#xff1a; 这是 Element UI 的 Vue 3 版本。ElMessage 是 Element Plus 中的…

在Linux上使用nginx反向代理部署Docker网站

在政务云上部署Web环境&#xff0c;为了保证服务器安全&#xff0c;甲方只开放一个端口且只允许使用https协议进行访问&#xff0c;经过思考&#xff0c;决定使用docker部署网站&#xff0c;使用nginx反向代理&#xff0c;通过不同的二级域名访问不同的端口。 1 使用docker部署…

编程语言|C语言——C语言变量的存储方式

前言 变量是程序中数据的存储空间的抽象。变量的存储方式可分为静态存储和动态存储两种。 静态存储变量通常是在程序编译时就分配一定的存储空间并一直保持不变&#xff0c;直至整个程序结束。在上一部分中介绍的全局变量的存储方式即属于此类存储方式。 动态存储变量是在程序执…

超越极限!《无名之辈》高阶武学与战术应对策略一览!

欢迎来到《无名之辈》世界&#xff01;在这里&#xff0c;决战不仅需要勇气&#xff0c;更需要智慧和策略。为了让你在游戏中游刃有余&#xff0c;以下是一份全面的游戏攻略&#xff0c;助你成为战场上的无敌之王&#xff01; 一、主角战斗技巧&#xff1a; 反击属性至关重要&a…

Vue3状态管理库--Pinia

Pinia快速入门 一、什么是Pinia &#xff1f; Pinia 是 Vue 的专属的最新状态管理库 &#xff0c;是 Vuex 状态管理工具的替代品。 Pinia官网链接 提供更加简单的API &#xff08;去掉了 mutation &#xff09;提供符合组合式风格的API &#xff08;和 Vue3 新语法统一&…