我需要用硬件定时器实现延迟功能。计时器值每毫秒递增一次。
通常的方法是使用定时器寄存器的宽度并使用与
对应的模数行为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>
使用这样的计时器有什么好方法? 我想避免模运算,因为这在微控制器上很昂贵。
编辑:分区模块尚未包含在微控制器代码中。
答案 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的'。