ucos-ii 的任务调度原理和实现
1、ucos-ii 任务创建与任务调度
1.1、任务的创建
当你调用 OSTaskCreate( ) 进行任务的创建的时候,会初始化任务的堆栈、保存cpu的寄存器、创建任务的控制块(OS_TCB)等的操作;
if (OSTCBPrioTbl[prio] == (OS_TCB *)0) { /* Make sure task doesn't already exist at this priority */
OSTCBPrioTbl[prio] = OS_TCB_RESERVED;/* Reserve the priority to prevent others from doing ... *//* ... the same thing until task is created. */OS_EXIT_CRITICAL();
psp = OSTaskStkInit(task, p_arg, ptos, 0u); /* Initialize the task's stack */
err = OS_TCBInit(prio, psp, (OS_STK *)0, 0u, 0u, (void *)0, 0u);if (err == OS_ERR_NONE) {if (OSRunning == OS_TRUE) { /* Find highest priority task if multitasking has started */OS_Sched();}} else {OS_ENTER_CRITICAL();
OSTCBPrioTbl[prio] = (OS_TCB *)0;/* Make this priority available to others */OS_EXIT_CRITICAL();}return (err);}
注意:ucosii不支持两个及以上相同的任务优先级的任务,ucosiii支持时间片轮转。
ucosii 的任务控制块是任务中很重要,它记录了任务的信息,包括优先级、延时时间、状态等信息。控制块定义如下:
typedef struct os_tcb {OS_STK *OSTCBStkPtr; /* Pointer to current top of stack */#if OS_TASK_CREATE_EXT_EN > 0uvoid *OSTCBExtPtr; /* Pointer to user definable data for TCB extension */OS_STK *OSTCBStkBottom; /* Pointer to bottom of stack */INT32U OSTCBStkSize; /* Size of task stack (in number of stack elements) */INT16U OSTCBOpt; /* Task options as passed by OSTaskCreateExt() */INT16U OSTCBId; /* Task ID (0..65535) */
#endifstruct os_tcb *OSTCBNext; /* Pointer to next TCB in the TCB list */struct os_tcb *OSTCBPrev; /* Pointer to previous TCB in the TCB list */#if (OS_EVENT_EN)OS_EVENT *OSTCBEventPtr; /* Pointer to event control block */
#endif#if (OS_EVENT_EN) && (OS_EVENT_MULTI_EN > 0u)OS_EVENT **OSTCBEventMultiPtr; /* Pointer to multiple event control blocks */
#endif#if ((OS_Q_EN > 0u) && (OS_MAX_QS > 0u)) || (OS_MBOX_EN > 0u)void *OSTCBMsg; /* Message received from OSMboxPost() or OSQPost() */
#endif#if (OS_FLAG_EN > 0u) && (OS_MAX_FLAGS > 0u)
#if OS_TASK_DEL_EN > 0uOS_FLAG_NODE *OSTCBFlagNode; /* Pointer to event flag node */
#endifOS_FLAGS OSTCBFlagsRdy; /* Event flags that made task ready to run */
#endifINT32U OSTCBDly; /* Nbr ticks to delay task or, timeout waiting for event */INT8U OSTCBStat; /* Task status */INT8U OSTCBStatPend; /* Task PEND status */INT8U OSTCBPrio; /* Task priority (0 == highest) */INT8U OSTCBX; /* Bit position in group corresponding to task priority */INT8U OSTCBY; /* Index into ready table corresponding to task priority */OS_PRIO OSTCBBitX; /* Bit mask to access bit position in ready table */OS_PRIO OSTCBBitY; /* Bit mask to access bit position in ready group */#if OS_TASK_DEL_EN > 0uINT8U OSTCBDelReq; /* Indicates whether a task needs to delete itself */
#endif#if OS_TASK_PROFILE_EN > 0uINT32U OSTCBCtxSwCtr; /* Number of time the task was switched in */INT32U OSTCBCyclesTot; /* Total number of clock cycles the task has been running */INT32U OSTCBCyclesStart; /* Snapshot of cycle counter at start of task resumption */OS_STK *OSTCBStkBase; /* Pointer to the beginning of the task stack */INT32U OSTCBStkUsed; /* Number of bytes used from the stack */
#endif#if OS_TASK_NAME_EN > 0uINT8U *OSTCBTaskName;
#endif#if OS_TASK_REG_TBL_SIZE > 0uINT32U OSTCBRegTbl[OS_TASK_REG_TBL_SIZE];
#endif
} OS_TCB;
2、任务调度实现
2.1、将任务优先级进行分组
因为ucosii最大优先级数量为64个,所以可以分成8组,每组8个优先级。
当一个任务被创建成功之后,它的组号由优先级的高三位决定(bit5 bit4 bit3),它在组内的编号由优先级的低三位决定(bit2 bit1 bit0),如下:
#if OS_LOWEST_PRIO <= 63u /* Pre-compute X, Y */
ptcb->OSTCBY = (INT8U)(prio >> 3u); // 组
ptcb->OSTCBX = (INT8U)(prio & 0x07u); // 组内编号
#else
2.2、任务就绪表
ucosii对任务优先级的调度管理是通过查询任务就绪表进行的。任务就绪表里面保存着当前所有任务的就绪状态,如下:
OSRdyTbl[8]说明:
1)它是uint8的数据类型。它的长度是8,每一个元素代表一个组,
比如 OSRdyTbl[0]代表第0组, OSRdyTbl[1]代表第1组,OSRdyTbl[2]代表第2组……以此类推。2)每一个元素中的每一个位(bit)代表组内的任务的就绪状态(1为就绪,0为未就绪)。 打个比方:
1)当优先级为12 的任务就绪时,那么对应的OSRdyTbl[1]的第4位bit,绝对等于1;
当整个系统中,当只有优先级为12的任务就绪,其他所有任务都没有就绪时,那么OSRdyTbl[1] 绝对等于0x10。2)当优先级为0和1的任务就绪时,那么对应的OSRdyTbl[0]的第0位bit以及第1位bit,都绝对等于1;
当整个系统中,当只有优先级为0和1的任务就绪,其他所有任务都没有就绪时,那么OSRdyTbl[0] 绝对等于0x03。
2.3、任务释放CPU使用权
当任务中调用 OSTimeDly( ) 时,会让任务进入休眠的状态,交出CPU的执行权给到其他就绪任务去执行,这个过程就发生了任务的切换。
简单而言就是会把任务就绪表 OSRdyTbl 中对应的任务优先级在组内的编号状态改变,从而使任务自身进入休眠状态。代码如下:
if (ticks > 0u) { /* 0 means no delay! */OS_ENTER_CRITICAL();
y = OSTCBCur->OSTCBY; /* Delay current task */
OSRdyTbl[y] &= (OS_PRIO)~OSTCBCur->OSTCBBitX;if (OSRdyTbl[y] == 0u) {
OSRdyGrp &= (OS_PRIO)~OSTCBCur->OSTCBBitY;}
OSTCBCur->OSTCBDly = ticks; /* Load ticks in TCB */OS_EXIT_CRITICAL();OS_Sched(); /* Find next task to run! */} 在上面的代码中发现了一个东西:OSRdyGrp。这个有什么用呢?
OSRdyGrp:管理任务就绪组的 OSRdyGrp是INT8U类型的,它每一个bit代表一个组,只要这个组内有任何一个任务就绪了,那对应的这个bit就会被设置为1,表示这个组内目前有就绪的任务。否者对应的位为0。
举个例子,如下:
1)系统中只有任务0就绪了,那么OSRdyGrp 便等于 0x01(二进制00000001)。
2)系统中有任务0和任务63都就绪了,那么OSRdyGrp 便等于 0x81(二进制10000001)。
2.4、任务实现调度切换操作
发生一次任务调度是通过 OS_Sched() 进行的。源码如下:
void OS_Sched (void)
{
#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
OS_CPU_SR cpu_sr = 0u;
#endifOS_ENTER_CRITICAL();if (OSIntNesting == 0u) { /* Schedule only if all ISRs done and ... */if (OSLockNesting == 0u) { /* ... scheduler is not locked */OS_SchedNew();
OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];if (OSPrioHighRdy != OSPrioCur) { /* No Ctx Sw if current task is highest rdy */
#if OS_TASK_PROFILE_EN > 0u
OSTCBHighRdy->OSTCBCtxSwCtr++; /* Inc. # of context switches to this task */
#endif
OSCtxSwCtr++; /* Increment context switch counter */OS_TASK_SW(); /* Perform a context switch */}}}OS_EXIT_CRITICAL();
} 这里的过程如下:
(1)先通过 OS_SchedNew() 找到当前处于就绪状态的最高优先级的任务,如下:
y = OSUnMapTbl[OSRdyGrp];
OSPrioHighRdy = (INT8U)((y << 3u) + OSUnMapTbl[OSRdyTbl[y]]);
(2)然后通过 OS_TASK_SW() 进行任务切换,它的过程如下:
1)OS_TASK_SW 只是一个宏,它实际替换的是 OSCtxSw()
#define OS_TASK_SW() OSCtxSw()2)OSCtxSw()是由汇编实现的
OSCtxSw
PUSH {R4, R5}
LDR R4, =NVIC_INT_CTRL ;触发PendSV异常 (causes context switch)
LDR R5, =NVIC_PENDSVSET
STR R5, [R4]
POP {R4, R5}
BX LR 就这样,上下文就完成了一次切换。

