Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1183523
  • 博文数量: 221
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 2139
  • 用 户 组: 普通用户
  • 注册时间: 2012-11-27 19:53
个人简介

JustForFun

文章分类

全部博文(221)

文章存档

2024年(6)

2023年(8)

2022年(2)

2021年(2)

2020年(29)

2019年(11)

2018年(23)

2017年(41)

2016年(76)

2015年(23)

我的朋友
最近访客

分类: 嵌入式

2015-07-21 22:03:09

  1. 原文地址: http://blog.csdn.net/sunrier/article/details/6555333
    //任务调度  
  2. //uCOS-II总是运行进入就绪态任务中优先级最高的那一个。确定哪个任务优先级最高,下面该哪个任务运行了的工作是  
  3. //由调度器(Scheduler)完成的。任务级的调度是由函数OSSched()完成的。中断级的调度是由另一个函数OSIntExt()完  
  4. //成的Scheduling。  
  5. //注意:1) 这是一个uCOS-II内部函数,你不能在应用程序中使用它  
  6. //     2) 给调度器上锁用于禁止任务调度(查看OSSchedLock()函数)  
  7. //说明:1)任务切换很简单,由以下两步完成,将被挂起任务的微处理器寄存器推入堆栈,然后将较高优先  
  8. //       级的任务的寄存器值从栈中恢复到寄存器中。在uCOS-II中,就绪任务的堆栈结构总是看起来  
  9. //       跟刚刚发生过中断一样,所有微处理器的寄存器都保存在栈中。换句话说,uCOS-II运行就绪态  
  10. //       的任务所要做的一切,只是恢复所有的CPU寄存器并运行中断返回指令。为了做任务切换,运行  
  11. //       OS_TASK_SW(),人为模仿了一次中断。多数微处理器有软中断指令或者陷阱指令TRAP来实现上  
  12. //       述操作。中断服务子程序或陷阱处理(Trap hardler),也称作事故处理(exception handler),  
  13. //       必须提供中断向量给汇编语言函数OSCtxSw()。OSCtxSw()除了需要OS_TCBHighRdy指向即将被  
  14. //       挂起的任务,还需要让当前任务控制块OSTCBCur指向即将被挂起的任务,移植uCOS-II,有关于  
  15. //       OSCtxSw()的更详尽的解释。  
  16. //     2)OS_Sched()的所有代码都属临界段代码。在寻找进入就绪态的优先级最高的任务过程中,为防止中  
  17. //       断服务子程序把一个或几个任务的就绪位置位,中断是被关掉的。为缩短切换时间,OSSched()全部  
  18. //       代码都可以用汇编语言写。为增加可读性,可移植性和将汇编语言代码最少化,OSSched()是用C写的。  
  19.   
  20. //任务调度函数  
  21. /*$PAGE*/
    /*
    *********************************************************************************************************
    *                                              SCHEDULER
    *
    * Description: This function is called by other uC/OS-II services to determine whether a new, high
    *              priority task has been made ready to run.  This function is invoked by TASK level code
    *              and is not used to reschedule tasks from ISRs (see OSIntExit() for ISR rescheduling).
    *
    * Arguments  : none
    *
    * Returns    : none
    *
    * Notes      : 1) This function is INTERNAL to uC/OS-II and your application should not call it.
    *              2) Rescheduling is prevented when the scheduler is locked (see OS_SchedLock())
    *********************************************************************************************************
    */
  22. void  OS_Sched (void)  
  23. {  
  24. #if OS_CRITICAL_METHOD == 3                            //中断函数被设定为模式3  
  25.     OS_CPU_SR  cpu_sr;  
  26. #endif      
  27.     INT8U      y;                                      //定义一个8位整数y  
  28.   
  29.   
  30.     OS_ENTER_CRITICAL();                               //关闭中断  
  31.     //如果中断嵌套次数>0,且上锁(调度器)嵌套次数>0,函数退出,不做任何调度  
  32.     if ((OSIntNesting == 0) && (OSLockNesting == 0)) {   
  33.         //如果函数不是在中断服务子程序中调用的,且调度允许的,则任务调度函数将找出进入就绪态的  
  34.         //最高优先级任务,进入就绪态的任务在就绪表中OSRdyTbl[]中相应位置位。  
  35.         y             = OSUnMapTbl[OSRdyGrp];          /* Get pointer to HPT ready to run              */  
  36.         OSPrioHighRdy = (INT8U)((y << 3) + OSUnMapTbl[OSRdyTbl[y]]);  
  37.         //找到最高优先级任务后,函数检查这个优先级最高的任务是否是当前正在运行的任务,以避免不  
  38.         //必要的任务调度,多花时间  
  39.         if (OSPrioHighRdy != OSPrioCur) {              /* No Ctx Sw if current task is highest rdy     */  
  40.             //为实现任务切换,OSTCBHighRdy必须指向优先级最高的那个任务控制块OS_TCB,这是通过将  
  41.             //以OSPrioHighRdy为下标的OSTCBPrioTbl[]数组中的那个元素赋给OSTCBHighRdy来实现的  
  42.             OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];  
  43.             OSCtxSwCtr++;                              //统计计数器OSCtxSwCtr加1,以跟踪任务切换次数  
  44.             OS_TASK_SW();                              //最后宏调用OS_TASK_SW()来完成实际上的任务切换  
  45.         }  
  46.     }  
  47.     OS_EXIT_CRITICAL();                                //打开中断  
  48. }  
