DIY简单的RTOS(二)任务切换

2023-11-02

从系统的角度看,任务是竞争系统资源的最小运行单元。
任务可以使用或等待CPU、使用内存空间等系统资源,并独立于其它任务运行。

项目地址



任务控制块

在其他RTOS中,任务一般是由:任务堆栈、任务控制块和任务函数三部分组成。
任务堆栈:上下文切换的时候用来保存任务的工作环境,就是STM32的内部寄存器值。

任务控制块:任务控制块用来记录任务的各个属性。

任务函数:由用户编写的任务处理代码(一般无返回值,单个void *参数,不会返回)

	void  task1Entry(void *param){
		for(;;){
			
		}
	}

在这里插入图片描述

在本文中,任务控制块只定义了栈指针

typedef uint32_t stack_task;

typedef struct _losTask{
	stack_task *stack;
}losTask;

结构体的首地址跟第一个元素的地址一致,我们可以通过该任务栈保存参数,例如寄存器的值。

我们知道一个函数的执行内核会从高地址到低地址分配栈,堆,数据区,代码区等
在这里插入图片描述
栈stack(函数内部定义的局部变量和函数形参)它们在进入函数时自动分配地址,退出函数时自动收回。
堆区(heap)— 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收。




任务初始化

一些RTOS的任务栈如下图所示(来源mculover666):
在这里插入图片描述
在高地址保存程序状态寄存器(xPSR),R15(函数入口参数)等。
那么我们要做的就是把这些寄存器压入任务栈中,这里把一些没有用到的寄存器设置成对应寄存器编号的值,代码如下

void los_task_init(losTask * task,void (*taskEntry)(void *),void *param,stack_task *stack){
    //初始化任务栈
    //传入末端,先减后操作.
    *(--stack) = (unsigned long)(1<<24);      //xPSR
    *(--stack) = (unsigned long)taskEntry;    //PC寄存器
    *(--stack) = (unsigned long)0x14;         //R14(LR)寄存器
    *(--stack) = (unsigned long)0x12;         //R12
    *(--stack) = (unsigned long)0x13;         //R13
    *(--stack) = (unsigned long)0x2;          //R2
    *(--stack) = (unsigned long)0x1;          //R1
    *(--stack) = (unsigned long)param;            //R0(程序入口参数)

    //其他寄存器.
    *(--stack) = (unsigned long)0x11;       //R11
    *(--stack) = (unsigned long)0x10;       //R10
    *(--stack) = (unsigned long)0x9;        //R9
    *(--stack) = (unsigned long)0x8;        //R8
    *(--stack) = (unsigned long)0x7;
    *(--stack) = (unsigned long)0x6;
    *(--stack) = (unsigned long)0x5;
    *(--stack) = (unsigned long)0x4;
    task->stack = stack;
}

在这里插入图片描述

T标志位:该位反映处理器的运行状态。当该位为1时,程序运行于THUMB状态(arm执行16位指令的状态,即16位状态),否则运行于ARM状态。




任务调度

这里只有两个任务,简单起见使用固定的方式,或者采用求余的方式实现。

void los_task_sched(){
	if (currentTask == taskTable[0]){
		nextTask = taskTable[1];
	}else{
		nextTask = taskTable[0];
	}
	los_task_switch();
}

在los_task_switch中触发pendsv异常即可。




任务入口函数

该任务入口函数里面是死循环,把task1Flag取反延时在调用任务调度函数执行下一个任务。

//定义任务
losTask task1;	
//定义任务栈
stack_task task1Env[1024];
//任务初始化
los_task_init(&task1,task1Entry,(void *)0x11111111,&task1Env[1024]);
void task1Entry(void *param){
	for(;;){
		task1Flag = !task1Flag;
		delay(100);
		los_task_sched();
	}
};



主函数


int main(){
	//任务初始化
	los_task_init(&task1,task1Entry,(void *)0x11111111,&task1Env[1024]);
	los_task_init(&task2,task2Entry,(void *)0x22222222,&task2Env[1024]);
	//初始化任务数组
	taskTable[0] = &task1;
	taskTable[1] = &task2;
	//赋值nextTask
	nextTask = taskTable[0];
	los_task_run();	//执行第一个任务
	return 0;
}



汇编指令分析

