В уроке узнаем о широтно-импульсной модуляции, о реализации этого способа управления в контроллерах Ардуино, о режимах и функциях работы с ШИМ в Ардуино.
Предыдущий урок Список уроков Следующий урок
Прервемся на урок от разработки контроллера холодильника, для того чтобы научиться работать с широтно-импульсным модулятором Ардуино.
В нашей разработке используется именно такой способ регулирования мощности на элементе Пельтье.
- Широтно-импульсная модуляция.
- Формирование аналогового сигнала.
- Широтно-импульсные модуляторы в Ардуино.
- Увеличение частоты и разрядности ШИМ Ардуино.
Широтно-импульсная модуляция (ШИМ) это способ управления мощностью на нагрузке с помощью изменения скважности импульсов при постоянной амплитуде и частоте импульсов.
Можно выделить две основные области применения широтно-импульсной модуляции:
- Во вторичных источниках питания, различных регуляторах мощности, регуляторах яркости источников света, скорости вращения коллекторных двигателей и т.п. В этих случаях применение ШИМ позволяет значительно увеличить КПД системы и упростить ее реализацию.
- Для получения аналогового сигнала с помощью цифрового выхода микроконтроллера. Своеобразный цифро-аналоговый преобразователь (ЦАП). Очень простой в реализации, требует минимума внешних компонентов. Часто достаточно одной RC цепочки.
Принцип регулирования с помощью ШИМ – изменение ширины импульсов при постоянной амплитуде и частоте сигнала.
На диаграмме можно увидеть основные параметры ШИМ сигнала:
- Ui - амплитуда импульсов ;
- Ton – время активного (включенного) состояния сигнала;
- Toff – время отключенного состояния сигнала;
- Tpwm – время периода ШИМ.
Даже интуитивно понятно, что мощность на нагрузке пропорциональна соотношению времени включенного и отключенного состояния сигнала.
Это соотношение определяет коэффициент заполнения ШИМ:
Kw = Ton / Tpwm.
Он показывает, какую часть периода сигнал находится во включенном состоянии. Может меняться:
- от 0 – сигнал всегда выключен;
- до 1 - сигнал все время находится во включенном состоянии.
Чаще используют процентный коэффициент заполнения. В этом случае он находится в пределах от 0 до 100%.
Среднее значение электрической мощности на нагрузке строго пропорционально коэффициенту заполнения. Когда говорят, что ШИМ равен, например, 20%, то имеют в виду именно коэффициент заполнения.
Формирование аналогового сигнала.
Если сигнал ШИМ пропустить через фильтр низких частот (ФНЧ), то на выходе фильтра мы получим аналоговый сигнал, напряжение которого пропорционально коэффициенту заполнения ШИМ.
U = Kw * Ui
В качестве ФНЧ можно использовать простейшую RC цепочку.
Из-за неидеальной характеристики такого фильтра частота среза должна быть минимум на порядок меньше частоты ШИМ. Для простого RC фильтра частота среза вычисляется по формуле:
F = 1 / (2 π R C).
- При повышении частоты среза ФНЧ на выходе фильтра увеличиваются пульсации с частотой ШИМ.
- При уменьшении частоты среза фильтра снижается время реакции выходного аналогового сигнала на изменения ширины импульсов.
Из этого вытекает главный недостаток широтно-импульсной модуляции. Метод способен синтезировать только достаточно медленные аналоговые сигналы или требует применения фильтров низких частот с высокой добротностью, сложных в реализации.
Я бы рекомендовал:
- В случае, когда к быстродействию аналогового сигнала жестких требований нет выбирать заведомо заниженную частоту среза фильтра.
- Если необходимо оптимизировать быстродействие аналогового преобразователя, то лучше промоделировать схему.
Даже простейшие моделирующие программы вычисляют уровень пульсаций достаточно точно. Вот результаты моделирования на SwCAD для ШИМ частотой 500 Гц и RC фильтрами с частотами среза 500 Гц, 50 Гц и 5 Гц. Зеленым цветом показана диаграмма ШИМ, синим – напряжение на выходе RC фильтра.
Частота среза 500 Гц (10 кОм, 32 нФ).
Частота среза 50 Гц (10 кОм, 320 нФ).
Частота среза 5 Гц (10 кОм, 3,2 мкФ).
Точность преобразования широтно-импульсных модуляторов определяется погрешностью амплитуды импульсов (т.е. стабильностью питания микроконтроллера) и значением падения напряжения на ключах цифровых выходов микроконтроллера. Как правило, точность ШИМ микроконтроллеров невысока. Добиться высокой точности ШИМ преобразования можно с помощью дополнительной схемы с аналоговыми ключами и источником опорного напряжения.
К недостаткам использования широтно-импульсных модуляторов в качестве ЦАП также следует отнести высокое выходное сопротивление. Оно определяется сопротивлением резистора RC фильтра и не может быть низким из-за малой нагрузочной способности выходов микроконтроллера.
Широтно-импульсные модуляторы в Ардуино.
Платы Ардуино на базе микроконтроллеров ATmega168/328 имеют 6 аппаратных широтно-импульсных модуляторов. Сигналы ШИМ могут быть сгенерированы на выводах 3, 5, 6, 9, 10, 11.
Управление аппаратными ШИМ осуществляется с помощью системной функции analogWrite().
void analogWrite(pin, val)
Функция переводит вывод в режим ШИМ и задает для него коэффициент заполнения. Перед использованием analogWrite() функцию pinMode() для установки вывода в режим “выход” вызывать необязательно.
Аргументы:
- pin – номер вывода для генерации ШИМ сигнала.
- val – коэффициент заполнения ШИМ. Без дополнительных установок диапазон val от 0 до 255 и соответствует коэффициенту заполнения от 0 до 100 %. Т.е. разрядность системных ШИМ в Ардуино 8 разрядов.
analogWrite(9, 25); // на выводе 9 ШИМ = 10%
Частота ШИМ Ардуино 488,28 Гц.
Для генерации ШИМ используются все три таймера Ардуино.
Таймер | Используется для генерации ШИМ на выводах |
Таймер 0 | выводы 5 и 6 |
Таймер 1 | выводы 9 и 10 |
Таймер 2 | выводы 3 и 11 |
Если таймер используется для других целей, например для прерывания, то параметры ШИМ соответствующих выводов могут не соответствовать указанным выше.
Поэтому, при использовании библиотек MsTimer2, TimerOne или им подобных некоторые выводы в качестве ШИМ сигналов использовать нельзя.
Увеличение частоты и разрядности ШИМ Ардуино.
Система Ардуино устанавливает на всех выводах ШИМ параметры:
- частота 976,56 Гц для Timer 0;
- частота 488,28 Гц для Timer 1 и Timer 2;
- разрешение 8 разрядов (0…255).
Очень низкая частота. Для большинства приложений совершенно не допустимая.
В разработке контроллера элемента Пельтье, начатой в предыдущем уроке, частота ШИМ должна быть не менее 30-50 кГц. В интернете достаточно много предложений по увеличению частоты ШИМВо всех описываются методы увеличения частоты до 31 кГц. В принципе приемлемый вариант, но мне захотелось большего.
Я разобрался с Таймером 1 микроконтроллера ATmega168/328, перевел ШИМ в быстродействующий режим и добился частоты ШИМ Ардуино до 62,5 кГц. Заодно я научился менять разрядность ШИМ. Чтобы в следующий раз не копаться в документации на микроконтроллеры ATmega168/328 я свел всевозможные варианты ШИМ для таймера 1 в таблицу.
Строчки из правого столбца для выбранного варианта необходимо написать в функции setup().
Варианты параметров ШИМ на выводах 9 и 10 Ардуино (таймер 1).
Разрешение | Частота ШИМ | Команды установки режима |
8 бит | 62 500 Гц | TCCR1A = TCCR1A & 0xe0 | 1; TCCR1B = TCCR1B & 0xe0 | 0x09; |
7 812,5 Гц | TCCR1A = TCCR1A & 0xe0 | 1; TCCR1B = TCCR1B & 0xe0 | 0x0a; |
|
976,56 Гц | TCCR1A = TCCR1A & 0xe0 | 1; TCCR1B = TCCR1B & 0xe0 | 0x0b; |
|
244,14 Гц | TCCR1A = TCCR1A & 0xe0 | 1; TCCR1B = TCCR1B & 0xe0 | 0x0c; |
|
61,04 Гц | TCCR1A = TCCR1A & 0xe0 | 1; TCCR1B = TCCR1B & 0xe0 | 0x0d; |
|
9 бит | 31 250 Гц | TCCR1A = TCCR1A & 0xe0 | 2; TCCR1B = TCCR1B & 0xe0 | 0x09; |
3 906,25 Гц | TCCR1A = TCCR1A & 0xe0 | 2; TCCR1B = TCCR1B & 0xe0 | 0x0a; |
|
488,28 Гц | TCCR1A = TCCR1A & 0xe0 | 2; TCCR1B = TCCR1B & 0xe0 | 0x0b; |
|
122,07 Гц | TCCR1A = TCCR1A & 0xe0 | 2; TCCR1B = TCCR1B & 0xe0 | 0x0c; |
|
30,52 Гц | TCCR1A = TCCR1A & 0xe0 | 2; TCCR1B = TCCR1B & 0xe0 | 0x0d; |
|
10 бит | 1 5625 Гц | TCCR1A = TCCR1A & 0xe0 | 3; TCCR1B = TCCR1B & 0xe0 | 0x09; |
1 953,13 Гц | TCCR1A = TCCR1A & 0xe0 | 3; TCCR1B = TCCR1B & 0xe0 | 0x0a; |
|
244,14 Гц | TCCR1A = TCCR1A & 0xe0 | 3; TCCR1B = TCCR1B & 0xe0 | 0x0b; |
|
61,04 Гц | TCCR1A = TCCR1A & 0xe0 | 3; TCCR1B = TCCR1B & 0xe0 | 0x0c; |
|
15,26 Гц | TCCR1A = TCCR1A & 0xe0 | 3; TCCR1B = TCCR1B & 0xe0 | 0x0d; |
Следующий скетч генерирует на выводе 9 ШИМ с частотой 62,5 кГц и коэффициентом заполнения примерно 10 %.
void setup() {
// ШИМ 8 разрядов, 62,5 кГц
TCCR1A = TCCR1A & 0xe0 | 1;
TCCR1B = TCCR1B & 0xe0 | 0x09;
analogWrite(9, 25); // на выводе 9 ШИМ=10%
}
void loop() {
}
Это максимально возможная частота ШИМ Ардуино для большинства плат (с частотой генератора 16 мГц).
В следующем уроке вернемся к разработке контроллера элемента Пельтье.
приветствую Эдуард. Вот тут. http://avr-start.ru/?p=367. правда на втором таймере получили 125 кГц. Может ветку в форуме откроем. Разработка Ардуино-контроллера элемента Пельтье. Импульсный (ключевой) регулятор напряжения.
Я решил первый таймер использовать. С ним и разобрался. А что касается форума — открывайте тему, буду рад. Я собирался написать там про увеличение частоты ШИМ Ардуино.
Может я что-то не понимаю. Но максимальная частота в микроконтроллере 16 МГц. Это соответствует периоду 62,5 нс. 62,5 * 256 = 16 мкс. Т.е. при разрядности 8 период ШИМ не может быть меньше 16 мкс или частота выше 62,5 мкс.
1/16000000=0,0000000625
нано 10 в минус9
Я ошибся. Последнее число 62,5 кГц, а не мкс. В остальном все правильно.
я думаю что Вы правы если таймер тикает с частотой процессора то 16 000 000 / 256 = 62 500 или 62,5 кГЦ
Спасибо, очень понятно всё написано.
Правда при испытаниях на ардуино UNO:
10 бит 1 562,5 Гц и 1 953,13 Гц
случается странность.
от 0 до 1024 яркость светодиода плавно растёт, но при значении 255 она увеличивается до максимума.
for (int i=0; i <= 1024; i++){
analogWrite(9, i); // устанавливаем значение на 9 ножке
Serial.println(i);
delay(100);
}
Другие частоты не пробовал.
Все режимы я не проверял. Но 10 разрядов на высокой частоте у меня работало. Разрядность ШИМ 8 или именно число 255 неправильно отрабатывается? Максимальное значение ШИМ должно быть 1023.
Сергей, а Вы правы. Запустил Вашу программу.
void setup() {
// 10 бит 1 562,5 Гц
TCCR1A = TCCR1A & 0xe0 | 3;
TCCR1B = TCCR1B & 0xe0 | 0x09;
}
void loop() {
for (int i=0; i < 1024; i++){ analogWrite(9, i); delay(100); } } Посмотрел осциллографом. Все коды отрабатываются правильно, кроме 255. Код 511 тоже работает правильно. У меня предположение такое. Функция analogWrite() некорректно обрабатывает данные разрядностью больше, чем 8. Код 255 при расширении до 16ти разрядов выглядит как 65535, т.е. все 1. Это особенность двоичной знаковой математики. 255 это -1, а -1 при 16ти разрядах это 65535. Происходит расширение знаковой переменной. Я пробовал явно указывать отсутствие знака (unsigned)i. Не помогло. Получается, что необходимо искусственно исключить код 255 или работать с регистрами таймера.
В этой программке в цикле я просто вставил условие что бы прибавить единицу к переменной » i » когда она равна 255 что бы она перескочила сразу на 256. Надо бы ещё проверить одинакова ли разность в уровне сигнала между 253-254 и 254-256. Тогда проблему можно решить только дополнительным условием.
Хочу применить склеенный светодиод фоторезистор для регулировки тока. С дополнительным измерением тока, путём измерения падения напряжения на резисторе.
Правильнее непосредственно с регистрами таймера 1 работать. На форуме я написал как http://mypractic-forum.ru/viewtopic.php?t=15
Спасибо автору за проделанную работу.
Спасибо. Приятно слышать.
Я использую такой код для ШИМ:
/* Вызываем для изменения скважности) */
void analogWrite16(uint16_t value) { OCR1A = value;}
/* Вызываем в setup() */
void setup16bitPWM () {
pinMode(9,OUTPUT);
TCCR1A=(1<<COM1A1)|(1<<COM1A0)|(1<<WGM11);
TCCR1B=(1<<WGM13)|(1<<WGM12)|(1<<CS10); //mode14 FastPwm
ICR1=65535;
OCR1A=32768; //50% default value
}
Подскажите команды установки первоначального режима т.е. как вернуться к режиму по умолчанию?
строки закоментировал, частота стала по умолчанию, есть глюки не пойму отчего
Здравствуйте!
Установки вернутся при первом же сбросе контроллера. Данные во флэш памяти не меняются.
Спасибо!
Эдуард подскажите пожалуйста, (плата про мини 328p 3,3В 8МГц) в макетном варианте при отладке использовал пины:
SoftwareSerial SIM800(8, 7); // RX, TX модем
#define ONE_WIRE_BUS 4 // датчики температуры
на пин 9 ШИМ analogWrite(IMMO_Pin, 127)
с настройками
TCCR1A = TCCR1A & 0xe0 | 2;
TCCR1B = TCCR1B & 0xe0 | 0x09;
на этом же пине 9 пробовал tone() все ок.
пин 10, 11, 12 на реле через транзисторы.
все это сочетание отлично работало!
развел, протравил плату и использовал другие пины (на момент разводки посчитал что все будет ОК)
SoftwareSerial SIM800(4, 5); // RX, TX модем
#define ONE_WIRE_BUS 7 // датчики температуры
вместо 9 использовал пин 6 и использую функцию tone(6_Pin, 10000) т.к. неумею включать более высокую частоту шим на этом пине.
так же с пин 10, 11, 12 на реле через транзисторы.
так вот теперь нехотят срабатывать реле…
вопрос: при таком сочетании пинов могут ли быть какие то внутренние конфликты??
Здравствуйте!
Не знаю. Как-то у вас все запутано. Функция tone() использует таймер 2. ШИМ вывода 6 работает от таймера 0, который еще используется для системного времени. Отключайте функцию tone(), смотрите.
Здравствуйте!
Интересует смысл записи:
TCCR1A = TCCR1A & 0xe0 | 1;
TCCR1B = TCCR1B & 0xe0 | 0x09;
и аналогичных…
Как я понял, & 0xe0 обнуляет первые 5 битов регистров TCCR1х, а | 1 устанавливает единичку бита 0, | 0x09 устанавливает единички битов 0 и 3.
В таком случае строка TCCR1B = TCCR1B & 0xe0 | 0x09; ясна. Мы сбрасываем все биты, отвечающих за настройки, которые хотим изменить. Потом устанавливаем нужные биты.
Но тогда не понятно, зачем в первой строке сбрасывать все 5 битов. Достаточно сбросить два бита. К тому же биты одного канала шим (COM1A1:COM1A0) не меняются, а в другом канале шим бит COM1B1 не меняется, бит COM1B0 сбрасывается. То есть устанавливаются разные настройки для двух каналов ШИМ.
Или я что-то не совсем понял.
Здравствуйте!
Я уже не точно помню, надо смотреть форматы регистров таймера.
А что касается разной настройки 2х каналов ШИМ, то это не так. TCCR1A и TCCR1B это регистры одного канала ШИМ.
Просто в даташите написано, что два канала ШИМ… TCCR1A и TCCR1B это регистры управления одного таймера. А в этих регистрах есть биты управления обоими каналами ШИМ.
А так ШИМ работает. В данном случае сброшенные биты, возможно, ни на чего не влияют. Но, чтобы лишние биты не затрагивать на всякий случай, можно написать:
TCCR1A = TCCR1A & 0xfc | 1;
TCCR1B = TCCR1B & 0xe0 | 0x09;
Значит я ошибаюсь.
Добрый день. По поводу большей частоты. Если понизить разрядность, скажем, до 6 бит. Частота же должна увеличиться.
Выбираем режим WGM13=WGM12=WGM11=1 — FastPWM mode 0xE и в регистр ICR1 пишем значение 63 в качестве верхней границы таймера. Тогда получим 6 бит разрядности при частоте 250кГц. Только у меня нет осциллографа для проверки своих диванных размышлений 🙂
Доброго времени суток!
Правильно ли я понимаю, что для изменения частоты ШИМ на 5 и 6 пинах нужно в функцию setup добавить строки:
TCCR1A = TCCR1A & 0xe0 | 1;
TCCR1B = TCCR1B & 0xe0 | 0x0a;
Если да, то повлияет ли эти изменения на работу других узлов. К ардуинке подключены драйвер двигателя (пины: 3,4,5,6,7,8), nrf24l01(пины:9,10,11,12,13) и планирую еще магнитометр(пины:А4,А5).
Здравствуйте!
Не поменяет, если в других блоках не используется таймер 1. Эти строки меняют только режим таймера 1.
А вы смотрели эти ШИМ сигналы? Выше 1килогерца, они сильно порченые, у меня, во всяком случае.
У меня что-то не работает. Плата — MEGA 2560
Хотел сделать простой ШИМ регулятор мощности, но больше чем 490Гц не выдает (стандартная частота потов). Один порт на моей плате дает почти 1кГц — порт 4.
Подскажете куда копать?
По читал документацию, разобрался. Жаль что могу получить только 32кГц из 4-х портов. И 62 из 2-х
Привет. Если не трудно, помогите пожалуйста, надо построить на ардуино ШИМ на 20 Гц, заполнение от 30 до 96%%(Мерил осциллографом) . Что такое битность не понял, но может мне и не надо, нужно разово другу помочь. Он устанавливает на свою газель движок от тойоты, а там управление вентиляторами по ШИМ. По Вашей статье вроде ничего сложного, но как пересчитать на 20 Гц не соображу. Спасибо.
Здравствуйте!
«Битность» — это разрешающая способность ШИМ. Т.е. сколько градаций ШИМ он способен сформировать. Например, если у вас выбрано разрешение 9 бит, то это означает максимальное число градаций 511 ( 2 в степени 9 минус 1). Тогда, если вам необходим коэффициент заполнения 100%, надо задать 511, если 30%, надо задать 511 * 30 / 100 = 153.
Что касается вашей задачи. Если вас устроит период ШИМ из таблицы, например, 30 или 15 Гц, то заносите значения из таблицы, а коэффициент заполнения определяете исходя из разрешающей способности, как я написал выше. Если необходима частота периода точно 20 Гц, тогда надо разбираться с таймерами Atmega328. Но ничего сложного там нет.
На сколько я понял работу таймер-счётчика на Atmega 328, в таймере Т1 можно задать ШИМ до пяти с небольшим МГц, но в ущерб разрядности. На железе не проверял (нет под рукой), а в симуляторе PROTEUS всё выдаёт.
Для «оптимальных» 100кГц
void setup() {
// Четырнадцатый режим таймер-счётчика Т1
// ШИМ 100 кГц, разрядность 160 ступеней,
TCCR1A = 0b10000010;
TCCR1B = 0b01011001;
ICR1 = 160;
analogWrite(9, 80); // на выводе 9 ШИМ=50%
}
void loop() {
}