Таймер 2 «Очистить OC2B при сравнении совпадений» не работает в режиме CTC

Это продолжение моего предыдущего вопроса.

У меня Timer2 находится в режиме CTC, при этом TOP=OCR2A установлен на 150 (с предварительным делителем 8, что дает временной интервал 75 мкс).

В техническом описании указано, что установка COM2B1 в 1 в TCCR2A «очистит OC2B при сравнении» (= вывод D3 Arduino), когда вы находитесь в режиме CTC.

Я хотел бы использовать эту функциональность для получения сигнала "ШИМ" с периодом 75 мкс, с рабочим циклом, определяемым OCR2B. Я понимаю, что это очень запутанный способ достижения этого, но в конечном итоге я хочу постоянно изменять OCR2B, чтобы получить (быстро) изменяющийся рабочий цикл.

В прерывании канала сравнения A я хотел бы перевести D3 в высокий уровень, полагаясь на функцию «очистки при совпадении сравнения» канала B, чтобы перевести его в низкий уровень через небольшой промежуток времени.

У меня есть следующий минимальный пример:

#define OCIEA 1
#define CA21 1

void setup() {
  // PD3 как выход
  DDRD |= (1 << PD3);

  // Приостановите таймеры, чтобы они синхронизировались
  GTCCR = (1<<TSM)|(1<<PSRASY)|(1<<PSRSYNC); // Остановить все таймеры

  // Сбросить таймер
  TCNT2 = 0; // устанавливаем timer2 на 0 (8-битный таймер)

  // Включить режим CTC
  TCCR2A = (1 << WGM21); // Таймер 2 в CTC (TOP = OCR2A)

  // Очистить выходные контакты при сравнении совпадений
  TCCR2A |= (1 << COM2B1); // Очистить OC2B при совпадении

  // Установить предделитель
  TCCR2B = (1 << CA21); // устанавливаем делитель таймера 2 на 8

  // Установить сравнение выходных данных
  OCR2A = 150; // Определяет TOP для Timer2

  // Определяет ширину импульса
  OCR2B = 75; // Таймер 2 выход B (управляет OC2B = PD3 = D3)

  // Включить прерывания для таймера 2
  TIMSK2 = (1 << OCIEA);

  // Снова устанавливаем таймеры
  GTCCR = 0; // освободить все таймеры
}

ISR(TIMER2_COMPA_vect)
{
  TCCR2A &= ~((1 << COM2B1) | (1 << COM2B0)); // Отключить очистку OC2B при совпадении
  DDRD |= (1 << PD3); // Включить вывод
  PORTD |= (1 << PD3); // Выход высокий
  TCCR2A |= (1 << COM2B1); // Включить очистку OC2B при совпадении
}

void loop() {

}

В идеале ISR должен состоять только из PORTD |= (1 << PD3);, но это не дает желаемого мной 50% рабочего цикла, но, по-видимому, невозможно записывать на вывод при включенном COM2B1, поэтому я пробовал различные комбинации его отключения и повторного подключения вывода, но все, что я получаю, это очень, очень короткий импульс. Похоже, как только COM2B1 снова включается, вывод переходит на низкий уровень, хотя сопоставление сравнения на канале B еще не должно было произойти.

Установка COM2B0 вместо COM2B1 работает так, как и ожидалось: вывод переключает состояние (но это не то, что мне нужно).

Почему это не работает так, как я ожидаю, и есть ли способ получить желаемое поведение? Кроме того, если это невозможно, в чем, черт возьми, смысл функции очистки при сравнении совпадений, если вы вообще не можете включить пин при ее использовании?

Я обнаружил, что могу получить желаемое поведение, установив COM2B0 вместо COM2B1 (переключать при совпадении, а не очищать при совпадении) и принудительно выполнить сравнение в прерывании (выключая вывод), чтобы позже «реальное» переключение при совпадении выключило его. Однако это не идеально (так как если реальное и принудительное совпадение перекрываются, я теряю отслеживание состояния вывода), и мне все еще интересно, в чем смысл функции очистки при совпадении, если она просто принудительно устанавливает вывод на низкий уровень.

, 👍3


1 ответ


-3

Arduino предварительно настраивается как

TCCR2A = (1 << WGM20);

TCCR2B = (1 << WGM22);

таким образом Первоначально сбросить регистр

TCCR2A=0;//сброс регистра

TCCR2B=0;//сброс регистра

,