Таймер 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 (переключать при совпадении, а не очищать при совпадении) и принудительно выполнить сравнение в прерывании (выключая вывод), чтобы позже «реальное» переключение при совпадении выключило его. Однако это не идеально (так как если реальное и принудительное совпадение перекрываются, я теряю отслеживание состояния вывода), и мне все еще интересно, в чем смысл функции очистки при совпадении, если она просто принудительно устанавливает вывод на низкий уровень.
2 ответа
Лучший ответ:
Режимы ШИМ управляют выводами на обоих концах цикла.
Суть режимов CTC в том, что они управляют выводом только на одном конце отсчета, но позволяют явно управлять другим концом.
Для явного управления обоими концами используйте обычный режим.
Чтобы установить бит OC2B с помощью FOC2B в TCCR2B с помощью прерывания:
ISR(TIMER2_COMPA_vect)
{
TCCR2A |= (1 << COM2B0); // Установить OC2B при сравнении совпадений
TCCR2B |= (1 << FOC2B ); // Принудительное сравнение выходных данных B OC2B
TCCR2A &= ~(1 << COM2B0); // Очистить OC2B при сравнении совпадений
}
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
- Генерация стабильной частоты
- Генерация импульса 200 кГц на Arduino Uno в обычном режиме
- Изменчивая переменная не обновляется с таймера ISR
- ATmega328P - проблема с использованием таймера 2 для генерации тона
- Точность синхронизации Arduino nano
- Настройка таймера ATMega328p (Arduino)
- Интервальный таймер на Arduino: Сомнения по поводу библиотеки TimerOne
- Что означает «Обновление OCR1x в» в таблице WGM ATMEGA328?
Я думаю, что потенциальным решением может быть активация в прерывании установки при совпадении, принудительное совпадение, а затем возврат к очистке при совпадении (и, возможно, принудительное совпадение снова, если я обнаружу, что принудительное и «реальное» совпадения накладываются друг на друга). Я не смогу попробовать это до сегодняшнего дня, и это все еще кажется неоправданно сложным., @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