你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【安富莱STM32F407之uCOS-III教程】第11章 μCOS-III内核函数分析

[复制链接]
baiyongbin2009 发布时间:2014-12-24 19:55
阅读主题, 点击返回1楼
收藏 评论23 发布时间:2014-12-24 19:55
23个回答
baiyongbin2009 回答时间:2014-12-24 20:17:52
11.8  安全关键IEC61508
    关于IEC61508,大家有个了解即可,更详细的资料可以查阅wiki百科进行了解或者查找相关的文档说明。
11.8.1      IEC61508基本概念
    IEC 61508是一项用于工业领域的国际标准,其名称是《电气/电子/可编程电子安全相关系统的功能安全》。由国际电工委员会发布,其目的要建立一个可应用于各种工业领域的基本功能安全标准。它将功能安全定义为:“是受控设备(EUC)或受控设备系统总体安全中的一部分;其安全性是依赖于电气/电子/可编程电子(E/E/PE)安全相关系统、其他技术的安全相关系统或外部风险降低措施的正确机能。”
     (一) IEC61508中的基本定义
1.  安全功能 (safety function)
    针对规定的危险事件,为达到或保持受控设备(EUC)的安全状态,由E/E/PE安全系统、其他技术安全系统或外部风险降低设施实现的功能。
2.  安全完整性 (Safety integrity)
    在规定的条件下、规定的时间内,安全系统成功实现所要求的安全功能的概率。这一定义着重于安全系统执行安全功能的可靠性。在确定安全完整性过程中,应包括所有导致非安全状态的因素,如随机的硬件失效,软件导致的失效以及由电气干扰引起的失效,这些失效的类型,尤其是硬件失效可用测量方法来定量,如在危险模式中的失效和系统失效率,或按规定操作的安全防护系统失效的概率。但是,系统的安全完整性还取决于许多因素,这些因素无法精确定量,仅可定性考虑。
3.  E/E/PE系统
    基于电气/电子和可编程电子装置的用于控制、防护或监视的系统,包括系统中所有的元素如电源、传感器、所有其他输入输出装置及所有通信手段。
4.    EUC(EquipmentUnder Control)
    受控设备,指用于制造、运输、医疗或其他领域的设备、机器、装置或装备。
5. 可接受凤险 (ACCeptable risk)
    风险指的是出现伤害的概率及该伤害严重性的组合。可接受风险指根据当今社会的水准所能够接受的风险。
6.    安全 (Safety)
    不存在不可接受的风险。
7.    安全系统 (Safely-elated-syStem)
    是用于两个目的:一是执行要求的安全功能以达到或保持EUC的安全状态;二是自身或与其他E/E/PES安全系统、其他技术安全系统或外部风险降低设施一道,对于要求的安全功能达到必要的安全完整性。安全系统是在接受命令后采取适当的动作以防止EUC进入危险状态。安全系统的失效应被包括在导致确定的危险事件中。尽管可能有其他系统具备安全功能,但仅是指用其自身能力达到要求的允许风险的安全系统。安全系统可大致分为安全控制系统和安全防护系统。
    安全系统可以是EUC控制系统的组成部分,也可用传感器和/或执行器与EUC的接口,既可用在EUC控制系统中执行安全功能的方式达到要求的安全完整性水平,也可用分离的/独立的专门用于安全的系统执行安全功能。
    (二)IEC61508的基本概念
    IEC61508标准规定随机失效的后果必须定量评估,使用随机存取测量系统 (RAMS)方法计算有效性。量化与故障相关的系统失效是没有用的,应当通过组织指导来避免系统失效,或通过技术措施来控制。
    1.风险和安全完整性慨念 
    2.功能安全保证的内容
        功能安全保证主要包括两部分内容:失效识别和安全完整性水平。
(1)失效识别。
    失效就是功能单元失去实现其功能的能力。一些功能是根据所达到的行为进行规定的,在执行功能时,某些特定的行为是不允许的,这些行为的出现就是失效。失效可能是随机失效,这种失效通常由于硬件装置的耗损所致。也可能是系统失效,这在硬件和软件中都可能出现。失效识别就是要分辨出不同部件的各种失效原因,估算出系统失效概率。
(2)安全完整性水平 (SIL) (safetyintegrity level)。
    一种离散的水平,用于规定分配给E/E/PE安全系统的安全功能的安全完整性要求,安全系统的安全完整性水平越高,安全系统实现所要求的安全功能失败的可能性就越低。IEC61508中规定系统有4种安全完整性水平,SIL4是最高的,安全完整性水平1是最低的。
