ШИМ-контроллер: схема, принцип работы, управление. AVR131: Использование высокочастотной ШИМ микроконтроллеров AVR

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

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

Нам необходимо в начале периода ШИМ сигнала выставлять определенную ногу МК в 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); }; /*****************************************************************************************************************/ } /*****************************************************************************************************************/

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

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

Введение

Данные "Рекомендации…" являются руководством по использованию высокочастотного широтно-импульсного модулятора (ШИМ), который присутствует в некоторых микроконтроллерах 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 (с большим масштабом)

ШИМ - Широтно импульсная модуляция
PWM - Pulse Width Modulation (т.е. то же самое, что и ШИМ)

Что такое ШИМ и зачем он нужен?

Зачем нужен программный ШИМ?

Затем, что на самом AVR (Atmega) каналов шим 1-2, что часто не хватает для того, что надо.

Пусть у нас есть 3 (три) светодиода и яркостью каждого их них мы хотим управлять индивидуально. Встроенных ШИМ каналов таймера не хватит. И, вообще, может мы еще какой-то особый контроль хотим осуществлять над каждым из них. Поэтому сажаем их на обычные ноги (в примере PORTC ноги 3,4,5) и управляем программно.

Дополнительная информация по поводу подключения: http://www.radiokot.ru/start/mcu_fpga/avr/05/ и в даташите к контроллеру.

Расчет резистора для светодиода:

Питание: 5В. Падение напряжения на светодиоде можно считать 1.5В. Тока на светодиоде должен быть не более 20мА (некоторые поспорят, что надо 15мА, но мне нравится поярче).
По закону Ома: I=U/R, R=U/I=(5-1.5)/0.02=175 Ом. Я поставил резисторы R1,R2 и R2 - 220 Ом.

Алгоритм

Простейший вариант - вечный цикл. Вариант с прерыванием будет позже (ниже), сейчас рассмотрим простой пример, чтобы понять суть.

Во-первых надо определить с двумя вещами: с какой частотой будут моргать светодиоды, чтобы не было видно этого моргания и, второе, сколько уровней яркости может иметь светодиод.

