uCosii从任务的建立到运行

μC/OS-Ⅱ从任务的建立到运行


前言

最近在学习ucosii实时操作系统,记录下学习过程,以待日后查阅.
tips:本文所用ucosii版本为V2.86,硬件平台为STM32.


一、任务建立到运行整体流程

μC/OS-Ⅱ任务从建立到运行的整体流程如下所述:

1. μC/OS-Ⅱ初始化: OSInit();
2. 创建任务: Create_Task();
3. 开始运行OS: OSStart();
4. 开启时钟节拍:systick_init();

整体例程

int main(void)
{			
	OSInit();						// μC/OS-Ⅱ初始化
	OSTaskCreate(Task1,\
				 0,\
				 &Task1_Stk[Task1_STK_SIZE-1],\
				 Task1_PRIO);		//创建任务
	OSStart();						// 开始运行OS
	systick_init();					//开启时钟节拍
	return 0;
}

二、分步功能实现

1.μC/OS-Ⅱ初始化

在调用μC/OS-Ⅱ的任何其它服务之前,μC/OS-Ⅱ要求用户首先调用系统初始化函数OSIint()。OSIint()初始化μC/OS-Ⅱ
所有的变量和数据结构(见 OS_CORE.C)。
OSInit()会自动建立空闲任务 idle task,这个任务总是处于就绪态的。

OS_InitTaskIdle();       /* Create the Idle Task  */           

空闲任务OSTaskIdle()的优先级总是设成最低,即 OS_LOWEST_PRIO。也就是说当前系统中无其他任务运行时,idle task 空闲任务就会运行。
如果统计任务允许 OS_TASK_STAT_EN 和任务建立扩展允许都设为 1,则 OSInit()还会建立统计任务OSTaskStat()并且让其进入就绪态。OSTaskStat 的优先级总是设为 OS_LOWEST_PRIO-1。

#if OS_TASK_STAT_EN > 0
    OS_InitTaskStat();  /* Create the Statistic Task */
#endif

下图为调用 OSInit()之后,一些μC/OS-Ⅱ变量和数据结构之间的关系。
调用 OSInit()之后的数据结构
空闲任务和统计任务的任务控制块(OS_TCBs)是用双向链表链接在一起的。OSTCBList 指向这个链表的起始处。当建立一个任务时,这个任务总是被放在这个链表的起始处。换句话说,OSTCBList 总是指向最后建立的那个任务。链的终点指向空字符 NULL(也就是零)。
因为这两个任务都处在就绪态,在就绪任务表 OSRdyTbl[]中的相应位是设为 1 的。还有,因为这两个任务的相应位是在 OSRdyTbl[]的同一行上,即属同一组,故 OSRdyGrp 中只有 1 位是设为 1 的。(关于OSRdyTbl[]和OSRdyGrp接下来会讲到)。
μC/OS-Ⅱ还初始化了空任务控制块缓冲区,该缓冲区为单向链表,允许μC/OS-Ⅱ从缓冲区中迅速得到或释放一个缓冲区中的元素。

OS_InitTCBList();   /* Initialize the free list of OS_TCBs  */ 

注意,空任务控制块在空缓冲区中的数目取决于最多任务数 OS_MAX_TASKS,这个最多任务数是在 OS_CFG.H 文件中定义的。μC/OS-Ⅱ自动安排总的系统任务数 OS_N_SYS_TASKS(见文件μC/OS-Ⅱ.H)。控制块 OS_TCB 的数目也就自动确定了。
系统初始化成功后就该进行下一步创建任务了。

2.创建任务

任务可以在多任务调度开始前建立,也可以在其它任务的执行过程中被建立。 在开始多任务调度(即调用 OSStart())前,用户必须建立至少一个任务。任务不能由中断服务程序(ISR)来建立。
OSTaskCreate()为任务创建函数,其代码如下。

