uc/OS-II操作系统:uc/OS中的任务_中(如不懂——>请收下我的膝盖)

注:本章接着上一章节书写

四、任务就续表及任务调度

1、什么是多任务系统
并发:
    同一个处理器轮换地运行多个程序。或者说是由多个程序轮班地占用处理器这个资源。且在占用这个资源期间,并不一定能够把程序运行完毕。

在这里插入图片描述
那么处理器如何进行程序的切换呢?

两句话:
(1)处理器是个傻瓜,PC让它干啥,它就干啥。
(2)PC是个指路器,它指向哪儿,处理器就去哪儿。
从此可以知道,哪个程序占有了PC,哪个程序就占有了处理器。
深刻地理解PC是理解系统进行程序切换动作的关键。

那么我们如何操作PC?

1)数据传送指令
(2)子程序返回指令(由堆
栈弹出)
(3)中断、中断返回指令
(由堆栈弹出)
系统是通过把待运行程序的地址赋予程序计数器PC来实现程序的切换的。

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

多任务切换与处理器之间关系的处理?
1、首先在内存中为每个任务创建一个虚拟的处理器(处理器部分的运行环境)
2、当需要运行某个任务时,就把该任务的虚拟处理器复制到实际处理器中
3、当需要终止当前任务时,则把任务对应的虚拟处理器复制到内存
4、再把另一个需要运行的任务的需处理器复制到实际处理器中
调度器:
由操作系统的调度器按某种规则来进行这两个复制操作

总结来说,任务的切换是任务运行环境的切换
2、虚处理器
虚拟处理器应该存储的主要信息:
1、程序的断点地址(PC)
2、任务堆栈指针(SP)
3、程序状态字寄存器(PSW)
4、通用寄存器内容
5、函数调用信息(已存在于堆栈)
这些内容通常保存在任务堆栈中,这些内容也常叫做任务的上下文。

(1)任务切换的关键

任务切换的关键是把程序的“私有堆栈指针”赋予处理器的的堆栈指针SP,实质上系统是通过SP的切换来实现程序的切换的。
用户需要建立概念:
(1)具有控制块的程序才是一个可以被系统所运行的任务
(2)程序代码、私有堆栈、任务控制块是任务的三要件
(3)任务控制块提供了运行环境的存储位置
3、任务就续表的结构

为了能够使系统清楚地知道,系统中哪些任务已经就绪,哪些还没有就绪,μC/OS_II 在 RAM中设立了一个记录表,系统中的每个任务都在这个表中占据一 Bit 的位置,并用这个位置的状态(1或者0)来表示任务是否处于就绪状态,这个表就叫做任务就绪状态表,简称叫任务就绪表 ---- 一个 INT8U 的数组 OSRdyTbl[ ] 充当,最多8个元素,可以标示64个任务。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4、任务优先级数据结构分析

(1)uC/OS-II 最多管理64个任务,Prio值域:0 ~ 63,对应的二进制数 000,000 ~ 111,111(6bit), OSRdyGrp(任务组就绪变量)8 bit,任务就续数组元素 OSRdyTbl 也是8bit。
(2)prio.D[5:3] — 对应 OSRdyTbl 的下标(任务组号 x ), 也对应 OSRdyGrp 的位号。
(3)prio.D[2:0] —对应 OSRdyTbl 元素的位号(任务组号 y )
备注:这就是 prio 的值和任务就绪表的映射关系。

举例:prio = 29 的任务在任务就续表中的表示。prio = 29  , 其 8 进制表示为:35 O

在这里插入图片描述
依照 prio “置/清” 任务就绪表的操作,在 uC/OS-II 中预定义了一个 OSMapTbl[ ] 数组:

OSMapTbl[0] = 0000,0001B
OSMapTbl[1] = 0000,0010B
OSMapTbl[2] = 0000,0100B
OSMapTbl[3] = 0000,1000B
OSMapTbl[4] = 0001,0000B
OSMapTbl[5] = 0010,0000B
OSMapTbl[6] = 0100,0000B
OSMapTbl[7] = 1000,0000B

在程序中,可以用下面的代码把优先级别为 prio 的任务置为就绪状态:

OSRdyGrp | = OSMapTbl[prio>>3];
OSRdyTbl[prio>>3] | = OSMapTbl[prio&0x07];

使用如下代码可使一个优先级别为prio的任务脱离就绪状态:

if((OSRdyTbl[prio>>3]&=~OSMapTbl[prio&0x07])==0)
OSRdyGrp &= ~ OSMapTbl[prio>>3];

5、任务就续表的操作
1)从 prio 到就绪表( OSRdyGrp、OSRdyTbl[ ] )的操作(进入/脱离 ---- 就绪状态)。
(2)从就绪表( OSRdyGrp、OSRdyTbl[ ] )的当前状态(位图)到最高优先级别 prio 的(任务)映射操作。

