打印
[STM32F4]

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

[复制链接]
3139|18
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
Eric2013|  楼主 | 2014-12-24 19:18 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 Eric2013 于 2014-12-24 19:20 编辑

特别说明:
1.  本教程是安富莱电子原创。
2.  安富莱STM32F407开发板资料已经全部开源,开源地址:地址链接
3.  当前共配套300多个实例,4套用户手册。

第11章  μCOS-III内核函数分析

    本期教程开始分析μCOS-III的内核函数,源码的分析采用先对源码进行注释,然后讲解函数实现的功能和相关的原理分析,最后是举一个例子(如果这个函数是供外部函数调用的)。内核函数很重要,是学习任务管理,任务间通信机制的基础。希望初学的同学认真学习,这部分应该算是μCOS-III的核心代码。
    11.1 系统配置文件
    11.2 源码文件
    11.3 μCOS-III初始化
    11.4 μCOS-III启动
    11.5 获取系统版本
    11.6 空闲任务
    11.7 临界段
    11.8 安全关键IEC61508
    11.9 任务切换
    11.10 调度锁
    11.11 Round-Robin调度
    11.12 总结

11.1  系统配置文件
    下面先简单说明下μCOS-III中几个配置文件的作用,方便分析源码的时候查看,配置文件主要有以下几个:


11.1.1      lib_cfg.h配置文件
    lib_cfg.h文件内容如下:
/*
*********************************************************************************************************
*                                               MODULE
*********************************************************************************************************
*/

#ifndef  LIB_CFG_MODULE_PRESENT
#define  LIB_CFG_MODULE_PRESENT

/*
*********************************************************************************************************
*                                          uC/LIB CONFIGURATION
*********************************************************************************************************
*/

#define  LIB_MEM_CFG_ARG_CHK_EXT_EN     DEF_ENABLED
                                         /*   DEF_DISABLED     Argument check DISABLED       */
                                         /*   DEF_ENABLED      Argument check ENABLED        */

#define  LIB_MEM_CFG_OPTIMIZE_ASM_EN    DEF_ENABLED
                                         /*   DEF_DISABLED     Assembly-optimized function(s) DISABLED   */
                                         /*   DEF_ENABLED      Assembly-optimized function(s) ENABLED    */

#define  LIB_MEM_CFG_ALLOC_EN           DEF_ENABLED
                                         /*   DEF_DISABLED     Memory allocation DISABLED    */
                                         /*   DEF_ENABLED      Memory allocation ENABLED     */

#define  LIB_MEM_CFG_HEAP_SIZE          23u * 1024u     /* Configure Heap Memory Size  */

/*
*********************************************************************************************************
*                                             MODULE END
*********************************************************************************************************
*/

#endif                  
     lib_cfg.h是用于给uC/LIB做配置的头文件。如果程序中使用uC/LIB的话,需要调用函数Mem_Init()进行初始化。
11.1.2      os_cfg.h配置文件
     os_cfg.h文件中的内容如下:
#ifndef OS_CFG_H
#define OS_CFG_H


/* ---------------------------- MISCELLANEOUS -------------------------- */
#define OS_CFG_APP_HOOKS_EN             1u   /* Enable (1) or Disable (0) application specific hooks  */
#define OS_CFG_ARG_CHK_EN               1u   /* Enable (1) or Disable (0) argument checking           */
#define OS_CFG_CALLED_FROM_ISR_CHK_EN   1u   /* Enable (1) or Disable (0) check for called from ISR   */
#define OS_CFG_DBG_EN                   1u   /* Enable (1) debug code/variables                       */
#define OS_CFG_ISR_POST_DEFERRED_EN     0u   /* Enable (1) or Disable (0) Deferred ISR posts          */
#define OS_CFG_OBJ_TYPE_CHK_EN          1u   /* Enable (1) or Disable (0) object type checking        */
#define OS_CFG_TS_EN                    1u   /* Enable (1) or Disable (0) time stamping               */

#define OS_CFG_PEND_MULTI_EN  1u   /* Enable (1) or Disable (0) code generation for multi-pend feature   */

#define OS_CFG_PRIO_MAX       64u  /* Defines the maximum number of task priorities (see OS_PRIO data type) */

#define OS_CFG_SCHED_LOCK_TIME_MEAS_EN  0u   /* Include code to measure scheduler lock time           */
#define OS_CFG_SCHED_ROUND_ROBIN_EN     0u   /* Include code for Round-Robin scheduling               */
#define OS_CFG_STK_SIZE_MIN            64u   /* Minimum allowable task stack size                     */


/* ----------------------------- EVENT FLAGS --------------------------- */
#define OS_CFG_FLAG_EN          1u   /* Enable (1) or Disable (0) code generation for EVENT FLAGS   */
#define OS_CFG_FLAG_DEL_EN      1u   /* Include code for OSFlagDel()                                */
#define OS_CFG_FLAG_MODE_CLR_EN 1u   /* Include code for Wait on Clear EVENT FLAGS                  */
#define OS_CFG_FLAG_PEND_ABORT_EN 1u /* Include code for OSFlagPendAbort()                          */


/* -------------------------- MEMORY MANAGEMENT ------------------------ */
#define OS_CFG_MEM_EN           1u   /* Enable (1) or Disable (0) code generation for MEMORY MANAGER  */


/* --------------------- MUTUAL EXCLUSION SEMAPHORES ------------------- */
#define OS_CFG_MUTEX_EN                 1u   /* Enable (1) or Disable (0) code generation for MUTEX   */
#define OS_CFG_MUTEX_DEL_EN             1u   /* Include code for OSMutexDel()                         */
#define OS_CFG_MUTEX_PEND_ABORT_EN      1u   /* Include code for OSMutexPendAbort()                   */


/* --------------------------- MESSAGE QUEUES -------------------------- */
#define OS_CFG_Q_EN                     1u   /* Enable (1) or Disable (0) code generation for QUEUES  */
#define OS_CFG_Q_DEL_EN                 1u   /* Include code for OSQDel()                             */
#define OS_CFG_Q_FLUSH_EN               1u   /* Include code for OSQFlush()                           */
#define OS_CFG_Q_PEND_ABORT_EN          1u   /* Include code for OSQPendAbort()                       */


/* ----------------------------- SEMAPHORES ---------------------------- */
#define OS_CFG_SEM_EN                   1u   /* Enable (1) or Disable (0) code generation for SEMAPHORES */
#define OS_CFG_SEM_DEL_EN               1u   /* Include code for OSSemDel()                              */
#define OS_CFG_SEM_PEND_ABORT_EN        1u   /* Include code for OSSemPendAbort()                        */
#define OS_CFG_SEM_SET_EN               1u   /* Include code for OSSemSet()                              */


/* -------------------------- TASK MANAGEMENT -------------------------- */
#define OS_CFG_STAT_TASK_EN             1u   /* Enable (1) or Disable(0) the statistics task   */
#define OS_CFG_STAT_TASK_STK_CHK_EN     1u   /* Check task stacks from statistic task          */

#define OS_CFG_TASK_CHANGE_PRIO_EN      1u   /* Include code for OSTaskChangePrio()            */
#define OS_CFG_TASK_DEL_EN              1u   /* Include code for OSTaskDel()                   */
#define OS_CFG_TASK_Q_EN                1u   /* Include code for OSTaskQXXXX()                 */
#define OS_CFG_TASK_Q_PEND_ABORT_EN     1u   /* Include code for OSTaskQPendAbort()            */
#define OS_CFG_TASK_PROFILE_EN          1u   /* Include variables in OS_TCB for profiling      */
#define OS_CFG_TASK_REG_TBL_SIZE        1u   /* Number of task specific registers              */
#define OS_CFG_TASK_SEM_PEND_ABORT_EN   1u   /* Include code for OSTaskSemPendAbort()               */
#define OS_CFG_TASK_SUSPEND_EN          1u   /* Include code for OSTaskSuspend() and OSTaskResume() */


/* -------------------------- TIME MANAGEMENT -------------------------- */
#define OS_CFG_TIME_DLY_HMSM_EN         1u   /* Include code for OSTimeDlyHMSM()                   */
#define OS_CFG_TIME_DLY_RESUME_EN       1u   /* Include code for OSTimeDlyResume()                 */


/* ------------------------- TIMER MANAGEMENT -------------------------- */
#define OS_CFG_TMR_EN         1u   /* Enable (1) or Disable (0) code generation for TIMERS      */
#define OS_CFG_TMR_DEL_EN     1u   /* Enable (1) or Disable (0) code generation for OSTmrDel()  */

#endif
    这个配置文件比较的重要,主要用于μCOS-III源码中相关函数的配置。
