关于嵌入式C中的计时器

时间:2014-05-14 07:56:07

标签: c timer embedded avr

所以我明天要参加考试。我错过了一个讲座,但我有一个有记录的教授讲座。在讲座中,教授提到我们需要知道定时器如何在嵌入式处理器中工作。

我有一个基本的理解,但我对数学部分感到困惑。教授说,例如他会给我们一个以某种速率X运行的12位定时器。我们必须先设置定时器值并等待它溢出。如果我们希望定时器等待3毫秒,我们将定时器设置为什么?

此外,教授说"它是一个简单的数学,给我们时钟等于1,000,000,时间将是1000,所以我们可以很容易地进行划分。"

有人可以解释一下定时器是如何正常工作的,以及我需要做些什么来正确地获得数学部分。

3 个答案:

答案 0 :(得分:4)

大多数嵌入式计时器的工作方式如下:

  • 将计时器设置为某个初始值T
  • 启动计时器
  • 计时器每个计时器时钟减少一次
  • 当定时器达到0(或下溢超过0)时,产生中断

因此,经过的时间只有T / timer_clock_rate,其中T是初始计时器值,timer_clock_rate将取决于您如何配置计时器。

因此,例如,如果您想要3 ms延迟并且您的定时器时钟速率为1 MHz(即定时器每1μs递减一次),那么您需要初始定时器值3000(3000 x1μs= 3 ms)。

编辑:另见@ Rev1.0的答案 - 显然AVR计时器计数而非下降 - 请注意其他一些微控制器系列使用倒计时器。但是,相同的一般原则适用于两者,但是您加载的初始常量将根据您是否向上或向下计数而不同。

答案 1 :(得分:2)

虽然保罗的例子可能足以让你知道它是如何运作的,但它解决的问题与你提出的问题有些不同。

当计时器达到最大值时,会发生上述溢出。对于12位定时器(2 ^ 12),这将是4096。给定1MHz的时钟(每个刻度1个)你必须数到3000才能得到像保罗已经指出的3ms。

所以你要把定时器的初始值设置为4096 - 3000 = 1096,以便在3ms后发生溢出。

答案 2 :(得分:1)

只需按照尺寸即可。 X是每秒周期数,假设一个周期是一个周期(如果有预分频器,那么这里有另一个调整,定时器以滴答计数)。一秒钟是1000毫秒。所以只需安排所有这些尺寸,以便他们取消只留下你想要的尺寸

1 tick     X cycles   1 second            3 milliseconds
-------- * -------- * ----------------- * -------------- 
1 cycles   1 second   1000 milliseconds

取消所有单位除以自己。从小学数学(几乎)任何分开的东西都是一个,只需将其应用于单位。离去:

1 tick    X     1       3 
------ * --- * ----- * --- 
1         1    1000 

因此,无论您的定时器时钟源频率是以每秒周期数(Hz)为单位乘以3并除以1000.如果该时钟频率为1000000,则(1000000 * 3)/ 1000 = 3000。

这就是你如何轻松弄清楚什么是乘法和分成什么,适用于各种转换风格。无论如何,每小时英里数达到每秒公里数。

然后只需遵循Rev1.0的回答或Paul R.

有时你需要注意一件N-1的事情,要么记录在案,要么你可以测试。例如,如果你有一个递减计数器,文档会/应该说如果计时器翻转或中断它何时达到零或更晚,通常它们是在AFTER,当实际滚动​​发生时,所以3000到0包括3001计数,你稍微偏离,所以对于这样的系统,你需要用2999编程定时器以获得3000个滴答。对于向上计数器,它通常是两种方式中的一种,从零到编程值,从0到2999的相同交易计数得到3000计数,因此您可能在寄存器中编程2999而不是3000.或者您编程的值是Rev1.0显示的开始计数,并且翻转是在寄存器大小为的所有1值之后,在这种情况下,它们告诉你12位是0xFFF,不要使0xFFF - 3000错误并得到1095,容易按照Rev1.0所示的方式(0xFFF + 1)-3000 = 4096-3000 = 1096进行,这是你的开始计数。

同样适用于预分频器,你必须非常小心地阅读他们所说的你用2编程除以2还是编程1除以2?如果你编程0是一个除以1或无效或除以最大值,或无效的除数设置会发生什么?哪些适合尺寸分析?滴答/周期。预分频器除以8意味着每8个周期就会得到一个刻度,因此这是1个刻度/ 8个周期。

现在有时你会有一个系统时钟分为外设时钟而外设时钟是定时器的,那么你可能有预分频器那么n个系统时钟/ 1个外设时钟,然后1个外设时钟/ 1个定时器时钟,然后1个滴答是M个定时器时钟。把所有内容排成一列,除了一个取消之外,你就去了。

您也可以反过来这样做。从我们现在拥有的数字3000计时器滴答是3毫秒或0.003秒。 3000 / 0.003是每秒刻度或每秒周期1000000.

但是,如果我们有一个不同的控制器或一个我们不知道的时钟(或者我们有一个水晶我们知道但我们怀疑在某个地方我们无法在文档中找到预分频器),那么让定时器滚动超过4096个滴答例如,我们使用秒表或示波器或其他东西测量,在任何一种情况下都不准确,但可能会给我们一个粗略的想法,以确定是否有预分频器或我们实际运行的是什么时钟如果有pll倍增时钟等等。假设每4096个计时器刻度为0.0005秒,4096 / 0.0005 = 8192000 hz。现在,如果原理图中的晶体/振荡器或者我们可以读取器件的16Mhz表示有意义8000000/4096 = 0.000512而8Mhz是16Mhz的一半,那么你的测量结果可能是微弱的,时钟有一些准确性也可能会有所偏差。所以你查看文档以查看是否有内部振荡器,如果没有,那么你可能正在运行16Mhz时钟,但是有2个被记录,你没有找到或没有记录(它发生了一些时间) )并且您的计时器正在运行系统时钟/ 2。现在您可以将该数字用作X并找出您需要的任何数字。为什么不将计时器计数到1000或其他更容易计算的数字。这也很好,但可以做更多的工作和更多的实验,有时你有一个自由运行的计时器,你无法重置一些最大或最小计数,而你只能说

while(1)
{
while((read_timer()&0x1000)==0) continue;
turn_gpio_on();
while((read_timer()&0x1000)!=0) continue;
turn_gpio_off();
}

测量开启时间或关闭时间,即0x1000滴答。在你的计算器上进行十进制数学运算时,十六进制不是十进制数1000,但是当你只需使用一位和一位操作来切换gpio / led就可以了。

最后一点是,你可以阅读文档和原理图,并认为你知道它是如何工作的,但是你应该测试你的结果,如果你偏离一些整数倍,尤其是它是2的幂你的数学错误是一些整数,或者在你不知道的芯片中有一个时钟除数或者看起来不够难以找到,这也可能意味着你可能已经认为你将晶体速度提升到其他速度使用pll,也许那里有一个错误,芯片中的所有东西都没有以所需的速度运行。

(如果这个答案对你很有用,那么在向我提出保护之前,请先注意保罗和Rev1.0,谢谢,只需扩展他们的答案)。