Таймер 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

Обсуждение

Я думаю, что потенциальным решением может быть активация в прерывании установки при совпадении, принудительное совпадение, а затем возврат к очистке при совпадении (и, возможно, принудительное совпадение снова, если я обнаружу, что принудительное и «реальное» совпадения накладываются друг на друга). Я не смогу попробовать это до сегодняшнего дня, и это все еще кажется неоправданно сложным., @Tom van der Zanden

Почему бы вам не использовать режим 7 вместо режима 2? Режим 7 объединяет CTC с быстрой ШИМ, что, похоже, вам и нужно, хотя он и не _официально_ называется «CTC» (но почему вас должно волновать официальное название?)., @Edgar Bonet

Используйте решение Эдгара. Или используйте ISR(TIMER2_COMPB_vect), чтобы установить вывод на низкий уровень, но это не идеально., @Gerben

Это имеет смысл. Кажется, мне следовало бы более внимательно прочитать ответы, которые я получил на свой исходный вопрос. Спасибо. Я не уверен, стоит ли мне удалять это сейчас (поскольку более внимательное прочтение исходного вопроса решает мою проблему), но мне все еще интересно, почему то, что я придумал, не работает и каково использование "clear on match" в режиме CTC. Кроме того, я думаю, что это сильный случай того, что я страдаю от [проблемы XY](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem)., @Tom van der Zanden


2 ответа


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

2

Режимы ШИМ управляют выводами на обоих концах цикла.

Суть режимов CTC в том, что они управляют выводом только на одном конце отсчета, но позволяют явно управлять другим концом.

Для явного управления обоими концами используйте обычный режим.

Чтобы установить бит OC2B с помощью FOC2B в TCCR2B с помощью прерывания:

ISR(TIMER2_COMPA_vect)
{
  TCCR2A |=  (1 << COM2B0); // Установить OC2B при сравнении совпадений
  TCCR2B |=  (1 << FOC2B ); // Принудительное сравнение выходных данных B OC2B
  TCCR2A &= ~(1 << COM2B0); // Очистить OC2B при сравнении совпадений
}
,

-3

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

TCCR2A = (1 << WGM20);

TCCR2B = (1 << WGM22);

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

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

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

,

Это было бы уместно, если бы OP использовал операторы |= и &=, чтобы изменить только _некоторые_ биты TCCR2A и TCCR2B. Однако OP уже _перезаписывает_ эти регистры оператором =, делая ваш ответ бессмысленным., @Edgar Bonet

Поскольку вы использовали форматирование блочных цитат, вероятно, вы откуда-то взяли эту информацию. Пожалуйста, отредактируйте свой ответ и включите ссылку на источник, откуда она взялась. Она случайно не отсюда, [Проблема с Timer2 в режиме CTC на плате arduino uno](https://www.avrfreaks.net/comment/1056146#comment-1056146)? Плагиат, как правило, не приветствуется., @Greenonline