11.8.2      启动安全关键OSSafetyCriticalStart
    源码中加入了部分安全关键的代码,内容如下:
  1. /*
  2. ***********************************************************************************************************
  3. *                                    创建对象已经不安全
  4. *
  5. * 函数说明: 这个函数是供用户调用的,用户一旦调用了这个函数就表示所有的初始化已经完成。内核对象不再运行被创建。
  6. * 形    参: 无
  7. * 返 回 值: 无
  8. * 注    意: 无
  9. ***********************************************************************************************************
  10. */

  11. #ifdef OS_SAFETY_CRITICAL_IEC61508
  12. void  OSSafetyCriticalStart (void)
  13. {
  14.     OSSafetyCriticalStartFlag = DEF_TRUE;
  15. }

  16. #endif
复制代码
1.    这个函数是供用户调用的,用户一旦调用了这个函数就表示所有的初始化已经完成。内核对象不再运行被创建。后面讲任务间通信机制的时候会看到相关代码,比如创建定时器的函数中:
  1. #ifdef OS_SAFETY_CRITICAL_IEC61508
  2.     if (OSSafetyCriticalStartFlag == DEF_TRUE) {
  3.        *p_err = OS_ERR_ILLEGAL_CREATE_RUN_TIME;
  4.         return;
  5.     }
  6. #endif
复制代码
11.8.3      函数使用举例
  1. void AppStartTask(void *p_arg)
  2. {
  3.      (void)& p_arg
  4.      OSSafetyCriticalStart ();           //直接在启动函数中调用即可
  5.      while(DEF_ON)
  6.      {
  7. }
  8. }
复制代码



baiyongbin2009 回答时间:2014-12-24 20:21:18
剩下内容,明日继续,敬请关注,谢谢各位!
巅峰残狼 回答时间:2014-12-24 21:04:24
很好很强大,支持更新
baiyongbin2009 回答时间:2014-12-25 17:03:59
11.9  任务切换
    如果大家认真学习了前面几期教程,μCOS-III中的任务切换还是很好理解的。μCOS-III中的任务切换主要分为两部分,一个是中断级任务切换,另一个是任务级中断切换。
11.9.1      任务级任务切换OSSched()
    任务级的任务切换主要通过下面的函数实现:
  1. /*
  2. ************************************************************************************************************                                                      任务级调度
  3. *
  4. * 函数说明: 此函数由其它的uC/OS-III函数调用,主要是用来获取当前需要执行的最高优先级任务,这个是任务级调度,*           要和前面的中断级调度OSIntExit()区分开。
  5. * 形    参: 无
  6. * 返 回 值: 无
  7. * 注    意: 1) 使用调度锁的话,调度功能将被关闭 (见 OSSchedLock())
  8. ***********************************************************************************************************
  9. */

  10. void  OSSched (void)
  11. {
  12.     CPU_SR_ALLOC();                                                                                   (1)



  13.     if (OSIntNestingCtr > (OS_NESTING_CTR)0) {         /* 是否存在中断嵌套? */                        (2)
  14.         return;                                        /* 是 ... 只有不存在中断嵌套的时候才能调用 */
  15.     }

  16.     if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) {   /* 使用调度锁? */                              (3)
  17.         return;                                        /* 是  */
  18.     }

  19.     CPU_INT_DIS();
  20.     OSPrioHighRdy   = OS_PrioGetHighest();             /* 获取当前需要执行的最高优先级任务 */         (4)
  21.     OSTCBHighRdyPtr = OSRdyList[OSPrioHighRdy].HeadPtr;                                               (5)
  22.     if (OSTCBHighRdyPtr == OSTCBCurPtr) {              /* 获取的最高优先级任务是否是当前任务 */
  23.         CPU_INT_EN();                                  /* 是 ... 不需要执行任务切换 */
  24.         return;
  25.     }

  26. #if OS_CFG_TASK_PROFILE_EN > 0u
  27.     OSTCBHighRdyPtr->CtxSwCtr++;                       /* 增加此任务的切换次数  */
  28. #endif
  29.     OSTaskCtxSwCtr++;                                  /* 增加总的任务切换次数  */

  30. #if defined(OS_CFG_TLS_TBL_SIZE) && (OS_CFG_TLS_TBL_SIZE > 0u)
  31.     OS_TLS_TaskSw();
  32. #endif

  33.     OS_TASK_SW();                                       /* 执行任务切换  */                           (6)
  34.     CPU_INT_EN();
  35. }
复制代码
1.    这句话在前面临界段小节有讲,这里是定义一个局部变量。
2.    存在中断嵌套的情况下调用这个函数会返回。
3.    调度器被锁的情况下调用这个函数会返回。
4.    这个函数是获取当前需要执行的最高优先级任务的方法,也算是调度器的核心,在下期教程会给大家详细的讲解。
5.    由于μCOS-III已经支持时间片调度,这句话是从同优先级的链表中获得当前需要执行的任务。
6.    执行任务级任务切换。

