Отличительные особенности:

  • Генерация аналоговых сигналов с помощью ШИМ
  • Высокочастотная масштабируемая синхронизация ШИМ

Введение

Данные "Рекомендации…" являются руководством по использованию высокочастотного широтно-импульсного модулятора (ШИМ), который присутствует в некоторых микроконтроллерах AVR. В состав "Рекомендаций…" входит пример ассемблерного кода, который демонстрирует, как использовать высокочастотный ШИМ микроконтроллера ATtiny26. Таймер с высокочастотным ШИМ также имеется в ATtiny15.

Для генерации импульсов используется режим быстрой ШИМ с переменным заполнением импульсов на выходе OC1A (PB1). Для получения из цифрового ШИМ-сигнала сигнала синусоидальной формы на выходе должен быть предусмотрен аналоговый фильтр.

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

1. Принцип действия

ШИМ в сочетания с аналоговым фильтром может использоваться для генерации аналоговых выходных сигналов, т.е. в качестве цифро-аналогового преобразователя (ЦАП). В качестве основы используется последовательность прямоугольных импульсов с постоянным периодом следования (фиксированная частота преобразования). Для генерации различных аналоговых уровней регулируется заполнение импульсов и, таким образом, изменяется длительность импульсов. Если необходимо сформировать высокий аналоговый уровень, то длительность импульса увеличивают и наоборот.

Усреднение аналогового сигнала за один период (с помощью аналогового фильтра) позволяет сгенерировать аналоговый сигнал. При заполнении импульсов 50% аналоговый сигнал равен половине напряжения питания, а при 75%-ом заполнении импульсов - аналоговый сигнал равен 75% от напряжения питания. Примеры фильтрации выходных сигналов показаны в конце данного документа.

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

Рисунок 1. Низкочастотный RC-фильтр

Если аналоговый сигнал поступает к низкоомному входу, то между выходом фильтра и нагрузкой должен быть включен буферный усилитель. Это предотвращает нагружение конденсатора и появление пульсирующего напряжения.

На рисунке 2 показана реальная осциллограмма ШИМ-сигнала с переменным заполнением импульсов.


Рисунок 2. ШИМ-сигнал с переменным заполнением импульсов

В микроконтроллерах AVR для генерации ШИМ-сигналов используются таймеры-счетчики. Для изменения несущей частоты ШИМ изменяется частота синхронизации таймера и вершина счета. Повышение частоты синхронизации и/или снижение вершины счета приводят к повышению частоты переполнения таймера и, как следствие, увеличивается частота ШИМ. Максимальной разрешающей способности (вершина счета 255) соответствует максимальная частота ШИМ 250 кГц. Дальнейшее увеличение частоты ШИМ возможно путем уменьшения разрешающей способности, но в этом случае сокращается количество шагов при установке заполнения импульсов от 0 до 100%.

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


Рисунок 3. Значения счетчика и ШИМ-выход

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

2. Альтернативные области применения

Высокоскоростной таймер может также использоваться для генерации высокочастотных цифровых сигналов, которые в свою очередь используются для синхронизации других цифровых каскадов. При установке очень малой вершины счета можно генерировать сигналы с очень высокой частотой.

Максимальная тактовая частота таймера микроконтроллера ATtiny26 равна 64 МГц (без предварительного деления). При частоте ШИМ 16 МГц (вершина счета 3) в регистр OCR можно записать значение 0, 1 (заполнение 25%), 2 (заполнение 50%, рисунок 4а) или 3 (заполнение 100%). Этим показывается, что снижением вершины счета увеличивается несущая частота ШИМ.

Для достижения максимальной выходной частоты от таймера его необходимо перевести в режим без ШИМ. Вершина счета и содержимое OCR должны быть равны 0. Счетчик в этом случае зависает на 0. Установка действия по совпадению равным "toggle output" (инвертирование выхода) приводит к инвертированию (переключению) выхода каждый такт таймера. В результате достигается частота 32 МГц (рисунок 4б).


