【问题标题】:Clock on Atmega8Atmega8 上的时钟
【发布时间】: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 分钟。不,我没有示波器。

标签: microcontroller avr avr-gcc atmel atmega


【解决方案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 移动到中断函数的开头。几个小时后我们会看到它是否有帮助。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-08
  • 2023-03-10
相关资源
最近更新 更多