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

【安富莱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扩展软件包
关注我们
st-img 微信公众号
st-img 手机版