Рисунок 4. Высокочастотный цифровой выход

3. Пример применения

Рисунок 4 иллюстрирует, как генерировать синусоидальный сигнал из высокочастотного ШИМ-сигнала.

Программный код состоит из 3 частей: инициализация, процедура обработка прерывания по переполнению таймера 1 и цикл в режиме сна. В данном примере полагается, что микроконтроллер работает на тактовой частоте 8 МГц.


Рисунок 5. Блок-схема основного цикла программы генерации синусоидального сигнала

3.1. Инициализация

Выход компаратора таймера 1 (OC1A) необходимо настроить на вывод.

Далее выполняется установка таймера 1: подготавливается тактовый источник таймера - запускается схема ФАПЧ, которая должна войти в синхронизм (захват) с системной частотой синхронизации. ФАПЧ требует порядка 100 мс для захвата с системной синхронизацией и, поэтому, перед выполнением последующих действий необходимо подождать установку флага захвата ФАПЧ. Как только ФАПЧ захватывается его необходимо выбрать в качестве тактового источника таймера.

Далее выбирается режим ШИМ с инвертированием вывода OC1A по совпадению и устанавливается вершина счета равной 0xFF. Значение вершины счета определяет разрешающую способность и несущую частоту ШИМ- чем выше значение вершины, тем выше разрешающая способность и ниже несущая частота.

Теперь таймер готов к запуску: установка предделителя приводит к запуску таймера. В завершении разрешается прерывание по переполнению таймера.


Рисунок 6. Процедура инициализации (инициализирует вывод и таймер 1 для работы в режиме быстрой ШИМ)

3.2. Процедура обработки прерывания

Когда таймер 1 достигает значения из OCR1C (0xFF) вызывается процедура обработки прерывания по переполнению таймера. Поскольку значение OCR1C - константа, то и данное событие возникает с постоянной периодичностью. Данный период определяет несущую частоту выходного ШИМ-сигнала.

В процедуре обработки прерывания реализована таблица для генерации синусоидального сигнала. При каждом входе в процедуру увеличивается указатель для доступа к таблице, чтобы всякий раз загружались новые значения. Значение, считанное из таблицы, записывается в регистр OCR1A. Таким образом, генерируемая последовательность импульсов может быть преобразована в синусоидальный сигнал. Обратите внимание, что регистр OCR1A буферизован и что перезапись из буферного регистра в действительный регистр OCR1A происходит при переполнении таймера.

Для выполнения процедуры обработки прерывания необходимо 13 тактов. На вызов процедуры и возврат из нее также затрачивается время - всего потребуется 21 такт. Поскольку таймер 1 является 8-разрядным, то прерывание возникает каждые 256/(Частота_ШИМ/Системная_частота) тактов. В данном примере полагается тактирование внутренним RC-генератором частотой 8 МГц. Если используется максимальная тактовая частота ШИМ 64 МГц, то переполнение таймера возникает каждые 32 системных такта.

Несмотря на возможность тактироваться максимальной частотой 64МГц, в данном примере частота синхронизации таймера принята 4…16 МГц, чтобы дополнительно продемонстрировать работу с предварительным делителем.


Рисунок 7. Блок-схема процедура обработки прерывания по переполнению таймера

3.3. Холостой ход

В процессе ожидания возникновения прерывания микроконтроллер переводится в экономичный режим сна "Холостой ход" (Idle). По завершении обработки прерывания микроконтроллер возвращается в режим сна.

4. Осциллограммы

На следующих рисунках приведены осциллограммы генерации синусоидальных сигналов с помощью микроконтроллера ATtiny26. На осциллограммах представлены два сигнала: цифровой сигнал с выхода OC1A и обработанный/фильтрованный ШИМ-сигнал. Для формирования аналогового синусоидального сигнала использовался простой RC-фильтр с параметрами R = 10 кОм и C = 100 нФ, которым соответствует настроечная частота фильтра 1 кГц. Таким образом, синусоида пропускается, а высокочастотная несущая частота подавляется.