По уровням яркости пусть будет 256. 0 - выключен полностью, 255 - включен полностью (т.е. ШИМ канал находится в логической единице все время, т.е. duty cycle = 100%.

Однако, сейчас я малек запутаю вас.

Суть в том, что у нас ПЛЮС диода на схеме тыкнут на прямую на питание, а минус идет через резистор к ноге (где резистор - не важно, важно что к ноге МК). Поэтому светодиод светится, когда на ноге МК низкий уровень, т.е. ноль, т.е. нога внутри МК прокинута на GND, т.е. на ЗЕМЛЮ. Это значит, что на самом деле 0 и 1 в ШИМ должны быть инвертированы. Т.е. чем дольше в сигнале будет 0 по отношению к 1, тем ярче будет диод.

И так, уровней яркости 256.

О каком моргании идет речь? Суть в том, что если мы должны подать ШИМ сигнал на много много диодов и делаем это последовательно на каждый, то после вывода сигнала на первый диод надо вернуться к выводу сигнала на него же за такое время, чтобы:

  1. успеть сформировать полноценный ШИМ сигнал,
  2. не прошло более 1/25 секунды, иначе будет заметное мигание светодиода,
  3. между отрезками сигнала ШИМ не было заметных пауз в генерации шим, т.е. чтобы ШИМ сигнал НЕ БЫЛ ИСКАЖЕН.

Вот пример искажения ШИМ сигнала:

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

И так, вот исходный код (для AVR studio, т.е. gcc):

#define F_CPU 1000000UL #include #include #define LEDS_N 3 #define LEDS_PORT PORTC #define LEDS_DDR DDRC int main() { register unsigned char scancounter=0; register unsigned char i; register unsigned char glow=0; unsigned char level={0,16,32}; // which part of all cycles the led is ON unsigned char ledbits={0b00001000,0b00010000, 0b00100000}; // set C5 direction - output LEDS_DDR=0b11111111; // turn off all leds LEDS_PORT=0b11111111; for(;;){ // main pwm part for (i=0;i=level[i]){ // off - turn on the pin LEDS_PORT|=ledbits[i]; } else { // on - turn off he pin LEDS_PORT&=~ledbits[i]; } } scancounter++; // led brightness change if (!scancounter){ for (i=0;i128)level[i]=0; } } } }

Принцип работы программы

Есть счетчик отрезков времени - scancount. Максимальное значение этого счетчика - это количество уровней яркости минус 1. Каждый оборот цикла он увеличивается на единицу, потом переваливает за 255 и снова становится 0. В каждом обороте цикла происходит установка сигнала для каждого светодиода. Если счетчик меньше больше или равен уровню яркости, то выключаем диод. Если счетчик меньше уровня яркости заданного для диода - то включаем это диод. И как каждый цикл. Например, если уровень яркости равен 0, то счетчик всегда будет равен или более нуля и диод всегда будет выключен. Если уровень яркости 255, то счетчик будет меньше этого значения 254 из 255 оборотов счетчика и будет гореть практически в полную силу. Если яркость установлена в 50, то 50 первых оборотом цикла диод будет включен, а 206 оставшихся оборотов - выключен, т.е. на него будет подана 50/256 тока от максимума.

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

Надо также знать, что зависимость яркости от тока у светодиодов НЕ ЛИНЕЙНАЯ. Т.е. 128 не в два раза тусклее, чем 255 и не в 2 раза ярче, чем 64.

За сколько проворачивается весь цикл со всеми диодами, нас здесь мало интересует, так как понятно, что на чистоте 1Мгц (именно на ней у меня работает МК), это будет достаточно быстро, чтобы глаз не видел никаких мерцаний.

Фото сборки:


нажмите на фото, чтобы увеличить

И вот видео работы: (avi, divx, 3MB)
Видео плохо показывает процесс перехода яркости, так как матрица фотоаппарата не обладает такой инерцией зрения, как человеческий глаз, но, в целом, процесс виден.

ШИМ (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.
И напоследок видосик, как это все должно работать. Успехов в изучении)

В устройствах на микроконтроллерах иногда требуется генерировать аналоговый сигнал. В зависимости от частоты аналогового сигнала, требуемого разрешения и типа используемого микроконтроллера, выполнить это можно несколькими способами. А именно: с помощью широтно-импульсной модуляции, используя функционал аппаратных таймеров или программную реализацию, с помощью встроенного цифроаналогового преобразователя (ЦАП`а), с помощью внешних схем цифроаналоговых преобразователей на дискретных элементах или с помощью внешних микросхем цифроаналоговых преобразователей.

1. Принцип генерации аналогового сигнала с помощью ШИМ (PWM)

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


Таким образом, меня этот коэффициент, можно генерировать аналоговые сигналы произвольной формы. Причем как переменные, например, синусоида, пила или человеческая речь, так и постоянные (произвольный уровень напряжения).

1.1 Характеристики сигнала

Максимальная амплитуда выходного аналогового сигнала будет определяться амплитудой логической единицы цифрового ШИМ сигнала. Если микроконтроллер питается от +5 В, то грубо говоря, амплитуда выходного аналогового сигнала будет от 0 до 5 В.

Минимальный шаг изменения аналогового сигнала (разрешение) будет определяться выражением:


dUa = Umax/2^n,


где Umax максимальная амплитуда аналогового сигнала (В), а n - разрядность счетчика реализующего ШИМ.

Например, ШИМ сигнал формируется с помощью программного 8-ми разрядного счетчика. Количество градаций ШИМ сигнала, которые можно получить с помощью этого счетчика, равно 2^8 = 256. Тогда разрешение аналогового сигнала при Umax = 5 В будет равно


dUa = 5/256 = 0,0195 В.


Частота ШИМ сигнала будет определять так:


Fpwm = Fcpu/(K*2^n),


где Fcpu - тактовая частота микроконтроллера (Гц), K - коэффициент предделителя счетчика, n - разрядность счетчика.

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

Fpwm = 8000000/(8*256) = ~3906 Гц


Частота выходного аналогового сигнала будет определяться выражением:

Fa = Fpwm/Ns = Fcpu/(K*2^n*Ns),


где Fpwm - частота ЩИМ сигнала, а Ns - количество отсчетов аналогового сигнала.

Например, ШИМ сигнал реализуется на 8-ми разрядном счетчике с коэффициентом предделителя равным 8 и тактовой частотой микроконтроллера 8 МГц. В памяти микроконтроллера записано 32 отсчета синусоидального сигнала, которые представляют собой один его период. Тогда частота выходной синусоиды будет равна:

Fa = 8000000/(8*2^8 * 32) = ~122 Гц

Разрядность ЦАП`a сделанного на основе ШИМ эквивалентна разрядности используемого счетчика.

1.2 Аппаратная реализация ШИМ

Все современные микроконтроллеры имеют в своем составе таймеры/счетчики. Один или несколько режимов этих таймеров предназначены для генерации ШИМ сигнала. Как правило этот сигнал генерируется на специальных выводах. Например, у микроконтроллера mega16 фирмы Atmel 8-ми разрядный таймер/счетчик Т0 имеет два режима генерации ШИМ сигнала (быстрый ШИМ и ШИМ с точной фазой), а для вывода сигнала используется пин порта B - OC0 (PINB3).

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

1.3 Программная реализация ШИМ

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

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

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

Ниже приведен пример кода, который выполняет функцию генерацию аналогового сигнала с помощью аппаратной и программной широтно-импульсной модуляции. Код написан для микроконтроллера atmega16, тактовая частота 8 МГц, компилятор IAR. На выходах PB2 и PB3 генерируются две синусоиды (разной частоты) из 32 двух отсчетов.


#include
#include
#include

#define SPWM_PIN 2

//таблица синуса
__flash uint8_t tableSin =
{
152,176,198,218,234,245,253,255,
253,245,234,218,198,176,152,128,
103, 79, 57, 37, 21, 10, 2, 0,
2, 10, 21, 37, 57, 79,103,128
};

uint8_t softCount = 0;
uint8_t softComp = 0;

int main(void)
{
//настройка портов
PORTB = 0;
DDRB = 0xff;

//разрешение прерывания по совпадению Т0
TIMSK = (1< //режим FastPWM, неинв. шим сигнал, предделитель 8
TCCR0 = (1< (0<

//обнуляем счетный регистр
TCNT0 = 0;
OCR0 = 0;

Enable_interrupt();
while(1);
return 0;
}

//прерывание таймера Т0
#pragma vector = TIMER0_COMP_vect
__interrupt void Timer0CompVect(void)
{
static uint8_t i = 0;
static uint8_t j = 0;

OCR0 = tableSin[i];
i = (i + 1) & 31;

//программный ШИМ
softCount++;
if (softCount == 0){
PORTB |= (1< softComp = tableSin[j];
j = (j + 1) & 31;
}

If (softCount == softComp){
PORTB &= ~(1< }
}

1.4 Фильтр для ШИМ

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

Рассмотрим пример. ШИМ сигнал генерируется аппаратным 8-ми разрядным счетчиком с коэффициентом предделителя равным 8, тактовая частота микроконтроллера 8МГц, количество отсчетов аналогового сигнала - 32.

Частота ШИМ сигнала будет равна:

Fpwm = Fcpu/(K*2^n) = 8000000/(8*256) = ~3906 Гц

Частота аналогового сигнала будет равна:

Fa = Fpwm/Ns = 3906/32 = 122 Гц

Выберем частоту среза равную 200 Гц и рассчитаем номиналы пассивного низкочастотного RC фильтра. Частота среза такого фильтра определяется выражением:

Fc = 1/(2*Pi*R*C),

где R - номинал резистора (Ом), а C -емкость конденсатора (Ф).

Задавшись номиналом одного из компонентов можно вычислить номинал второго. Для резистора номиналом 1 кОм, емкость конденсатора будет равна:


C = 1/(2*Pi*Fc*R) = 1/(6.28 * 1000*200) = ~0.8 мкФ


Выбираем ближайшее значение из ряда E12 - 0.82 мкФ. При таких номиналах фильтра мы получим уже похожий аналоговый сигнал.

Однако, как правило, одного звена пассивного фильтра будет не достаточно. Потому что после него аналоговых сигнал все еще будет содержать большое количество гармоник.