11.9.2      中断级任务切换OSIntExit()
    中断级任务切换是由中断函数调用的,内容如下:
  1. /*
  2. ***********************************************************************************************************
  3. *                                                进入中断服务程序
  4. * 功能说明: 此函数用通知uC/OS-III系统程序将要执行interrupt service routine(ISR)。这样uC/OS-III就可以不断
  5. *           跟踪中断嵌套次数的变化,这样就能够保证系统只有在最后一层中断执行任务调度。
  6. * 形    参: 无
  7. * 返 回 值: 无
  8. * 注    意: 1) 此函数必须在中断关闭情况下调用。
  9. *           2) 用户可以不调用这个函数,直接调用全局变量OSIntNestingCtr进行操作即可。
  10. *           3) 用户必须调用函数OSIntExit(),即使直接的操作'OSIntNestingCtr'。
  11. *           4) 用户必须成对的调用OSIntEnter() 和 OSIntExit()。换句话说,用户必须在中断服务程序开始和结尾的
  12. *              时候成对调用OSIntEnter() 和 OSIntExit()。        
  13. *           5) uC/OS-III系统的中断嵌套层数最高250。
  14. ***********************************************************************************************************
  15. */

  16. void  OSIntEnter (void)                                                                               (1)
  17. {
  18.     if (OSRunning != OS_STATE_OS_RUNNING) {       /* 检测OS是否开始运行 */
  19.         return;                                   /* 否,返回 */
  20.     }

  21.     if (OSIntNestingCtr >= (OS_NESTING_CTR)250u) {   /* 中断嵌套次数是不是超过250 */
  22.         return;                                      /* 是,返回 */
  23.     }

  24.     OSIntNestingCtr++;                               /* 中断嵌套次数执行加一 */                       (2)
  25. }

  26. /*
  27. ***********************************************************************************************************
  28. *                                                 退出中断服务程序
  29. *
  30. * 函数说明: 此函数用于通知uC/OS-III系统已经完成中断服务程序,然后调用调度器决定是否切换还到新的高优先级任务
  31. * 形    参: 无
  32. * 返 回 值: 无
  33. * 注    意: 1) 用户必须成对的调用OSIntEnter() 和 OSIntExit()。
  34. *           2) 使用调度锁的话,调度功能将被关闭 (见 OSSchedLock())
  35. ***********************************************************************************************************
  36. */

  37. void  OSIntExit (void)
  38. {
  39.     CPU_SR_ALLOC();



  40.     if (OSRunning != OS_STATE_OS_RUNNING) {          /* OS是否开始运行  */
  41.         return;                                      /* 否,返回        */
  42.     }

  43.     CPU_INT_DIS();
  44.     if (OSIntNestingCtr == (OS_NESTING_CTR)0) {  /* 防止错误使用,在这个函数OSIntNestingCtr不会为0的情况 */
  45.         CPU_INT_EN();
  46.         return;
  47.     }
  48.     OSIntNestingCtr--;                                                                               (3)
  49.     if (OSIntNestingCtr > (OS_NESTING_CTR)0) {    /* 是否还存在中断嵌套 */
  50.         CPU_INT_EN();                             /* 是,返回  */
  51.         return;
  52.     }

  53.     if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) {   /* 是否有使用调度锁 */
  54.         CPU_INT_EN();                                  /* 是,返回  */
  55.         return;
  56.     }

  57.     OSPrioHighRdy   = OS_PrioGetHighest();              /* 查询需要执行的最高优先级任务 */
  58.     OSTCBHighRdyPtr = OSRdyList[OSPrioHighRdy].HeadPtr; /* 获取最高优先级任务的TCB地址 */
  59.     if (OSTCBHighRdyPtr == OSTCBCurPtr) {               /* 获取的最高优先级任务TCB是不是当前任务 */
  60.         CPU_INT_EN();                                   /* 是,返回 */
  61.         return;
  62.     }

  63. #if OS_CFG_TASK_PROFILE_EN > 0u
  64.     OSTCBHighRdyPtr->CtxSwCtr++;                  /* 任务切换次数加一,这里是指的某个任务的切换次数  */
  65. #endif
  66.     OSTaskCtxSwCtr++;                             /* 系统总的任务切换次数  */

  67. #if defined(OS_CFG_TLS_TBL_SIZE) && (OS_CFG_TLS_TBL_SIZE > 0u)
  68.     OS_TLS_TaskSw();
  69. #endif

  70.     OSIntCtxSw();                                 /* 执行中断级任务切换 */                            (4)
  71.     CPU_INT_EN();
  72. }
复制代码
1.    OSIntEnter()和OSIntExit()必须配套的使用,要不会造成嵌套计数错误。
2.    嵌套计数加一。
3.    嵌套次数减一。
4.    执行中断级任务切换。

11.9.3      函数使用举例
    函数OSSched ()不是供用户调用的,而函数OSIntEnter() 和 OSIntExit()是供用户在中断任务中调用的,下面举个例子:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: SDIO_IRQHandler
  4. *    功能说明: SDIO中断服务程序
  5. *    形    参:无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. void SDIO_IRQHandler(void)
  10. {
  11.      CPU_SR_ALLOC();
  12.    
  13.      CPU_CRITICAL_ENTER();
  14.      OSIntEnter()
  15.      CPU_CRITICAL_EXIT();

  16.      SD_ProcessIRQSrc();

  17.      /* 在os_core.c文件里定义,如果有更高优先级的任务就绪了,则执行一次任务切换 */
  18.      OSIntExit();
  19. }