Рисунок 8. Фильтрованный и нефильтрованный выход OC1A


Рисунок 9. Фильтрованный и нефильтрованный выход OC1A (с большим масштабом)

26 сентября 2012 в 13:36

Многоканальный программный ШИМ в AVR

  • Разработка под Arduino

Что такое ШИМ и как он работает особо подробно расписывать не буду, информацию без труда найдёте на просторах интернета. Коснусь лишь общих понятий. ШИМ - это Широтно-Импульсная Модуляция, (по-английски PWM - Pulse Width Modulation) уже из самого названия ясно, что здесь что-то связанное с импульсами и их шириной. Если изменять ширину (длительность) импульсов постоянной частоты, то можно управлять, например, яркостью источника света, скоростью вращения вала электродвигателя или температурой какого-либо нагревательного элемента. Обычно, именно с помощью ШИМ микроконтроллер управляет подобной нагрузкой. Микроконтроллеры имеют аппаратную реализацию ШИМ, но, к сожалению, количество аппаратных ШИМ-каналов ограничено, например, в AТmega88 их аж шесть штук, в ATtiny2313 - четыре, в ATmega8 - три, а в ATtiny13 только два. В AVR ШИМ-каналы используют таймеры и их регистры сравнения OCRxx. Изменяя их содержимое и задавая параметры таймеров, в зависимости от задач, можно управлять состоянием, связанного с регистром, выхода - подавать на него 1 либо 0. То же самое можно организовать программно, управляя любым выводом контроллера, а главное, реализовать большее количество ШИМ-каналов, чем имеется на борту аппаратных. Практически, количество каналов ограничено лишь количеством ножек-выводов микроконтроллера (по крайней мере, если говорить о семействах Mega или Tiny). Как оказалось, алгоритм довольно прост, но у меня ушло некоторое время на его понимание и полное осознание.

Данный алгоритм подробно изложен в оригинальном Appnote AVR136: Low-Jitter Multi-Channel Software PWM. Принцип работы программной реализации заключается в имитации работы таймера в режиме ШИМ. Требуемая длительность импульсов задаётся переменными, соответственно, по одной на каждый канал (в моём коде lev_ch1, lev_ch2, lev_ch3), а так же задаются «близнецы» этих переменных, которые хранят значение для конкретного периода работы таймера (в моём коде buf_lev_ch1, buf_lev_ch2, buf_lev_ch3). Восьмибитный таймер запускается на основной частоте МК и генерирует прерывание по переполнению, то есть, каждые 256 тактов. Это накладывает ограничение на длительность процедуры обработки прерывания - необходимо уложиться в 256 тактов, чтобы не пропустить следующее прерывание. В результате, один полный период ШИМ равняется 256*256=65536-и тактам. Восьмибитная переменная-счетчик (в моём примере counter) увеличивается на единицу каждое прерывание и действует, как указатель позиции внутри цикла ШИМ. Всё это обеспечивает разрешение (минимальный шаг) ШИМ в 1/256, а частоту импульсов в ƒ/(256*256), где ƒ-частота задающего генератора микроконтроллера. Следует заметить, что тактовая частота микроконтроллера должна быть довольно высокой. В моём примере ATtiny13 работает на максимально возможной частоте, без применения внешнего генератора - 9,6МГц. Это даёт период ШИМ в 9600000/65536≈146,5Гц чего вполне достаточно в большинстве случаев.
Код на C, пример реализации идеи для МК ATtiny13 (три канала ШИМ на выводах PB0, PB1, PB2):

