Широтно-импульсная модуляция сокращенно ШИМ (PWM) в платформе Arduino позволяет получать прямоугольные импульсы с изменяемой длительностью импульса при постоянной частоте и амплитуде импульсов. Сигнал ШИМ применяется для плавного изменения мощности на нагрузке, поступающей от источника питания. Например, с целью регулирования скорости вращения вала двигателя; плавности изменения яркости освещения или подсветки.
Платы Arduino Uno и Arduino Nano на базе ATmega168/328 имеют 6 аппаратных ШИМ модуляторов на выхода D3, D5, D6, D9, D10, D11.
Управление ШИМ сигналом осуществляется с помощью функции, analogWrite которая генерирует на выходе аналоговый сигнал и задает коэффициент заполнения импульса. Arduino устанавливает на выводах частоту 488,28 Гц и разрешение 8 разрядов (от 0 до 255). За генерацию ШИМ сигнала отвечают 3 таймера, за выходы D5 и D6 отвечает Timer0, за D9 и D10 Timer1, а за выходы D3 и D11 Timer2. Таймеры 0 и 2 8-и битные, таймер 1 16-и битный.
Стандартная функция analogWrite не позволяет получить другую частоту или разрядность ШИМ сигнала, но если обращаться к регистрам микроконтроллера напрямую, то можно получить частоту ШИМ от 7.6 Гц до 62,5 кГц и разрешением от 8 до 10 бит.
Рассмотрим пример реализации ШИМ сигнала на примере таймера 1 микроконтроллера ATmega168/328.
void setup() { pinMode(9,OUTPUT); cli(); TCCR1A = 0; TCCR1B = 0; TCNT1 = 0; TCCR1A |= (1<<COM1A1); TCCR1B |= (1<<WGM12); TCCR1A |= (1<<WGM11) | (1<<WGM10); TCCR1B |= (1 << CS10); ICR1 = 1023; OCR1A = 512; // F=16000000/1024/1/1=15625 Hz // PWM 50.05 % sei(); } void loop(){}
За работу ШИМ отвечает несколько регистров, рассмотрим подробней их настройку.
TCCR1A — регистр управления, определяет поведение выводов OC1A и OC1B (биты 1 и 2 порта B) при совпадении значений в регистре с TCNT1A и регистрах сравнения OCR1A/OCR1B, а также для выборов режимов ШИМ.
TCCR1B — регистр управления
Через эти два регистра осуществляется основная настройка управления PWM
Биты COM1A1/COM1A0 и COM1B1/COM1B0 регистра TCCR1A определяют поведение выводов OC1A/OC1B (D9/D10) при совпадении значений регистров сравнения OCR1A/OCR1B со значением счётного регистра TCNT1.
При установке битов COM1A1/COM1A0 и COM1B1/COM1B0 [1:0] — неинвертирующий ШИМ
При установке битов COM1A1/COM1A0 и COM1B1/COM1B0 [1:1] — инвертирующий ШИМ
Биты WGM10, WGM11 и WGM12 регистров TCCR1A иTCCR1A определяют режим работы PWM.
Как видно на скриншоте PWM имеет 2 типа модуляции:
- Fast PWM — в этом режиме счетчик считает от нуля до максимального значения (зависит от разрядности), после достижения переполнения сбрасывается в ноль и счет начинается снова. Когда значение в счетчике достигает значения регистра сравнения, то соответствующий ему вывод ОСхх сбрасывается в ноль.
- Phase Correct PWM — ШИМ с точной фазой. Счетчик считает сначала от 0 до максимального значения (зависит от разрядности), потом от максимального значения (зависит от разрядности) до 0. Вывод OCxx при первом совпадении сбрасывается, при втором устанавливается. Частота ШИМ при этом падает в два раза.
Биты CS10, CS11 и CS12 регистра TCCR1B определяют значение делителя:
ICR1 — в этот регистр записывается текущее состояние счётчика при появлении активного входного сигнала на выводе ICP (бит 0 порта B), в нем указываем максимальное значение (зависит от разрядности).
OCR1A — регистр сравнения который сравнивает свое значение со значение счетного регистра TCNT1 , в случае совпадения выполняются действия, определённые регистром TCCR1A.
На этом настройка PWM закончена. При работе с таймерами, например микроконтроллера Atmega328 следует учитывать, что таймер 0 задействован в функциях delay() и millis(), а таймер 2 в функции tone().
Для удобства настройки ШИМ можно воспользоваться простым онлайн калькулятором, который позволяет задать параметры PWM и получить код настройки таймера: