uCOSii系列 延时函数OSTimeDlyHMSM剖析

目前在学习uCOSii,基于STM32F103。对uCOS的延时函数觉得有意思。遂深入代码查看如何操作的。

首先回顾一下函数的基本用法.

例:OSTimeDlyHMSM(0, 0,1, 0); 是延时1秒。

括号里的参数分别为:小时,分钟,秒,毫秒。从函数名HMSM也可以看出,H=hours,M=minutes,S=seconds,M=ms。

查看代码:

*********************************************************************************************************
*                                     DELAY TASK FOR SPECIFIED TIME
*
* Description: This function is called to delay execution of the currently running task until some time
*              expires.  This call allows you to specify the delay time in HOURS, MINUTES, SECONDS and
*              MILLISECONDS instead of ticks.
*
* Arguments  : hours     specifies the number of hours that the task will be delayed (max. is 255)
*              minutes   specifies the number of minutes (max. 59)
*              seconds   specifies the number of seconds (max. 59)
*              milli     specifies the number of milliseconds (max. 999)
*
* Returns    : OS_ERR_NONE
*              OS_ERR_TIME_INVALID_MINUTES
*              OS_ERR_TIME_INVALID_SECONDS
*              OS_ERR_TIME_INVALID_MS
*              OS_ERR_TIME_ZERO_DLY
*              OS_ERR_TIME_DLY_ISR
*
* Note(s)    : The resolution on the milliseconds depends on the tick rate.  For example, you can't do
*              a 10 mS delay if the ticker interrupts every 100 mS.  In this case, the delay would be
*              set to 0.  The actual delay is rounded to the nearest tick.
*********************************************************************************************************
*/

#if OS_TIME_DLY_HMSM_EN > 0
INT8U  OSTimeDlyHMSM (INT8U hours, INT8U minutes, INT8U seconds, INT16U ms)
{
    INT32U ticks;
    INT16U loops;


    if (OSIntNesting > 0) {                      /* See if trying to call from an ISR                  */
        return (OS_ERR_TIME_DLY_ISR);
    }
#if OS_ARG_CHK_EN > 0
    if (hours == 0) {
        if (minutes == 0) {
            if (seconds == 0) {
                if (ms == 0) {
                    return (OS_ERR_TIME_ZERO_DLY);
                }
            }
        }
    }
    if (minutes > 59) {
        return (OS_ERR_TIME_INVALID_MINUTES);    /* Validate arguments to be within range              */
    }
    if (seconds > 59) {
        return (OS_ERR_TIME_INVALID_SECONDS);
    }
    if (ms > 999) {
        return (OS_ERR_TIME_INVALID_MS);
    }
#endif
                                                 /* Compute the total number of clock ticks required.. */
                                                 /* .. (rounded to the nearest tick)                   */
    ticks = ((INT32U)hours * 3600L + (INT32U)minutes * 60L + (INT32U)seconds) * OS_TICKS_PER_SEC
          + OS_TICKS_PER_SEC * ((INT32U)ms + 500L / OS_TICKS_PER_SEC) / 1000L;
    loops = (INT16U)(ticks >> 16);               /* Compute the integral number of 65536 tick delays   */
    ticks = ticks & 0xFFFFL;                     /* Obtain  the fractional number of ticks             */
    OSTimeDly((INT16U)ticks);
    while (loops > 0) {
        OSTimeDly((INT16U)32768u);
        OSTimeDly((INT16U)32768u);
        loops--;
    }
    return (OS_ERR_NONE);
}
#endif

可以发现在函数参数里hours,minutes,seconds为INT8U,8位无符号ms为INT16U,16为无符号。

在STM32F103系列中可知,hours,minutes,seconds这三个参数范围为0~255,ms参数范围为0~65535。

 

原代码中有两个宏定义,分别是:

1)OS_TIME_DLY_HMSM_EN

2)OS_ARG_CHK_EN

可以在os_cfg.h文件中找到。

对于1),如果想使用这个OSTimeDlyHMSM延时函数,则在os_cfg.h中把OS_TIME_DLY_HMSM_EN置为1即可。如果想裁剪这个函数,置为0就可以裁剪。编译的时候就不会把这个函数编译进去,达到裁剪的效果。

                                       /* --------------------- TIME MANAGEMENT ---------------------- */
#define OS_TIME_DLY_HMSM_EN       1    /*     Include code for OSTimeDlyHMSM()                         */
#define OS_TIME_DLY_RESUME_EN     1    /*     Include code for OSTimeDlyResume()                       */
#define OS_TIME_GET_SET_EN        1    /*     Include code for OSTimeGet() and OSTimeSet()             */
#define OS_TIME_TICK_HOOK_EN      1    /*     Include code for OSTimeTickHook()                        */

对于2),只是一个参数检测。如果想以符合现实时间概念来写延时函数的参数。就把OS_ARG_CHK_EN置为1即可。这样程序就会检测你的填写的参数是否符合。比如:minutes,seconds不能超过59,ms不能超过999。超过了就会返回错误提示,以及所有参数是否都为0,都为0则也返回错误提示。

                                       /* ---------------------- MISCELLANEOUS ----------------------- */
#define OS_APP_HOOKS_EN           1    /* Application-defined hooks are called from the uC/OS-II hooks */
#define OS_ARG_CHK_EN             0    /* Enable (1) or Disable (0) argument checking                  */
#define OS_CPU_HOOKS_EN           1    /* uC/OS-II hooks are found in the processor port files         */

 

查看一下是如何将时间计算为Tick的。

ticks = ((INT32U)hours * 3600L + (INT32U)minutes * 60L + (INT32U)seconds) * OS_TICKS_PER_SEC
          + OS_TICKS_PER_SEC * ((INT32U)ms + 500L / OS_TICKS_PER_SEC) / 1000L;

OS_TICKS_PER_SEC表示是1秒有多少个系统TICK。目前系统时间用的是STM32的SYSTICK,定时为10ms。即OS_TICKS_PER_SEC的数值为100。这个值也在os_cfg.h文件中。

#define OS_TICK_STEP_EN           1    /* Enable tick stepping feature for uC/OS-View                  */
#define OS_TICKS_PER_SEC       100    /* Set the number of ticks in one second  

((INT32U)hours * 3600L + (INT32U)minutes * 60L + (INT32U)seconds) * OS_TICKS_PER_SEC对于时,分,秒的TICK计算,这部分问题不大。前面都是算多少秒,后面再一起乘OS_TICKS_PER_SEC就能算出有多少个TICK。

关键是后面毫秒部分的计算。

OS_TICKS_PER_SEC * ((INT32U)ms + 500L / OS_TICKS_PER_SEC) / 1000L;

以我现在比如1ms,这也只算出0.6。数值也不是0.1个TICK,也不够1个TICK的基数。

找了一下,发现函数前面的注释做出来解释:

* Note(s)    : The resolution on the milliseconds depends on the tick rate.  For example, you can't do
*              a 10 mS delay if the ticker interrupts every 100 mS.  In this case, the delay would be
*              set to 0.  The actual delay is rounded to the nearest tick.

 

毫秒分辨率取决于TICK的速度。例如:如果ticker设置的时间中断为100ms,则不能进行10ms的延时。这种情况下,延迟会进行四舍五入。

比如我现在ticker是为10ms进中断,进行1ms的延时只会是四舍五入。但是延时又不能全部是0,就默认为1。1个TICK的延时。

你可能感兴趣的:(uCOSii)