__asm void PendSV_Handler(void){
    
    IMPORT currentTask
    IMPORT nextTask
    //判断PSP寄存器是否为0
    MRS R0,PSP
    //不需要保存状态直接恢复
    CBZ R0,PendSVHandler_nosave
    //保存另外一些寄存器
    STMDB R0!,{R4-R11}
    
    LDR R1,=currentTask
    LDR R1,[R1]
    STR R0,[R1]

    
PendSVHandler_nosave
    LDR R0,=currentTask
    LDR R1,=nextTask
    LDR R2,[R1]
    STR R2,[R0]	
    

    //取出堆栈地址
    LDR R0,[R2]
    LDMIA R0!,{R4-R11}

    //切换
    MSR PSP,R0
    ORR LR,LR,#0x04
    BX LR   //退出堆栈
}

在这里插入图片描述
在这里插入图片描述

准备执行第二个任务

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
这段汇编代码比较简单,就是寄存器的入栈和出栈。




仿真效果

在这里插入图片描述
寄存器R4-R11的值,我们在初始化的时候手动入栈了,如图所示,出栈成功。

在这里插入图片描述
当该任务被调度执行时,CPU会自动将任务栈中最前面的8个寄存器值加载到CPU寄存器中,完成「下文环境切换」。




不足之处

  • 任务的切换需要调用任务调度函数,明显是不可行的
  • 任务控制块的定义过于简单



参考

Cotex-M内核双堆栈指针MSP和PSP

RTOS内功修炼记(一)—— 任务到底应该怎么写?

01课堂-从0到1实现RTOS

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

DIY简单的RTOS(二)任务切换 的相关文章

  • RTOS任务切换原理与实现

    曾今只是使用过移植好的RTOS进行任务开发 xff0c 对其实现的底层原理一直一知半解 xff0c 正好接触到了李述桐老师的课程以及一些网上的资料 xff0c 让我对实时操作系统的原理有了更深的理解 xff0c 特此把一些原理和思考记录下来
  • 通过Linux学习RTOS

    通过Linux学习RTOS 原文 xff1a http blog csdn net zoomdy article details 50549901 mingdu zheng at gmail dot com RTOS应用很广 xff0c 种
  • 手写RTOS-PendSV中断

    今天这一篇 xff0c 我们说一下操作系统都要用到的PendSV中断 xff0c 整个操作系统中 xff0c 要自己写的的汇编代码不超过20行 xff0c 全部都在PendSV中断里 以下是 Cotex M3权威指南 里对PendSV的描述
  • RTOS信号量、邮箱、队列与事件

    一 定义 信号量 xff0c 邮箱 xff0c 队列的最大不同在于它们发送的内容不同 1 信号量是一个触发信号 xff0c 也是一个计数器 xff0c 等待接收信号的任务一般只有接收到信号才可以执行 xff0c 否则任务一直暂停 xff08
  • 主流 RTOS 评估

    1 RT Thread RT Thread 是国内出产的一款非常优秀的 RTOS 它和 FreeRTOS uCos 等经典 RTOS 最大的不同是 xff1a 它不仅仅是一个实时内核 xff0c 还具备丰富的中间层组件 它提供了一个完整的软
  • 【RTOS的最通俗理解】行业大佬用一篇文章带你快速理解RTOS

    文章目录 单片机 RTOS 架构 1 RTOS的概念 1 1 用人来类比单片机程序和RTOS 1 1 1 我无法一心多用1 2 2 我可以一心多用 1 2 程序简单示例 2 架构的概念 2 1 用人来类比电子产品2 2 要深入理解RTOS就
  • 基于RTOS的软件开发理论

    文章目录 1 RTOS的特点2 任务设计2 1 任务的特性2 2 任务划分的方法2 2 1 设备依赖性任务2 2 2 关键任务2 2 3 紧迫任务2 2 4 数据处理任务2 2 5 触发条件相同的任务2 2 6 运行周期相同的任务2 2 7
  • RTOS消息队列和邮箱区别

    消息队列可以发送多条消息 xff0c 消息队列遵守FIFO特性 xff0c 只能一条一条读和写消息 消息队列是邮箱数组 如果发送者是一对一的方式发送邮件 xff0c 则等待列表中的优先级最高的任务将获取邮件 xff1b 如果是以广播的方式发
  • RTOS 中 Task 之间资源共享示例

    RTOS 中 Task 之间资源共享示例 什么是共享资源 大型项目往往需要创建多个任务 xff0c 任务之间协同合作完成一个大型的功能 在前述的章节中 xff0c 我们讲述了任务间的同步与通信 xff0c 但合作与竞争总是相辅相成的 任务
  • NuttX RTOS

    目录 综述 NuttX是什么 看看这些文件和功能 它怎么会是一个小小的操作系统呢 xff1f NuttX讨论组 你想谈谈NuttX的特性吗 xff1f 你需要帮助吗 xff1f 问题吗 错误吗 下载 我在哪里可以买到NuttX xff1f
  • STM32 Free RTOS实战

    FreeRTOS是一个开源的实时操作系统 使用的平台 xff1a 秉火STM32 Cortex M3内核开发板 xff0c Free RTOS v8 2 3 多任务流水灯 span class token builtin class nam
  • RTOS论文笔记(二)

    李在林 韩宏克 嵌入式Linux实时性分析及改造 2010 Linux 的实时性测试 中断延迟测试 在Linux中 xff0c 内核或驱动程序显式地关 开中断 xff0c 一般是通过调用 cli sti 来进行操作的 在调用 cli 时 x
  • [开发过程]<RTOS>关于RT-Thread

    以前一直折腾FreeRTOS 没时间折腾RT Thread 虽然暂时对RT Thread学的不深 但是从学习难度和社区支持来看 相信多年后RT Thread会成为主流 大概是因为很多RT Thread的中文资料吧 入门还要先学FreeRTO
  • 内核7-线程间同步

    目录 1 信号量 1 1 信号量机制 1 2 信号量的使用场合 1 2 1 线程同步 1 2 2 锁 1 2 3 中断与线程的同步 1 2 4 资源计数 1 3 信号量控制块 1 4 函数 1 4 1 rt sem init 函数 1 4
  • RT-Thread记录(八、理解 RT-Thread 内存管理)

    RT Thread内核的我们已经基本都学习过了 除了基本的线程操作和通信 内核部分还有内存管理和中断处理 本文主要就来说说内存管理相关问题 目录 前言 一 为什么要内存管理 二 RT Thread 内存堆管理 2 1 RT Thread 内
  • FreeRTOS(1):任务

    目录 一 FreeRTOS 介绍 什么是 FreeRTOS 为什么选择 FreeRTOS FreeRTOS 资料与源码下载 FreeRTOS 实现多任务的原理 二 移植 FreeRTOS 到STM32 手动移植 使用CubeMX快速移植 快
  • FreeRTOS-创建删除任务

    1 FreeRTOSConfig h文件 FreeRTOSConfig h配置文件作用 对FreeRTOS进行功能配置和裁剪 以及API函数的使能 相关的宏可以分为三大类 INCLUDE 配置FreeRTOS中可选的API函数 config
  • 13-FreeRTOS任务创建与删除

    任务创建和删除API函数位于文件task c中 需要包含task h头文件 task h里面包函数任务的类型函数 例如 对xTaskCreate的调用 通过指针方式 返回一个TaskHandle t 变量 然后可将该变量用vTaskDele
  • RTX线程通信之——线程标志

    文章目录 Thread Flags 概念 RTX线程标志API 案例 LED灯同步闪亮 小结 参考资料 Thread Flags In a real application we need to be able to communicate
  • 将 DKM 项目链接到内核映像 (VIP) 项目作为 VxWorks Workbench4 中的子项目/额外模块

    如何将 DKM 项目与内核映像 VIP 项目链接 加载 以便我可以从内核映像项目的 usrAppInit c 调用 DKM 项目 应用程序 的入口点函数 以在启动时自动启动应用程序 有人可以描述步骤或向我指出任何文档吗 将 DKM 项目添加

