Заставить TCNT оставаться ниже OCRxA на ATmega328P

Я использую таймер и ISR TIMERx_COMPA для генерации сигнала в «фоновом режиме».

Этот ISR срабатывает, когда таймер достигает определенного значения (OCRxA), которое, в свою очередь, может быть изменено пользователем. После срабатывания ISR таймер сбрасывается и наступает следующий период ожидания.

Если значение сравнения (OCRxA) изменяется на значение ниже текущего значения таймера до достижения старого значения сравнения, таймер продолжает работать до тех пор, пока не переполнится обратно до 0 и не достигнет нового

code>OCRxA значение. Это приводит к тому, что сигнал не генерируется до тех пор, пока таймер не зациклится, что может быть довольно долгим для 16-битного таймера TIMER1.

Есть несколько способов обойти эту проблему:

  1. Сбрасывайте TCNTx в ноль всякий раз, когда OCRxA. Легко, но один сигнал всегда будет не по времени.
  2. Если TCNTx больше, чем OCRxA (после изменения OCRxA), сбросьте его до значения чуть ниже OCRxA
  3. Если TCNTx больше, чем OCRxA, запустить прерывание вручную, при этом генерируется сигнал и TCNTx сбрасывается

Я считаю, что третий вариант будет самым чистым как с точки зрения проверки наличия проблемы, так и с точки зрения качества сигнала.

Это, безусловно, X ->; Да проблема, поэтому я открыт для других подходов.

Мой вопрос сейчас такой: Могу ли я вручную перейти к ISR независимо от его «нормального» триггера?

, 👍1

Обсуждение

@Juraj Правда, я полагаю, SE «Электротехника» был бы более подходящим? Однако я программирую Arduino Uno с помощью Arduino IDE. Я всегда чувствовал, что грань между этими двумя SE очень тонка, особенно когда Arduino используется только как простой способ программирования AVR., @towe

Я задаю конкретные вопросы по AVR на https://www.avrfreaks.net/forum/., @Juraj


1 ответ


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

2

Могу ли я вручную перейти к ISR независимо от его «нормального» триггера?

Это должно быть возможно, но, вероятно, это не лучшее решение.

Это, безусловно, X ->; Да проблема, поэтому я открыт для других подходы.

Кажется, вы используете таймер в режиме CTC. В этом режиме, когда вы пишете в OCRxA, регистр немедленно обновляется, что приводит к проблеме, с которой вы столкнулись. Решение состоит в том, чтобы вместо этого установить таймер в режим «быстрого ШИМ». В режиме быстрого ШИМ регистр OCRxA двойная буферизация: вы фактически будете писать в буферный регистр, и OCRxA автоматически обновляется из этого буфера по тому же таймеру. тактовый цикл, который очищает счетчик.

Может показаться нелогичным использовать режим ШИМ, когда вам не нужен функция ШИМ. Однако, пока «режим сравнения вывода» установлен на «нормальная работа порта» для обоих каналов, таймер не будет генерировать любой выход ШИМ, и вы можете законно использовать быстрый режим ШИМ только для его функция двойного буфера.

,

Это просто великолепно. Кажется, он отлично работает с моим тестовым кодом, даже не проверяя, прошел ли TCNT мимо OCRxA. Задержка буферов не имеет значения, поскольку OCRxA обновляется только один раз в миллисекунду. Мне немного стыдно признаться, что я даже не использовал CTC, весь код был в «нормальном» режиме (режим 0), и я сбрасывал TCNT в качестве первого действия в ISR. Вы имели в виду «режим 4», где я мог бы просто опустить сброс «TCNT», верно?, @towe

У меня был код, который проверял, насколько «TCNT» больше, чем «OCRxA», и выводил это через последовательный порт. Теперь это «всегда» отображает часть этого «запаздывания». Прав ли я, полагая, что мое **реальное** значение TCNT сравнивается с **буферизованным** OCRxA, а не с **активным** OCRxA, и что эта метрика теперь будет бессмысленной/ожидаемой? Если да, то есть ли способ прочитать «активный» OCRxA по сравнению с тем, что в буфере еще не «активен»?, @towe

@TobiasWeiß: Re «_весь код был в «нормальном» режиме (режим 0) [...]._»: поскольку пролог ISR занимает некоторое время и может даже задерживаться из-за других прерываний, период вашего прерывания, скорее всего, будет быть больше, чем вы хотите. «_Вы имели в виду «режим 4» [...], верно?_» Верно. «_Прав ли я, полагая, что он сравнивает мое **реальное** значение TCNT с **буферизованным** OCRxA [...]?_» Судя по разделу «Выходные единицы сравнения» таблицы данных, это казалось бы, это так. «_Есть ли какой-нибудь способ прочитать «активный» OCRxA [...]?_» Мне это не известно., @Edgar Bonet