时钟在Atmega8上

时间:2014-10-11 17:18:22

标签: microcontroller avr avr-gcc atmel atmega

我正在尝试在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;
 }

2 个答案:

答案 0 :(得分:2)

请注意,当您致电

TCNT0 -= TMR_RELOAD;

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

1/31250 * 250 = 8ms

每秒更快,导致

8ms * 60 x 60 x3 = 86.4s

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

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

  

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

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

您还可以考虑使用32.768kHz时钟晶振。

答案 1 :(得分:1)

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