Atmega8 上的时钟

Posted

技术标签:

【中文标题】Atmega8 上的时钟【英文标题】:Clock on Atmega8 【发布时间】:2014-10-11 17:18:22 【问题描述】:

我正在尝试在 Atmega8 上做一个时钟。 我有 8Mhz 石英。

我使用 timer0 中断作为时钟计时:

/* Settings */
#define TMR_RELOAD      80 - 5 /* 8 kHz / 80 = 100 Hz */

#define TMR_CNT_MAX     100 /* 1Hz internal counter */

/* internal variables */
static uint8_t tmr_cnt;

inline void TMR0_Init()

  /* set clock source f_t0 = 8МHz/1024 = 8 kHz */
  TCCR0 = _BV(CS00) | _BV(CS02);

  TIMSK |= _BV(TOIE0); /* Enable TMR0 interrupt on overflow*/


ISR (TIMER0_OVF_vect)

  if (tmr_cnt == 0)
    Clock_Tick1s();


  tmr_cnt++;
  if (tmr_cnt >= TMR_CNT_MAX)
    tmr_cnt = 0;


  TCNT0 -= TMR_RELOAD;

问题是我的时钟跑得太快或太慢了。

我放入 TCNT0 寄存器的计算值是 80,但在这种情况下时钟运行得太慢了。 当我使用 80-4 时,时钟也运行得太慢了。我用80-5的时候太快了。

我不知道,怎么可能???

更新: 现在设置如下,但问题依然存在。

/* Settings */
#define TMR_RELOAD      125 /* 31.25 kHz / 125 = 250 Hz */
#define TMR_CNT_MAX     250 /* 1Hz internal counter */

inline void TMR0_Init()

  /* set clock source f_t0 = 8МHz/256 = 31.25 kHz */
  TCCR0 = _BV(CS02);

  TIMSK |= _BV(TOIE0); /* Enable TMR0 interrupt on overflow*/


ISR (TIMER0_OVF_vect)

  TCNT0 -= TMR_RELOAD;

  if (tmr_cnt == 0)
    Clock_Tick1s();

  tmr_cnt++;
  if (tmr_cnt >= TMR_CNT_MAX)
    tmr_cnt = 0;
 

【问题讨论】:

“太快”是多少?例如每小时多少秒?有示波器吗? 每 3 小时大约 5 分钟。不,我没有示波器。 【参考方案1】:

请注意,当您调用时

TCNT0 -= TMR_RELOAD;

TCNT0 寄存器已经为 0。所以你得到 TCNT0 = 131,这需要 124 个滴答声才能溢出。这意味着你的时钟是

1/31250 * 250 = 8ms

每秒更快,结果是

8ms * 60 x 60 x3 = 86.4s

每 3 小时。这不是您在 cmets 中提到的 5 分钟,但错误就在那里。您的 8MHz 晶体可能会产生一些额外的错误。这取决于晶体质量以及谐振电路的设计。

我建议您使用 Timer2 的输出比较中断,而不是使用溢出中断并重新加载 TCNT 值。

“输出比较寄存器包含一个 8 位值,它与计数器值 (TCNT2) 持续进行比较。匹配可用于生成输出比较中断...”

它更容易处理,您不必处理“重新加载”计时器。

您也可以考虑使用 32.768kHz 时钟晶体。

【讨论】:

1) 以 250Hz 的频率发生中断。 1/250 = 4 毫秒。它计算 125 个 TMR0 滴答 => 1 个额外的 TMR0 计数 = 4ms / 125 = 32 uS。 32 uS * 60 * 60 = 115.2 毫秒/小时。或每 3 小时 0.35 秒。 ------- 2) “输出比较寄存器包含一个 8 位值,该值与计数器值 (TCNT2) 连续比较。匹配可用于生成输出比较中断......”为了在中断之前有自定义时间间隔,无论如何您都需要将新值加载到 TCNT2 中。 3) 今天我注意到当我离开公寓时出现了很大的延迟(每 10 小时 4 小时)。可能也是电源的问题。 4) 感谢您的帮助! @vitperov:嗯。如果寄存器 TCNT0 仅计数 124 而不是 125,则寄存器 TCNT0 为 1“滴答”关闭(1/31250 = 32us)。由于您在一秒完成之前计数到 250,因此您每秒关闭 250 * 32us -> 8ms。还是我错过了什么? 你是对的!每小时 30 秒,每 3 小时 86.4 秒。【参考方案2】:

第一个问题很明显,频率为8MHz/1024=7812.5 Hz,即使用80没有意义。操作 TCNT0 也是一个问题,因为自从计数器达到零并执行中断并且代码流到达最后一条指令后,存在一些延迟。第三个是晶振频率,你确定真的是8MHz吗?因为不适当的容性负载或只是频移可能会带来时序误差。

【讨论】:

谢谢!我修复了频率分配器并将TCNT0 -= TMR_RELOAD 移动到中断函数的开头。几个小时后我们会看到它是否有帮助。谢谢!

以上是关于Atmega8 上的时钟的主要内容,如果未能解决你的问题,请参考以下文章

Arduino生成ATmega8的运行程序并下载

ATMEGA8A + SPI 内存异常行为

利用Arduino IDE对ATMEGA8等单片机编程

ATmega8仿真——LED 数码管的学习

基于ATMEGA8的Arduino Nano(UNO)开发板

AVR UART 接收到错误的字节