11.1.3      os_cfg_app.h配置文件
os_cfg_app.h文件的内容如下:
#ifndef OS_CFG_APP_H
#define OS_CFG_APP_H

/*
***********************************************************************************************************
*                                            CONSTANTS
***********************************************************************************************************
*/

/* --------------------- MISCELLANEOUS ------------------ */
#define  OS_CFG_MSG_POOL_SIZE            100u       /* Maximum number of messages                        */
#define  OS_CFG_ISR_STK_SIZE             256u       /* Stack size of ISR stack (number of CPU_STK elements) */
#define  OS_CFG_TASK_STK_LIMIT_PCT_EMPTY  10u       /* Stack limit position in percentage to empty       */


/* ---------------------- IDLE TASK --------------------- */
#define  OS_CFG_IDLE_TASK_STK_SIZE       128u            /* Stack size (number of CPU_STK elements)    */


/* ------------------ ISR HANDLER TASK ------------------ */
#define  OS_CFG_INT_Q_SIZE                10u            /* Size of ISR handler task queue             */
#define  OS_CFG_INT_Q_TASK_STK_SIZE      128u            /* Stack size (number of CPU_STK elements)    */

/* ------------------- STATISTIC TASK ------------------- */
#define  OS_CFG_STAT_TASK_PRIO     (OS_CFG_PRIO_MAX - 2u) /* Priority                                */
#define  OS_CFG_STAT_TASK_RATE_HZ         10u             /* Rate of execution (10 Hz Typ.)          */
#define  OS_CFG_STAT_TASK_STK_SIZE       128u             /* Stack size (number of CPU_STK elements) */


/* ------------------------ TICKS ----------------------- */
#define  OS_CFG_TICK_RATE_HZ            1000u   /* Tick rate in Hertz (10 to 1000 Hz)                   */
#define  OS_CFG_TICK_TASK_PRIO             1u   /* Priority                                             */
#define  OS_CFG_TICK_TASK_STK_SIZE       128u   /* Stack size (number of CPU_STK elements)              */
#define  OS_CFG_TICK_WHEEL_SIZE           16u   /* Number of 'spokes' in tick wheel                     */

/* ----------------------- TIMERS ----------------------- */
#define  OS_CFG_TMR_TASK_PRIO      (OS_CFG_PRIO_MAX - 2u)   /* Priority                                 */
#define  OS_CFG_TMR_TASK_RATE_HZ          10u               /* Rate for timers (10 Hz Typ.)             */
#define  OS_CFG_TMR_TASK_STK_SIZE        128u               /* Stack size (number of CPU_STK elements)  */
#define  OS_CFG_TMR_WHEEL_SIZE            17u               /* Number of 'spokes' in timer wheel        */

#endif
    这个文件主要是内核任务的配置,包括中断管理任务,空闲任务,统计任务,嘀嗒定时器任务已经定时器任务。

沙发
Eric2013|  楼主 | 2014-12-24 19:22 | 只看该作者
(续)11.1  系统配置文件
11.1.4      app_cfg.h配置文件
    app_cfg.h文件夹中的内容如下:
#ifndef  APP_CFG_MODULE_PRESENT
#define  APP_CFG_MODULE_PRESENT


/*
*********************************************************************************************************
*                                            TASK PRIORITIES
*********************************************************************************************************
*/

#define  APP_CFG_TASK_START_PRIO                              2u
#define  APP_CFG_TASK_UPDATE_PRIO                             3u
#define  APP_CFG_TASK_COM_PRIO                                4u
#define  APP_CFG_TASK_USER_IF_PRIO                            5u
#define  APP_CFG_TASK_GUI_PRIO                        (OS_CFG_PRIO_MAX - 4u)
#define  APP_CFG_TASK_GUIRefresh_PRIO                 (OS_CFG_PRIO_MAX - 4u)

/*
*********************************************************************************************************
*                                            TASK STACK SIZES
*                             Size of the task stacks (# of OS_STK entries)
*********************************************************************************************************
*/

#define  APP_CFG_TASK_START_STK_SIZE                      1024u
#define  APP_CFG_TASK_UPDATE_STK_SIZE                     1024u
#define  APP_CFG_TASK_COM_STK_SIZE                        1024u
#define  APP_CFG_TASK_USER_IF_STK_SIZE                    1024u
#define  APP_CFG_TASK_GUI_STK_SIZE                        1024u
#define  APP_CFG_TASK_GUIRefresh_STK_SIZE                 1024u

#endif
    这个文件主要用于用户任务的配置。
11.1.5      cpu_cfg.h配置文件
    cpu_cfg.h文件中的内容如下:
#ifndef  CPU_CFG_MODULE_PRESENT
#define  CPU_CFG_MODULE_PRESENT


/*
*********************************************************************************************************
*                                       CPU NAME CONFIGURATION
*
* Note(s) : (1) Configure CPU_CFG_NAME_EN to enable/disable CPU host name feature :
*
*               (a) CPU host name storage
*               (b) CPU host name API functions
*
*           (2) Configure CPU_CFG_NAME_SIZE with the desired ASCII string size of the CPU host name,
*               including the terminating NULL character.
*
*               See also 'cpu_core.h  GLOBAL VARIABLES  Note #1'.
*********************************************************************************************************
*/

                                            /* Configure CPU host name feature (see Note #1) :      */
#define  CPU_CFG_NAME_EN                         DEF_ENABLED
                                            /*   DEF_DISABLED  CPU host name DISABLED               */
                                            /*   DEF_ENABLED   CPU host name ENABLED                */

                                            /* Configure CPU host name ASCII string size ...        */
#define  CPU_CFG_NAME_SIZE                                16    /* ... (see Note #2).               */

/*
*********************************************************************************************************
*                                     CPU TIMESTAMP CONFIGURATION
*
* Note(s) : (1) Configure CPU_CFG_TS_xx_EN to enable/disable CPU timestamp features :
*
*               (a) CPU_CFG_TS_32_EN   enable/disable 32-bit CPU timestamp feature
*               (b) CPU_CFG_TS_64_EN   enable/disable 64-bit CPU timestamp feature
*
*           (2) (a) Configure CPU_CFG_TS_TMR_SIZE with the CPU timestamp timer's word size :
*
*                       CPU_WORD_SIZE_08         8-bit word size
*                       CPU_WORD_SIZE_16        16-bit word size
*                       CPU_WORD_SIZE_32        32-bit word size
*                       CPU_WORD_SIZE_64        64-bit word size
*
*               (b) If the size of the CPU timestamp timer is not a binary multiple of 8-bit octets
*                   (e.g. 20-bits or even 24-bits), then the next lower, binary-multiple octet word
*                   size SHOULD be configured (e.g. to 16-bits).  However, the minimum supported word
*                   size for CPU timestamp timers is 8-bits.
*
*                   See also 'cpu_core.h  FUNCTION PROTOTYPES  CPU_TS_TmrRd()  Note #2a'.
*********************************************************************************************************
*/

                                                /* Configure CPU timestamp features (see Note #1) :     */
#define  CPU_CFG_TS_32_EN                       DEF_ENABLED
#define  CPU_CFG_TS_64_EN                       DEF_DISABLED
                                                /*   DEF_DISABLED  CPU timestamps DISABLED              */
                                                /*   DEF_ENABLED   CPU timestamps ENABLED               */

                                                /* Configure CPU timestamp timer word size ...          */
                                                /* ... (see Note #2) :                                  */
#define  CPU_CFG_TS_TMR_SIZE                    CPU_WORD_SIZE_32


/*
*********************************************************************************************************
*                        CPU INTERRUPTS DISABLED TIME MEASUREMENT CONFIGURATION
*
* Note(s) : (1) (a) Configure CPU_CFG_INT_DIS_MEAS_EN to enable/disable measuring CPU's interrupts
*                   disabled time :
*
*                   (a)  Enabled,       if CPU_CFG_INT_DIS_MEAS_EN      #define'd in 'cpu_cfg.h'
*
*                   (b) Disabled,       if CPU_CFG_INT_DIS_MEAS_EN  NOT #define'd in 'cpu_cfg.h'
*
*                   See also 'cpu_core.h  FUNCTION PROTOTYPES  Note #1'.
*
*               (b) Configure CPU_CFG_INT_DIS_MEAS_OVRHD_NBR with the number of times to measure &
*                   average the interrupts disabled time measurements overhead.
*
*                   Recommend a single (1) overhead time measurement, even for instruction-cache-enabled
*                   CPUs, since critical sections are NOT typically called within instruction-cached loops.
*                   Thus a single non-cached/non-averaged time measurement is a more realistic overhead
*                   for the majority of non-cached interrupts disabled time measurements.
*
*                   See also 'cpu_core.c  CPU_IntDisMeasInit()  Note #3a'.
*********************************************************************************************************
*/

