RTOS学习之旅(一)(ucosIII 任务初始化创建及TCB)

最近有时间学习操作系统方面的知识,所以做些笔记加深印象。在这方面确实是小白了。学的是野火的资料。这个资料确实不错,但是有些地方还是要自己进行总结归纳进行学习。
我总结这个有点多,慢慢看可以看懂的。

1.前后台系统和多任务系统

1.1 前后台系统

之前接触的比较多的是前后台系统,就是
外部事件的响应在中断里面完成,事件的处理还是回到轮询系统中完成,中断在这里我们称为后台,main 函数里面的无限循环我们称为后台。
RTOS学习之旅(一)(ucosIII 任务初始化创建及TCB)_第1张图片
在顺序执行后台程序的时候,如果有中断来临,那么中断会打断后台程序的正常执行流,转而去执行中断服务程序,在中断服务程序里面标记事件,如果事件要处理的事情很简短,则可在中断服务程序里面处理,如果事件要处理的事情比较多,则返回到后台程序里面处理。

1.2多任务系统

相比前后台系统,多任务系统的事件响应也是在中断中完成的,但是事件的处理是在任务中完成的。
在多任务系统中,任务跟中断一样,也具有优先级,优先级高的任务会被优先执行。当一个紧急的事件在中断被标记之后,如果事件对应的任务的优先级足够高,就会立马得到响应。相比前后台系统,多任务系统的实时性又被提高了。
RTOS学习之旅(一)(ucosIII 任务初始化创建及TCB)_第2张图片
RTOS学习之旅(一)(ucosIII 任务初始化创建及TCB)_第3张图片
相比前后台系统中后台顺序执行的程序主体,在多任务系统中,根据程序的功能,我们把这个程序主体分割成一个个独立的,无限循环且不能返回的小程序,这个小程序我们称之为任务。每个任务都是独立的,互不干扰的,且具备自身的优先级,它由操作系统调度管理。加入操作系统后,我们在编程的时候不需要精心地去设计程序的执行流,不用担心每个功能模块之间是否存在干扰。

2.多任务系统的大致框架

在编程时,ucosIII有很多固定文件,这里就先不全部写了。写一些重要的。
main函数写在app.c文件里

#include "os.h"
#include "ARMCU3.h"

uint32_t flag1;
uint32_t flag2;

//TCB,STACK声明
#define TASK1_STK_SIZE 20
#define TASK2_STK_SIZE 20

static CPU_STK TASK1Stk[TASK1_STK_SIZE];
static SPU_STK TASK2Stk[TASK2_STK_SIZE];

static OS_TCB TASK1TCB;
static OS_TCB TASK2TCB;

void Task1(void *p_arg);
void Task2(void *p_arg);

int main(void)
{
	OS_ERR err;
	//初始化全局变量
	OSInit(&err);

	OSTaskCreate((OS_TCB *)     &Task1TCB,
				 (OS_TASK_PTR)  Task1,
				 (void * )      0,
				 (CPU_STK *)    &Task1Stk[0],
				 (CPU_STK_SIZE) Task1_STK_SIZE,
				 (OS_ERR *)     &err);
	OSTaskCreate((OS_TCB *)     &Task2TCB,
				 (OS_TASK_PTR)  Task2,
				 (void *)       0,
				 (CPU_STK *)    &Task2Stk[0],
				 (CPU_STK_SIZE) Task2_STK_SIZE,
				 (OS_ERR *)     &err);
	//将任务假如到就绪列表
	OSRdyList[0].HeadPtr = &Task1TCB;
	OSRdyList[1].HeadPtr = &Task2TCB;
	//启动OS,不再返回
	OSStart(&err);

	void Task1(void *p_arg)
	{
		while(1)
		{
			flag1 =1;
			delay(100);
			flag1 = 0;
			delay(100);
			//手动切换任务
			OSOched();
		}
	}
	void Task2(void *p_arg)
	{
		while(1)
		{
			flag2 =1;
			delay(100);
			flag2 = 0;
			delay(100);
			//手动切换任务
			OSOched();
		}
	}
}

这就是大致流程,具体后序有说明。在这只要知道这个和前后台区别和大致代码流程

3.任务

**在多任务系统中,我们根据功能的不同,把整个系统分割
成一个个独立的且无法返回的函数,这个函数我们称为任务,也有人称之为线程。**就像上面的Task1这样的函数。