依照任务就绪表的状态计算 prio 的操作,在 uC/OS-II 中预定义了一个 OSUnMapTbl[ ] 数组:

INT8U  const  OSUnMapTbl[ ] =  {
    
    
	0,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
	4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
	5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
	… …
	};

备注:该数组共计256个元素

在这里插入图片描述
说明:在 “按图索骥” 算法中,对于所有的任务其 “索骥” 时间都是一致的。
S1、以系统变量 OSRdyGrp 为下标,查 OSUnMapTbl[] 表,可得 y 。
S2、以 OSRdyTbl[] 的第 y 元素为下标,查 OSUnMapTbl[] 表,可得 x 。

用下代码可从任务就绪表中获取优先级别最高的就绪任务(prio):

y = OSUnMapTal[OSRdyGrp];       // D5、D4、D3位
x = OSUnMapTal[OSRdyTbl[y]];   // D2、D1、D0位
prio = (y<<3)+x;		           // 优先级别 
或
y = OSUnMapTbl[OSRdyGrp];
prio = (INT8U)((y << 3) + OSUnMapTbl[OSRdyTbl[y]]);

总结:
uC/OS-II 系统就是通过查找任务就绪表来获取待运行任务的优先级,即最高优先级的任务句柄,并进行任务调度。

6、任务的调度
1)任务切换 ---- CPU 从运行某一任务转换到运行另一任务的过程。
(2)任务调度---- 按照某规则进行任务切换的工作过程。
(3)uC/OS-II 中的任务切换有 “任务调度器” 来完成。
(4)任务调度器的两项主要工作:①从任务就绪表中查找优先级最高的就绪任务,②实现任务切换。
(5)uC/OS-II 中有两个 “任务调度器” :任务级的调度器( OS_Sched( ) ),中断级的调度器( OSIntCtxSw( ) )

调度器进行任务切换的两个工作步骤:

1)获得待运行任务 TCB 的指针
获得了最高优先权就绪任务的 “优先级” 后(存放在全局系统变量 OSPrioHighRdy ) ,用下指令即可获取该任务的 TCB,很简单:
OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy ]2)断点数据切换
其主要工作:完成当前任务到待运行任务的切换。
几个概念:
断点 --- 当前任务被终止运行的位置。
断点数据 --- 断点处 CPU 的 PC、SP、PSW 以及通用寄存器(R0~R12)的当前数据。

在这里插入图片描述
任务切换宏 OS_TASK_SW( ) 依次完成的7项工作:

被中止Task的断点指针(PC)入栈保护
被中止Task通用寄存器入栈保护
被中止Task系统管理 SP →该TCB->OSTCBStkPtr
获得待运行任务TCB
获得待运行任务 TCB->OSTCBStkPtr
恢复待运行任务CPU现场(不包含PC)
切换CPU.PC ,使CPU接续运行待运行Task断点。

五、任务的创建

任务的创建 — 创建该任务的TCB;在TCB中将该任务的Code、Stack关联起来和TCB共同构成Task。
uC/OS-II提供两个系统函数创建Task :

OSTaskCreate( )
OSTaskCreateExt( )

创建任务的一般方法:

Task 可在主函数 main( ) 中操作系统调度启动(OSStart( ))前创建。
也可在Task中创建其他的Task,应用中习惯使用此结构。
uC/OS-II要求:在OSStart( )前,必须至少创建一个用户Task。

创建任务的示意代码:

void main( )
{
    
     
	… …				//主要是系统硬件初始化
	OSInit( );			// uC/OS-II 初始化
	… …				//创建消息机制
	OSTaskCreate(Task_A,……);   	// 创建任务A
	OSStart( );			// 启动多任务调动
}
void Task_A(void * pdata)	//任务A
{
    
    
	……			// 安装并启动 uC/OS-II 系统时钟
	OSStatInit( );		// 初始化统计任务(如果需要的话)
	……			// 在此处可以创建其他任务
	For ( ; ; )		// Task_A 任务体
	{
    
    
		……
	}
}
两个延时函数的原型:
void  OSTimeDly( INT16U ticks )              /* ticks 是节拍数 */
INT8U  OSTimeDlyHMSM (INT8U hours, INT8U minutes, 
             INT8U seconds, INT16U milli)   /* 绝对时间延时,位于OS_TIME.C */
备注:
1、参数值域 hours<255, minutes<59, seconds<59, milli<999
2、这两个系统函数定义在OS_TIME.C文件中。
3、关于节拍周期定义在OS_CFG.H文件中。

本章完,下面章节会继续更新!

猜你喜欢

转载自blog.csdn.net/Mr_zhang1911116/article/details/123524521