Как получить частоту 38 кГц на выводе Arduino?
Обновлено Редакция GAW
Содержание
Генерировать 38 кГц в цикле с delayMicroseconds() неудобно: процессор занят, а прерывания сбивают период. У ATmega328P эту работу делает таймер: в режиме CTC счётчик считает до OCR и обнуляется, а выход при каждом совпадении меняет уровень.
Формула
где N — предделитель (DS40002061B, разд. 18.7.2). При fclk = 16 МГц и N = 1:
| OCR2A | Частота | Отклонение от 38 кГц |
|---|---|---|
| 209 | 38 095 Гц | +0,25 % |
| 210 | 37 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.
Источники
- 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)
- Arduino. ArduinoCore-avr (коммит 11b9130) — Uno — 16 МГц (uno.build.f_cpu); Timer2 управляет ШИМ выводов 3 и 11, Timer0 — millis() и delay()
Нашли ошибку?
Смотрите также
- Режим CTC (сброс при совпадении)Счётчик таймера обнуляется при совпадении с регистром сравнения
- Таймер AVR и STM32Предделитель, OCRnA, PSC и ARR под частоту, мёртвое время, энкодер
- ИК-код NECАдрес и команда ↔ код, тайминги кадра, код для Arduino
- Таймеры AVRTimer0/1/2, режимы WGM, предделители, формулы ШИМ, захват, примеры