复制代码

baiyongbin2009 回答时间:2014-12-25 17:06:57
11.10  调度锁
    给调度器加锁后将禁止任务调度,直到任务完成后,调用调度器解锁函数才能重新开始任务调度。这里一定要明白一点,调度锁只是将调度器关闭,并不影响中断的执行,该进中断还是要进的,只是不会执行任务切换。
11.10.1      调度器加锁OSSchedLock()
  1. /*
  2. ***********************************************************************************************************
  3. *                                                 调度器加锁
  4. *
  5. * 函数功能: 此函数的主要作用是给系统调度器加锁,这样系统就无法进行任务调度了。
  6. * 形    参: p_err     错误代码指针变量:
  7. *                     OS_ERR_NONE                 调度器被锁
  8. *                     OS_ERR_LOCK_NESTING_OVF     调度锁嵌套次数 > 250
  9. *                     OS_ERR_OS_NOT_RUNNING       如果uC/OS-III还没有开始运行
  10. *                     OS_ERR_SCHED_LOCK_ISR       如果在中断服务程序中调用此函数
  11. * 返 回 值: 无
  12. * 注    意: 1) OSSchedLock() 和 OSSchedUnlock() 必须成对的使用.
  13. ***********************************************************************************************************
  14. */

  15. void  OSSchedLock (OS_ERR  *p_err)
  16. {
  17.     CPU_SR_ALLOC();



  18. #ifdef OS_SAFETY_CRITICAL
  19.     if (p_err == (OS_ERR *)0) {
  20.         OS_SAFETY_CRITICAL_EXCEPTION();
  21.         return;
  22.     }
  23. #endif

  24. #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
  25.     if (OSIntNestingCtr > (OS_NESTING_CTR)0) {    /* 不允许在中断服务程序中调用此函数*/              (1)
  26.        *p_err = OS_ERR_SCHED_LOCK_ISR;
  27.         return;
  28.     }
  29. #endif

  30.     if (OSRunning != OS_STATE_OS_RUNNING) {       /* 确认系统已经开始运行 */
  31.        *p_err = OS_ERR_OS_NOT_RUNNING;
  32.         return;
  33.     }

  34.     if (OSSchedLockNestingCtr >= (OS_NESTING_CTR)250u) {   /* 防止OSSchedLockNestingCtr溢出 */      (2)
  35.        *p_err = OS_ERR_LOCK_NESTING_OVF;
  36.         return;
  37.     }

  38.     CPU_CRITICAL_ENTER();
  39.     OSSchedLockNestingCtr++;                              /* 增加嵌套次数 */                         (3)
  40. #if OS_CFG_SCHED_LOCK_TIME_MEAS_EN > 0u
  41.     OS_SchedLockTimeMeasStart();                                                                     (4)
  42. #endif
  43.     CPU_CRITICAL_EXIT();
  44.    *p_err = OS_ERR_NONE;
  45. }
复制代码

1.    这里表示不允许在中断服务程序中调用调度锁函数。
2.    调度锁的嵌套次数范围0~250,用户不能超出250。
3.    嵌套次数加一。
4.    开启调度锁时间测量,这里是记录一下起始时间。

11.10.2      调度器解锁OSSchedUnlock
  1. /*
  2. ***********************************************************************************************************
  3. *                                                 调度器解锁
  4. *
  5. * 函数功能: 此函数的主要作用是给系统调度器解锁,重新使能调度
  6. * 形    参: p_err     错误代码指针变量:
  7. *                     OS_ERR_NONE
  8. *                     OS_ERR_OS_NOT_RUNNING       系统还没有开始运行
  9. *                     OS_ERR_SCHED_LOCKED         调度器仍然是加锁状态
  10. *                     OS_ERR_SCHED_NOT_LOCKED     调度没有被加锁
  11. *                     OS_ERR_SCHED_UNLOCK_ISR     如果在中断服务程序中调用此函数
  12. * 返 回 值: 无
  13. * 注    意: 1) OSSchedLock() 和 OSSchedUnlock() 必须成对的使用.
  14. ***********************************************************************************************************
  15. */

  16. void  OSSchedUnlock (OS_ERR  *p_err)
  17. {
  18.     CPU_SR_ALLOC();



  19. #ifdef OS_SAFETY_CRITICAL
  20.     if (p_err == (OS_ERR *)0) {
  21.         OS_SAFETY_CRITICAL_EXCEPTION();
  22.         return;
  23.     }
  24. #endif

  25. #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
  26.     if (OSIntNestingCtr > (OS_NESTING_CTR)0) {      /* 不允许在ISR中调用此函数  */
  27.        *p_err = OS_ERR_SCHED_UNLOCK_ISR;
  28.         return;
  29.     }
  30. #endif

  31.     if (OSRunning != OS_STATE_OS_RUNNING) {         /* 确认多任务已经开始运行  */
  32.        *p_err = OS_ERR_OS_NOT_RUNNING;
  33.         return;
  34.     }

  35.     if (OSSchedLockNestingCtr == (OS_NESTING_CTR)0) {   /* 是否给调度器加锁  */
  36.        *p_err = OS_ERR_SCHED_NOT_LOCKED;
  37.         return;
  38.     }

  39.     CPU_CRITICAL_ENTER();
  40.     OSSchedLockNestingCtr--;                            /* 递减调度锁计数器 */                       (1)
  41.     if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) {
  42.         CPU_CRITICAL_EXIT();                            /* 调度器仍然在加锁状态  */
  43.        *p_err = OS_ERR_SCHED_LOCKED;
  44.         return;
  45.     }

  46. #if OS_CFG_SCHED_LOCK_TIME_MEAS_EN > 0u
  47.     OS_SchedLockTimeMeasStop();
  48. #endif

  49.     CPU_CRITICAL_EXIT();                                 /* 重新使能调度器  */
  50.     OSSched();                                           /* 运行调度器  */                           (2)
  51.    *p_err = OS_ERR_NONE;
  52. }