//任务调度//uCOS-II总是运行进入就绪态任务中优先级最高的那一个。确定哪个任务优先级最高,下面该哪个任务运行了的工作是//由调度器(Scheduler)完成的。任务级的调度是由函数OSSched()完成的。中断级的调度是由另一个函数OSIntExt()完//成的Scheduling。//注意:1) 这是一个uCOS-II内部函数,你不能在应用程序中使用它// 2) 给调度器上锁用于禁止任务调度(查看OSSchedLock()函数)//说明:1)任务切换很简单,由以下两步完成,将被挂起任务的微处理器寄存器推入堆栈,然后将较高优先// 级的任务的寄存器值从栈中恢复到寄存器中。在uCOS-II中,就绪任务的堆栈结构总是看起来// 跟刚刚发生过中断一样,所有微处理器的寄存器都保存在栈中。换句话说,uCOS-II运行就绪态// 的任务所要做的一切,只是恢复所有的CPU寄存器并运行中断返回指令。为了做任务切换,运行// OS_TASK_SW(),人为模仿了一次中断。多数微处理器有软中断指令或者陷阱指令TRAP来实现上// 述操作。中断服务子程序或陷阱处理(Trap hardler),也称作事故处理(exception handler),// 必须提供中断向量给汇编语言函数OSCtxSw()。OSCtxSw()除了需要OS_TCBHighRdy指向即将被// 挂起的任务,还需要让当前任务控制块OSTCBCur指向即将被挂起的任务,移植uCOS-II,有关于// OSCtxSw()的更详尽的解释。// 2)OS_Sched()的所有代码都属临界段代码。在寻找进入就绪态的优先级最高的任务过程中,为防止中// 断服务子程序把一个或几个任务的就绪位置位,中断是被关掉的。为缩短切换时间,OSSched()全部// 代码都可以用汇编语言写。为增加可读性,可移植性和将汇编语言代码最少化,OSSched()是用C写的。//任务调度函数void OS_Sched (void){#if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3 OS_CPU_SR cpu_sr;#endif INT8U y; //定义一个8位整数y OS_ENTER_CRITICAL(); //关闭中断//如果中断嵌套次数>0,且上锁(调度器)嵌套次数>0,函数退出,不做任何调度 if ((OSIntNesting == 0) && (OSLockNesting == 0)) { //如果函数不是在中断服务子程序中调用的,且调度允许的,则任务调度函数将找出进入就绪态的//最高优先级任务,进入就绪态的任务在就绪表中OSRdyTbl[]中相应位置位。 y = OSUnMapTbl[OSRdyGrp]; /* Get pointer to HPT ready to run */ OSPrioHighRdy = (INT8U)((y << 3) + OSUnMapTbl[OSRdyTbl[y]]);//找到最高优先级任务后,函数检查这个优先级最高的任务是否是当前正在运行的任务,以避免不//必要的任务调度,多花时间 if (OSPrioHighRdy != OSPrioCur) { /* No Ctx Sw if current task is highest rdy *///为实现任务切换,OSTCBHighRdy必须指向优先级最高的那个任务控制块OS_TCB,这是通过将//以OSPrioHighRdy为下标的OSTCBPrioTbl[]数组中的那个元素赋给OSTCBHighRdy来实现的 OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy]; OSCtxSwCtr++; //统计计数器OSCtxSwCtr加1,以跟踪任务切换次数 OS_TASK_SW(); //最后宏调用OS_TASK_SW()来完成实际上的任务切换 } } OS_EXIT_CRITICAL(); //打开中断}

