使用计时器延迟

时间:2012-04-27 12:22:18

标签: c embedded

我需要用硬件定时器实现延迟功能。计时器值每毫秒递增一次。

通常的方法是使用定时器寄存器的宽度并使用与

对应的模数行为
volatile int TimerReg;

void Delay(int amount)
{
    int start = TimerReg;
    int elapsed;

    do
    {
        eleapsed = TimerReg - start;
    } while (elapsed < amount);
}

这在TimerReg的宽度为int时有效。在这种情况下,差异now - start是一个稳定增长的值。

但是当TimerReg的宽度小于int的宽度时,或者(在我的情况下)定时器仅从0..1000开始计数,当计时器从999超过1000到0时会出现问题。 / p>

使用这样的计时器有什么好方法? 我想避免模运算,因为这在微控制器上很昂贵。

编辑:分区模块尚未包含在微控制器代码中。

6 个答案:

答案 0 :(得分:3)

这样的事情怎么样:

volatile int TimerReg;

void Delay(int amount)
{
  int start = TimerReg;
  int elapsed;
  int rolled_over = 0;
  int last_time = start;

  do
  {
    int timer_reg = TimerReg;
    // Check for rollover
    if(last_time > timer_reg) {
      // ROLLOVER_INTERVAL is the magic number at which the timer rolls over to 0
      rolled_over += ROLLOVER_INTERVAL - start;
      start = 0;
    }
    last_time = timer_reg;
    if(rolled_over == 0) {
      elapsed = timer_reg - start;
    } else {
      elapsed = timer_reg + rolled_over;
    }
  } while (elapsed < amount);
}

当然,还有两个if-tests和另外两个变量,所以可能有更高效的解决方案。

答案 1 :(得分:1)

谁控制定时器翻转?如果您可以将其更改为例如0xFFF翻转到0x000而不是999到000,那么您可以使用简单的掩码

elapsed = (TimerReg - start)&0xFFF;

哪个很便宜

elapsed = (TimerReg - start)%1000; 

是你现在所处的地方非常昂贵。

另一个不那么糟糕的选择是Edvard发布的内容,基本上是检查滚动

nowtime = TimerReg;
if(nowtime < start)
{
   elapsed = (1000 - start) + nowtime;
}
else
{
   elapsed = nowtime - start;
}

以上所有假设都是一个向上计时器。

微控制器通常包含多个定时器,最好留下一个计数到最大计数(0xFFFF或0xFFFFFFFF或其他)并滚动到零,以便您可以立即使用 - 最后一次您想要测量时间(比翻滚价值的时间短。)

答案 2 :(得分:0)

如果你有一个真正的硬件计时器,你会喜欢这样:

start_timer();
while ( (timer_flag_register & bitmask)==0 )
{
  do_stuff();
}

其中start_timer()将硬件定时器计数器设置为[主定时器计数器] + [延迟时间]。经过一段时间后,硬件会设置一个标志(或调用中断服务程序)。几乎每个MCU上的每个硬件定时器都以这种方式工作。

答案 3 :(得分:0)

当计时器达到其值时,您可以使用中断来递增全局计数器(例如,每1000毫秒)。

答案 4 :(得分:0)

我明白了。当定时器寄存器的宽度与int的宽度相同时,这是隐含的。将计时器的数字圆圈添加到elapsed值是足够的,当它为负值时,将其置于有效范围内。

volatile int TimerReg; /* value range: 0..999 */
const int TimerMaxValue = 999;

void Delay(int amount) 
{ 
    int start = TimerReg; 
    int elapsed; 

    do 
    { 
        eleapsed = TimerReg - start;
        if (elapsed < 0) eplapsed += (TimerMaxValue + 1);
    } while (elapsed < amount); 
} 

答案 5 :(得分:-1)

您的1ms定时器(奈奎斯特频率)比您的轮询代码慢得多。因此,您可以简单地使用uqual运算符'=':

volatile int TimerReg;

void Delay(int amount)
{
    int future = TimerReg + amount;

    while (TimerReg != future);
}

在我看来,这是一个优雅的解决方案,但它只有在'TimerReg'可以在其全范围内自由运行时才有效,例如: '0xFFFF的'。