复制代码

1.    调度锁嵌套计数减一。
2.    调度器被锁期间,有些任务可能会就绪,所以这里加上了调度函数。

11.10.3      调度器被锁时间测量OS_SchedLockTimeMeas
    函数比较简单,这里就直接将内容贴上,特别注意函数的注释。
  1. /*
  2. ***********************************************************************************************************
  3. *                                               调度锁时间测量
  4. *
  5. * 函数说明: 此函数用测量调度锁锁住调度的最大时间。
  6. * 形    参: 无
  7. * 返 回 值: 无
  8. * 注    意: 1) 系统函数,用户程序不能调用
  9. *           2) 这两个函数要在中断禁止的情况下调用。
  10. *           3) 我们可以直接读取CPU_TS_TmrRd(),即使是16位定时器。原因是我们不建议调度器被锁的时间超过65536
  11. *              个计数。 换句话说,如果调度器被锁的时间超过65536,那么对于实时系统来说不是一件好事。
  12. ***********************************************************************************************************
  13. */

  14. #if OS_CFG_SCHED_LOCK_TIME_MEAS_EN > 0u
  15. void  OS_SchedLockTimeMeasStart (void)
  16. {
  17.     if (OSSchedLockNestingCtr == 1u) {
  18.         OSSchedLockTimeBegin = CPU_TS_TmrRd();
  19.     }
  20. }

  21. void  OS_SchedLockTimeMeasStop (void)
  22. {
  23.     CPU_TS_TMR  delta;


  24.     if (OSSchedLockNestingCtr == (OS_NESTING_CTR)0) {    /* 确认没有调度锁嵌套  */
  25.         delta = CPU_TS_TmrRd()                           /* 计算时间差 */
  26.               - OSSchedLockTimeBegin;
  27.         if (OSSchedLockTimeMax    < delta) {             /* 检测最大值*/
  28.             OSSchedLockTimeMax    = delta;
  29.         }
  30.         if (OSSchedLockTimeMaxCur < delta) {             /* 检测最大值(for resettable value) */
  31.             OSSchedLockTimeMaxCur = delta;
  32.         }
  33.     }
  34. }
  35. #endif
复制代码

11.10.4      函数使用举例
    下面这个例子是为了防止截屏的过程中被其它任务打断,加入了调度锁功能。
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: AppTaskGUIUpdate
  4. *    功能说明: 本函数主要用于实现截图和串口打印UCOS任务的执行情况        
  5. *    形    参:p_arg 是在创建该任务时传递的形参
  6. *    返 回 值: 无
  7.      优 先 级:3
  8. *********************************************************************************************************
  9. */
  10. static void AppTaskGUIUpdate(void *p_arg)
  11. {
  12.      OS_ERR        err;
  13.      uint8_t       Pic_Name = 0;
  14.      char buf[20];
  15.      CPU_BOOLEAN SemFlag;

  16.      (void)p_arg;
  17.          
  18.      while(1)
  19.      {   
  20.          SemFlag = BSP_OS_SemWait(&SEM_SYNCH, 0);
  21.          if(SemFlag == DEF_OK)
  22.          {   
  23.               sprintf(buf,"0:/Picture/%d.bmp",Pic_Name);
  24.               OSSchedLock(&err);
  25.               GUI_SaveBMP(0, 0, LCD_GetXSize(), LCD_GetYSize(),buf);
  26.               OSSchedUnlock(&err);      
  27.          }                                                                                                                  
  28.      }  
  29. }
复制代码


baiyongbin2009 回答时间:2014-12-25 17:07:16
巅峰残狼 发表于 2014-12-24 21:04
很好很强大,支持更新