#define F_CPU 9600000 //fuse LOW=0x7a #include #include uint8_t counter=0; uint8_t lev_ch1, lev_ch2, lev_ch3; uint8_t buf_lev_ch1, buf_lev_ch2, buf_lev_ch3; void delay_ms(uint8_t ms) //функция задержки { while (ms) { _delay_ms(1); ms--; } } int main(void) { DDRB=0b00000111; // установка PortB пины 0,1,2 выходы TIMSK0 = 0b00000010; // включить прерывание по переполнению таймера TCCR0B = 0b00000001; // настройка таймера, делитель выкл sei(); // разрешить прерывания lev_ch1=0; //начальные значения lev_ch2=64; //длительности ШИМ lev_ch3=128; //трёх каналов while (1) //бесконечная шарманка { for (uint8_t i=0;i<255;i++) { lev_ch1++; //увеличиваем значения lev_ch2++; //длительности ШИМ lev_ch3++; //каждого канала delay_ms(50); //пауза 50мс } } } ISR (TIM0_OVF_vect) //обработка прерывания по переполнению таймера { if (++counter==0) //счетчик перехода таймера через ноль { buf_lev_ch1=lev_ch1; //значения длительности ШИМ buf_lev_ch2=lev_ch2; buf_lev_ch3=lev_ch3; PORTB |=(1<Думаю, всё достаточно наглядно и пояснения излишни. Для значений длительности и их буферов, при большем числе каналов, возможно, будет лучше использовать массивы, но в данном примере, я этого делать не стал, ради большей наглядности.
Проверено на avr-gcc-4.7.1 и avr-libc-1.8.0. Компиляция и получение файла прошивки:
avr-gcc -mmcu=attiny13 -Wall -Wstrict-prototypes -Os -mcall-prologues -std=c99 -o softPWM.obj softPWM.c
avr-objcopy -O ihex softPWM.obj softPWM.hex
Для правильной работы нужно выставить младшие fuse-биты в 0x7a (частота 9,6МГц). в avrdude это, например, делается так:
avrdude -p t13 -c usbasp -U lfuse:w:0x7a:m

Мой вариант реализации на ассемблере. Программа делает абсолютно то же самое, что и предыдущий код на C.
;чтобы не тянуть include-файл.list .equ DDRB= 0x17 .equ PORTB= 0x18 .equ RAMEND= 0x009f .equ SPL= 0x3d .equ TCCR0B= 0x33 .equ TIMSK0= 0x39 .equ SREG= 0x3f ;это лишь демонстрация, потому регистров и не жалеем.def temp=R16 .def lev_ch1=R17 .def lev_ch2=R18 .def lev_ch3=R19 .def buf_lev_ch1=R13 .def buf_lev_ch2=R14 .def buf_lev_ch3=R15 .def counter=R20 .def delay0=R21 .def delay1=R22 .def delay2=R23 .cseg .org 0 ;таблица прерываний из даташита: rjmp RESET ; Reset Handler rjmp EXT_INT0 ; IRQ0 Handler rjmp PIN_CHG_IRQ ; PCINT0 Handler rjmp TIM0_OVF ; Timer0 Overflow Handler rjmp EE_RDY ; EEPROM Ready Handler rjmp ANA_COMP ; Analog Comparator Handler rjmp TIM0_COMPA ; Timer0 CompareA Handler rjmp TIM0_COMPB ; Timer0 CompareB Handler rjmp WATCHDOG ; Watchdog Interrupt Handler rjmp ADC_IRQ ; ADC Conversion Handler ;RESET: EXT_INT0: PIN_CHG_IRQ: ;TIM0_OVF: EE_RDY: ANA_COMP: TIM0_COMPA: TIM0_COMPB: WATCHDOG: ADC_IRQ: reti RESET: ldi temp,0b00000111 ; назначаем PortB пины PB0, PB1 out DDRB,temp ; и PB2 выходами ldi temp,0 ; выставляем все выводы out PORTB,temp ; PortB в 0 ldi temp,low(RAMEND) ; инициализация out SPL,temp ; стека ldi temp,0b00000001 ; вкл. таймер out TCCR0B,temp ; без делителя ldi temp,0b00000010 ; вкл. прерывание out TIMSK0,temp ; таймера по переполнению sei ; разрешить прерывания start_pwm: ; бесконечная шарманка inc lev_ch1 ; увеличиваем значения inc lev_ch2 ; длительности ШИМ inc lev_ch3 ; по всем каналам rcall delay ; небольшая пауза для плавности rjmp start_pwm delay: ; процедура задержки ldi delay2,$01 ; выставляем число ldi delay1,$77 ; до скольки считать ldi delay0,$00 ; $017700 - даст задержку в 50мс loop: subi delay0,1 ; считаем sbci delay1,0 ; считаем sbci delay2,0 ; считаем brcc loop ret TIM0_OVF: ; обработка прерывания таймера push temp ; на всякий пожарный сохраняем in temp,SREG ; temp и SREG в стеке push temp inc counter ; счетчик перехода таймера через 0 cpi counter,0 ; если не 0, то проверяем brne ch1_off ; не надо ли чего погасить mov buf_lev_ch1,lev_ch1 ; если счетчик 0 mov buf_lev_ch2,lev_ch2 ; то задаем новые mov buf_lev_ch3,lev_ch3 ; значения длительности ШИМ каналов ldi temp,0b00000111 ; включить все out PORTB,temp ; три выхода ch1_off: ; а не погасить ли нам cp counter,buf_lev_ch1 ; первый канал? brne ch2_off ; нет, рано - проверяем второй cbi PORTB,0 ; да погасить ch2_off: ; а не погасить ли нам cp counter,buf_lev_ch2 ; второй канал? brne ch3_off ; нет, рано - проверяем третий cbi PORTB,1 ; да погасить ch3_off: ; а не погасить ли нам cp counter,buf_lev_ch3 ; третий канал? brne irq_end ; нет, рано - двигаемся к выходу из прерывания cbi PORTB,2 ; да, погасить irq_end: ; достаем из стека pop temp ; SREG и temp out SREG,temp pop temp reti ;выходим из прерывания
Компилируется с помощью avra или tavrasm. Не забыть про fuse-биты (см. выше).