3.1创建任务

在多任务系统中,每个任务都是独立的,互不干扰的,所以要为每个任务都分配独立的栈空间,这个栈空间通常是一个预先定义好的全局数组。就是上面的 TsakStk[TASK1_STK_SIZE]
在多任务系统中,有多少个任务就需要定义多少个任务堆栈。

typedef unsigned short     CPU_INT16U;
typedef unsigned short     CPU_INT32U;
typedef unsigned short     CPU_INT08U;

typedef CPU_INT32U   CPU_ADDR;

typedef CPU_INT32U       CPU_STK;
typedef CPU_ADDR         CPU_STK_SIZE;

3.2定义任务控制块TCB

系统为了顺利的调度任务,为每个任务都额外定义了一个任务控制块TCB(Task Control Block),这个任务控制块就相当于任务的身份证,里面存有任务的所有信息,比如任务的堆栈,任务名称,任务的形参等。有了这个任务控制块之后,以后系统对任务的全部操作都可以通过这个 TCB 来实现。
TCB也是一种数据类型,定义如下:

typedef struct os_tcb OS_TCB;
struct os_tcb{
	CPU_STK         *StkPtr;  //堆栈指针
	CPU_STK_SIZE    StkSize;  //堆栈大小
};

现在OS_TCB成员还少,后面会增加。

3.3实现任务创建函数

任务的堆栈,任务的函数实体,任务的 TCB 最终需要联系起来才能由系统进行统一调度。那么这个联系的工作就由任务创建函数 OSTaskCreate 来实现。这个函数在os_task.c中

typedef void    (*OS_TASK_PTR)(void *p_arg);
void OSTaskCreate(OS_TCB       *p_tcb,
				  OS_TASK_PTR  p_task,  //(1)
				  void         *p_arg,  //(2)
				  CPU_STK      *p_stk_base, //(3)
				  CPU_STK_SIZE stk_size, //(4)
				  OS_ERR       *p_err)	//(5)	
{
	CPU_STK *p_sp;
	p_sp = OSTaskStkInit(p_task,
						 p_arg,
						 p_stk_base,
						 stk_size);
	p_tcb->StkPtr = p_sp;
	p_tcb->StkSize = stk_size;

    *p_err  = OS_ERR_NONE;

}

(1) 这个我的理解是类似于回调函数那样
(2)是任务形参,用来传递任务参数
(3) 用来指向任务堆栈的起始地址
(4) 堆栈的大小
(5) 错误码
OSTaskStkInit实现不写了,太长了。
RTOS学习之旅(一)(ucosIII 任务初始化创建及TCB)_第4张图片RTOS学习之旅(一)(ucosIII 任务初始化创建及TCB)_第5张图片
(1) p_task 是任务名,指示着任务的入口地址,在任务切换的时候,需要加载到 R15,即 PC 寄存器,这样 CPU 就可以找到要运行的任务。
(2)p_arg 是任务的形参,用于传递参数,在任务切换的时候,需要加载到寄存器 R0。R0 寄存器通常用来传递参数。
(6)任务第一次运行的时候,加载到 CPU 寄存器的环境参数我们要 预先初始化好。初始化的顺序固定,首先是异常发生时自动保存的 8 个寄存器,即 xPSR、 R15、R14、R12、R3、R2、R1 和 R0。其中 xPSR 寄存器的位 24 必须是 1,R15 PC 指针必须存的是任务的入口地址,R0 必须是任务形参。
在这里插入图片描述
这个意思是将剩余栈的栈顶指针 p_sp 保存到任务控制块 TCB 的第一个成员 StkPtr 中。

**任务创建好之后,我们需要把任务添加到一个叫就绪列表的数组里面,表示任务已经
就绪,系统随时可以调度。**就是这个
在这里插入图片描述
这里数组是有类型的:

typedef struct os_rdy_list    OS_RDY_LIST;
struct os_rdy_list{
	OS_TCB  *HeadPtr;
	OS_TCB  *TailPtr;
};

HeadPtr用来指向任务TCB,TailPtr是同一个优先级支持多个任务的时候才需要使用头尾指针来将 TCB 串成一个双向链表。

先写到这,手打有点累了。

你可能感兴趣的:(ucosIII,操作系统,rtos,堆栈,嵌入式)