谢谢支持!!
baiyongbin2009 回答时间:2014-12-25 17:12:01
11.11  Round-Robin调度
    μCOS-III中的时间片调度功能做的很完善,支持全局的时间片设置,也支持每个任务的单独设置。关于时间片调度,咱们在前几期教程也有讲解。
11.11.1      配置参数OSSchedRoundRobinCfg()
  1. /*
  2. ***********************************************************************************************************
  3. *                                      配置ROUND-ROBIN调度参数
  4. *
  5. * 函数功能: 调用此函数用更改ROUND-ROBIN调度的参数。
  6. * 形    参: en                DEF_EN:使能ROUND-ROBIN
  7. *                             DEF_DIS:禁止ROUND-ROBIN
  8. *           dflt_time_quanta  默认的时间片数,如果是0 那么就表示时间片是默认的OSCfg_TickRate_Hz / 10.
  9. *           p_err             错误代码指针变量
  10. *                             OS_ERR_NONE       调用成功
  11. * 返 回 值: 无
  12. ***********************************************************************************************************
  13. */

  14. #if OS_CFG_SCHED_ROUND_ROBIN_EN > 0u
  15. void  OSSchedRoundRobinCfg (CPU_BOOLEAN   en,
  16.                             OS_TICK       dflt_time_quanta,
  17.                             OS_ERR       *p_err)
  18. {
  19.     CPU_SR_ALLOC();


  20. #ifdef OS_SAFETY_CRITICAL
  21.     if (p_err == (OS_ERR *)0) {
  22.         OS_SAFETY_CRITICAL_EXCEPTION();
  23.         return;
  24.     }
  25. #endif

  26.     CPU_CRITICAL_ENTER();                                                                        (1)
  27.     if (en != DEF_ENABLED) {                                                                     (2)
  28.         OSSchedRoundRobinEn = DEF_DISABLED;
  29.     } else {
  30.         OSSchedRoundRobinEn = DEF_ENABLED;
  31.     }

  32.     if (dflt_time_quanta > (OS_TICK)0) {                                                         (3)
  33.         OSSchedRoundRobinDfltTimeQuanta = dflt_time_quanta;
  34.     } else {
  35.         OSSchedRoundRobinDfltTimeQuanta = (OS_TICK)(OSCfg_TickRate_Hz / (OS_RATE_HZ)10);
  36.     }
  37.     CPU_CRITICAL_EXIT();
  38.    *p_err = OS_ERR_NONE;
  39. }
  40. #endif
复制代码
1.    由于这几个参数是全局变量,所以必须关闭中断。
2.    根据形参设置是否使能时间片调度。
3.    变量OSSchedRoundRobinDfltTimeQuanta是用来设置默认的时间片个数,也就是说,如果程序中没有单独配置任务的时间片个数,就会使用这个默认时间片个数。

11.11.2      放弃剩余时间片OSSchedRoundRobinYield ()
    这个函数的主要功能就是任务在完成工作的情况下,如果还有剩余的时间片,可以放弃这些时间去执行另外的同优先级任务(切记,是另外的同优先级任务)
  1. /*
  2. ***********************************************************************************************************
  3. *                                    当任务不再需要剩余时间片时放弃CPU使用权
  4. *
  5. * 功能说明: 当任务的时间片还没用完的时候,可以通过此函数放弃剩余时间片,也就是放弃CPU使用权。
  6. * 形    参: p_err  错误代码指针变量
  7. *                  OS_ERR_NONE                   函数调用成功
  8. *                  OS_ERR_ROUND_ROBIN_1          此优先级下只有这一个任务,能够放弃CPU权
  9. *                  OS_ERR_ROUND_ROBIN_DISABLED   Round Robin调度没有使能
  10. *                  OS_ERR_SCHED_LOCKED           调度器被锁
  11. *                  OS_ERR_YIELD_ISR              不能在中断服务程序中调用此函数
  12. * 返 回 值: 无
  13. * 注    意: 1) 此函数必须在任务中调用
  14. ***********************************************************************************************************
  15. */

  16. #if OS_CFG_SCHED_ROUND_ROBIN_EN > 0u
  17. void  OSSchedRoundRobinYield (OS_ERR  *p_err)
  18. {
  19.     OS_RDY_LIST  *p_rdy_list;
  20.     OS_TCB       *p_tcb;
  21.     CPU_SR_ALLOC();



  22. #ifdef OS_SAFETY_CRITICAL
  23.     if (p_err == (OS_ERR *)0) {
  24.         OS_SAFETY_CRITICAL_EXCEPTION();
  25.         return;
  26.     }
  27. #endif

  28. #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
  29.     if (OSIntNestingCtr > (OS_NESTING_CTR)0) {      /* 不能在ISR中调用此函数 */
  30.        *p_err = OS_ERR_YIELD_ISR;
  31.         return;
  32.     }
  33. #endif

  34.     if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) {  /* 调度器被锁不能执行此函数  */
  35.        *p_err = OS_ERR_SCHED_LOCKED;
  36.         return;
  37.     }

  38.     if (OSSchedRoundRobinEn != DEF_TRUE) {            /* 确认round-robin已经使能 */
  39.        *p_err = OS_ERR_ROUND_ROBIN_DISABLED;
  40.         return;
  41.     }

  42.     CPU_CRITICAL_ENTER();
  43.     p_rdy_list = &OSRdyList[OSPrioCur];                /* 此优先级下仅有这一个任务  */               (1)
  44.     if (p_rdy_list->NbrEntries < (OS_OBJ_QTY)2) {
  45.         CPU_CRITICAL_EXIT();
  46.        *p_err = OS_ERR_ROUND_ROBIN_1;
  47.         return;
  48.     }

  49.     OS_RdyListMoveHeadToTail(p_rdy_list);               /* 移动当前任务的TCB到列表末  */            (2)
  50.     p_tcb = p_rdy_list->HeadPtr;                        /* 获取列表首端的TCB  */
  51.     if (p_tcb->TimeQuanta == (OS_TICK)0) {              /* 是0,使用默认的时间片数 */                (3)
  52.         p_tcb->TimeQuantaCtr = OSSchedRoundRobinDfltTimeQuanta;
  53.     } else {
  54.         p_tcb->TimeQuantaCtr = p_tcb->TimeQuanta;       /* 加载新的时间片数  */
  55.     }

  56.     CPU_CRITICAL_EXIT();

  57.     OSSched();                                          /* 运行调度器  */                             (4)
  58.    *p_err = OS_ERR_NONE;
  59. }
  60. #endif
