Рубрики
Схемы на AVR

Использование широтно-импульсной модуляции (ШИМ) в микроконтроллерах AVR ATmega16

Широтно-импульсная модуляция (сокр. ШИМ, от англ. PWM — Pulse Width Modulation) является технологией, позволяющей изменять ширину импульсов в то время как частота следования импульсов остается постоянной. В настоящее время она применяется в разнообразных системах контроля и управления, а также в различных приложениях, таких как, к примеру, управление скоростью вращения двигателей, измерениях, управление мощностью чего-либо, связь и др.

Также при использовании ШИМ можно генерировать аналоговые сигналы используя цифровые сигналы. В данной статье мы рассмотрим основы применения широтно-импульсной модуляции (ШИМ) в микроконтроллере ATmega16 (семейство AVR) на примере изменения интенсивности свечения светодиода. Данный пример уже рассматривался на нашем сайте в этой статье (более подробная и наглядная статья), но здесь материал изложен немного по другому – у вас есть возможность выбрать какой из этих материалов использовать.

Контакты ШИМ в микроконтроллере AVR ATmega16

Микроконтроллер Atmega16 имеет 4 контакта для использования ШИМ модуляции — PB3(OC0), PD4(OC1B), PD5(OC1A), PD7(OC2). Более наглядно они представлены на следующем рисунке.

Также ATmega16 имеет два 8-битных (Timer0 и Timer2) и один 16-битный таймер (Timer1). Для понимания принципов формирования ШИМ мы должны понимать основы работы с этими таймерами. Как известно, частота представляет собой количество циклов в секунду поэтому она однозначно связано зависимостью с временем. То есть чем более высокая частота нам нужна, тем более быстрый таймер мы должны использовать. Чем выше частота ШИМ, тем более точно мы можем управлять ее параметрами.

В данной статье для управления ШИМ в микроконтроллере ATmega16 мы будем использовать его Timer2. С его помощью можно выбрать коэффициент заполнения/скважность (duty cycle) ШИМ в широких пределах. Кратко рассмотрим основы этого процесса.

Что такое ШИМ сигнал

ШИМ – это сигнал с различными интервалами ON и OFF сигнала (различными продолжительностями включения). Время, в течение которого сигнал имеет высокий уровень, называется временем включения (“on time”), а время, в течение которого сигнал имеет низкий уровень — время выключения (“off time”). У ШИМ сигнала есть два параметра, которые мы рассмотрим далее.

Коэффициент заполнения (скважность) ШИМ

Процент времени, в течение которого ШИМ сигнал имеет высокий уровень, называется коэффициентом заполнения (скважностью). К примеру, коэффициент заполнения ШИМ сигнала с периодом (длительностью) 100 мс, в котором в течение 50 мс сигнал имеет высокий уровень и в течение 50 мс имеет низкий уровень, равен 50%. Аналогично, если для такой же длительности (100 мс) сигнал 25 мс остается на высоком уровне и 75 мс на низком, то коэффициент заполнения для такого сигнала будет равен 25%. Для его определения нам необходимо знать только длительность высокого уровня сигнала (длительность низкого уровня легко определить как разность между периодом сигнала и длительность сигнала высокого уровня). Более наглядно ШИМ сигнал представлен на следующем рисунке.

Формула для расчета коэффициента заполнения/скважности (Duty Cycle) выглядит следующим образом:

Duty Cycle (%) = On Time/(On Time + Off Time)

Таким образом, изменяя коэффициент заполнения ШИМ сигнала мы можем изменять интенсивность свечения светодиода.

Выбор режима ШИМ

После выбора нужного нам коэффициента заполнения необходимо выбрать еще режим ШИМ – то есть то, каким образом ШИМ будет работать. Существует три типа ШИМ:

  1. Быстрая ШИМ (Fast PWM).
  2. ШИМ с коррекцией фазы (Phase Correct PWM).
  3. ШИМ с коррекцией фазы и частоты (Phase and Frequency Correct PWM).

Быстрая ШИМ используется в случаях когда нам не важна фаза импульсов, например, управление скоростью вращения двигателя или яркостью свечения светодиода.

Для генерации быстрой ШИМ нам необходимо будет запустить на таймере счет и когда он досчитает до определенного значения сбрасывать значение таймера снова в ноль. Таким образом мы установим период следования ШИМ импульсов. Таким образом мы можем контролировать импульс, устанавливая высокое значение сигнала когда счетчик таймера досчитает до определенного значения. А когда счетчик будет возвращаться в 0 на это время сигнал будет низкого уровня. Таким образом, мы имеем большую гибкость в управлении ШИМ сигналом используя всего лишь один таймер.