//os_cpu.h

#define  OS_TASK_SW()         OSCtxSw()
os_cpu_a.asm
;*********************************************************************************************************
;                               PERFORM A CONTEXT SWITCH (From task level)
;                                           void OSCtxSw(void)
;
; Note(s) : 1) OSCtxSw() is called when OS wants to perform a task context switch.  This function
;              triggers the PendSV exception which is where the real work is done.
;*********************************************************************************************************
OSCtxSw
    LDR     R0, =NVIC_INT_CTRL                                  ; Trigger the PendSV exception (causes context switch)
    LDR     R1, =NVIC_PENDSVSET
    STR     R1, [R0]
    BX      LR 
关于PendSV见<ucos 内核任务启动及任务切换>调用PendSV函数
 

/*
*********************************************************************************************************
*                              FIND HIGHEST PRIORITY TASK READY TO RUN
*
* Description: This function is called by other uC/OS-II services to determine the highest priority task
*              that is ready to run.  The global variable 'OSPrioHighRdy' is changed accordingly.
*
* Arguments  : none
*
* Returns    : none
*
* Notes      : 1) This function is INTERNAL to uC/OS-II and your application should not call it.
*              2) Interrupts are assumed to be disabled when this function is called.
*********************************************************************************************************
*/
static  void  OS_SchedNew (void)
{
//本函数没有检查最高任务是否是当前运行的任务。也没有在中断中的判断
#if OS_LOWEST_PRIO <= 63                         /* See if we support up to 64 tasks                   */
    INT8U   y;

    y             = OSUnMapTbl[OSRdyGrp];
    OSPrioHighRdy = (INT8U)((y << 3) + OSUnMapTbl[OSRdyTbl[y]]);
#else                                            /* We support up to 256 tasks                         */
    INT8U   y;
    INT16U *ptbl;

    if ((OSRdyGrp & 0xFF) != 0) {       //0XFF?????? />                            //有任务优先级低于64的函数就绪时那高于64的就不要计算了,算了最高优先级也不是它
        y = OSUnMapTbl[OSRdyGrp & 0xFF];
    } else {
        y = OSUnMapTbl[(OSRdyGrp >> 8) & 0xFF] + 8;
                           //上面是看看OSRdyGrp的低八位,这里看OSRdyGrp 高八位。>>8就可以当场和只有八位时一样的情况来处理了。
    }
    ptbl = &OSRdyTbl[y];
    if ((*ptbl & 0xFF) != 0) {
        OSPrioHighRdy = (INT8U)((y << 4) + OSUnMapTbl[(*ptbl & 0xFF)]);
    } else {
        OSPrioHighRdy = (INT8U)((y << 4) + OSUnMapTbl[(*ptbl >> 8) & 0xFF] + 8);
    }
#endif
阅读(1936) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~