复制代码
1.    获取此优先级的就绪链表。从而得到此优先级下任务的个数,如果同优先级下只有一个任务,将退出这个函数。
2.    移动同优先级就绪链表中任务的位置,从实现同优先级下任务的切换。
3.    参数p_tcb->TimeQuanta = 0的时候就会使用默认的时间片个数,如果非0,就会给这个任务的时间片计数器赋予相应的时间片个数。
4.    执行任务调度。

baiyongbin2009 回答时间:2014-12-25 17:13:09
(续)11.11  Round-Robin调度

11.11.3       Round-Robin调度算法OS_SchedRoundRobin ()
    当多个任务有相同的优先级时,μCOS-III允许任务在切换到另一个任务前运行特定的时间,也就是大家常说的时间片。这个过程就是Round-Robin调度或者时间片调度。如果任务不需要将所有的时间片用完,可以调用上面讲的函数OSSchedRoundRobinYield (),放弃剩余时间片从而切换到同优先级的另一个任务。μCOS-III支持用户在系统运行过程中使能或者禁止时间片调度,同时也支持全局的时间片设置,也支持每个任务的单独设置。
    为了更好的说明Round-Robin调度算法,下面举一个例子(截图来自官方书籍):Task #1,Task #2,Task #3都运行在优先级 X,任务运行的时间片个数都是4。
11.4.png
1.     一开始是Task #3在运行,运行期间每个嘀嗒定时器中断都会让Task #3的时间片计数减一。
2.     第四次进入嘀嗒定时器中断后,Task #3的4个时间片已经用完。
3.     切换到同优先级就绪链表中下一个任务Task #1。
4.     Task #1开始运行直到时间片用完。
5.     切换到Task #3运行。
6.     Task #3运行一段时间后,调用函数OSSchedRoundRobinYield ()放弃剩余时间片。
7.     切换到Task #1运行。
8.     这里要特别注意:Task #1会运行4个时间片,图片上面画的不是很准确。
    有了上面基础后,在解析一下相关函数。
  1. /*
  2. ***********************************************************************************************************
  3. * 运行ROUND-ROBIN 调度算法
  4. *
  5. * 函数说明: 此函数每个嘀嗒定时器中断被调用,通过此函数来计算同优先级中是否有任务要执行。
  6. * 形 参: p_rdy_list 就绪链表指针
  7. * 返 回 值: 无
  8. * 注 意: 1) 内部函数调用,用户程序不能调用
  9. ***********************************************************************************************************
  10. */

  11. #if OS_CFG_SCHED_ROUND_ROBIN_EN > 0u
  12. void OS_SchedRoundRobin (OS_RDY_LIST *p_rdy_list)
  13. {
  14. OS_TCB *p_tcb;
  15. CPU_SR_ALLOC();



  16. if (OSSchedRoundRobinEn != DEF_TRUE) { /* 确认round-robin调度已经使能 */ (1)
  17. return;
  18. }

  19. CPU_CRITICAL_ENTER();
  20. p_tcb = p_rdy_list->HeadPtr;

  21. if (p_tcb == (OS_TCB *)0) { (2)
  22. CPU_CRITICAL_EXIT();
  23. return;
  24. }

  25. if (p_tcb == &OSIdleTaskTCB) { (3)
  26. CPU_CRITICAL_EXIT();
  27. return;
  28. }

  29. if (p_tcb->TimeQuantaCtr > (OS_TICK)0) { /* 时间片计数减一 */ (4)
  30. p_tcb->TimeQuantaCtr--;
  31. }

  32. if (p_tcb->TimeQuantaCtr > (OS_TICK)0) { /* 时间片还没有用完 */ (5)
  33. CPU_CRITICAL_EXIT();
  34. return;
  35. }

  36. if (p_rdy_list->NbrEntries < (OS_OBJ_QTY)2) { /* 是否只有一个同优先级任务 */ (6)
  37. CPU_CRITICAL_EXIT(); /* 是的,退出 */
  38. return;
  39. }

  40. if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) { /* 调度器被锁,不能执行round-robin */ (7)
  41. CPU_CRITICAL_EXIT();
  42. return;
  43. }

  44. OS_RdyListMoveHeadToTail(p_rdy_list); /* 将当前的OS_TCB移到就绪链表的末尾 */ (8)
  45. p_tcb = p_rdy_list->HeadPtr; /* 获取修改后的就绪链表头部OS_TCB */
  46. if (p_tcb->TimeQuanta == (OS_TICK)0) { /* 检测是否需要使用默认的时间片 */ (9)
  47. p_tcb->TimeQuantaCtr = OSSchedRoundRobinDfltTimeQuanta;
  48. } else {
  49. p_tcb->TimeQuantaCtr = p_tcb->TimeQuanta; /* 加载新的时间片 */
  50. }
  51. CPU_CRITICAL_EXIT();
  52. }
  53. #endif
