3

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

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

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 时,就会出现问题。

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

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

4

6 回答 6

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 测试和两个变量,所以可能有一个更有效的解决方案。

于 2012-04-27T12:39:28.633 回答
1

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

elapsed = (TimerReg - start)&0xFFF;

这是非常便宜的

elapsed = (TimerReg - start)%1000; 

是你现在的位置,非常昂贵。

不太糟糕的替代方案是爱德华发布的内容,基本上检查翻车

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

以上所有内容都假设一个向上计数的计时器。

微控制器通常包含多个计时器,最好留下一个计数到最大计数(0xFFFF 或 0xFFFFFFFF 或其他)并翻转为零的计时器,这样您就可以立即使用 - 持续任何您想要测量时间的时间(短于翻转值得时间)。

于 2012-04-27T13:49:28.350 回答
0

如果你有一个真正的硬件计时器,你可以这样做:

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

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

于 2012-04-27T13:54:03.777 回答
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); 
} 
于 2012-04-27T14:29:42.520 回答
0

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

于 2012-04-27T14:21:37.260 回答
-1

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

volatile int TimerReg;

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

    while (TimerReg != future);
}

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

于 2012-05-01T07:34:59.493 回答