ШИМ (PWM) — широтно-импульсная модуляция. Не нужно пугаться данного термина. Это всего навсего способ регулирования напряжения. Допустим подсветка монитора горит слишком ярко, вы меняете яркость. А что же происходит в этот момент на самом деле?

Представим себе, что подсветка монитора это несколько светодиодов. Питается все это дело от постоянного напряжения. Но вот нам понадобилось уменьшить яркость монитора. Логично ответить, что это можно сделать переменным резистором. На маленьких токах — возможно. Но на больших, резистор будет сильно греться. Сильно возрастут габариты, потери, энергопотребление.

Поэтому люди придумали схему на транзисторах, которая делает из постоянного напряжения пульсирующее. Оказывается, пульсирующее напряжение, в зависимости от заполнения периода будет эквивалентно постоянному напряжению. Т.е. если в течение периода напряжение 50% времени было включено, 50% выключено, то эквивалент постоянного напряжения будет равен 50% от номинального.

В цифрах это просто — было 5В постоянного напряжения прогнали через ШИМ — получили 2,5В. Если заполнение импульса равно 75%, то эквивалентное постоянное напряжение будет 3,75В. Думаю идея понятна.

Теперь приступим к практической реализации. Будем при помощи микроконтроллера изменять заполнение от 0 до 100%, потом от 100% до нуля. Конечный результат должен выглядеть так:

Чтобы было более наглядно, подключим светодиод. В результате у нас будет плавно включаться и отключаться светодиод.

Запускаем наш любимый CodeVision. Создаем проект при помощи мастера. В разделе таймеров (Timers), выбираем Timer 2 и выставляем настройки как на рисунке.

Если попробовать сгенерировать проект, то прога может ругнуться. Соглашаемся, ведь у нас нога 3 порта В должна быть настроена как выход.

Приводим код к следующему виду:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #include void main(void ) { PORTB= 0x00 ; DDRB= 0x08 ; // Timer/Counter 2 initialization ASSR= 0x00 ; TCCR2= 0x6C ; TCNT2= 0x00 ; OCR2= 0x00 ; TIMSK= 0x00 ; while (1 ) { } ; }