INT8U  OSTaskCreate (void (*task)(void *p_arg), void *p_arg, OS_STK *ptos, INT8U prio)
{
    OS_STK    *psp;
    INT8U      err;
#if OS_CRITICAL_METHOD == 3                  /* Allocate storage for CPU status register               */
    OS_CPU_SR  cpu_sr = 0;
#endif



#if OS_ARG_CHK_EN > 0
    if (prio > OS_LOWEST_PRIO) {             /* Make sure priority is within allowable range           */
        return (OS_ERR_PRIO_INVALID);
    }
#endif
    OS_ENTER_CRITICAL();
    if (OSIntNesting > 0) {                  /* Make sure we don't create the task from within an ISR  */
        OS_EXIT_CRITICAL();
        return (OS_ERR_TASK_CREATE_ISR);
    }
    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, 0);              /* Initialize the task's stack         */
        err = OS_TCBInit(prio, psp, (OS_STK *)0, 0, 0, (void *)0, 0);
        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);
    }
    OS_EXIT_CRITICAL();
    return (OS_ERR_PRIO_EXIST);
}

从中可以知道,OSTaskCreate()需要四个参数:

  • task 是任务代码的指针;
  • pdata 是当任务开始执行时传递给任务的参数的指针;
  • ptos是分配给任务的堆栈的栈顶指针;
  • prio 是分配给任务的优先级。

以main函数中的
OSTaskCreate(Task1, 0,&Task1_Stk[Task1_STK_SIZE-1],Task1_PRIO);
为例。
Task1函数如下:

static void Task1(void *para)
{
	para = para;
	while(1)
	{
		//在此处添加要做的工作
		OSTimeDlyHMSM(0,0,0,50); //50ms延时,释放cpu控制权
	}
}

Task1任务的优先级定为30:

#define Task1_PRIO  30

在创建Task1时,首先要对该任务的优先级的有效性进行检测:

if (prio > OS_LOWEST_PRIO) {      /* Make sure priority is within allowable range           */
        return (OS_ERR_PRIO_INVALID);
    }

当设置的优先级比定义的最低优先级还小时(数值越大优先级越小)就会返回优先级不可用错误。
确定当前创建任务时不在中断中:

if (OSIntNesting > 0) {                  /* Make sure we don't create the task from within an ISR  */
        OS_EXIT_CRITICAL();
        return (OS_ERR_TASK_CREATE_ISR);
    }

当创建任务是在中断中时就会返回OS_ERR_TASK_CREATE_ISR错误。
接下来才是创建任务的重点

if (OSTCBPrioTbl[prio] == (OS_TCB *)0) { /* 确定任务的优先级不是已存在的优先级  */
        OSTCBPrioTbl[prio] = OS_TCB_RESERVED;/* 设置该优先级为已占用  */
                                            
        OS_EXIT_CRITICAL();
        psp = OSTaskStkInit(task, p_arg, ptos, 0);/* 建立任务的堆栈*/
        err = OS_TCBInit(prio, psp, (OS_STK *)0, 0, 0, (void *)0, 0);
        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);
    }

这部分判断当前任务的优先级是否为已经被其他任务占用的优先级,一个优先级只能有一个任务。然后就是OSTaskStkInit建立任务的堆栈,该函数是与处理器的硬件体系相关的函数。OS_TCBInit负责初始化任务的tcb,这部分与任务的调度有极大的关,重点来说一下这个函数中有关任务调度的部分。截取如下:

#if OS_LOWEST_PRIO <= 63
        ptcb->OSTCBY             = (INT8U)(prio >> 3);          /* Pre-compute X, Y, BitX and BitY     */
        ptcb->OSTCBX             = (INT8U)(prio & 0x07);
        ptcb->OSTCBBitY          = (INT8U)(1 << ptcb->OSTCBY);
        ptcb->OSTCBBitX          = (INT8U)(1 << ptcb->OSTCBX);
#else
     .
     .
     .
#endif
	 .
	 .
	 .
	 OSTCBPrioTbl[prio] = ptcb;
     .
     .
     .
        OSRdyGrp               |= ptcb->OSTCBBitY;         /* Make task ready to run                   */
        OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
        OSTaskCtr++;                                       /* Increment the #tasks counter             */
        

OS_TCB结构体定义在ucos_ii.h文件中


3.多任务开启

4.开启时钟节拍

5.任务调度


总结

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值