Перейти к содержанию

Как получить частоту 38 кГц на выводе Arduino?

Обновлено Редакция GAW

Генерировать 38 кГц в цикле с delayMicroseconds() неудобно: процессор занят, а прерывания сбивают период. У ATmega328P эту работу делает таймер: в режиме CTC счётчик считает до OCR и обнуляется, а выход при каждом совпадении меняет уровень.

Формула

f=fclk2⋅N⋅(1+OCR)f = \frac{f_\text{clk}}{2 \cdot N \cdot (1 + \text{OCR})}

где N — предделитель (DS40002061B, разд. 18.7.2). При fclk = 16 МГц и N = 1:

OCR2AЧастотаОтклонение от 38 кГц
20938 095 Гц+0,25 %
21037 915 Гц−0,22 %

Расчёт наш; другие частоты и предделители для обоих таймеров подбирает калькулятор таймера.

Код для Arduino Uno

void setup() {
  pinMode(11, OUTPUT);                   // OC2A = PB3
  TCCR2A = (1 << COM2A0) | (1 << WGM21); // toggle OC2A, CTC
  TCCR2B = (1 << CS20);                  // prescaler 1
  OCR2A = 209;                           // ~38.1 kHz
}
void loop() {}

COM2A1:0 = 01 включает переключение OC2A при совпадении (табл. 18-2), WGM21 вместе с нулевыми WGM20 и WGM22 — режим CTC с вершиной OCR2A. На выводе 11 получается меандр со скважностью 50 %.

Что учесть

  • Таймер занят. Timer2 обслуживает и ШИМ выводов 3 и 11 — analogWrite() на них работать не будет. Timer1 (выводы 9 и 10) тоже годится: у него CTC с вершиной OCR1A — режим 4.
  • Пачки. Код пульта — это пачки несущей и паузы. Несущую включают и выключают битами COM2A1:0, а длительности протокола задаёт программа; их таблица — в калькуляторе NEC.
  • Светодиод. Вывод ATmega328P не даёт импульсного тока ИК-светодиода для дальности в метры — нужен транзисторный ключ.

Режимы и регистры всех трёх таймеров собраны в статье «Таймеры AVR».

Похожие вопросы

Почему после этого перестал работать analogWrite на выводе 3?

Вывод 3 Arduino Uno тоже работает от Timer2, а мы перевели таймер в режим CTC с другим предделителем. Наш вывод: пока таймер занят несущей, ШИМ на выводах 3 и 11 недоступен. Timer0 не трогают — от него зависят millis() и delay().

Можно ли получить ровно 38 000 Гц?

От 16 МГц — нет: делитель 2 · (1 + OCR) должен быть целым, а 16 000 000 / 38 000 ≈ 421,05. Ближайшие варианты — 38 095 Гц (OCR2A = 209) и 37 915 Гц (OCR2A = 210), это +0,25 % и −0,22 % (наш расчёт). ИК-приёмнику такая разница не важна.

Как включать и выключать несущую для пачек кода?

Переключать биты COM2A1:0: при 01 таймер управляет выводом, при 00 вывод возвращается к обычному порту и держит уровень из PORTB. Наш совет — перед выключением записывать в порт ноль, чтобы светодиод не остался гореть. Длительности пачек и пауз протокола NEC посчитает калькулятор NEC.

Источники

  1. Microchip. ATmega48A/PA/88A/PA/168A/PA/328/P Data Sheet (DS40002061B) — 18.7.2 — CTC Timer2 при WGM22:0 = 2, вершина OCR2A; f = f_clk / (2 · N · (1 + OCR2A)); табл. 18-2 — COM2A1:0 = 01: переключение OC2A при совпадении; 15.7.2 — то же для Timer0; таблица выводов — PB3 (MOSI/OC2A/PCINT3)
  2. Arduino. ArduinoCore-avr (коммит 11b9130) — Uno — 16 МГц (uno.build.f_cpu); Timer2 управляет ШИМ выводов 3 и 11, Timer0 — millis() и delay()

Нашли ошибку?