#include void main(void) { PORTB=0x00; DDRB=0x08; // Timer/Counter 2 initialization ASSR=0x00; TCCR2=0x6C; TCNT2=0x00; OCR2=0x00; TIMSK=0x00; while (1) { }; }

Уделим внимание строке OCR2=0x00; Эта переменная как раз и отвечает за величину заполнения импульса. Изменяется данная величина от 0 до 255(0хFF), т.е. 255 соответствует 100% -му заполнению (постоянный ток). Следовательно, если нужно 30% заполнение (255/100)*30=77. Далее 77 переводим в шестнадцатеричную систему OCR2=0x4D;

TCCR2=0x6C; Изменяя данную величину мы можем регулировать частоту ШИМ. Величина частоты работы ШИМ кратна частоте, на которой работает микроконтроллер. В проекте использована частота микроконтроллера 8 МГц, частоту ШИМ использовали 125кГц, следовательно делитель равен 8/125=64
0x6C в двоичной системе счисления 1101100, открываем даташит на Atmega8 и видим описание регистра TCCR2, так вот 1101100 последние цифры 100 и отвечают за выбор частоты работы ШИМ

Приступим непосредственно к программе:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 #include #include void main(void ) { PORTB= 0x00 ; DDRB= 0x08 ; ASSR= 0x00 ; TCCR2= 0x6C ; TCNT2= 0x00 ; OCR2= 0x00 ; TIMSK= 0x00 ; while (1 ) { while (OCR2< 0xff ) { OCR2= OCR2+ 0x01 ; delay_ms(5 ) ; } while (OCR2> 0x00 ) { OCR2= OCR2- 0x01 ; delay_ms(5 ) ; } } ; }

#include #include void main(void) { PORTB=0x00; DDRB=0x08; ASSR=0x00; TCCR2=0x6C; TCNT2=0x00; OCR2=0x00; TIMSK=0x00; while (1) { while(OCR2<0xff) { OCR2=OCR2+0x01; delay_ms(5); } while(OCR2>0x00) { OCR2=OCR2-0x01; delay_ms(5); } }; }

Код прост до безобразия: сначала в цикле увеличиваем заполнение от 0 до 255(ff), потом уменьшаем от 255 до 0.
И напоследок видосик, как это все должно работать. Успехов в изучении)

Широтно-импульсная модуляция (ШИМ) – это метод преобразования сигнала, при котором изменяется длительность импульса (скважность), а частота остаётся константой. В английской терминологии обозначается как PWM (pulse-width modulation). В данной статье подробно разберемся, что такое ШИМ, где она применяется и как работает.

Область применения

С развитием микроконтроллерной техники перед ШИМ открылись новые возможности. Этот принцип стал основой для электронных устройств, требующих, как регулировки выходных параметров, так и поддержания их на заданном уровне. Метод широтно-импульсной модуляции применяется для изменения яркости света, скорости вращения двигателей, а также в управлении силовым транзистором блоков питания (БП) импульсного типа.

Широтно-импульсная (ШИ) модуляция активно используется в построении систем управления яркостью светодиодов. Благодаря низкой инерционности, светодиод успевает переключаться (вспыхивать и гаснуть) на частоте в несколько десятков кГц. Его работа в импульсном режиме воспринимается человеческим глазом как постоянное свечение. В свою очередь яркость зависит от длительности импульса (открытого состояния светодиода) в течение одного периода. Если время импульса равно времени паузы, то есть коэффициент заполнения – 50%, то яркость светодиода будет составлять половину от номинальной величины. С популяризацией светодиодных ламп на 220В стал вопрос о повышении надёжности их работы при нестабильном входном напряжении. Решение было найдено в виде универсальной микросхемы – драйвера питания, работающего по принципу широтно-импульсной или частотно-импульсной модуляции. Схема на базе одного из таких драйверов детально описана .

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

