Конфигурация прерывания AVR

Проблема в том, что временное поведение полностью неверно (фактор 30).

У меня есть ATmega 644PA, который работает с частотой 8 МГц (предохранитель CKDIV8 не установлен).
Я хотел прерывание каждые 1 мс. Я использую Timer1 (16-битный таймер) в режиме сравнения.
Прескалер был выбран в зависимости от диапазона времени, который мне нужен.
Здесь от 1 мс до ~ 2 с. (ограничено 16-битным регистром таймера)

Расчет

ЦП: 8.000.000 Гц
Предделитель: 256

8.000.000 Гц / 256 = 31250 циклов / с (Гц)

1000 мс = 31250 циклов
1 мс = 30,25 цикла (31,25 - 1, запуск регистрации таймера с 0)

Отсюда я могу рассчитать это, например:
100 мс = 3025 циклов
2 с = 60500 циклов

Код

Запуск таймера

    cli();                  // disable global interrupts
    TCCR1A = (1 << WGM01);  // CTC ON
    TCCR1B = 0x04;          // Prescaler 256
    OCR1A  = 30;            // set compare reg.
    TIMSK1 = (1 << OCIE1A); // set interrupt mask
    TCNT1  = 0x00;          // set counter reg. to zero
    sei();                  // enable global interrupts

ISR:

ISR(TIMER1_COMPA_vect)
{
  // start own code
  ...
  // end own code
  TCNT1 = 0x00; // reset counter reg. to zero after match (same which should CTC do)
}

Теперь у меня есть, например, изменчивая переменная, которая будет увеличиваться в функции ISR.
Я опрашиваю переменную и жду так долго, пока она не достигнет 60500, что равно 2 с.
После этого я просто зажег светодиод.

Я измерил это по телефону, и до того, как загорится светодиод, требуется 1 минута.
Это занимает слишком много времени с множителем 30 => 60 секунд, разделенных на 2, равны 30.
Я также пытался использовать внешнюю программу для вычисления этого, она пришла к тем же результатам. (0x1E = 30)
 Снимок экрана

Кто-то знает, в чем моя ошибка?


person RisuRyu    schedule 27.12.2016    source источник


Ответы (1)


2 секунды - это 60500 циклов. Но ваша ISR увеличивает изменчивую переменную каждые 1 миллисекунду. Естественно, чтобы переменная достигла значения 60500, потребуется 60,5 секунд.

В качестве примечания, лучше изменить значение сравнения, чем сбрасывать TCNT, чтобы избежать временного дрейфа. То есть, позвольте счетчику работать свободно, и используйте OCR1A += 31; для перехода к следующему прерыванию. При сбросе TCNT время в ISR игнорируется.

person uncleO    schedule 27.12.2016
comment
Спасибо, это имеет смысл. - person RisuRyu; 28.12.2016