Режим очистки при совпадении (CTC)
В этом режиме таймер на каждом такте увеличивает на единицу значение регистра TCNTn от 0 до верхней границы, задаваемой регистром OCRnx, и при совпадении значение регистра TCNTn обнуляется. При этом устанавливается флаг прерывания OCFnx, а также переключается логический уровень на выводе OCnx.
Временная диаграмма работы таймера-счётчика в режиме CTC:
Если разрешено прерывание по совпадению TIMERn_COMPx_vect, то вызывается функция-обработчик, в которой можно изменить верхнюю границу, присвоив новое значение регистру OCRnx. Но поскольку в регистрах таймеров-счётчиков не используется двойная буферизация, то при высокой тактовой частоте таймера запись в регистр OCRnx значения, близкого к 0 из функции-обработчика прерывания может привести к тому, что флаг прерывания будет таймер установлен ещё до того, как функция-обработчик завершится, и таким образом один или несколько периодов таймера окажутся пропущенными.
Например, я захотел сгенерировать синусоиду. И вот, как будет выглядеть осцилограмма моего генератора:
В режиме CTC вывод OCnx может автоматически переключать своё состояние при каждом совпадении. Если в регистр OCRnx записать значение 0, то он будет переключаться с максимальной частотой, равной половине тактовой частоты таймера.
Для расчёта частоты импульсов, которую можно получить на выводе OCnx, можно использовать формулу
Focnx = Fclk/(2*N*(1+OCRnx),
где Fclk равен тактовой частоте таймера, а N равен коэффициенту предделителя (например, 8, 32, 64, ...).
Флаг переполнения TOVn в режиме CTC устанавливается так же, как и в нормальном режиме.
Режим очистки при совпадении (CTC)
Пример использования таймера-счётчика в режиме CTC
В данном примере я с помощью потенциометра, подключенного ко входу Analog 0, буду управлять импульсами на выводе OC2A (пин Digital 11 на плате Arduino UNO).
Я задал тактирование таймера-счётчика 2 с предделителем /1024, что даёт частоты импульсов от 30.5 Гц значении OCR2A, равном 255, до 7812 Гц при значении, равном 0.
В скетче используется библиотека VEduino.
Код скетча (скачать):
#include <ve_avr.h> // Используется библиотека VEduino
void setup()
{
setModeOutput(DEV_TIMER2_OCA); // Пин OC2A в режим вывода
DEV_TIMER2.setClockSelect(Prescaler2::Prescaler_1024); // 16МГц / 1024 = 15625 Гц. Таймер-счётчик 2 будет
// увеличивать значение регистра TCNT2 на единицу
// каждые 64 микросекунды.
DEV_TIMER2.setWaveGenMode(Timer2::CTC); // Режим CTC таймера-счётчика
DEV_TIMER2.setCompOutModeA(Timer2::Toggle); // Переключать вывод OC2A при TCNT2 == OCR2A
}
void loop()
{
int potValue = analogRead(0); // Считать значение частоты, заданное потенциометром
OCR2A = map(potValue, 0, 1023, 255, 0); // Задать значение регистра OCR2A
delay(100);
}