ucosII 系统节拍、软件定时器节拍计算

一、 OS_TICKS_PER_SEC 

        OS_TICKS_PER_SEC 是系统节拍数的参数,代表着在1s的时间内系统进几次滴答中断进行任务调度。

如下例代码所示,

1.CPU主频为168M,滴答定时器时钟配置为8分频,即滴答定时器时钟为21M,代表着一秒钟计数21M次。

2.SysTick->LOAD为重装载寄存器,当其计数到0后进入滴答中断。

3.此时当重装载寄存器的值为21 * 1000000时,代表着1S进入1次滴答中断,将其与OS_TICKS_PER_SEC建立联系,即21 * 1000000 / OS_TICKS_PER_SEC .若OS_TICKS_PER_SEC = 200,则进入滴答中断的时间缩小200倍,代表着在1S时间内进入200次滴答定时器中断,所以滴答定时器的中断时间(任务调度周期)就为1/200 = 0.005S = 5 ms,频率F = 1/t = 200hz。

#define delay_ostickspersec	OS_TICKS_PER_SEC	//OS时钟节拍,即每秒调度次数

//STM32F407的系统运行时钟配置为168M,函数delay_init()传参168

void delay_init(u8 SYSCLK)

{
    u32 reload;

    SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); 
    
    reload=SYSCLK/8;                        //每秒钟的计数次数 单位为M       
    reload*=1000000/delay_ostickspersec;    //根据delay_ostickspersec设定溢出时间
                                            //reload为24位寄存器,最大值:16777216,在168M下,约合0.7989s左右           
    SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk;       //开启SYSTICK中断
    SysTick->LOAD=reload;                     //每1/delay_ostickspersec秒中断一次    
    SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk;     //开启SYSTICK     

}

二、OS_TMR_CFG_TICKS_PER_SEC

OS_TMR_CFG_TICKS_PER_SEC用于定时器分频,如图所示,定时器模块的时钟节拍实际上是Hook在操作系统的时钟节拍上再分频的,这也决定了其精度不会超过系统时钟节拍(好像超过了也没什么意义),跟Hook有关的代码(os_cpu_c.c中)如下:

……
#if (OS_TMR_EN > 0)
static  INT16U  OSTmrCtr;
#endif
……
void  OSTimeTickHook (void)
{
……
#if OS_TMR_EN > 0
    OSTmrCtr++;
    if (OSTmrCtr >= (OS_TICKS_PER_SEC / OS_TMR_CFG_TICKS_PER_SEC)) {
        OSTmrCtr = 0;
        OSTmrSignal();
    }
#endif
}
……


可以看出,实际上定时器模块是通过计数的方式对系统节拍进行了分频,系统每Tick了OS_TICKS_PER_SEC / OS_TMR_CFG_TICKS_PER_SEC下就通知(OSTmrSignal)一次定时器模块,要是OS_TMR_CFG_TICKS_PER_SEC大于OS_TICKS_PER_SEC 的话,那相除的结果就是0,也就是每次系统Tick都会通知定时器模块。再通过定时器的创建函数OSTmrCreate()中dly、period的周期来确认定时器的定时时间。

如下例所示,此时系统节拍为5MS进一次滴答中断,定时器则是在200/100次中断后通知定时器模块,period分别为 10 、 20,实现了100ms、200ms的定时,当定时时间到后调用相对应的回调函数进行操作。

#define OS_TICKS_PER_SEC        200u  
 /* Set the number of ticks in one second                        */
​​​​​​​#define OS_TMR_CFG_TICKS_PER_SEC 100u
/*Rate at which timer management task runs (Hz)            */



tmr1=OSTmrCreate(10,10,OS_TMR_OPT_PERIODIC,(OS_TMR_CALLBACK)tmr1_callback,0,"tmr1",&err);		//100ms执行一次
tmr2=OSTmrCreate(10,20,OS_TMR_OPT_PERIODIC,(OS_TMR_CALLBACK)tmr2_callback,0,"tmr2",&err);		//200ms执行一次

三、延时函数:以系统节拍数为单位

        OSTimeDly()是以系统节拍为处理单位的,实际的时间与希望的时间是有误差的,最坏的情况下误差接近一个系统节拍。因此时间管理服务函数只能用在对时间精度要求不高的场合,或者时间间隔较长的场合。

        通过一个实例来说明下:我们设计一个任务,让一个LED以50个时钟节拍为单位

void TaskLED (void *pdata)

{

…… //初始化代码

while (1)  //循坏控制LED以固定频率闪烁

{



IO0CLR = LED1;//点亮LED

OSTimeDly(25);//延时25个节拍

IO0SET = LED1;//熄灭LED

OSTimeDly(25);//延时25个节拍

}

}

注意:上面的设计是OSTimeDly() 控制任务的周期性执行,还可以用它来控制任务的运行节拍。

OSTimeDlyHMSM(hours, minutes,seconds, ms)是一个以时、分、秒、毫秒为参数的延时函数。函数在内部把这些参数转换为时钟节拍,再通过单次或多次调用OSTimeDly()进行延时和任务调度,所以延时原理和调用延时函数OSTimeDly()是一样的。

相关宏定义:

1)OS_TIME_DLY_HMSM_EN                //使能

2)OS_ARG_CHK_EN                //参数合法检测

对于延时的计算如下:

((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;

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

* 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的延时,精度单位为100ms。这种情况下,延迟会被四舍五入掉。

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

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值