В одной из будущих статей мне понадобится источник ШИМ сигнала с настраиваемой частотой и скважностью.
Решила по-быстрому описать настройку ШИМ для ATmega328. Так как этот МК является основой множества отладочных плат, ардуинщикам такая статья тоже может пригодиться :)
Посмотрим в документации к МК регистры, в которых настраивается режим работы таймера и частота его работы:
Битами WGMx устанавливается режим работы таймера:
Битами COMx - работа выходов OC1A/OC1B (да, тут два канала ШИМ)
Битами CS1X - предделитель частоты таймера
Кратко рассмотрим работу "быстрой" ШИМ (Fast PWM) и ШИМ с точной фазой и частотой (Phase and Frequency Correct PWM) у Timer1.
В режиме Fast PWM с каждым тактом счета увеличивается регистр TCNT1. Когда число в нем становится равным числу в регистре сравнения OCR1/ICR1, выход OC1x становится равным нулю (если ШИМ неинвертирован) или единице (если ШИМ инвертирован).
Когда счетчик досчитает до верха (TOP), то выход снова станет равным единице (если ШИМ неинвертирован), TCNT1 будет обнулен, а OCR1/ICR1 может быть записано новое значение, если нужно поменять скважность.
Частота "быстрого" ШИМ считается по формуле:
fclk - частота тактирования МК (16 МГц для большинства плат Arduino),
N - предделитель (1, 8, 64, 256, 1024 в зависимости от настройки),
TOP - верхнее значение счета.
Значение TOP в режимах 5, 6, 7 фиксированное (0x00FF (255), 0x01FF (511), 0x03FF (1023)). Чем больше значение TOP, тем дольше будет период ШИМ.
В режиме 14 регистром сравнения является OCR1, значение TOP устанавливается через регистр ICR1.
В режиме 15 регистром сравнения является ICR1, значение TOP устанавливается через регистр OCR1.
В чем разница у двух последних режимов?
Регистр OCR1 благодаря использованию внутреннего буфера обновляется быстрее, чем ICR1. Поэтому, если частота меняется часто, и важно быстродействие, лучше выбрать режим 15.
Если частота фиксированная, а чаще меняется скважность, можно использовать режим 14.
Fast PWM имеет наибольшую максимальную частоту, но несимметричен.
Если нужен симметричный ШИМ сигнал, следует использовать режимы с точной фазой (Phase Correct).
В таких режимах TCNT сначала увеличивается до TOP, а потом начинает уменьшаться до 0. Выход OC при первом совпадении становится нулевым, а при втором - "единичным" (если ШИМ неинвертирован).
Частота ШИМ с точной фазой считается по формуле:
А теперь - самое интересное: код и проверка работы!
Итак, код для Arduino (для опроса клавиш используется прерывание таймера 0, используется моя немного сокращенная библиотека).
Код для настоящих мужиков чистой ATmega328 (тут никаких дополнительных библиотек не надо, кроме стандартных):
И, напоследок, видео работы:
Вдогонку можете глянуть пару статей об Arduino и AVR :)
Или, если не любите микроконтроллеры, про получение ШИМ другим способами:
Можете дать автору копеечку на кофе, а можете и не давать :)