Масштабное применение ШИМ отражено во всех LCD панелях со светодиодной подсветкой. К сожалению, в LED мониторах большая часть ШИ-преобразователей работает на частоте в сотни Герц, что негативно отражается на зрении пользователей ПК.

Микроконтроллер Ардуино тоже может функционировать в режиме ШИМ контроллера. Для этого следует вызвать функцию AnalogWrite() с указанием в скобках значения от 0 до 255. Ноль соответствует 0В, а 255 – 5В. Промежуточные значения рассчитываются пропорционально.

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

ШИМ-контроллер является неотъемлемой частью современного импульсного блока питания. Он управляет работой силового транзистора, расположенного в первичной цепи импульсного трансформатора. За счёт наличия цепи обратной связи напряжение на выходе БП всегда остаётся стабильным. Малейшее отклонение выходного напряжения через обратную связь фиксируется микросхемой, которая мгновенно корректирует скважность управляющих импульсов. Кроме этого современный ШИМ-контроллер решает ряд дополнительных задач, способствующих повышению надёжности источника питания:

  • обеспечивает режим плавного пуска преобразователя;
  • ограничивает амплитуду и скважность управляющих импульсов;
  • контролирует уровень входного напряжения;
  • защищает от короткого замыкания и превышения температуры силового ключа;
  • при необходимости переводит устройство в дежурный режим.

Принцип работы ШИМ контроллера

Задача ШИМ контроллера состоит в управлении силовым ключом за счёт изменения управляющих импульсов. Работая в ключевом режиме, транзистор находится в одном из двух состояний (полностью открыт, полностью закрыт). В закрытом состоянии ток через p-n-переход не превышает несколько мкА, а значит, мощность рассеивания стремится к нулю. В открытом состоянии, несмотря на большой ток, сопротивление p-n-перехода чрезмерно мало, что также приводит к незначительным тепловым потерям. Наибольшее количество тепла выделяется в момент перехода из одного состояния в другое. Но за счёт малого времени переходного процесса по сравнению с частотой модуляции, мощность потерь при переключении незначительна.

Широтно-импульсная модуляция разделяется на два вида: аналоговая и цифровая. Каждый из видов имеет свои преимущества и схемотехнически может реализовываться разными способами.

Аналоговая ШИМ

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

Цифровая ШИМ

Широтно-импульсная модуляция в цифровой интерпретации является одной из многочисленных функций микроконтроллера (МК). Оперируя исключительно цифровыми данными, МК может формировать на своих выходах либо высокий (100%), либо низкий (0%) уровень напряжения. Однако в большинстве случаев для эффективного управления нагрузкой напряжение на выходе МК необходимо изменять. Например, регулировка скорости вращения двигателя, изменение яркости светодиода. Что делать, чтобы получить на выходе микроконтроллера любое значение напряжения в диапазоне от 0 до 100%?

Вопрос решается применением метода широтно-импульсной модуляции и, используя явление передискретизации, когда заданная частота переключения в несколько раз превышает реакцию управляемого устройства. Изменяя скважность импульсов, меняется среднее значение выходного напряжения. Как правило, весь процесс происходит на частоте в десятки-сотни кГц, что позволяет добиться плавной регулировки. Технически это реализуется с помощью ШИМ-контроллера – специализированной микросхемы, которая является «сердцем» любой цифровой системы управления. Активное использование контроллеров на основе ШИМ обусловлено их неоспоримыми преимуществами:

  • высокой эффективности преобразования сигнала;
  • стабильность работы;
  • экономии энергии, потребляемой нагрузкой;
  • низкой стоимости;
  • высокой надёжности всего устройства.

Получить на выводах микроконтроллера ШИМ сигнал можно двумя способами: аппаратно и программно. В каждом МК имеется встроенный таймер, который способен генерировать ШИМ импульсы на определённых выводах. Так достигается аппаратная реализация. Получение ШИМ сигнала с помощью программных команд имеет больше возможностей в плане разрешающей способности и позволяет задействовать большее количество выводов. Однако программный способ ведёт к высокой загрузке МК и занимает много памяти.

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

Пример использования ШИМ регулятора

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

Читайте так же

Был рассмотрен аппаратный ШИМ генератор микроконтроллера. Всё в нем хорошо, но есть несколько "но":
- аппаратный ШИМ жёстко привязан к определенным выводам МК, его невозможно переназначить на другую ногу
- количество аппаратных ШИМ каналов ограничено, их количество зависит от модели МК
- разрядность аппаратного ШИМ невозможно изменить

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

Нам необходимо в начале периода ШИМ сигнала выставлять определенную ногу МК в 1 или 0 (в зависимости от того, какой сигнал нам нужен), а потом, по достижении заданной длительности импульса, инвертировать значение ножки. Делать это удобнее всего в прерывании по переполнению. Так мы и поступим, воспользуемся прерыванием по переполнению таймера T0. Управлять будем RGB светодиодом, поэтому и названия переменных и макроопределения для портов сделаем удобочитаемыми.

/*блок дефайнов***************************************************************************************************/ #define RED PORTB.0 #define GREEN PORTB.1 #define BLUE PORTB.2 /*****************************************************************************************************************/ /*объявляем прерменные********************************************************************************************/ unsigned char red=255, green, blue; //переменные, для изменения скважности ШИМ в программе unsigned char red_b, green_b, blue_b; //переменные, для буферизации значений скважности ШИМ unsigned char count; //переменная- счетчик вызовов обработчика прерываний unsigned char temp=1; //переменная для работы алгоритма смены цветов /*****************************************************************************************************************/

Когда наступает прерывание, необходимо увеличить программный счетчик на 1 и проверить, не переполнился ли он. Если таймер переполнен, то нужно на все ножки, на которые выводится ШИМ, вывести логическую 1, а так же сохранить переменные в буфер. Переменные в буфер сохраняются для того, чтобы данные о скважности обновлялись раз в начале каждого периода, это исключает непредсказуемое поведение выхода. Далее сравниваем значение счетчика со значением буфера скважности каждого канала. Если счетчик достиг этого значения- выводим в соответствующую ногу МК логический 0.

/*обработчик прерывания*******************************************************************************************/ interrupt void timer0_ovf_isr(void) { count++; if (count == 0){ //если счетчик переполнился и принял значение 0 red_b = red; //сохранием значения в буфер green_b = green; blue_b = blue; RED =1; //выставляем ноги, отвечающие за ШИМ в логическую 1 GREEN =1; BLUE =1; } if (red_b == count) { RED = 0;} //по достижении заданной скважности выводим логический 0 в ножку МК if (green_b == count) { GREEN = 0;} if (blue_b == count) { BLUE = 0;} } /*****************************************************************************************************************/

Для демонстрации работы будем выводить на светодиод плавную смену цвета по цветам радуги (Каждый Охотник Желает Знать Где Сидит Фазан). Для этого воспользуемся нехитрым алгоритмом, который будем крутить в бесконечном цикле.

/*главная функция*************************************************************************************************/ void main(void) { PORTB=0x08; //конфигурируем порт DDRB=0x07; TCCR0=0x01; //настраиваем таймер TCNT0=0x00; TIMSK=0x01; //разрешаем генерацию прерывания по переполнению таймера T0 #asm("sei") //глобально разрешаем прерывания /*бесконечный цикл************************************************************************************************/ while (1) { if (temp==1) {if (green < 255) green += 1; else temp = 2;} if (temp==2) {if (red > 0) red -= 1; else temp = 3;} if (temp==3) {if (blue < 255) blue += 1; else temp = 4;} if (temp==4) {if (green > 0) green -= 1; else temp = 5;} if (temp==5) {if (red < 255) red += 1; else temp = 6;} if (temp==6) {if (blue > 0) blue -= 1; else temp = 1;} delay_ms(2); }; /*****************************************************************************************************************/ } /*****************************************************************************************************************/