#if 0                                              /* Configure CPU interrupts disabled time ...           */
#define  CPU_CFG_INT_DIS_MEAS_EN                   /* ... measurements feature (see Note #1a).             */
#endif

                                                   /* Configure number of interrupts disabled overhead ... */
#define  CPU_CFG_INT_DIS_MEAS_OVRHD_NBR      1u    /* ... time measurements (see Note #1b).                */

/*
*********************************************************************************************************
*                                    CPU COUNT ZEROS CONFIGURATION
*
* Note(s) : (1) (a) Configure CPU_CFG_LEAD_ZEROS_ASM_PRESENT  to define count leading  zeros bits
*                   function(s) in :
*
*                   (1) 'cpu_a.asm',  if CPU_CFG_LEAD_ZEROS_ASM_PRESENT       #define'd in 'cpu.h'/
*                                         'cpu_cfg.h' to enable assembly-optimized function(s)
*
*                   (2) 'cpu_core.c', if CPU_CFG_LEAD_ZEROS_ASM_PRESENT   NOT #define'd in 'cpu.h'/
*                                         'cpu_cfg.h' to enable C-source-optimized function(s) otherwise
*
*               (b) Configure CPU_CFG_TRAIL_ZEROS_ASM_PRESENT to define count trailing zeros bits
*                   function(s) in :
*
*                   (1) 'cpu_a.asm',  if CPU_CFG_TRAIL_ZEROS_ASM_PRESENT      #define'd in 'cpu.h'/
*                                         'cpu_cfg.h' to enable assembly-optimized function(s)
*
*                   (2) 'cpu_core.c', if CPU_CFG_TRAIL_ZEROS_ASM_PRESENT  NOT #define'd in 'cpu.h'/
*                                         'cpu_cfg.h' to enable C-source-optimized function(s) otherwise
*********************************************************************************************************
*/

#if 1                                              /* Configure CPU count leading  zeros bits ...          */
#define  CPU_CFG_LEAD_ZEROS_ASM_PRESENT            /* ... assembly-version (see Note #1a).                 */
#endif

#if 0                                              /* Configure CPU count trailing zeros bits ...          */
#define  CPU_CFG_TRAIL_ZEROS_ASM_PRESENT           /* ... assembly-version (see Note #1b).                 */
#endif

/*
*********************************************************************************************************
*                                             MODULE END
*********************************************************************************************************
*/

#endif                                         /* End of CPU cfg module include.                       */
    这个文件里面主要是uC/CPU相关的配置。

使用特权

评论回复
板凳
Eric2013|  楼主 | 2014-12-24 19:23 | 只看该作者
11.2  源码文件
    μCOS-III中的源码主要包含如下文件:

                              
    上面截图中是μCOS-III相关的源码文件,后面的几期教程就是把这几个文件讲清楚。本期教程主要是讲解os_core文件中的相关函数。学期源码前还有看一下os_type.h文件中的内容(主要是变量的类型,这个一定得了解下):
/*
***********************************************************************************************************
*                                                 INCLUDE HEADER FILES
***********************************************************************************************************
*/

typedef   CPU_INT16U      OS_CPU_USAGE; /* CPU Usage 0..10000                     <16>/32 */

typedef   CPU_INT32U      OS_CTR;       /* Counter,                                    32 */

typedef   CPU_INT32U      OS_CTX_SW_CTR; /* Counter of context switches,               32 */

typedef   CPU_INT32U      OS_CYCLES;    /* CPU clock cycles,                                   <32>/64 */

typedef   CPU_INT32U      OS_FLAGS;     /* Event flags,                                      8/16/<32> */

typedef   CPU_INT32U      OS_IDLE_CTR;  /* Holds the number of times the idle task runs,       <32>/64 */

typedef   CPU_INT16U      OS_MEM_QTY;   /* Number of memory blocks,                            <16>/32 */
typedef   CPU_INT16U      OS_MEM_SIZE;  /* Size in bytes of a memory block,                    <16>/32 */

typedef   CPU_INT16U      OS_MSG_QTY;   /* Number of OS_MSGs in the msg pool,                  <16>/32 */
typedef   CPU_INT16U      OS_MSG_SIZE;  /* Size of messages in number of bytes,                <16>/32 */

typedef   CPU_INT08U      OS_NESTING_CTR; /* Interrupt and scheduler nesting,                  <8>/16/32 */

typedef   CPU_INT16U      OS_OBJ_QTY;     /* Number of kernel objects counter,                   <16>/32 */
typedef   CPU_INT32U      OS_OBJ_TYPE;    /* Special flag to determine object type,                   32 */

typedef   CPU_INT16U      OS_OPT;         /* Holds function options                              <16>/32 */

typedef   CPU_INT08U      OS_PRIO;        /* Priority of a task,                               <8>/16/32 */

typedef   CPU_INT16U      OS_QTY;         /* Quantity                                            <16>/32 */

typedef   CPU_INT32U      OS_RATE_HZ;     /* Rate in Hertz                                            32 */

typedef   CPU_INT32U      OS_REG;         /* Task register                                     8/16/<32> */
typedef   CPU_INT08U      OS_REG_ID;      /* Index to task register                            <8>/16/32 */

typedef   CPU_INT32U      OS_SEM_CTR;     /* Semaphore value                                     16/<32> */

typedef   CPU_INT08U      OS_STATE;       /* State variable                                    <8>/16/32 */

typedef   CPU_INT08U      OS_STATUS;      /* Status                                            <8>/16/32 */

typedef   CPU_INT32U      OS_TICK;        /* Clock tick counter                                  <32>/64 */
typedef   CPU_INT16U      OS_TICK_SPOKE_IX; /* Tick wheel spoke position                         8/<16>/32 */

typedef   CPU_INT16U      OS_TMR_SPOKE_IX; /* Timer wheel spoke position                        8/<16>/32 */


使用特权

评论回复
地板
Eric2013|  楼主 | 2014-12-24 19:28 | 只看该作者
本帖最后由 Eric2013 于 2014-12-24 19:31 编辑

11.3  μcos-III初始化
    下面开始讲解os_core.c文件中的函数,这个文件里面的函数比较多,为了方便大家更好的学习这个文件中的相关函数,这里对其进行了分类,先从μCOS-III的初始化开始讲解。
11.3.1      初始化
    根据前面os_cfg.h文件中的配置,用户可以配置程序中需要执行的函数。μCOS-III的初始化函数OSInit()中涉及的全局变量和函数的初始化比较多,这里将其汇总一下,下面是全局变量的初始化:

全局变量


初始值


变量说明


OSIntNestingCtr


0


中断嵌套的层数(0~250)


OSRunning

  
OS_STATE_OS_STOPPED
  

系统是否开始运行标志


OSSchedLockNestingCtr


0


调用了调度锁的嵌套层数


OSTCBCurPtr

  
0
  

指向当前正在运行任务控制块指针


OSTCBHighRdyPtr


0


指向最高优先级就绪任务控制块指针


OSPrioCur

  
0
  

当前正在运行的任务优先级


OSPrioHighRdy


0


具有最高优先级别的就绪任务的优先级


OSPrioSaved

  
0
  

保存任务优先级


OSSchedLockTimeBegin


0


使用调度锁起始时间


OSSchedLockTimeMax

  
0
  

调度器被锁的最长时间


OSSchedLockTimeMaxCur


0


当前调度器被锁的最长时间


OSSafetyCriticalStartFlag

  
DEF_FALSE
  

系统安全关键开始标志


OSSchedRoundRobinEn


DEF_FALSE


使能Round-Robin调度


OSSchedRoundRobinDfltTimeQuanta

  
OSCfg_TickRate_Hz / 10u
  

默认Round-Robin调度时间片大小


OS_AppTaskCreateHookPtr


0


任务创建钩子函数指针


OS_AppTaskDelHookPtr

  
0
  

任务删除钩子函数指针


OS_AppTaskReturnHookPtr


0


任务返回钩子函数指针


OS_AppIdleTaskHookPtr

  
0
  

空闲钩子函数指针


OS_AppStatTaskHookPtr


0


启动任务钩子函数指针


OS_AppTaskSwHookPtr

  
0
  

任务切换钩子函数指针


OS_AppTimeTickHookPtr


0


滴答定时器钩子函数指针


OSTaskRegNextAvailID


0


任务寄存器下一个有效ID

    函数OSInit()中的其它初始化会在后面讲到的时候再做详细阐述。下面把初始化函数做一下分析。
