Таймеры Arduino UNO — Часть 3. Режимы работы таймеров (CTC, Fast PWM, Phase Correct PWM)
Теория
Режим CTC (Clear Timer on Compare Match)
В режиме CTC (сброс таймера по совпадению) счётчик таймера считает до заданного значения в регистре OCRnA, после чего автоматически сбрасывается в ноль. Это удобно для генерации точных интервалов времени и сигналов заданной частоты.
Режим Fast PWM
Fast PWM — это режим генерации ШИМ (широтно-импульсной модуляции), при котором таймер быстро считает от нуля до максимума и сразу сбрасывается. Этот режим используется, когда нужна максимальная частота ШИМ, например, для управления яркостью светодиодов или скоростью двигателей.
Режим Phase Correct PWM
Phase Correct PWM — режим, при котором таймер считает вверх до максимального значения, а затем обратно вниз до нуля. Благодаря этому форма сигнала симметрична, что уменьшает искажения, но частота в два раза ниже по сравнению с Fast PWM.
Регистр TCCRnA и TCCRnB
Режим работы таймера задаётся комбинацией битов в регистрах TCCRnA и TCCRnB:
WGMn0..WGMn2— выбор режима работы (Normal, CTC, Fast PWM, Phase Correct PWM).COMnA1, COMnA0— настройка поведения вывода OCnA.CSn0..CSn2— выбор предделителя (prescaler) — 1, 8, 64, 256, 1024.
Предделители (prescalers)
Предделитель делит частоту тактового генератора (обычно 16 МГц для Arduino UNO) для замедления счёта таймера. Например, при делителе 64 частота таймера будет 16 МГц / 64 = 250 кГц.
Практика
Генерация точного сигнала 1 кГц на пине
void setup() {
pinMode(9, OUTPUT);
// Настройка Timer1 в CTC режиме
TCCR1A = 0;
TCCR1B = 0;
OCR1A = 7999; // (16 МГц / (2 * 1 кГц)) - 1 при делителе 1
TCCR1B |= (1 << WGM12); // CTC режим
TCCR1B |= (1 << CS10); // Предделитель 1
TCCR1A |= (1 << COM1A0); // Переключение состояния пина OC1A (D9)
}
void loop() {
// Ничего не делаем, сигнал генерируется аппаратно
}
Настройка частоты ШИМ на Timer2
void setup() {
pinMode(3, OUTPUT);
// Настройка Timer2 в Fast PWM
TCCR2A = 0;
TCCR2B = 0;
TCCR2A |= (1 << WGM21) | (1 << WGM20); // Fast PWM
TCCR2A |= (1 << COM2B1); // Вывод ШИМ на OC2B (D3)
TCCR2B |= (1 << WGM22); // Установка TOP через OCR2A
OCR2A = 124; // TOP = 124 → Частота = 16МГц / (64 * (124+1)) ≈ 2 кГц
OCR2B = 62; // 50% скважность
TCCR2B |= (1 << CS22); // Делитель 64
}
void loop() {
}
Проект: Генератор квадратного сигнала с заданной частотой
В этом проекте мы будем генерировать сигнал на пине D9 с частотой, которую задаёт переменная frequency.
int frequency = 2000; // Частота в Гц
void setup() {
pinMode(9, OUTPUT);
// Настройка Timer1 для CTC
TCCR1A = 0;
TCCR1B = 0;
int prescaler = 8; // Выбираем предделитель
OCR1A = (16000000 / (2 * prescaler * frequency)) - 1;
TCCR1B |= (1 << WGM12); // CTC
TCCR1B |= (1 << CS11); // Предделитель 8
TCCR1A |= (1 << COM1A0); // Переключение состояния на OC1A (D9)
}
void loop() {
// Сигнал генерируется аппаратно
}
Таким образом, мы можем легко генерировать стабильные частоты без использования delay() или millis(), что особенно полезно для точных измерительных и управляющих систем.