复制代码
1.     检测Round-Robin调度是否使能。
2.     确保此优先级下存在任务。
3.     这句话的意思是说:不允许用户将应用任务的优先级设置的和空闲任务优先级一样,也就是说空闲任务的优先级下不能有其它任务。
4.     时间片减一。
5.     任务的时间片还没有用完,退出继续执行。
6.     同优先级下必须有两个及其以上的任务才能继续往下执行。
7.     如果调度器被锁,不能执行Round-Robin调度。
8.     通过调整同优先级下的就绪链表获得下一个要执行的任务。
9.     判断使用全局的默认时间片个数还是使用单独设计的时间片个数。

11.11.4       函数使用举例
  1. /*
  2. *********************************************************************************************************
  3. * 函数名: main
  4. * 功能说明: 标准c程序入口。
  5. * 形 参:无
  6. * 返回值: 无
  7. *********************************************************************************************************
  8. */

  9. int main(void)
  10. {
  11. OS_ERR err;

  12. OSInit(&err);

  13. /* 使能并设置全局时间片个数 */
  14. OSSchedRoundRobinCfg(DEF_ENABLED,
  15. 8,
  16. &err);

  17. OSTaskCreate((OS_TCB *)&AppTaskStartTCB,
  18. (CPU_CHAR *)"App Task Start",
  19. (OS_TASK_PTR )AppTaskStart,
  20. (void *)0,
  21. (OS_PRIO )APP_CFG_TASK_START_PRIO,
  22. (CPU_STK *)&AppTaskStartStk[0],
  23. (CPU_STK_SIZE )APP_CFG_TASK_START_STK_SIZE / 10,
  24. (CPU_STK_SIZE )APP_CFG_TASK_START_STK_SIZE,
  25. (OS_MSG_QTY )0,
  26. (OS_TICK )0,
  27. (void *)0,
  28. (OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
  29. (OS_ERR *)&err);

  30. OSStart(&err);

  31. return (0);
  32. }


  33. /*
  34. *********************************************************************************************************
  35. * 函 数 名: AppTaskCom
  36. * 功能说明: 此任务未使用
  37. * 形 参:p_arg 是在创建该任务时传递的形参
  38. * 返 回 值: 无
  39. *********************************************************************************************************
  40. */

  41. static void AppTaskCOM(void *p_arg)
  42. {
  43. OS_ERR err;

  44. (void)p_arg;


  45. while(1)
  46. {
  47. ……
  48. OSSchedRoundRobinYield (&err);
  49. ……
  50. }


  51. }
复制代码



baiyongbin2009 回答时间:2014-12-25 17:14:11
11.12  总结
    本期教程涉及到的内容较多,如果是初学的,一定要多花点时间消耗下,如果学习过程中遇到很多问题,不要担心,随着后面教程的进行会理解的更深刻。

caiyuhui74748 回答时间:2015-8-6 16:21:23
辛苦。。。。。。。。。。。学习

所属标签

STM32团队

意法半导体微控制器和微处理器拥有广泛的产品线,包含低成本的8位单片机和基于ARM® Cortex®-M0、M0+、M3、M4、M33、M7及A7内核并具备丰富外设选择的32位微控制器及微处理器


最新内容

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
微信公众号二维码 微信公众号
手机版二维码 手机版