11.3.2      初始化函数OSInit()
/*
***********************************************************************************************************
*                                                    初始化
*
* 功能说明: 此函数用于uC/OS-III的内部初始化,这个函数是使用uC/OS-III时需要第一个执行的函数,切记不要搞错顺*           序,然后才是任务创建和OS_Start().
* 形    参: p_err    变量指针,用于返回错误代码
*                    OS_ERR_NONE    初始化成功
*                    Other          根据调用的子函数返回其它OS_ERR_xxx
* 返 回 值: 无
***********************************************************************************************************
*/

void  OSInit (OS_ERR  *p_err)
{
    CPU_STK      *p_stk;
    CPU_STK_SIZE  size;



#ifdef OS_SAFETY_CRITICAL                                  /* 安全关键代码 */                                                               (1)
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return;
    }
#endif

    OSInitHook();                                           /* 初始化钩子函数 */                                      

    OSIntNestingCtr                 = (OS_NESTING_CTR)0;    /* 清零中断嵌套计数*/                                                           (2)

    OSRunning                       =  OS_STATE_OS_STOPPED; /* 多任务运行标志,初始化为还没开始  */

    OSSchedLockNestingCtr           = (OS_NESTING_CTR)0;    /* 调度锁计数清零  */

    OSTCBCurPtr                     = (OS_TCB *)0;          /* 初始化 OS_TCB 指针为已知状态 */                                               (3)
    OSTCBHighRdyPtr                 = (OS_TCB *)0;

    OSPrioCur                       = (OS_PRIO)0;     /* 初始化优先级变量为已知状态  */
    OSPrioHighRdy                   = (OS_PRIO)0;
    OSPrioSaved                     = (OS_PRIO)0;

#if OS_CFG_SCHED_LOCK_TIME_MEAS_EN > 0u               /* 调度锁时间测量 */
    OSSchedLockTimeBegin            = (CPU_TS)0;
    OSSchedLockTimeMax              = (CPU_TS)0;
    OSSchedLockTimeMaxCur           = (CPU_TS)0;
#endif

#ifdef OS_SAFETY_CRITICAL_IEC61508                    /* 安全关键开启标志 */                                                                   (4)
    OSSafetyCriticalStartFlag       =  DEF_FALSE;
#endif

#if OS_CFG_SCHED_ROUND_ROBIN_EN > 0u                  /* 时间片调度默认配置 */                                                   (5)
    OSSchedRoundRobinEn             = DEF_FALSE;
    OSSchedRoundRobinDfltTimeQuanta = OSCfg_TickRate_Hz / 10u;
#endif

    if (OSCfg_ISRStkSize > (CPU_STK_SIZE)0) {                                                                                                      (6)
        p_stk = OSCfg_ISRStkBasePtr;                  /* 清零异常堆栈,方便后面做堆栈利用率检测   */
        if (p_stk != (CPU_STK *)0) {
            size  = OSCfg_ISRStkSize;
            while (size > (CPU_STK_SIZE)0) {
                size--;
               *p_stk = (CPU_STK)0;
                p_stk++;
            }
        }
    }

#if OS_CFG_APP_HOOKS_EN > 0u                                                                                                                   (7)
    OS_AppTaskCreateHookPtr = (OS_APP_HOOK_TCB )0;     /* 初始化钩子函数指针  */
    OS_AppTaskDelHookPtr    = (OS_APP_HOOK_TCB )0;
    OS_AppTaskReturnHookPtr = (OS_APP_HOOK_TCB )0;

    OS_AppIdleTaskHookPtr   = (OS_APP_HOOK_VOID)0;
    OS_AppStatTaskHookPtr   = (OS_APP_HOOK_VOID)0;
    OS_AppTaskSwHookPtr     = (OS_APP_HOOK_VOID)0;
    OS_AppTimeTickHookPtr   = (OS_APP_HOOK_VOID)0;
#endif

#if OS_CFG_TASK_REG_TBL_SIZE > 0u
    OSTaskRegNextAvailID    = (OS_REG_ID)0;     /* 清零任务寄存器下一个有效 ID */
#endif

    OS_PrioInit();                              /* 初始化优先级位图 */

    OS_RdyListInit();                           /* 初始化就行列表 */

   
#if OS_CFG_FLAG_EN > 0u                         /* 初始化事件标志组 */
    OS_FlagInit(p_err);
    if (*p_err != OS_ERR_NONE) {
        return;
    }
#endif


#if OS_CFG_MEM_EN > 0u                         /* 初始化内存管理 */
    OS_MemInit(p_err);
    if (*p_err != OS_ERR_NONE) {
        return;
    }
#endif


#if (OS_MSG_EN) > 0u                          /* 初始化OS_MSGs空闲列表  */
    OS_MsgPoolInit(p_err);
    if (*p_err != OS_ERR_NONE) {
        return;
    }
#endif


#if OS_CFG_MUTEX_EN > 0u                      /* 初始化互斥信号量 */
    OS_MutexInit(p_err);
    if (*p_err != OS_ERR_NONE) {
        return;
    }
#endif


#if OS_CFG_Q_EN > 0u
    OS_QInit(p_err);                         /* 初始化消息队列 */
    if (*p_err != OS_ERR_NONE) {
        return;
    }
#endif


#if OS_CFG_SEM_EN > 0u                       /* 初始化信号量 */
    OS_SemInit(p_err);
    if (*p_err != OS_ERR_NONE) {
        return;
    }
#endif


#if defined(OS_CFG_TLS_TBL_SIZE) && (OS_CFG_TLS_TBL_SIZE > 0u)
    OS_TLS_Init(p_err);                    /* 创建任务前,初始化 */
    if (*p_err != OS_ERR_NONE) {
        return;
    }
#endif


    OS_TaskInit(p_err);                    /* 初始化任务管理 */
    if (*p_err != OS_ERR_NONE) {
        return;
    }


#if OS_CFG_ISR_POST_DEFERRED_EN > 0u
    OS_IntQTaskInit(p_err);                /* 初始化中断队列管理任务 */
    if (*p_err != OS_ERR_NONE) {
        return;
    }
#endif

   
    OS_IdleTaskInit(p_err);                /* 初始化空闲任务  */
    if (*p_err != OS_ERR_NONE) {
        return;
    }


    OS_TickTaskInit(p_err);                /* 初始化嘀嗒定时器任务 */
    if (*p_err != OS_ERR_NONE) {
        return;
    }


#if OS_CFG_STAT_TASK_EN > 0u               /* 初始化统计任务  */
    OS_StatTaskInit(p_err);
    if (*p_err != OS_ERR_NONE) {
        return;
    }
#endif


#if OS_CFG_TMR_EN > 0u                     /* 初始化定时器管理任务  */
    OS_TmrInit(p_err);
    if (*p_err != OS_ERR_NONE) {
        return;
    }
#endif


#if OS_CFG_DBG_EN > 0u
    OS_Dbg_Init();                          /* OS调试初始化  */
#endif


    OSCfg_Init();                           /* OS配置初始化  */
}
     1.    如果用户在工程预定义中加入了OS_SAFETY_CRITICAL,那么函数就会执行参数检查功能,如果参数不满足条件的话就会进入安全关键异常                                                 OS_SAFETY_CRITICAL_EXCEPTION()。安全关键的代码是需要用户去实现的。
    2.    OSIntNestingCtr  用于记录中断嵌套次数,在μCOS-III中使用中断的话,一般采用如下的方式:
void  OS_CPU_SysTickHandler (void)
{
CPU_SR_ALLOC();

CPU_CRITICAL_ENTER();
OSIntNestingCtr++;                                          
CPU_CRITICAL_EXIT();

//添加用户代码

OSIntExit();                                            
}
    也就是说进入中断后,先将OSIntNestingCtr加一,退出的时候再执行减一。为什么要这么做?为了说明这个问题,这里举一个例子,假如有低优先级中断A和高优先级中断B,A中断执行的时候,中断B抢占了A的执行,中断B执行完退出的时候会执行函数OSIntExit();(这个函数最主要的作用就是中断级任务切换)。可以想象,如果没有中断嵌套计数变量,退出高优先级中断B的时候运行函数OSIntExit();有可能会执行中断级任务切换,此时执行任务切换的话就会破换正常的寄存器入栈和出栈顺序,从而使得系统崩溃。其实进入Cortex-M3/M4时代已经不存在这个问题了,因为我们设置PendSV中断为最低的优先级(任务切换是在PendSV中断里面执行的),PendSV中断会在所有其它高优先级中断执行完后才会得到执行。
    为了使得μCOS-III可以适应各种处理器内核和复杂的系统设置,中断嵌套计数还是很有必要的。

    3.    当前任务控制块指针OSTCBCurPtr和最高就绪任务的任务控制块指针OSTCBHighRdyPtr都指向了0地址空间。初始为指向0地址空间主要是为了使这两个指针变量都有个初始量。而且方便后面用到这两个指针变量的函数进行检测。
    4.    默认安全关键的标志OSSafetyCriticalStartFlag是关闭的。
    5.    这里个两个变量:OSSchedRoundRobinEn            = DEF_FALSE;
                          OSSchedRoundRobinDfltTimeQuanta= OSCfg_TickRate_Hz / 10u;
    是用于配置时间片的,默认时间片调度是关闭的,时间片大小是OSCfg_TickRate_Hz / 10u。这两个关于时间片的配置变量大家一定要记住。
    6.    这里是几个钩子函数指针,初始化钩子函数,关于钩子函数,咱们在上期教程有详细讲解。
函数中还有有很多其它的初始化,我们会在后面再跟大家详细的讲述。

使用特权

评论回复
5
Eric2013|  楼主 | 2014-12-24 19:33 | 只看该作者
11.4  μcos-III启动
    不像其它RTOS,μCOS-III有一个标准的初始化过程,所以特别建议初学的同学按照这个过程进行初始化,如果不按照这个过程进行初始化,往往会出现莫名其妙的后果,标准的初始化流程如下:
/*
***********************************************************************************************************
*    函 数 名: main
*    功能说明: 标准c程序入口。
*    形    参:无
*    返 回 值: 无
***********************************************************************************************************
*/
int main(void)
{
    OS_ERR  err;
   
    /* 第一步:初始化系统 */
    OSInit(&err);                                            

    /* 第二步:至少创建一个任务,这里是创建了一个启动任务 */
OSTaskCreate((OS_TCB       *)&AppTaskStartTCB,            
                 (CPU_CHAR     *)"App Task Start",
                 (OS_TASK_PTR   )AppTaskStart,
                 (void         *)0,
                 (OS_PRIO       )APP_CFG_TASK_START_PRIO,
                 (CPU_STK      *)&AppTaskStartStk[0],
                 (CPU_STK_SIZE  )APP_CFG_TASK_START_STK_SIZE / 10,
                 (CPU_STK_SIZE  )APP_CFG_TASK_START_STK_SIZE,
                 (OS_MSG_QTY    )0,
                 (OS_TICK       )0,
                 (void         *)0,
                 (OS_OPT        )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
                 (OS_ERR       *)&err);

    /* 第三步:启动系统 */
    OSStart(&err);                                               
    (void)&err;
   
    return (0);
}

/*
***********************************************************************************************************
*    函 数 名: AppTaskStart
*    功能说明: 这是一个启动任务,在多任务系统启动后,必须初始化滴答计数器(在BSP_Init中实现)
*    形    参:p_arg 是在创建该任务时传递的形参
*    返 回 值: 无
     优 先 级:2
***********************************************************************************************************
*/
static  void  AppTaskStart (void *p_arg)
{
OS_ERR      err;   
   (void)p_arg;

     /* 第四步:初始化外设驱动 */
     bsp_Init();
     CPU_Init();
     /* 第五步:初始化嘀嗒定时器 */
     BSP_Tick_Init();                     

#if OS_CFG_STAT_TASK_EN > 0u
     OSStatTaskCPUUsageInit(&err);  
#endif

#ifdef CPU_CFG_INT_DIS_MEAS_EN
    CPU_IntDisMeasMaxCurReset();
#endif
                                       
    AppTaskCreate();                                          
    while (1)
     {                                       
         bsp_LedToggle(1);
         OSTimeDly(1000, OS_OPT_TIME_DLY, &err);
    }
}
    上面的五部就是标准的初始化流程,一定要按照这个顺序进行,这个流程是官方推荐的。为什么要按照这个流程进行初始化? 随着后面源码的讲解,大家会深刻的领悟到这一点。
11.4.2      启动函数OSStart ()
/*
***********************************************************************************************************
*                                                 开始多任务
*
* 函数说明: 此函数用开始多任务处理,调用这个函数前一定要先调用OSStart(),然后至少需要创建一个应用任务。
* 形   参: p_err     错误代码指针变量
*                    OS_ERR_FATAL_RETURN    OS已经运行,OSStart()返回。
*                    OS_ERR_OS_RUNNING      OS已经开始运行, 再调用OSStart()无效
* 返 回 值: 无
* 说    明: 1) OSStartHighRdy():
*              a) 然后调用OSTaskSwHook()
*              b) 加载OSTCBHighRdyPtr指向的任务控制块
*              c) 执行任务
*           2) 正常启动OS的话,函数OSStart()是不返回参数的。如果返回的话,会返回致命错误。
***********************************************************************************************************
*/

void  OSStart (OS_ERR  *p_err)
{
#ifdef OS_SAFETY_CRITICAL                                                                           (1)                                                                              
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return;
    }
#endif

    if (OSRunning == OS_STATE_OS_STOPPED) {                                                         (2)
        OSPrioHighRdy   = OS_PrioGetHighest();            /* 获取需要执行的最高优先级任务 */        (3)
        OSPrioCur       = OSPrioHighRdy;
        OSTCBHighRdyPtr = OSRdyList[OSPrioHighRdy].HeadPtr;                                         (4)
        OSTCBCurPtr     = OSTCBHighRdyPtr;
        OSRunning       = OS_STATE_OS_RUNNING;                                                      (6)
        OSStartHighRdy();                                 /* 开始执行任务切换,执行最高优先级任务 */(7)
       *p_err           = OS_ERR_FATAL_RETURN;            /* 正常不会运行到这里 */                  (8)
    } else {
       *p_err           = OS_ERR_OS_RUNNING;              /* OS已经启动 */                          (9)
    }
}
1.     后面大家会看到,只要是供用户调用的函数和部分内部函数里面都会有这个安全关键代码,主要是用来防止错误的输入形参。
2.     前面初始化的时候,设置OSRunning = OS_STATE_OS_STOPPED,所以按照正常的初始化顺序,程序会进入到if语句中。
3.     通过函数OS_PrioGetHighest()可以获得当前需要执行的最高优先级任务,这个会在下期教程跟大家详细讲述。
4.     从任务的就绪链表中获得当前需要执行的最高优先级任务。
5.     设置系统的运行状态为OSRunning = OS_STATE_OS_RUNNING,然后开始μCOS-III多任务的执行。
6.     关于这个函数,咱们在上期教程中有详细的讲解,这个函数执行完就会进入到PendSV中断。
7.     正常情况下程序是不会执行到这里的。
8.     如果系统已经启动了,用户程序要是再次调用这个函数会进入到这里。

使用特权

评论回复
6
Eric2013|  楼主 | 2014-12-24 19:34 | 只看该作者
11.5  获取系统版本
    有时候我们需要获取系统的版本号,下面就是系统版本的获取函数。这个函数比较简单,特别注意函数注释。
/*
***********************************************************************************************************
*                                                    获取版本号
*
* 函数说明: 此函数用于获取uC/OS-III的版本号,获取的结果是原版本号乘以了10000,比如版本号是3.01.02,那么获
*           取的结果就是30102.
* 形    参: p_err  错误代码指针变量
* 返 回 值: uC/OS-III的版本号乘以10000.
***********************************************************************************************************
*/

CPU_INT16U  OSVersion (OS_ERR  *p_err)
{
#ifdef OS_SAFETY_CRITICAL
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return ((CPU_INT16U)0u);
    }
#endif

   *p_err = OS_ERR_NONE;
    return (OS_VERSION);
}


使用特权

评论回复
7
Eric2013|  楼主 | 2014-12-24 19:36 | 只看该作者
本帖最后由 Eric2013 于 2014-12-24 19:38 编辑

11.6  空闲任务
    几乎所有的小型RTOS中都会有一个空闲任务,空闲任务应该属于系统任务,是必须要执行的,用户程序不能将其关闭。不光小型系统中有空闲任务,大型的系统里面也有的,比如XP,下面的截图就是XP中的空闲进程。
                              
    空闲任务主要有以下几个作用:
  l 我们不能让系统一直在执行各个应用任务,这样的话系统利用率就是100%,系统就会一直的超负荷运行,所以空闲任务很有必要。
  l 为了更好的实现低功耗,空闲任务也很有必要,我们可以在空闲任务中实现睡眠,待机等低功耗措施。
11.6.1      创建空闲任务OS_IdleTaskInit ()
/*
***********************************************************************************************************
*                                               初始化空闲任务
*
* 函数说明: 此函数用于创建
* 形    参: p_err    错误代码指针变量
* 返 回 值: 无
* 说    明: 1) 这个函数属于uC/OS-III内部函数,用户程序不能调用这个函数。
***********************************************************************************************************
*/

void  OS_IdleTaskInit (OS_ERR  *p_err)
{
#ifdef OS_SAFETY_CRITICAL
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return;
    }
#endif

    OSIdleTaskCtr = (OS_IDLE_CTR)0;
                                           /* ---------------- 创建空闲任务 ---------------- */
    OSTaskCreate((OS_TCB     *)&OSIdleTaskTCB,
                 (CPU_CHAR   *)((void *)"uC/OS-III Idle Task"),
                 (OS_TASK_PTR)OS_IdleTask,
                 (void       *)0,
                 (OS_PRIO     )(OS_CFG_PRIO_MAX - 1u),
                 (CPU_STK    *)OSCfg_IdleTaskStkBasePtr,
                 (CPU_STK_SIZE)OSCfg_IdleTaskStkLimit,
                 (CPU_STK_SIZE)OSCfg_IdleTaskStkSize,
                 (OS_MSG_QTY  )0u,
                 (OS_TICK     )0u,
                 (void       *)0,
                 (OS_OPT      )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR | OS_OPT_TASK_NO_TLS),
                 (OS_ERR     *)p_err);
}
    关于任务的创建,本期教程暂时还不做介绍。
11.6.2      空闲任务OS_IdleTask ()
/*
***********************************************************************************************************
*                                                      空闲任务
*
* 函数说明: uC/OS-III内部任务
* 形    参: p_arg    用于任务创建时传递的参数
* 返 回 值: 无
* 注    意: 1) 空闲任务是uC/OS-III的内部任务,用户程序不能调用它
*           2) 在临界区后面调用OSIdleTaskHook()是为了确保有些处理器在使能中断后需要过几个时钟周期才能真正
*              使能。比如Philip XA
*           3) 用户可以在钩子函数中加入待机,休眠等低功耗操作
***********************************************************************************************************
*/

void  OS_IdleTask (void  *p_arg)
{
    CPU_SR_ALLOC();                                                                               (1)



    p_arg = p_arg;                 /* 防止编译器警告 */                                           (2)

    while (DEF_ON) {                                                                              (3)
        CPU_CRITICAL_ENTER();
        OSIdleTaskCtr++;                                                                          (4)
#if OS_CFG_STAT_TASK_EN > 0u
        OSStatTaskCtr++;                                                                          (5)
#endif
        CPU_CRITICAL_EXIT();

        OSIdleTaskHook();          /* 调用钩子函数 */                                             (6)
    }
}
1.    函数CPU_SR_ALLOC()是为CPU_CRITICAL_ENTER()和CPU_CRITICAL_EXIT()申请一个变量:
                #define  CPU_SR_ALLOC()           CPU_SR cpu_sr = (CPU_SR)0
    这个是临界代码段,在下面一个小节有详细讲解。
2.    这样做是为了防止编译器警告。
3.    μCOS-III中主要有以下布尔宏定义:
宏定义
数值
DEF_FALSE
0u
DEF_TRUE
1u
DEF_NO
0u
DEF_YES
1u
DEF_DISABLED
0u
DEF_ENABLED
1u
DEF_INACTIVE
0u
DEF_ACTIVE
1u
DEF_INVALID
0u
DEF_VALID
1u
DEF_OFF   
0u
DEF_ON
1u
DEF_CLR
0u
DEF_SET   
1u
DEF_FAIL
0u
DEF_OK
1u
4.    空闲任务计数。
5.    统计任务计数,这两个计数都是为了计算CPU利用率。
6.    用户可以在钩子函数中加入待机,休眠等低功耗操作。

使用特权

评论回复
8
Eric2013|  楼主 | 2014-12-24 19:42 | 只看该作者
本帖最后由 Eric2013 于 2014-12-24 19:44 编辑

11.7  临界段

11.7.1      临界段基本概念
    代码的临界段也称为临界区,指处理时不可分割的代码。一旦这部分代码开始执行,则不允许任何中断打入。为确保临界段代码的执行,在进入临界段之前要关中断,而临界段代码执行完以后要立即开中断。
    从代码上来看,处在关中断和开中断之间的代码段就是临界段。
    由于各厂商的CPU和C编译器的关中断和开中断的方法以及指令不尽相同,为增强μCOS-III的可移植性(即在μCOS-III的各个C语言函数中尽可能地不出现汇编语言代码),μCOS-III用CPU_INT_DIS()和CPU_INT_EN()这两个宏封装了与系统硬件相关的关中断和开中断指令。
    另外,不要在临界段中调用μCOS-III提供的功能函数,防止系统崩溃。
11.7.2      临界段相关的宏定义
    CPU_INT_DIS()和CPU_INT_EN()可以以下四种不同的实现方法。
#define  CPU_CRITICAL_METHOD_NONE                  0u 
#define  CPU_CRITICAL_METHOD_INT_DIS_EN            1u
#define  CPU_CRITICAL_METHOD_STATUS_STK            2u
#define  CPU_CRITICAL_METHOD_STATUS_LOCAL          3u
    至于在实际应用时使用哪种方法,取决于用户使用的处理器和C编译器。用户可以通过cpu.h文件中的宏定义进行选择:
#define  CPU_CFG_CRITICAL_METHOD    CPU_CRITICAL_METHOD_STATUS_LOCAL

typedef  CPU_INT32U                 CPU_SR;

#if  (CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL)
#define  CPU_SR_ALLOC()             CPU_SR  cpu_sr = (CPU_SR)0
#else
#define  CPU_SR_ALLOC()
#endif



#define  CPU_INT_DIS()         do { cpu_sr = CPU_SR_Save(); } while (0)                                (1)
#define  CPU_INT_EN()          do { CPU_SR_Restore(cpu_sr); } while (0)                                (2)

#ifdef   CPU_CFG_INT_DIS_MEAS_EN

#define  CPU_CRITICAL_ENTER()  do { CPU_INT_DIS();         \
CPU_IntDisMeasStart(); }  while (0)

#define  CPU_CRITICAL_EXIT()   do { CPU_IntDisMeasStop();  \
CPU_INT_EN();          }  while (0)

#else

#define  CPU_CRITICAL_ENTER()  do { CPU_INT_DIS(); } while (0)
#define  CPU_CRITICAL_EXIT()   do { CPU_INT_EN();  } while (0)
#endif
1.    当CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_INT_DIS_EN时
    这种方式最简单,即直接使用处理器的开中断和关中断指令来实现宏。但是不推荐使用这种方式,因为不支持中断嵌套,但是考虑到有些处理器或者编译器仅支持这种方式,不得不选择这种方式。
2.    当CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_INT_DIS_EN时
    这种方法稍复杂些,但可使CPU中断使能标志的状态在临界段前和临界段后不发生变化。
    进入临界段前:
        (1) Push/save  中断状态保存到堆栈中
        (2) Disable    关闭中断
    退出临界段:
        (3) Pop/restore  恢复中断标志
3.    当CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL时
    这种方法的前提是,用户使用的C编译器具有扩展功能。用户可获得程序状态字的值,这样就可把该值保存在C函数的局部变量中,而不必压到堆栈里。上面的宏定义就是采用的这种方式,也就是(1),(2)注释的地方。
4.    关于临界段,在文件os.h中也有几个相关的宏定义,这几个宏定义的含义会在后面跟大家讲
#if      OS_CFG_SCHED_LOCK_TIME_MEAS_EN> 0u && defined(CPU_CFG_INT_DIS_MEAS_EN)
#define OS_SCHED_LOCK_TIME_MEAS_START()   OS_SchedLockTimeMeasStart()
#else
#define OS_SCHED_LOCK_TIME_MEAS_START()
#endif


#if     OS_CFG_SCHED_LOCK_TIME_MEAS_EN > 0u && defined(CPU_CFG_INT_DIS_MEAS_EN)
#define OS_SCHED_LOCK_TIME_MEAS_STOP()    OS_SchedLockTimeMeasStop()
#else
#define OS_SCHED_LOCK_TIME_MEAS_STOP()
#endif

#if OS_CFG_ISR_POST_DEFERRED_EN > 0u                      /* Deferred ISR Posts */
                                                          /* Lock the scheduler */
#define  OS_CRITICAL_ENTER()                                       \
         do {                                                     \
            CPU_CRITICAL_ENTER();                                \
            OSSchedLockNestingCtr++;                              \
             if(OSSchedLockNestingCtr == 1u) {                    \
                OS_SCHED_LOCK_TIME_MEAS_START();                  \
             }                                                     \
            CPU_CRITICAL_EXIT();                                  \
         } while (0)
                                                          /* Lock the scheduler but re-enable interrupts*/
#define  OS_CRITICAL_ENTER_CPU_EXIT()                              \
         do {                                                     \
            OSSchedLockNestingCtr++;                              \
                                                                  \
             if(OSSchedLockNestingCtr == 1u) {                    \
                OS_SCHED_LOCK_TIME_MEAS_START();                  \
             }                                                    \
            CPU_CRITICAL_EXIT();                                 \
         } while (0)

                                                         /* Scheduling occurs only if an interruptoccurs */
#define  OS_CRITICAL_EXIT()                                        \
         do {                                                      \
            CPU_CRITICAL_ENTER();                                 \
            OSSchedLockNestingCtr--;                              \
             if(OSSchedLockNestingCtr == (OS_NESTING_CTR)0) {     \
                 OS_SCHED_LOCK_TIME_MEAS_STOP();                   \
                 if(OSIntQNbrEntries > (OS_OBJ_QTY)0) {           \
                    CPU_CRITICAL_EXIT();                          \
                    OS_Sched0();                                  \
                 } else {                                          \
                    CPU_CRITICAL_EXIT();                          \
                 }                                                \
             } else {                                              \
                CPU_CRITICAL_EXIT();                              \
             }                                                    \
         } while (0)

#define OS_CRITICAL_EXIT_NO_SCHED()                               \
         do {                                                     \
            CPU_CRITICAL_ENTER();                                 \
            OSSchedLockNestingCtr--;                              \
             if(OSSchedLockNestingCtr == (OS_NESTING_CTR)0) {     \
                OS_SCHED_LOCK_TIME_MEAS_STOP();                   \
             }                                                    \
            CPU_CRITICAL_EXIT();                                 \
         } while (0)


#else                                             /* Direct ISR Posts  */


#define  OS_CRITICAL_ENTER()                    CPU_CRITICAL_ENTER()

#define OS_CRITICAL_ENTER_CPU_EXIT()

#define  OS_CRITICAL_EXIT()                     CPU_CRITICAL_EXIT()

#define OS_CRITICAL_EXIT_NO_SCHED()           CPU_CRITICAL_EXIT()

#endif

使用特权

评论回复
9
Eric2013|  楼主 | 2014-12-24 19:47 | 只看该作者
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
    源码中加入了部分安全关键的代码,内容如下:
/*
***********************************************************************************************************
*                                    创建对象已经不安全
*
* 函数说明: 这个函数是供用户调用的,用户一旦调用了这个函数就表示所有的初始化已经完成。内核对象不再运行被创建。
* 形    参: 无
* 返 回 值: 无
* 注    意: 无
***********************************************************************************************************
*/

#ifdef OS_SAFETY_CRITICAL_IEC61508
void  OSSafetyCriticalStart (void)
{
    OSSafetyCriticalStartFlag = DEF_TRUE;
}

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


使用特权

评论回复
10
Eric2013|  楼主 | 2014-12-24 20:20 | 只看该作者
剩下内容,明日继续,敬请期待,谢谢各位!

使用特权

评论回复
11
Eric2013|  楼主 | 2014-12-25 16:42 | 只看该作者
11.9  任务切换
    如果大家认真学习了前面几期教程,μCOS-III中的任务切换还是很好理解的。μCOS-III中的任务切换主要分为两部分,一个是中断级任务切换,另一个是任务级中断切换。
11.9.1      任务级任务切换OSSched()
    任务级的任务切换主要通过下面的函数实现:
/*
************************************************************************************************************                                                      任务级调度
*
* 函数说明: 此函数由其它的uC/OS-III函数调用,主要是用来获取当前需要执行的最高优先级任务,这个是任务级调度,*           要和前面的中断级调度OSIntExit()区分开。
* 形    参: 无
* 返 回 值: 无
* 注    意: 1) 使用调度锁的话,调度功能将被关闭 (见 OSSchedLock())
***********************************************************************************************************
*/

void  OSSched (void)
{
    CPU_SR_ALLOC();                                                                                   (1)



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

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

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

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

#if defined(OS_CFG_TLS_TBL_SIZE) && (OS_CFG_TLS_TBL_SIZE > 0u)
    OS_TLS_TaskSw();
#endif

    OS_TASK_SW();                                       /* 执行任务切换  */                           (6)
    CPU_INT_EN();
}
1.    这句话在前面临界段小节有讲,这里是定义一个局部变量。
2.    存在中断嵌套的情况下调用这个函数会返回。
3.    调度器被锁的情况下调用这个函数会返回。
4.    这个函数是获取当前需要执行的最高优先级任务的方法,也算是调度器的核心,在下期教程会给大家详细的讲解。
5.    由于μCOS-III已经支持时间片调度,这句话是从同优先级的链表中获得当前需要执行的任务。
6.    执行任务级任务切换。
11.9.2      中断级任务切换OSIntExit()
    中断级任务切换是由中断函数调用的,内容如下:
/*
***********************************************************************************************************
*                                                进入中断服务程序
* 功能说明: 此函数用通知uC/OS-III系统程序将要执行interrupt service routine(ISR)。这样uC/OS-III就可以不断
*           跟踪中断嵌套次数的变化,这样就能够保证系统只有在最后一层中断执行任务调度。
* 形    参: 无
* 返 回 值: 无
* 注    意: 1) 此函数必须在中断关闭情况下调用。
*           2) 用户可以不调用这个函数,直接调用全局变量OSIntNestingCtr进行操作即可。
*           3) 用户必须调用函数OSIntExit(),即使直接的操作'OSIntNestingCtr'。
*           4) 用户必须成对的调用OSIntEnter() 和 OSIntExit()。换句话说,用户必须在中断服务程序开始和结尾的
*              时候成对调用OSIntEnter() 和 OSIntExit()。        
*           5) uC/OS-III系统的中断嵌套层数最高250。
***********************************************************************************************************
*/

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

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

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

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

void  OSIntExit (void)
{
    CPU_SR_ALLOC();



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

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

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

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

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

#if defined(OS_CFG_TLS_TBL_SIZE) && (OS_CFG_TLS_TBL_SIZE > 0u)
    OS_TLS_TaskSw();
#endif

    OSIntCtxSw();                                 /* 执行中断级任务切换 */                            (4)
    CPU_INT_EN();
}
1.    OSIntEnter()和OSIntExit()必须配套的使用,要不会造成嵌套计数错误。
2.    嵌套计数加一。
3.    嵌套次数减一。
4.    执行中断级任务切换。
11.9.3      函数使用举例
    函数OSSched ()不是供用户调用的,而函数OSIntEnter() 和 OSIntExit()是供用户在中断任务中调用的,下面举个例子:
/*
*********************************************************************************************************
*    函 数 名: SDIO_IRQHandler
*    功能说明: SDIO中断服务程序
*    形    参:无
*    返 回 值: 无
*********************************************************************************************************
*/
void SDIO_IRQHandler(void)
{
     CPU_SR_ALLOC();
   
     CPU_CRITICAL_ENTER();
     OSIntEnter()
     CPU_CRITICAL_EXIT();

     SD_ProcessIRQSrc();

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


使用特权

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

void  OSSchedLock (OS_ERR  *p_err)
{
    CPU_SR_ALLOC();



#ifdef OS_SAFETY_CRITICAL
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return;
    }
#endif

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

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

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

    CPU_CRITICAL_ENTER();
    OSSchedLockNestingCtr++;                              /* 增加嵌套次数 */                         (3)
#if OS_CFG_SCHED_LOCK_TIME_MEAS_EN > 0u
    OS_SchedLockTimeMeasStart();                                                                     (4)
#endif
    CPU_CRITICAL_EXIT();
   *p_err = OS_ERR_NONE;
}
1.    这里表示不允许在中断服务程序中调用调度锁函数。
2.    调度锁的嵌套次数范围0~250,用户不能超出250。
3.    嵌套次数加一。
4.    开启调度锁时间测量,这里是记录一下起始时间。

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

void  OSSchedUnlock (OS_ERR  *p_err)
{
    CPU_SR_ALLOC();



#ifdef OS_SAFETY_CRITICAL
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return;
    }
#endif

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

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

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

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

#if OS_CFG_SCHED_LOCK_TIME_MEAS_EN > 0u
    OS_SchedLockTimeMeasStop();
#endif

    CPU_CRITICAL_EXIT();                                 /* 重新使能调度器  */
    OSSched();                                           /* 运行调度器  */                           (2)
   *p_err = OS_ERR_NONE;
}
1.    调度锁嵌套计数减一。
2.    调度器被锁期间,有些任务可能会就绪,所以这里加上了调度函数。

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

