目前在学习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的延时。