Необходимые компоненты

  1. Микроконтроллер ATmega16 (купить на AliExpress).
  2. Программатор AVR-ISP (купить на AliExpress), USBASP (купить на AliExpress) или другой подобный.
  3. Кварцевый генератор на 16 МГц (купить на AliExpress).
  4. Конденсатор 100 нФ (2 шт.) (купить на AliExpress).
  5. Конденсатор 22 пФ (2 шт.) (купить на AliExpress).
  6. Светодиод (2 шт.) (купить на AliExpress).
  7. Кнопка.
  8. Макетная плата.
  9. Соединительные провода.
  10. Источник питания с напряжением 5 Вольт.

Схема устройства

Схема устройства приведена на следующем рисунке.

Мы будем использовать для формирования ШИМ сигнала контакт OC2 микроконтроллера ATmega16, поэтому соедините контакт Pin21 (PD7) микроконтроллера со светодиодом.

Программирование ШИМ сигнала в микроконтроллере ATmega16 на языке С (Си)

Полный текст программы приведен ниже, а в этом разделе поясним ключевые особенности программы. Видео, демонстрирующее работу схемы, приведено в конце статьи. На видео вы можете видеть как яркость свечения светодиода будет изменяться постепенно в зависимости от изменения коэффициента заполнения ШИМ.

Начать программирование ШИМ ATmega16 необходимо с установки нужного значения регистра Таймера 2 – его биты приведены на следующем рисунке. Изменяя данные биты, мы можем настраивать нужные нам параметры ШИМ.

В регистре Таймера 2 три группы битов:

  1. FOC2 (Force Output Compare for Timer2) – устанавливается когда WGM биты определяют не режим ШИМ.
  2. WGM2(Wave Generation Mode for Timer2 – режим генерации волны) – эти биты контролируют последовательность счета, максимальное значение счета (TOP counter value) и какой тип формы сигналов будет использован.
  3. COM2 (Compare Output Mode for Timer2 – режим сравнения для Таймера 2) – можно выбрать режим с инвертированием и без инвертирования.

Установим биты WGM20 и WGM21 чтобы активировать режим быстрой ШИМ.

Для полной информации относительно возможных режимов ШИМ, устанавливаемых битами WGM20 и WGM21, посмотрите официальный даташит на ATmega16.

Поскольку мы не будем использовать предделитель, запишем в необходимые биты ‘001’:

Настройки режима сравнения (Compare Output Mode) для режима быстрой ШИМ приведены в следующей таблице.

COM21 COM20 Описание
0 0 Normal port operation, OC2 disconnected
0 1 Зарезервировано
1 0 Clear OC2 on Compare match, Set OC2 at TOP
1 1 Set OC2 on compare match, clear OC2 at TOP

Увеличиваем коэффициент заполнения ШИМ от 0 до 100% — таким образом яркость свечения светодиода будет изменяться с течением времени. Будем использовать значения в диапазоне 0-255, которые будем передавать в OCR2 – это как раз тот байт, который отвечает за установку того самого значения, которое задает различные продолжительности включения (отношение длительности импульса к периоду повторения) импульсов ШИМ.

Аналогичным образом уменьшаем коэффициент заполнения со 100% до 0% чтобы постепенно уменьшать яркость свечения светодиода.

Полный текст программы

Видео, демонстрирующее работу схемы

6 ответов к “Использование широтно-импульсной модуляции (ШИМ) в микроконтроллерах AVR ATmega16”

ДОБРЫЙ ДЕНЬ! КАК ПОЛУЧИТЬ СВЕРХ НИЗКУЮ ЧАСТОТУ ПЕРЕКЛЮЧЕНИЯ НА ВЫХОДЕ 0С1А НУ К ПРИМЕРУ 0,1ГЦ? ЕСЛИ В СЕКУНДУ ТО ЭТО РАЗ 10 СЕКУНД .

Добрый вечер. Ну если вы умеете, к примеру, делать частоту переключения равную 10 Гц (с помощью таймера), то сделайте в программу переменную-счетчик, которую инкрементируйте каждый раз при срабатывании прерывания от таймера, а когда ее значение достигнет 100 — обнуляйте ее и делайте необходимое переключение состояния контакта микроконтроллера. Таким образом, вы из частоты 10 Гц получите частоту 0,1 Гц. Надеюсь, мысль понятна

Как фьюзы выставляли?

Что-то мне подсказывает. Что второй цикл for должен выглядеть вот так:
for(duty=255; duty>0; duty—) // max to 0 duty cycle
{
OCR2=duty; // медленно уменьшаем яркость свечения светодиода
_delay_ms(10);
}

Да, спасибо что заметили опечатку, сейчас исправлю

«TCCR2 |=(1<<COM21)|(1<<CS20)|(0<<CS21)|(0<<CS22);"
В этом случае таймер будет остановлен вовсе.
Ошибка в описании и в исходнике!

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *