ISR для очень быстрых процессов, обнаружен странный код. Влияет ли ISR на поведение таймера?

В примере я нашел следующий код для выполнения очень быстрых изменений на выходе PWM. Это работает, однако меня интересуют некоторые детали.

TIMER2 был настроен в setup() следующим образом:

TCCR2A = 0;               // We need no options in control register A
TCCR2B = (1 << CS21);     // Set prescaller to divide by 8
TIMSK2 = (1 << OCIE2A);   // Set timer to call ISR when TCNT2 = OCRA2
OCR2A = 32;               // sets the frequency of the generated wave
sei();                    // Enable interrupts to generate waveform!

Если я правильно понимаю, таймер будет работать до переполнения и генерировать прерывания в любое время между ними, как определено OCR2A.

ISR(TIMER2_COMPA_vect) {  // Вызывается каждый раз, когда TCNT2 == OCR2A
  static byte index=0;    // Указывает на последовательные записи в волновой таблице
  OCR1AL = wave[index++]; // Обновить выход ШИМ
  asm("NOP;NOP");         // Тонкая настройка
  TCNT2 = 6;              // Время для компенсации времени, проведенного в ISR
}

TIMER2 используется для вызова этой подпрограммы в равноудаленные моменты времени. Чтобы адаптировать интервал времени между двумя вызовами ISR, автор устанавливает OCR2A, а внутри ISR сбрасывает TCNT2. Поскольку таймер сбрасывается в конце ISR, некоторое время «уже прошло». записывается в начальное значение таймера. Однако есть две вещи, которых я не понимаю.

  1. Почему не используется режим CTC при установке WGM21 в TCCR2A? Это должно вызывать ISR через определенные промежутки времени.

  2. Если не используется режим CTC, счетчик должен быть сброшен ISR. Но почему это не делается непосредственно в начале ISR? Каждый раз, когда ISR получает какие-то незначительные изменения, значение коррекции, записанное в TCNT2, должно быть изменено.

Я упустил какую-то важную деталь? Или моя идея использовать CTC лучше?

Для полноты картины в setup() выполняются только настройки таймера1:

pinMode(9, OUTPUT);       // Делаем вывод ШИМ таймера выходным
TCCR1B  = (1 << CS10);    // Установите прескалер на полные 16 МГц
TCCR1A |= (1 << COM1A1);  // вывод ШИМ становится низким, когда TCNT1=OCR1A
TCCR1A |= (1 << WGM10);   // Переводим таймер в режим 8-битной быстрой ШИМ
TCCR1B |= (1 << WGM12); 

loop() пуст.

, 👍4

Обсуждение

Ммм, не использовать CTC в таком случае для меня тоже не имеет особого смысла. Тем более что таймер не останавливается при вызове ISR сравнения. Он будет продолжать работать нормально, пока работает ISR (поскольку таймер работает аппаратно). Я бы предположил, что это просто плохой код, @chrisl


1 ответ


Лучший ответ:

5

Почему не используется режим CTC при установке WGM21 в TCCR2A?

Поскольку мы не можем читать мысли автора, мы не можем сказать наверняка. Это существо сказал, мне, наиболее вероятная причина в том, что либо автор не был знали о режиме CTC или просто не думали об этом.

Вы правы в том, что CTC – самый простой способ получить точную интервалы. Вы также правы, что сброс таймера в конце ISR делает код несколько хрупким. Если по какой-то причине мне нужно чтобы избежать CTC в таком коде, я бы

OCR2A += 32;

вместо сброса TCNT2.

,

Я склонен думать, что автор недостаточно хорошо знал режим CTC. Иначе я не могу объяснить предложенное решение. Я был просто ошеломлен, потому что это было опубликовано в журнале. https://makezine.com/projects/advanced-arduino-sound- Synthese/ Не то чтобы я думаю, что это гарантия качества, но кто знает..., @Ariser