ШИМ на таймерах Timer0 и Timer2
Таймер умеет не только вызывать прерывания, но и сам переключать вывод при совпадении счётчика с регистром сравнения. Так получается ШИМ — сигнал с постоянной частотой и изменяемой долей единицы, которым регулируют яркость, скорость двигателя и напряжение.
Обновлено Редакция GAW
AVR с нуляурок 6 из 825 мин
Цель урока: Настроить аппаратный ШИМ на выводах OC0A и OC2A ATmega328P, рассчитать его частоту и коэффициент заполнения и менять яркость светодиода записью в OCR.
ШИМ (широтно-импульсная модуляция) — прямоугольный сигнал с постоянной частотой, у которого меняется доля периода с высоким уровнем — коэффициент заполнения. Светодиод на ШИМ мигает так быстро, что глаз видит среднюю яркость, а двигатель и фильтр усредняют напряжение. Делать ШИМ программно, переключая вывод в прерывании, можно, но таймеры ATmega328P умеют это аппаратно.
Выводы ШИМ
У каждого таймера два блока сравнения A и B, и у каждого — свой вывод OCnx (разделы 14.3.1 и 14.3.3 даташита):
| Таймер | Вывод | Порт | Вывод Uno |
|---|---|---|---|
| Timer0 | OC0A | PD6 | 6 |
| Timer0 | OC0B | PD5 | 5 |
| Timer2 | OC2A | PB3 | 11 |
| Timer2 | OC2B | PD3 | 3 |
| Timer1 | OC1A, OC1B | PB1, PB2 | 9, 10 |
Сигнал таймера попадает на вывод, только если вывод настроен выходом битом DDR (раздел 15.6).
Режим Fast PWM
В режиме Fast PWM (WGM02:0 = 3) счётчик Timer0 считает от 0 (BOTTOM) до 0xFF и начинает заново (раздел 15.7.3). Биты COM0A1:0 = 10 включают прямой ШИМ: вывод OC0A сбрасывается в ноль при совпадении TCNT0 с OCR0A и ставится в единицу в начале периода (табл. 15-3). Частота:
При 16 МГц и делителе 64 это 16 000 000 / (64 · 256) ≈ 976,6 Гц. Единица держится от начала периода до совпадения, то есть OCR0A + 1 тактов из 256, и коэффициент заполнения равен (OCR0A + 1) / 256 — это наш вывод из описания режима. Крайние значения даташит описывает отдельно: OCR0A = 0xFF даёт постоянную единицу, а OCR0A = 0 — узкий импульс в каждом периоде, а не полный ноль.
В режимах ШИМ регистр OCR0A буферизован: новое значение вступает в силу только в вершине или в начале счёта (раздел 15.5), поэтому его можно менять в любой момент без искажённых импульсов.
Пример: плавная яркость светодиода
Светодиод с резистором 330 Ом подключим к выводу 6 Uno (PD6, OC0A):
#define F_CPU 16000000UL
#include <avr/io.h>
#include <stdint.h>
#include <util/delay.h>
int main(void)
{
DDRD |= _BV(DDD6); /* OC0A (PD6, pin 6) output */
TCCR0A = _BV(COM0A1) /* non-inverting PWM on OC0A */
| _BV(WGM01) | _BV(WGM00); /* mode 3: fast PWM, TOP = 0xFF */
TCCR0B = _BV(CS01) | _BV(CS00); /* clk/64: 976.6 Hz at 16 MHz */
for (;;) {
for (uint8_t d = 0; d < 255; d++) { /* fade in */
OCR0A = d;
_delay_ms(4);
}
for (uint8_t d = 255; d > 0; d--) { /* fade out */
OCR0A = d;
_delay_ms(4);
}
}
}
Процессор после настройки только меняет число в OCR0A — сам сигнал таймер выдаёт без его участия.
Режим Phase Correct
В режиме Phase Correct (WGM02:0 = 1) счётчик идёт от 0 до 0xFF и обратно, а вывод переключается при совпадении на подъёме и на спуске (раздел 15.7.4). Импульс получается симметричным относительно середины периода, а частота — вдвое ниже:
При 16 МГц и делителе 64 — около 490,2 Гц. Крайние значения здесь честные: OCR0A = 0 даёт постоянный ноль, OCR0A = 0xFF — постоянную единицу. Даташит рекомендует двухнаклонные режимы для управления двигателями. Чтобы переключить пример на Phase Correct, достаточно заменить в TCCR0A пару _BV(WGM01) | _BV(WGM00) на _BV(WGM00).
Timer2 и другие делители
Timer2 устроен так же, как Timer0, и регистры называются так же с цифрой 2: TCCR2A, TCCR2B, OCR2A. Отличается набор делителей: у Timer2 их семь — 1, 8, 32, 64, 128, 256 и 1024 (табл. 18-9), что даёт больше вариантов частоты. 16-битный Timer1 даёт ШИМ с вершиной до 0xFFFF и разрешением до 16 бит — его режимы разобраны в статье «Таймеры AVR».
Безопасность
ШИМ не делает вывод мощнее: ток в импульсе такой же, как при постоянной единице, и абсолютный максимум 40 мА на вывод остаётся в силе (раздел 29.1). Светодиод — только через резистор, двигатель, мощный светодиод или нагреватель — только через транзисторный ключ с диодом для индуктивной нагрузки.
Задание
Нужен ШИМ частотой около 8 кГц на выводе 11 Uno (OC2A) в режиме Fast PWM при 16 МГц.
- Какой делитель Timer2 выбрать и какой будет точная частота?
- Запишите настройку TCCR2A и TCCR2B и значение OCR2A для заполнения около 25 %.
Ответ и решение
-
Нужен делитель N ≈ 16 000 000 / (256 · 8000) ≈ 7,8. Ближайший у Timer2 — 8: частота 16 000 000 / (8 · 256) = 7812,5 Гц.
-
Вывод PB3 — выход, режим 3 и прямой выход, делитель 8 (CS22:0 = 010):
DDRB |= _BV(DDB3); /* OC2A (PB3, pin 11) */
TCCR2A = _BV(COM2A1) | _BV(WGM21) | _BV(WGM20); /* fast PWM, non-inverting */
TCCR2B = _BV(CS21); /* clk/8 */
OCR2A = 63; /* (63 + 1) / 256 = 25 % */
Что дальше
В уроке 7 научимся читать аналоговое напряжение и свяжем его с яркостью из этого урока. Частоту и разрешение ШИМ для разных делителей и вершин посчитает калькулятор ШИМ, а какие частоты выдаёт analogWrite на разных платах — калькулятор ШИМ Arduino. Регистры с битами — на страницах Timer0 и Timer2 атласа. Коротко о понятиях — термины «ШИМ», «Коэффициент заполнения», «Фазовый ШИМ» и «Сравнение по выходу».
Частые вопросы
Чем Fast PWM отличается от Phase Correct?
В Fast PWM счётчик идёт только вверх от 0 до вершины и сбрасывается, поэтому частота вдвое выше: fclk/(N·256) против fclk/(N·510). В Phase Correct счётчик идёт вверх и вниз, импульс симметричен относительно середины периода, и даташит рекомендует этот режим для управления двигателями.
Почему при OCR0A = 0 светодиод всё равно слабо светится?
В режиме Fast PWM с прямым выходом вывод устанавливается в единицу в начале каждого периода и сбрасывается при совпадении. При OCR0A = 0 даташит описывает это как узкий импульс в каждом периоде — один такт таймера из 256. Чтобы погасить вывод полностью, отключите ШИМ битами COM0A1:0 или используйте режим Phase Correct, где OCR0A = 0 даёт постоянный ноль.
Можно ли подключить двигатель прямо к выводу ШИМ?
Нет. Абсолютный максимум тока вывода ATmega328P — 40 мА, а двигатель потребляет сотни миллиампер и даёт выбросы напряжения при выключении. Двигатель включают через транзисторный ключ или драйвер с диодом, а вывод микроконтроллера управляет только затвором или базой.
Источники
- Microchip. ATmega48A/PA/88A/PA/168A/PA/328/P Data Sheet (DS40002061B) — разд. 1.1 и 14.3.1, 14.3.3: OC0A — PD6, OC0B — PD5, OC2A — PB3, OC2B — PD3; разд. 15.7.3: Fast PWM (WGM02:0 = 3 или 7), сброс OC0x при совпадении и установка в BOTTOM, частота fclk/(N·256), OCR0A = 0 — узкий импульс, OCR0A = MAX — постоянный уровень; разд. 15.7.4: Phase Correct (WGM02:0 = 1 или 5), частота fclk/(N·510), крайние значения дают постоянный уровень; разд. 15.6: выход OC0x виден на выводе только при DDR = 1; табл. 15-3 и 15-8: биты COM0A1:0 и WGM; разд. 15.5: двойная буферизация OCR0x в режимах ШИМ; разд. 18.11.1–18.11.2, табл. 18-9: TCCR2A, TCCR2B, делители Timer2 1, 8, 32, 64, 128, 256, 1024
- AVR-LibC 2.3.2: avr/io.h, заголовок iom328p.h (github.com/avrdudes/avr-libc) — имена битов COM0A1, WGM01, WGM00, CS01, CS00, COM2A1, WGM21, WGM20, CS21 и регистров OCR0A, OCR2A
- ArduinoCore-avr, variants/standard/pins_arduino.h (github.com/arduino/ArduinoCore-avr) — выводы Uno: 3 — PD3, 5 — PD5, 6 — PD6, 11 — PB3
Нашли ошибку?