有了任务控制块,接下来就是任务初始化了,其中分为创建块和创建任务。
有了任务控制块的模子就可以复制几个了,然后再把它们穿起来,统一管理。操作系统初始化函数就是做这件事的。
OSInit函数就是做这个的。此函数先初始化一些操作系统的一些全局变量,比如任务嵌套次数,空闲任务计数,操作系统运行
开关等。然后就开始将我们创建的各种块,比如任务控制块,事件管理块,内存块,消息块等初始化,然后穿成链表。需要
用到哪个功能时我们就使用创建这个功能的函数,此函数可以将这个链表上的节点摘下来并进行相应的初始化。uc不是动态
创建任务的,所以我们要先手动分配空间。
DCOS_TCB DCOS_Task_Block[TASK_NUM]; //任务控制块个数
int DCOS_Task_cnt; //任务数计数 在任务创建函数中用于计数任务数
DCOS_TCB *DCOS_TCBFreeList; //空闲链表头指针
DCOS_TCB *DCOS_TCBTaskList; //任务链表头指针
以下是我们的初始化函数。
/*********************************************************
函数名:任务初始化函数
参数: 最大任务数 (包括空闲任务在内的所有任务数)
功能: 初始化全局变量,
**********************************************************/
void DCOS_MuTask_Init(int Task_num)
{
int i = Task_num;
DCOS_Task_cnt = 0;//当前任务链表中节点数为0
DCOS_Running = DCOS_RUNING_F;
DCOS_OSTCBCur = (DCOS_TCB *)0; //当前任务控制块指针
DCOS_TCBTaskList = (DCOS_TCB *)0; //任务链表指针,指向空任务链表的第一个元素
DCOS_TCBFreeList = DCOS_Task_Block;//空链表头指针,指向空任务链表的第一个元素
for(i=0; i<Task_num-1; i++)
{
DCOS_Task_Block[i].next = &DCOS_Task_Block[i+1];//创建空任务链表
DCOS_Task_Block[i].init_flag = 0;
//任务初始化标志位清0
DCOS_Task_Block[i].prio = 255;
//任务优先级初始化
DCOS_TCBPrioTbl[i] = (void *)0;
//初始化任务优先级数组,这个在查找最高优先级任务置位就绪表时使用
}
DCOS_Task_Create(Idel, TASK_NUM-1, (void *)0, (DCOS_STK *)&Idel_Task[127], 128); //建立空闲任务
}
/****************************创建任务**************************************
参数说明
void (* Task_fun)() 任务函数
char *name 字符串参数
INT16U prio 优先级
void *p_arg 参数
DCOS_STK *ptos 栈顶指针
INT16U opt 堆栈大小
***************************************************************************/
int DCOS_Task_Create(void (* Task_fun)(), INT16U prio, void *p_arg, DCOS_STK *ptos,INT16U opt)
{
DCOS_CPU_SR cpu_sr;
DCOS_TCB *TCB_tmp;
//用于暂存任务控制块指针
DCOS_STK *STK_tmp;
//用于记录堆栈地址
//DCOS_ENTER_CRITICAL();
STK_tmp = DCOSTaskStkInit (Task_fun, p_arg, ptos, opt);
//初始化任务堆栈
//DCOS_EXIT_CRITICAL();
DCOS_ENTER_CRITICAL();
TCB_tmp = DCOS_TCBFreeList;
//从空闲任务链表中取出一个任务控制块
if(TCB_tmp != (DCOS_TCB *)0)
{
DCOS_TCBFreeList = TCB_tmp->next;
}
else
{
DCOS_Sys_Error();
}
DCOS_Task_cnt++;
//当前任务链表中节点数增加1
//DCOS_TCBTaskList = TCB_tmp; //重置任务链表表头
//*****************************记录一些任务信息**********************************
TCB_tmp->init_flag = 1;
//DCOS_OSTCBCur->code_name = name;
//DCOS_OSTCBCur->run_state = DCOS_STAT_RDY;
TCB_tmp->prio = prio;
TCB_tmp->fun = Task_fun;
TCB_tmp->DCOS_StkPtr = STK_tmp; //堆栈指针
TCB_tmp->DCOS_StkSize = opt;
//********************************************************************************
TCB_tmp->tick = 0;
//延时滴答记录,用于任务判定延时时的挂起和恢复
DCOS_TCBPrioTbl[prio] = TCB_tmp; //将当前任务控制块指针按照优先级顺序填入 任务优先级指针数组
//**********把任务控制块安装到任务链表中*********************************************
TCB_tmp->next = DCOS_TCBTaskList;
//将取下的任务控制块连接入就绪任务控制块表
TCB_tmp->prior = (DCOS_TCB *)0;
if(DCOS_TCBTaskList != (DCOS_TCB *)0)
{
DCOS_TCBTaskList->prior = TCB_tmp;
}
DCOS_TCBTaskList = TCB_tmp;
//************************************************************************************
//*************************在任务就绪组和就绪表中将当前任务就绪*************************
DCOS_RdyGrp |= DCOS_MapTbl[prio>>3];
//初始化任务就绪组
DCOS_RdyTbl[prio>>3] |= DCOS_MapTbl[prio&0x07];
//初始化任务就绪表
//**************************************************************************************
//******记录任务就绪表中位置,便于进行任务的就绪与挂起*******************************
TCB_tmp->DCOS_BY = prio>>3;
//用于取消任务就绪
TCB_tmp->DCOS_BX = prio&0x07;
TCB_tmp->DCOS_BBitY = DCOS_MapTbl[TCB_tmp->DCOS_BY]; //
TCB_tmp->DCOS_BBitX = DCOS_MapTbl[TCB_tmp->DCOS_BX];
/***********************************************
例如在延时函数中我们要清空当前任务的就绪状态,就需要使用这些变量快速查找到就绪组
和就绪表的相应位置,将其复位。在TimeTick中,当查找到任务有就绪时,就将其置位,同样
也需要用到这些变量
************************************************/
//*************************************************************************
DCOS_EXIT_CRITICAL();
/*************************************************************
通过上面的分析,我们可以知道在任务调度过程中,控制块直接相关的是任务堆栈,其余的
控制块变量用在需要查找相关任务属性的时候就可以调用控制块中的变量。
**************************************************************/
if(DCOS_Running == DCOS_RUNING_T)
{
DCOS_Sched(); //如果在任务中动态创建任务,创建后就可以直接调度,如果操作系统没开,函数直接返回,不会调度
}
return 1;
}