随机推荐

  • MySql SQL语句优化方法

    1 插入优化 当数据过大时 通过load函数上传 2 主键优化 页分裂 当数据乱序插入时 由于主键是按序排的 所以再插入时 当发现页的空间不够时 会通过重新开辟一个页 将原页中的数据拷贝进新的页中 并重新设定链表指针方向 页融合 当删除页内
  • Arduino Uno 实验7——SG90舵机

    SG90舵机简介 舵机是一种位置 角度 伺服的驱动器 适用于那些需要角度不断变化并可以保持的控制系统 主要是由外壳 电路板 驱动马达 直流电机 减速齿轮组 位置检测元件 控制电路 所构成 是一套自动 闭环 控制装置 所谓自动 闭环 控制就是
  • Spring包结构以及各个包之间引用关系说明

    Spring 包结构说明 spring jar 包含有完整发布的单个jar包 他包含有除spring mock jar之外的所有jar 原因是 spring mock jar只有在开发环境中才会用到 而且仅仅是作为一个辅助测试类存在 除了s
  • 解析#pragma指令

    在所有的预处理指令中 Pragma 指令可能是最复杂的了 它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作 pragma指令对每个编译器给出了一个方法 在保持与C和C 语言完全兼容的情况下 给出主机或操作系统专有的特征 依据定义
  • Eclipse安装STS(Spring Tool Suite (STS) for Eclipse)插件

    由于最近在学习SpringBooot 用Eclipse创建SpringBoot项目比较不爽 听说STS插件能直接创建SpringBoot项目 就动手安装一下 希望能对像我一样的小白有所帮助 STS 官网 https spring io to
  • 【毕业设计】基于stm32的便携式U盘设计与实现 - stm32制作U盘

    文章目录 0 前言 1 简介 2 主要器件 3 实现过程 4 部分核心代码 5 最后 0 前言 这两年开始毕业设计和毕业答辩的要求和难度不断提升 传统的毕设题目缺少创新和亮点 往往达不到毕业答辩的要求 这两年不断有学弟学妹告诉学长自己做的项
  • 如何解决网站被黑客攻击-深夜一次网站被攻击瘫痪

    情况 客户网站深夜被黑客攻击 服务器对外发出大量攻击行为流量 运维人员已经不可登录服务器进行安全操作 1首先看能不能后台登录经网站管理界面 如果可以的话那就去查看相关日志 确定黑客攻击的范围 一定要尽可能的得到所有的日志 数据库的 Web服
  • (AJAX/JSON)技术实现校验用户名是否存在

    案例 校验用户名是否存在 1 服务器响应的数据 在客户端使用时 要想当做json数据格式使用 有两种解决方案 1 get type 将最后一个参数type指定为 json 2 在服务器端设置MIME类型 response setConten
  • tensorflow教程_TensorFlow教程

    tensorflow教程 TensorFlow教程 TensorFlow Tutorial PDF Version Quick Guide Resources Job Search Discussion PDF版本 快速指南 资源资源 求职
  • nginx配置中root和alias的区别

    例 访问http 127 0 0 1 download 这个目录时候让他去 opt app code这个目录找 方法一 使用root关键字 location root usr share nginx location download gz
  • 水平集分割

    基于距离正则的水平集分割MATLAB代码 无需初始化 This Matlab code demonstrates an edge based active contour model as an application of the Dis
  • 深入理解Objective-C的Block

    最近时间少 也变得懒了 好久没在这里写文章了 眼看就到8月末了 还是整理一篇酝酿已久的吧 之前的文章中整理过用ObjectiveC开发中常用到的Block代码块 其中也提到了一个和block使用不当的crash例子 接着这个问题 本篇文章将
  • Ubuntu 11.10编译Android 4.0.1源码错误

    Android 4 0 1下载到自己的Ubuntu 11 10 64位 系统里 把整个编译环境都配置好了 参考 http www linuxidc net thread 2736 1 1 html 编译时还是出现了如下的错误提示
  • HTML5 页面布局【结合案例】

    新布局的意义 语义化 HTML5 可以让很多更语义化的结构化代码标签代替大量无意义的 div 标签 1 这种语义化的特性提升了网页的质量和语义 2 减少了以前用于CSS 调用的class 和 id 属性 对搜索引擎的友好 新的结构标签带来的
  • su root 与 su - root的区别

    su root 与 su root的区别 su 默认切到 root su 与su 的区别 su 是不改变当前变量 su 是切换到用户的变量 su只能获得root的执行权限 不能获得环境变量 而su 是切换到root并获得root的环境变量及
  • (Java课设)学生成绩管理系统(IDEA+SSM+Layuimini)

    一 系统介绍 1 开发环境 2 技术概要 3 设计概要 4 功能模块设计 二 系统展示 三 部分代码 Student java studentDao接口文件 StudentService java StudentController jav
  • 如何使用VisualVM进行性能分析本地java项目和远程java项目

    这里是weihubeats 觉得文章不错可以关注公众号小奏技术 文章首发 拒绝营销号 拒绝标题党 背景 在有时候我们需要分析java应用的一些内存 gc等情况进行性能分析 我们往往需要一些性能分析利器 而VisualVM算是其中一个 今天我
  • RTL8189ES/ETV/FTV系列模块定频软件操作手册

    使用说明 1 安装串口驱动 SecureCRT串口工具 2 右键打开我的电脑 选择属性 打开设备管理器 如下图示找到COM口 3 打开串口工具 按下图设置 4 打开机器电源 串口工具中会出现字符运行 停止后按ENTER出现下图 5 输入 号
  • Docker Compose的介绍及安装

    一 compose介绍 Compose是一个用来定义和运行复杂应用的Docker工具 一个使用Docker容器的应用 通常由多个容器组成 使用Docker Compose不再需要使用shell脚本来启动容器 Compose 通过一个配置文件
  • DIY简单的RTOS(二)任务切换

    从系统的角度看 任务是竞争系统资源的最小运行单元 任务可以使用或等待CPU 使用内存空间等系统资源 并独立于其它任务运行 项目地址 任务控制块 在其他RTOS中 任务一般是由 任务堆栈 任务控制块和任务函数三部分组成 任务堆栈 上下文切换的