相关文章:
ucos-ii 的任务调度原理和实现
ucosii 任务调度和原理1、ucos-ii 任务创建与任务调度 1.1、任务的创建 当你调用 OSTaskCreate( ) 进行任务的创建的时候,会初始化任务的堆栈、保存cpu的寄存器、创建任务的控制块(OS_TCB)等的操作; if (OSTCBPrioTbl[prio] (OS_…...
Solon2 开发之容器,七、切面与函数环绕拦截
想要环绕拦截一个 Bean 的函数。需要三个前置条件: 通过注解做为“切点”,进行拦截(不能无缘无故给拦了吧?费性能)Bean 的 method 是被代理的在 Bean 被扫描之前,完成环绕拦截的注册 1、定义切点和注册环…...
代码随想录第十天(28)
文章目录28. 找出字符串中第一个匹配项的下标看答案KMPnext数组(前缀表)最长公共前后缀如何计算前缀表前缀表与next数组时间复杂度分析28. 找出字符串中第一个匹配项的下标 莫得思路……好久没做题,都已经忘得差不多了 看答案 其实就是自己…...
循环队列来了解一下!!
笔者在之前的一篇文章,详细的介绍了:队列之单向链表与双向链表的模拟实现:https://blog.csdn.net/weixin_64308540/article/details/128742090?spm1001.2014.3001.5502 感兴趣的各位老铁,可以参考一下啦!下面进入循环…...
Idea打包springboot项目war包,测试通过
pom.xml文件 <!--包名以及版本号,这个是打包时候使用,版本可写可不写,建议写有利于维护系统--> <artifactId>tsgdemo</artifactId> <version>0.0.1-SNAPSHOT</version> <!--打包形式--> <packaging&…...
python+django高校师生健康信息管理系统pycharm
管理员功能模块 4.1登录页面 管理员登录,通过填写注册时输入的用户名、密码、角色进行登录,如图所示。 4.2系统首页 管理员登录进入师生健康信息管理系统可以查看个人中心、学生管理、教师管理、数据收集管理、问卷分类管理、疫情问卷管理、问卷调查管理…...
CUDA中的流序内存分配
文章目录CUDA中的流序内存分配1. Introduction2. Query for Support3. API Fundamentals (cudaMallocAsync and cudaFreeAsync)4. Memory Pools and the cudaMemPool_t注意:设备的内存池当前将是该设备的本地。因此,在不指定内存池的情况下进行分配将始终…...
开源、低成本的 Xilinx FPGA 下载器(高速30MHz)
目前主流的Xilinx下载器主要有两种:一种是Xilinx官方出品的Xilinx Platfom Cable USB,还有一个就是Xilinx的合作伙伴Digilent开发的JTAG-HS3 Programming Cable。 JTAG-HS系列最大支持30MHz下载速度,基于FTDI的FT2232方案。 JTAG-HS系列对比…...
Maven专题总结
1. 什么是Maven Maven 是一个项目管理工具,它包含了一个项目对象模型 (POM: Project Object Model),一组标准集合,一个项目生命周期(Project Lifecycle),一个依赖管理系统(Dependency Management System),和…...
谷粒商城--SPU和SKU
目录 1.SPU和SKU概念 2.表的关系理解 3.导入前端代码 4.完善后端接口 5.属性分组详情 6.规格参数详情 7. 销售属性详情 8.分组与属性关联 9.发布商品 10.仓库服务 1.SPU和SKU概念 SPU:standard product unit(标准化产品单元):是商品信息聚合的…...
二叉树OJ题(上)
✅每日一练:100. 相同的树 - 力扣(LeetCode) 题目的意思是俩棵树的结构不仅要相同,而且每个节点的值还要相同,如果满足上面2个条件,则成立! 解题思路: 从三个方面去考虑࿱…...
第一章 PDF语法
第一章 PDF语法PDF ObjectsNull ObjectsBoolean ObjectsNumeric ObjectsName ObjectsString ObjectsArray ObjectsDictionary ObjectsName treesNumber treesStream ObjectsDirect versus Indirect ObjectsFile StructureWhite-SpaceThe Four Sections of a PDFHeaderTrailerBo…...
IntelliJ IDEA 创建JavaFX项目运行
IntelliJ IDEA 创建JavaFX项目运行JavaFX官网文档:https://openjfx.io/openjfx-docs/ JavaFX 2008年12月05日诞生,是一个开源的下一代客户端应用程序平台,适用于基于 Java 构建的桌面、移动和嵌入式系统。这是许多个人和公司的协作努力&#…...
IC封装常见形式
参考:https://blog.csdn.net/dhs888888/article/details/127673300?utm_mediumdistribute.pc_relevant.none-task-blog-2defaultbaidujs_baidulandingword~default-0-127673300-blog-115610343.pc_relevant_multi_platform_whitelistv4&spm1001.2101.3001.4242…...
Linux通配符、转义符讲解
目录 通配符 通过通配符定义匹配条件 转义符 将所有的逻辑操作符都转换成字符 通配符 通过通配符定义匹配条件 * 任意字符都可以通配(也可以匹配空值) ? 匹配单个字符 [a-z] 匹配单个的小写英文字母 [A-Z] 匹配单个的大写英文…...
[OpenMMLab]提交pr时所需的git操作
git开发流程 准备工作 作为一个开发者,fork一个仓库之后应该先做什么? 1、下载仓库,创建上游代码库,查看当前的分支情况 git clone https://github.com/<your_name>/<repo_name>.git git remote add upstream git…...
pandas——groupby操作
Pandas——groupby操作 文章目录Pandas——groupby操作一、实验目的二、实验原理三、实验环境四、实验内容五、实验步骤一、实验目的 熟练掌握pandas中的groupby操作 二、实验原理 groupby(byNone, axis0, levelNone, as_indexTrue, sortTrue, group_keysTrue, squeezeFalse&…...
webpack.config.js哪里找?react项目关闭eslint监测
目录 webpack.config.js哪里找? react项目关闭eslint监测 webpack.config.js哪里找? 在React项目中,当我们需要修改一些配置时,发现找不到webpack.config.js,是我们创建的项目有问题吗,还需新创建项目的项…...
OpenCV 图像梯度算子
本文是OpenCV图像视觉入门之路的第12篇文章,本文详细的介绍了图像梯度算子的各种操作,例如:Sobel算子Scharr算子laplacian算子等操作。 OpenCV 图像梯度算子目录 1 Sobel算子 2 Scharr算子 3 laplacian算子 1 Sobel算子 Sobel算子是一种图…...
Linux c编程之Wireshark
Wireshark是一个网络报文分析软件,是网络应用问题分析必不可少的工具软件。网络管理员可以使用wireshark排查网络问题。程序开发人员可以用来分析应用协议、定位分析应用问题。无论是网络应用程序开发人员、测试人员、部署人员、技术支持人员,掌握wireshark的使用对于分析网络…...
LingBot-Depth部署避坑指南:常见问题与解决方案汇总
LingBot-Depth部署避坑指南:常见问题与解决方案汇总 1. 引言:为什么需要这份指南 当你第一次尝试部署LingBot-Depth时,可能会遇到各种意想不到的问题——从模型下载失败到GPU内存不足,从端口冲突到奇怪的输出结果。这些问题往往…...
手把手教你用RTABMAP+T265在Windows10上实现室内三维扫描(含标定技巧)
手把手教你用RTABMAPT265在Windows10上实现高精度室内三维扫描 第一次接触室内三维扫描时,我被这项技术深深吸引——它能让物理空间瞬间数字化,就像给现实世界按下"CtrlC"。但真正动手配置RTABMAP和T265相机时,才发现这条路并不平坦…...
1.1 AI技术全景图:从传统ML到大模型
AI技术全景图:从传统ML到大模型本文适合谁:完全没有AI背景的读者。读完这篇,你会知道"AI/机器学习/深度学习/大模型"这几个词是什么关系,以及你将要学的东西在整个AI世界里处于什么位置。AI发展经历了三个时代——本文带…...
嵌入式OLED UI组件库:轻量级C++组件化设计
1. 项目概述 OLED UI Components 是一个面向嵌入式平台的轻量级、组件化 OLED 用户界面开发库,专为基于 SSD1306 驱动芯片的单色 OLED 显示屏(典型分辨率为 12864)设计。该库不直接操作硬件寄存器,而是构建在 Adafruit_SSD1306 库…...
LFM2.5-1.2B-Thinking-GGUF前端面试题解析实战:模拟面试与答案生成
LFM2.5-1.2B-Thinking-GGUF前端面试题解析实战:模拟面试与答案生成 1. 开篇:AI如何改变前端面试准备方式 前端开发岗位的竞争日益激烈,技术面试的难度也水涨船高。传统的面试准备方式往往效率低下——求职者要么死记硬背网上的标准答案&…...
PowerShell效率提升秘籍:10个必备插件让你的终端飞起来
PowerShell效率革命:10款生产力插件深度评测与实战指南 对于每天与终端打交道的开发者来说,PowerShell的默认功能往往难以满足高效开发的需求。本文将深入剖析10款经过实战检验的效率工具,从智能补全到目录导航,从文件操作到命令解…...
用ChatTTS打造你的专属AI语音助手:从音色定制到批量合成音频的完整工作流
用ChatTTS打造你的专属AI语音助手:从音色定制到批量合成音频的完整工作流 在内容创作领域,音频正成为越来越重要的媒介形式。无论是知识付费课程的讲解、播客节目的制作,还是智能设备的语音交互,一个稳定、个性化的语音合成系统都…...
vscode-drawio扩展依赖更新:安全高效地管理第三方库
vscode-drawio扩展依赖更新:安全高效地管理第三方库 【免费下载链接】vscode-drawio This unofficial extension integrates Draw.io (also known as diagrams.net) into VS Code. 项目地址: https://gitcode.com/gh_mirrors/vs/vscode-drawio vscode-drawio…...
论文检测「生死局」破局指南:Paperxie 四大降重方案,精准对抗知网 / 维普 AIGC 检测
paperxie-免费查重复率aigc检测/开题报告/毕业论文/智能排版/文献综述https://www.paperxie.cn/weight?type1https://www.paperxie.cn/weight?type1 凌晨三点的电脑屏幕前,你盯着知网 AIGC 检测报告上刺眼的「99.8% 疑似度」,指尖冰凉 —— 刚写完的毕…...
手把手教你解决Unity视频播放问题:H264编码设置与RawImage的正确用法
Unity视频播放全攻略:H264编码优化与RawImage实战解析 在Unity项目开发中,视频播放功能看似简单,却暗藏诸多技术细节。许多开发者都曾遇到过视频不同步、颜色失真或性能低下的困扰。本文将深入剖析视频播放的核心技术要点,从编码格…...