#if OS_CFG_SCHED_LOCK_TIME_MEAS_EN > 0u
void  OS_SchedLockTimeMeasStart (void)
{
    if (OSSchedLockNestingCtr == 1u) {
        OSSchedLockTimeBegin = CPU_TS_TmrRd();
    }
}

void  OS_SchedLockTimeMeasStop (void)
{
    CPU_TS_TMR  delta;


    if (OSSchedLockNestingCtr == (OS_NESTING_CTR)0) {    /* 确认没有调度锁嵌套  */
        delta = CPU_TS_TmrRd()                           /* 计算时间差 */
              - OSSchedLockTimeBegin;
        if (OSSchedLockTimeMax    < delta) {             /* 检测最大值*/
            OSSchedLockTimeMax    = delta;
        }
        if (OSSchedLockTimeMaxCur < delta) {             /* 检测最大值(for resettable value) */
            OSSchedLockTimeMaxCur = delta;
        }
    }
}
#endif

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

     (void)p_arg;
         
     while(1)
     {   
         SemFlag = BSP_OS_SemWait(&SEM_SYNCH, 0);
         if(SemFlag == DEF_OK)
         {   
              sprintf(buf,"0:/Picture/%d.bmp",Pic_Name);
              OSSchedLock(&err);
              GUI_SaveBMP(0, 0, LCD_GetXSize(), LCD_GetYSize(),buf);
              OSSchedUnlock(&err);      
         }                                                                                                                  
     }  
}


使用特权

评论回复
13
Eric2013|  楼主 | 2014-12-25 16:52 | 只看该作者
11.11  Round-Robin调度
    μCOS-III中的时间片调度功能做的很完善,支持全局的时间片设置,也支持每个任务的单独设置。关于时间片调度,咱们在前几期教程也有讲解。
11.11.1      配置参数OSSchedRoundRobinCfg()
/*
***********************************************************************************************************
*                                      配置ROUND-ROBIN调度参数
*
* 函数功能: 调用此函数用更改ROUND-ROBIN调度的参数。
* 形    参: en                DEF_EN:使能ROUND-ROBIN
*                             DEF_DIS:禁止ROUND-ROBIN
*           dflt_time_quanta  默认的时间片数,如果是0 那么就表示时间片是默认的OSCfg_TickRate_Hz / 10.
*           p_err             错误代码指针变量
*                             OS_ERR_NONE       调用成功
* 返 回 值: 无
***********************************************************************************************************
*/

#if OS_CFG_SCHED_ROUND_ROBIN_EN > 0u
void  OSSchedRoundRobinCfg (CPU_BOOLEAN   en,
                            OS_TICK       dflt_time_quanta,
                            OS_ERR       *p_err)
{
    CPU_SR_ALLOC();


#ifdef OS_SAFETY_CRITICAL
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return;
    }
#endif

    CPU_CRITICAL_ENTER();                                                                        (1)
    if (en != DEF_ENABLED) {                                                                     (2)
        OSSchedRoundRobinEn = DEF_DISABLED;
    } else {
        OSSchedRoundRobinEn = DEF_ENABLED;
    }

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

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

#if OS_CFG_SCHED_ROUND_ROBIN_EN > 0u
void  OSSchedRoundRobinYield (OS_ERR  *p_err)
{
    OS_RDY_LIST  *p_rdy_list;
    OS_TCB       *p_tcb;
    CPU_SR_ALLOC();



#ifdef OS_SAFETY_CRITICAL
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return;
    }
#endif

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

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

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

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

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

    CPU_CRITICAL_EXIT();

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

11.11.3      Round-Robin调度算法OS_SchedRoundRobin()
    当多个任务有相同的优先级时,μCOS-III允许任务在切换到另一个任务前运行特定的时间,也就是大家常说的时间片。这个过程就是Round-Robin调度或者时间片调度。如果任务不需要将所有的时间片用完,可以调用上面讲的函数OSSchedRoundRobinYield (),放弃剩余时间片从而切换到同优先级的另一个任务。μCOS-III支持用户在系统运行过程中使能或者禁止时间片调度,同时也支持全局的时间片设置,也支持每个任务的单独设置。
    为了更好的说明Round-Robin调度算法,下面举一个例子(截图来自官方书籍):Task #1,Task #2,Task#3都运行在优先级 X,任务运行的时间片个数都是4。


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个时间片,图片上面画的不是很准确。
    有了上面基础后,在解析一下相关函数。
/*
***********************************************************************************************************
*                                        运行ROUND-ROBIN 调度算法
*
* 函数说明: 此函数每个嘀嗒定时器中断被调用,通过此函数来计算同优先级中是否有任务要执行。
* 形    参: p_rdy_list   就绪链表指针
* 返 回 值: 无
* 注    意: 1) 内部函数调用,用户程序不能调用
***********************************************************************************************************
*/

#if OS_CFG_SCHED_ROUND_ROBIN_EN > 0u
void  OS_SchedRoundRobin (OS_RDY_LIST  *p_rdy_list)
{
    OS_TCB   *p_tcb;
    CPU_SR_ALLOC();



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

    CPU_CRITICAL_ENTER();
    p_tcb = p_rdy_list->HeadPtr;                                 

    if (p_tcb == (OS_TCB *)0) {                                                                      (2)
        CPU_CRITICAL_EXIT();
        return;
    }

    if (p_tcb == &OSIdleTaskTCB) {                                                                   (3)
        CPU_CRITICAL_EXIT();
        return;
    }

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

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

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

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

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

11.11.4      函数使用举例
/*
*********************************************************************************************************
*    函数名: main
*    功能说明: 标准c程序入口。
*    形   参:无
*    返回值: 无
*********************************************************************************************************
*/

int main(void)
{
    OS_ERR  err;
   
OSInit(&err);
                                            
     /* 使能并设置全局时间片个数 */
    OSSchedRoundRobinCfg(DEF_ENABLED,
                             8,
                             &err);

     OSTaskCreate((OS_TCB       *)&AppTaskStartTCB,           
                 (CPU_CHAR     *)"App Task Start",
                 (OS_TASK_PTR   )AppTaskStart,
                 (void         *)0,
                 (OS_PRIO       )APP_CFG_TASK_START_PRIO,
                 (CPU_STK      *)&AppTaskStartStk[0],
                 (CPU_STK_SIZE  )APP_CFG_TASK_START_STK_SIZE / 10,
                 (CPU_STK_SIZE  )APP_CFG_TASK_START_STK_SIZE,
                 (OS_MSG_QTY    )0,
                 (OS_TICK       )0,
                 (void         *)0,
                 (OS_OPT        )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
                 (OS_ERR       *)&err);

OSStart(&err);  
                                                
    return (0);
}


/*
*********************************************************************************************************
*    函 数 名: AppTaskCom
*    功能说明: 此任务未使用     
*    形    参:p_arg 是在创建该任务时传递的形参
*    返 回 值: 无
*********************************************************************************************************
*/

static void AppTaskCOM(void *p_arg)
{   
     OS_ERR  err;

(void)p_arg;
   
      
     while(1)
     {
          ……
         OSSchedRoundRobinYield (&err);
         ……
     }
                                                                                                      
  
}


使用特权

评论回复
14
Eric2013|  楼主 | 2014-12-25 16:53 | 只看该作者
11.12  总结
    本期教程涉及到的内容较多,如果是初学的,一定要多花点时间消耗下,如果学习过程中遇到很多问题,不要担心,随着后面教程的进行会理解的更深刻。

使用特权

评论回复
15
hqtdzgs| | 2014-12-26 16:05 | 只看该作者
OS部分,要看看

使用特权

评论回复
16
fanxsd| | 2014-12-26 16:08 | 只看该作者
Eric2013 发表于 2014-12-25 16:53
11.12  总结    本期教程涉及到的内容较多,如果是初学的,一定要多花点时间消耗下,如果学习过程中遇到很 ...

出书了吗 或者PDF整套的文档,要好好学习一下

使用特权

评论回复
17
Eric2013|  楼主 | 2014-12-26 16:23 | 只看该作者
fanxsd 发表于 2014-12-26 16:08
出书了吗 或者PDF整套的文档,要好好学习一下

在这里下载PDF文档和配套例子:http://bbs.armfly.com/read.php?tid=1788

使用特权

评论回复
18
kfliuyan| | 2014-12-28 19:36 | 只看该作者
谢谢分享

使用特权

评论回复
19
白丁野老| | 2014-12-30 21:20 | 只看该作者
多谢楼主分享

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:RTX->μCOS-II->FreeRTOS->embOS->μCOS-III μCGUI->emWin->FatFs->DSP 淘宝:armfly.taobao.com

115

主题

639

帖子

34

粉丝