Функция analogWrite() в Arduino включает аппаратный ШИМ одного из таймеров микроконтроллера. Его частота не настраивается из Arduino API: её задают режим и делитель, которые ядро записывает в регистры таймеров при старте в функции init() (wiring.c). Всем таймерам ставится делитель 64, таймер 0 работает в режиме быстрого ШИМ, остальные — в режиме с коррекцией фазы.
Частоты по умолчанию
| Плата | Таймер | Выводы | Режим | Частота при 16 МГц |
|---|---|---|---|---|
| Uno, Nano (ATmega328P) | 0 | 5, 6 | быстрый | 976,56 Гц |
| 1 | 9, 10 | с коррекцией фазы | 490,20 Гц | |
| 2 | 3, 11 | с коррекцией фазы | 490,20 Гц | |
| Mega 2560 | 0 | 4, 13 | быстрый | 976,56 Гц |
| 1, 2, 3, 4, 5 | 11, 12; 9, 10; 2, 3, 5; 6, 7, 8; 44, 45, 46 | с коррекцией фазы | 490,20 Гц | |
| Leonardo, Micro (ATmega32U4) | 0 | 3, 11 | быстрый | 976,56 Гц |
| 1, 3 | 9, 10; 5 | с коррекцией фазы | 490,20 Гц | |
| 4 | 6, 13 | с коррекцией фазы и частоты | 490,20 Гц |
Выводы таймеров — из файлов pins_arduino.h плат. Частоты считаются по формулам даташита ATmega328P (разделы 15.7.3 и 15.7.4):
где N — делитель. Таймер 4 ATmega32U4 считает от 0 до OCR4C и обратно, его частота — fCLK/(2 · N · TOP) при TOP = 255 после сброса, то есть те же 490 Гц.
Как изменить частоту
Частоту меняют, записывая другой делитель в младшие биты CS регистра TCCRnB и не трогая остальные биты, — калькулятор выдаёт эту строку. Делители у таймеров разные: у 0, 1, 3, 4, 5 — 1, 8, 64, 256 и 1024; у таймера 2 есть ещё 32 и 128 (таблица 18-9 даташита ATmega328P), а у таймера 4 ATmega32U4 — 15 ступеней от 1 до 16384 (таблица 15-14). Скважность при этом по-прежнему задаёт analogWrite() значением 0–255.
Делитель меняется сразу для всех выводов таймера: на Uno выводы 9 и 10 всегда работают с одной частотой. Учитывайте и то, что ещё занимает таймеры в ядре Arduino:
- Таймер 0 отсчитывает время для
millis(),micros()иdelay(), ядро считает, что он переполняется каждые 64 · 256 тактов (wiring.c). Изменение делителя ускоряет или замедляет их во столько же раз. - tone() берёт таймер 2 на Uno и Mega и таймер 3 на Leonardo (Tone.cpp). Пока звучит тон, ШИМ на выводах этого таймера не работает. После
noTone()таймер 2 возвращается к настройкам Arduino с делителем 64, а таймер 3 — нет.
Скважность, среднее напряжение и ток через нагрузку при выбранной частоте помогут посчитать калькулятор ШИМ, а режимы таймеров AVR с произвольным периодом — калькулятор таймера. Какой вывод платы к какому выводу микроконтроллера подключён, показывает распиновка Arduino.
Частые вопросы
Какая частота ШИМ у analogWrite на Arduino Uno?
На выводах 5 и 6 (таймер 0, быстрый ШИМ) — 976,56 Гц, на выводах 3, 9, 10 и 11 (таймеры 1 и 2, ШИМ с коррекцией фазы) — 490,2 Гц. Ядро Arduino ставит всем таймерам делитель 64, а при 16 МГц это даёт 16 000 000 / (64 · 256) и 16 000 000 / (64 · 510).
Как сделать ШИМ 31 кГц на Arduino?
Поставить делитель 1 таймеру 1 (выводы 9 и 10) или таймеру 2 (выводы 3 и 11): TCCR1B = (TCCR1B & 0b11111000) | 0x01. В режиме с коррекцией фазы это 16 000 000 / 510 = 31 372,5 Гц — выше слышимого диапазона, поэтому так убирают писк двигателей и катушек. Таймер 0 для этого не трогают: от него зависят millis() и delay().
Почему после изменения ШИМ на выводах 5 и 6 сломался delay()?
Таймер 0, который управляет выводами 5 и 6 (на Mega — 4 и 13, на Leonardo — 3 и 11), одновременно отсчитывает время для millis(), micros() и delay(). Ядро считает, что он переполняется каждые 64 · 256 тактов. Если поставить делитель 8, переполнений станет в 8 раз больше, и delay(1000) продлится 125 мс.
Источники
- Arduino. ArduinoCore-avr, коммит 11b9130 (github.com/arduino/ArduinoCore-avr) — wiring.c, init(): делитель 64 у всех таймеров, таймер 0 — быстрый ШИМ и счёт millis(), таймеры 1, 2, 3, 4, 5 — ШИМ с коррекцией фазы, таймер 4 ATmega32U4 — с коррекцией фазы и частоты; variants/*/pins_arduino.h — выводы таймеров; Tone.cpp — tone() на таймере 2 (Uno, Mega) или 3 (Leonardo), disableTimer()
- Microchip. ATmega48A/PA/88A/PA/168A/PA/328/P Data Sheet (DS40002061B) — 15.7.3 — быстрый ШИМ f = f_clk / (N · 256); 15.7.4 — с коррекцией фазы f = f_clk / (N · 510) (эталон тестов); таблицы 15-9, 16-5 — делители 1, 8, 64, 256, 1024; таблица 18-9 — делители таймера 2: 1, 8, 32, 64, 128, 256, 1024
- Microchip (Atmel). ATmega16U4/32U4 datasheet (Atmel-7766J) — 14.8.5 — f = f_clk / (2 · N · TOP); 15.12.10 — OCR4C = 0xFF после сброса; таблица 15-14 — 15 делителей таймера 4 от 1 до 16384
Где пригодится
Встроить калькулятор на свой сайт
Скопируйте код и вставьте его в HTML страницы, статьи или вики. Виджет бесплатный, без рекламы, счётчиков и cookie. Условие одно — ссылка на GAW под рамкой остаётся на месте. Подробнее о виджетах
<iframe src="https://gaw.ru/embed/arduino-pwm/" title="Частота ШИМ Arduino: таймеры, выводы и смена делителя" width="100%" height="640" style="border:1px solid #e3e5e9;border-radius:8px" loading="lazy" allow="clipboard-write"></iframe>
<p style="margin:6px 0 0;font-size:14px">Калькулятор: <a href="https://gaw.ru/tools/arduino-pwm/">Частота ШИМ Arduino: таймеры, выводы и смена делителя</a> — GAW.ru</p>Автоподстройка высоты рамки
Если сайт разрешает скрипты, добавьте этот код один раз в любом месте страницы: рамка будет менять высоту вместе с результатом расчёта.
<script>window.addEventListener("message",function(e){if(e.origin!=="https://gaw.ru"||!e.data||e.data.type!=="gaw:embed-height")return;var f=document.querySelectorAll('iframe[src^="https://gaw.ru/embed/"]');for(var i=0;i<f.length;i++)if(f[i].contentWindow===e.source)f[i].style.height=e.data.height+"px"})</script>Обновлено .
Нашли ошибку в расчёте?