В предыдущем примере мы затронули тему использования счётчика/таймера ATtiny13 в обычном режиме и в режиме подсчёта импульсов (CTC). В этой статье я продолжаю тему таймера, но теперь мы рассмотрим его применение для реализации широтно-импульсной модуляции (ШИМ).
Все микроконтроллеры работают с цифровыми сигналами, т.е. с логическими уровнями сигнала: ноль (0 В), и единица (обычно равен напряжению питания 5В или 3.3В). Но что делать, если мы хотим получить на выходе какое-либо промежуточное значение? В таких случаях применяют Широтно-импульсную модуляцию (ШИМ, англ. pulse-width modulation (PWM)) — процесс управления мощностью, подводимой к нагрузке, путём изменения скважности импульсов, при постоянной частоте.
Широтно-импульсная модуляция представляет собой периодический импульсный сигнал. Существуют цифровые и аналоговые ШИМ, однополярные и двуполярные, и т.д. Но принцип их работы остается одинаковым вне зависимости от исполнения и заключается в сравнении двух видов сигналов: опорного (пилообразные или треугольные импульсы) и входного (постоянного, либо изменяемого нужным образом, в зависимости от конкретной задачи ШИМ). Эти сигналы сравниваются и, при пересечении их значений, изменяется уровень сигнала на выходе ШИМ. Выходное напряжение ШИМ имеет вид прямоугольных импульсов, изменяя их длительность, мы можем регулировать среднее значение напряжения на выходе ШИМ *.
* Если на выходе ШИМ использовать интегрирующую RC-цепь, то можно вместо импульсного получить постоянное напряжение нужной величины. Но в нашем примере со светодиодами можно обойтись и без этого, так как человеческий глаз всё равно не сможет разглядеть мерцания светодиода при используемой тактовой частоте.
Параметры ШИМ
- T — период тактирования (опорного сигнала);
- t — длительность импульса;
- S — скважность;
- D — коэффициент заполнения.
Скважность определяется отношением периода к длительности импульса:
S=T/t
Коэффициент заполнения — величина, обратная скважности:
D=1/S=t/T
Также, коэффициент заполнения можно выразить в процентах:
D=t/T*100%
Рассмотрим подробнее, как работает ШИМ в AVR микроконтроллерах, на примере ATtiny13.
Как уже упоминалось в предыдущем примере, в ATtiny13 реализовано две разновидности ШИМ: так называемые «Быстрая ШИМ» (Fast PWM) и «ШИМ с коррекцией фазы» (Phase correct PWM). Оба варианта основаны на использовании встроенного в МК восьмибитного счётчика/таймера T0. Таймер тут используется вместо опорного сигнала. Тактовая частота таймера задаётся предделителем тактовой частоты процессора, либо от внешнего тактового генератора. Режим тактирования задаётся битами CS02 (2), CS01 (1), CS00 (0) регистра TCCR0B:
- 000 — таймер/счетчик T0 остановлен
- 001 — тактовый генератор CLK
- 010 — CLK/8
- 011 — CLK/64
- 100 — CLK/256
- 101 — CLK/1024
- 110 — от внешнего источника на выводе T0 (7 ножка, PB2) по спаду сигнала
- 111 — от внешнего источника на выводе T0 (7 ножка, PB2) по возрастанию сигнала
Настройка таймера для ШИМ
Режим работы таймера задаётся битами WGM01 (1) и WGM00 (0) регистра TCCR0A:
- 00 — обычный режим
- 01 — режим ШИМ с коррекцией фазы
- 10 — режим подсчета импульсов (сброс при совпадении)
- 11 — режим быстрой ШИМ
Здесь нас интересуют варианты «01» и «11».
Биты COM0A1 (7) и COM0A0 (6) регистра TCCR0A задают, какой сигнал появится на выводе OC0A (5 ножка, PB0) при совпадении счётчика (регистр TCNT0) с регистром сравнения A (OCR0A).
В режиме «Быстрая ШИМ»:
- 00 — вывод OC0A не функционирует
- 01 — если бит WGM02 регистра TCCR0B установлен в 0, вывод OC0A не функционирует
- 01 — если бит WGM02 регистра TCCR0B установлен в 1, изменение состояния вывода OC0A на противоположное при совпадении с A
- 10 — установка 0 на выводе OC0A при совпадении с A, установка 1 на выводе OC0A при обнулении счётчика (неинверсный режим)
- 11 — установка 1 на выводе OC0A при совпадении с A, установка 0 на выводе OC0A при обнулении счётчика (инверсный режим)
В режиме «ШИМ с коррекцией фазы»:
- 00 — вывод OC0A не функционирует
- 01 — если бит WGM02 регистра TCCR0B установлен в 0, вывод OC0A не функционирует
- 01 — если бит WGM02 регистра TCCR0B установлен в 1, изменение состояния вывода OC0A на противоположное при совпадении с A
- 10 — установка 0 на выводе OC0A при совпадении с A во время увеличения значения счетчика, установка 1 на выводе OC0A при совпадении с A во время уменьшения значения счетчика (неинверсный режим)
- 11 — установка 1 на выводе OC0A при совпадении с A во время увеличения значения счетчика, установка 0 на выводе OC0A при совпадении с A во время уменьшения значения счетчика (инверсный режим)
Биты COM0B1 (5) и COM0B0 (4) регистра TCCR0A задают, какой сигнал появится на выводе OC0B (6 ножка, PB1) при совпадении счётчика (регистр TCNT0) с регистром сравнения B (OCR0B).
В режиме «Быстрая ШИМ»:
- 00 — вывод OC0B не функционирует
- 01 — резерв
- 10 — установка 0 на выводе OC0B при совпадении с B, установка 1 на выводе OC0B при обнулении счётчика (неинверсный режим)
- 11 — установка 1 на выводе OC0B при совпадении с B, установка 0 на выводе OC0B при обнулении счётчика (инверсный режим)
В режиме «ШИМ с коррекцией фазы»:
- 00 — вывод OC0B не функционирует
- 01 — резерв
- 10 — установка 0 на выводе OC0B при совпадении с B во время увеличения значения счетчика, установка 1 на выводе OC0B при совпадении с B во время уменьшения значения счетчика (неинверсный режим)
- 11 — установка 1 на выводе OC0B при совпадении с B во время увеличения значения счетчика, установка 0 на выводе OC0B при совпадении с B во время уменьшения значения счетчика (инверсный режим)
Быстрая ШИМ (Fast PWM)
В этом режиме счётчик считает от нуля до максимума. При установке нулевого значения счётчика — на выходе появляется импульс (устанавливается логическая единица). При совпадении с регистром сравнения — импульс сбрасывается (устанавливается логический ноль). В инверсном режиме, соответственно — наоборот.
ШИМ с коррекцией фазы (Phase correct PWM)
В этом режиме счётчик считает от нуля до максимума, а затем в обратном направлении — до нуля. В неинверсном режиме, при совпадении с регистром сравнения во время нарастания значения счётчика — импульс сбрасывается (устанавливается логический ноль). При совпадении во время убывания — появляется импульс (устанавливается логическая единица). В инверсном режиме, соответственно — наоборот. Недостатком данного режима является уменьшенная в два раза частота выходного сигнала по сравнению с режимом Fast PWM. Но зато при изменении скважности не смещаются центры импульсов. Основное назначение данного режима — делать многофазные ШИМ сигналы, например трехфазную синусоиду, чтобы при изменении скважности не сбивался угол фазового сдвига между двумя ШИМ сигналами.
Чтобы увидеть наглядно, как работает ШИМ, напишем небольшую программу (все опыты я провожу на своей отладочной плате, соответственно код привожу применительно к ней):
/*
* tiny13_board_pwm
* Демо-прошивка отладочной платы на ATtiny13.
* Демонстрация работы ШИМ на двух каналах:
* неинверсный сигнал на выходе OC0A, инверсный - на выходе OC0B.
*/
#define F_CPU 1200000UL
#include <avr/io.h>
#include <util/delay.h>
#define LED0 PB0 // OC0A
#define LED1 PB1 // OC0B
int main(void)
{
// Светидиоды:
DDRB |= (1 << LED0)|(1 << LED1); // выходы = 1
PORTB &= ~((1 << LED0)|(1 << LED1)); // по умолчанию отключены = 0
// Таймер для ШИМ:
TCCR0A = 0xB3; // режим ШИМ, неинверсный сигнал на выходе OC0A, инверсный - на выходе OC0B
TCCR0B = 0x02; // предделитель тактовой частоты CLK/8
TCNT0=0; // начальное значение счётчика
OCR0A=0; // регистр совпадения A
OCR0B=0; // регистр совпадения B
while(1)
{
do // Нарастание яркости
{
OCR0A++;
OCR0B = OCR0A;
_delay_ms(5);
}
while(OCR0A!=255);
_delay_ms(1000); // Пауза 1 сек.
do // Затухание
{
OCR0A--;
OCR0B = OCR0A;
_delay_ms(5);
}
while(OCR0A!=0);
_delay_ms(1000); // Пауза 1 сек.
}
}
Тут мы видим, что при старте МК в регистры сравнения A и B устанавливается 0, а счётчик запускается в режиме Fast PWM, с генерацией неинверсного ШИМ сигнала на выходе OC0A и инверсного — на выходе OC0B. В основном цикле значения регистров сравнения плавно меняются от 0 до максимума и обратно. В результате, светодиоды, подключенные к выводам OC0A и OC0B, будут поочерёдно плавно загораться и гаснуть, как бы в противофазе.
Но если приглядеться внимательнее, то видим, что один из светодиодов гаснет не до конца, а продолжает тускло светиться. Эта особенность характерна для Fast PWM режима. Дело в том, что в этом режиме, даже если записать в регистр сравнения 0, при переполнении (обнулении) счётчика на выходе всё равно устанавливается логическая единица, которая сбрасывается в следующем такте (по совпадению с регистром сравнения). Таким образом, в каждом периоде будет проскакивать по одному короткому импульсу длительностью 1 такт, но этого достаточно для засвечивания светодиода. Этот эффект визуально не заметен в инверсном режиме формирования выходных импульсов, т.к. в данном случае при обнулении счётчика будет происходить не короткий импульс, а наоборот — короткий провал во время максимального заполнения ШИМ. Этот провал можно увидеть на осциллографе, но такое мерцание светодиода человеческое зрение просто не заметит. Поэтому второй светодиод визуально загорается и гаснет полностью. В режиме ШИМ с коррекцией фазы, этот эффект отсутствует независимо, инверсный сигнал формируется на выходе или нет. Поменяем значение бита WGM01 (1) регистра TCCR0A с 1 на 0:
TCCR0A = 0xB1; // режим ШИМ с коррецией фазы, неинверсный сигнал на выходе OC0A, инверсный - на выходе OC0B
После перепрошивки МК можем убедиться, что оба светодиода гаснут полностью!
Эту особенность следует учитывать при разработке реальных проектов. Например, если мы захотим сделать регулятор яркости светодиодной подсветки, не следут использовать для этого ШИМ в режиме Fast PWM с неинверсной генерацией выходных импульсов.
Полезные ссылки
ATtiny13 Datasheet (официальный)
ATtiny13 Datasheet (урезанный вариант)
AVR. Учебный курс. Использование ШИМ
Таймер/счетчик T0 (8 бит)