ucos 之任务切换 源码分析 4

常见任务格式

//每个任务都有一个挂起,可以进行任务切换
void Task_LED(void *arg)
{
    (void)arg;                		// 'arg' 并没有用到,防止编译器提示警告
    while (1)
    {
        //用户实现功能代码
        OSTimeDlyHMSM(0, 0,0,1000);  //任务挂起 实现任务切换
    }
}


OSTimeDlyHMSM 时间延时 计数计算函数

//  延时时间计算  调用延时函数
INT8U  OSTimeDlyHMSM (INT8U   hours,     //小时
                      INT8U   minutes,   //分钟
                      INT8U   seconds,   //秒
                      INT16U  ms)        //毫秒
{
    INT32U ticks;


    if (OSIntNesting > 0u) {          /* 是否在中断See if trying to call from an ISR     */
            return (OS_ERR_TIME_DLY_ISR);
    }
    if (OSLockNesting > 0u) {       /* 查看是否调度被锁See if called with scheduler locked    */
        return (OS_ERR_SCHED_LOCKED);
    }
    #if OS_ARG_CHK_EN > 0u  
    if (hours == 0u) {           //延时时间是否0
        if (minutes == 0u) {
            if (seconds == 0u) {
                if (ms == 0u) {
                    return (OS_ERR_TIME_ZERO_DLY);
                }
            }
        }
    }
    if (minutes > 59u) {       
        return (OS_ERR_TIME_INVALID_MINUTES);    /* 判断时间范围是否正确      */
    }
    if (seconds > 59u) {
        return (OS_ERR_TIME_INVALID_SECONDS);
    }
    if (ms > 999u) {
        return (OS_ERR_TIME_INVALID_MS);
    }
    #endif
    //计算 延时的ms数       
    ticks = ((INT32U)hours * 3600uL + (INT32U)minutes * 60uL + (INT32U)seconds) * OS_TICKS_PER_SEC
          + OS_TICKS_PER_SEC * ((INT32U)ms + 500uL / OS_TICKS_PER_SEC) / 1000uL;
	//上面多了0.5ms为任务调度需要的时间
    OSTimeDly(ticks);  //延时函数
    return (OS_ERR_NONE);
}

OSTimeDly()时间延时函数

// 延时函数 将本任务从就绪列表中清除,让后调用OS_Sched()从就绪表中找到最高级任务运行
void  OSTimeDly (INT32U ticks)
{
    INT8U      y;
#if OS_CRITICAL_METHOD == 3u    /*    中断模式3        */
    OS_CPU_SR  cpu_sr = 0u;
#endif



    if (OSIntNesting > 0u) {       /* See if trying to call from an ISR 是否嵌套中断    */
        return;
    }
    if (OSLockNesting > 0u) {        /* See if called with scheduler locked 是否调度锁     */
        return;
    }
    if (ticks > 0u) {                            /* 0 means no delay!              */
        OS_ENTER_CRITICAL();
	//把OSRdyTbl清零
        y            =  OSTCBCur->OSTCBY;  
        OSRdyTbl[y] &= (OS_PRIO)~OSTCBCur->OSTCBBitX;
	//把OSRdyGrp清零:即去掉当前任务放到准备任务中
        if (OSRdyTbl[y] == 0u) {
            OSRdyGrp &= (OS_PRIO)~OSTCBCur->OSTCBBitY;
        }
	
        OSTCBCur->OSTCBDly = ticks;     /* Load ticks in TCB          */
        OS_EXIT_CRITICAL();
        OS_Sched();                 /* 系统调度   */
    }


OS_Sched()任务调度函数

void  OS_Sched (void)
{
    #if OS_CRITICAL_METHOD == 3u        
        OS_CPU_SR  cpu_sr = 0u;
    #endif


    OS_ENTER_CRITICAL();
    if (OSIntNesting == 0u) {        //是否中断嵌套  调度锁 
        if (OSLockNesting == 0u) {    
            OS_SchedNew();  //找到最高级优先级 详解见  http://my.oschina.net/u/274829/blog/263287
            OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];
            if (OSPrioHighRdy != OSPrioCur) {     /* 最高级任务 不是当前任务   */
    #if OS_TASK_PROFILE_EN > 0u
                OSTCBHighRdy->OSTCBCtxSwCtr++;    /* 当前任务调度次数  */
    #endif
                OSCtxSwCtr++;                /*任务切换次数 Increment context switch counter      */
                OS_TASK_SW();                /* 任务切换                    */
            }
        }
    }
    OS_EXIT_CRITICAL();

OSCtxSw 任务切换 汇编代码

//这里主要是为了产生 PendSV中断  任务切换在 PendSV_Handler 中进行切换
OSCtxSw
	PUSH    {R4, R5}                ;将R4,R5入栈
        LDR     R4, =NVIC_INT_CTRL  	;触发PendSV异常 (causes context switch)
        LDR     R5, =NVIC_PENDSVSET
        STR     R5, [R4]  ;产生软中断
	POP     {R4, R5}
        BX      LR  ;跳到原地址

 任务切换详细过程PendSV_Handler http://my.oschina.net/u/274829/blog/266098  

时间切换 

void  OSTimeTick (void)
{
    OS_TCB    *ptcb;
#if OS_TICK_STEP_EN > 0u
    BOOLEAN    step;
#endif
#if OS_CRITICAL_METHOD == 3u        /* Allocate storage for CPU status register     */
    OS_CPU_SR  cpu_sr = 0u;
#endif


#if OS_TIME_TICK_HOOK_EN > 0u
    OSTimeTickHook();                      /* Call user definable hook                     */
#endif
#if OS_TIME_GET_SET_EN > 0u
    OS_ENTER_CRITICAL();                  
    OSTime++;               //系统时间增加
    OS_EXIT_CRITICAL();
#endif
    if (OSRunning == OS_TRUE) {
#if OS_TICK_STEP_EN > 0u
        switch (OSTickStepState) {      /* Determine whether we need to process a tick  */
            case OS_TICK_STEP_DIS:         /* Yes, stepping is disabled       */
                 step = OS_TRUE;
                 break;

            case OS_TICK_STEP_WAIT:         /* No,  waiting for uC/OS-View to set ...       */
                 step = OS_FALSE;           /*      .. OSTickStepState to OS_TICK_STEP_ONCE */
                 break;

            case OS_TICK_STEP_ONCE:       /* Yes, process tick once and wait for next ... */
                 step            = OS_TRUE;    /*      ... step command from uC/OS-View  */
                 OSTickStepState = OS_TICK_STEP_WAIT;
                 break;

            default:                       /* Invalid case, correct situation              */
                 step            = OS_TRUE;
                 OSTickStepState = OS_TICK_STEP_DIS;
                 break;
        }
        if (step == OS_FALSE) {           /* Return if waiting for step command           */
            return;
        }
#endif
        ptcb = OSTCBList;                   /* Point at first TCB in TCB list               */
        while (ptcb->OSTCBPrio != OS_TASK_IDLE_PRIO) {  /* Go through all TCBs in TCB list  */
            OS_ENTER_CRITICAL();
            if (ptcb->OSTCBDly != 0u) {       /* No, Delayed or waiting for event with TO  */
                ptcb->OSTCBDly--;             /* Decrement nbr of ticks to end of delay  */
                if (ptcb->OSTCBDly == 0u) {       /* Check for timeout       */

                    if ((ptcb->OSTCBStat & OS_STAT_PEND_ANY) != OS_STAT_RDY) {
                        ptcb->OSTCBStat  &= (INT8U)~(INT8U)OS_STAT_PEND_ANY;  //清除事件标志    
                        ptcb->OSTCBStatPend = OS_STAT_PEND_TO;    /*时间超时 标志  */
                    } else {
                        ptcb->OSTCBStatPend = OS_STAT_PEND_OK;
                    }

                    if ((ptcb->OSTCBStat & OS_STAT_SUSPEND) == OS_STAT_RDY) {  /*准备好了  */
                        OSRdyGrp               |= ptcb->OSTCBBitY;      //加到就绪队列
                        OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
                    }
                }
            }
            ptcb = ptcb->OSTCBNext;                        /* Point at next TCB in TCB list                */
            OS_EXIT_CRITICAL();
        }
    }
}

时钟源  硬件时间中断提供

void  OSTickHandler (void)
{
#if OS_CRITICAL_METHOD == 3
    OS_CPU_SR cpu_sr;
#endif 

    OS_ENTER_CRITICAL();                         
    OSIntNesting++;
    OS_EXIT_CRITICAL();

    OSTimeTick();         /*  uC/OS-II's OSTimeTick()*/

    OSIntExit();                                 
}


转载于:https://my.oschina.net/u/274829/blog/266206

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值