Очень часто в робототехнике возникает необходимость плавно управлять каким-то процессом, будь то яркость светодиода, мощность обогревателя или скорость вращения моторчика. Вполне очевидно, что управление напрямую связано с изменением напряжения на потребителе: и светодиод будет по-другому светить, и моторчик крутиться с другой скоростью. Но проблема в том, что управлять напряжением может только такая штука, как ЦАП – цифро-аналоговый преобразователь, а в нашем микроконтроллере встроенного ЦАПа нет, у нас есть только цифровой сигнал, т.е. либо вкл, либо выкл:
Можно ли добиться плавного управления цифровым сигналом? Оказывается можно! Представьте себе вентилятор, вращающийся на полной мощности, напряжение постоянно. Представим теперь, что секунду напряжение подаётся, и секунду – нет, и так продолжается “по кругу”. Вентилятор начнёт крутиться в два раза медленнее, но мы скорее всего будем замечать моменты включения и выключения, особенно если вентилятор маленький. Большой вентилятор более инертен и там можно даже не заметить изменений скорости в пределах двух секунд. Можно теперь включать напряжение на 0.5 секунды, а на остальные 1.5 секунды – выключать. Вентилятор будет крутиться со скоростью 25% от максимальной. Мы с вами смогли представить так называемый ШИМ сигнал, широтно-импульсную модуляцию
С лампочкой накаливания оно тоже будет работать, она ведь весьма инертна, но вот со светодиодом мы будем видеть, как он включается и выключается, потому что он практически не имеет задержки включения/выключения. Что же делать? Всё очень просто, поднять частоту. В мысленном эксперименте у нас был период 2 секунды, что есть 0.5 Гц. А теперь представьте себе такой сигнал с частотой скажем 1000 Гц. Или 25’000 Гц (25 кГц). Теперь роль играет инертность глаза, он не заметит вспышек на такой частоте, для него это будет просто уменьшение яркости. Задача решена! Изменяя так называемое “заполнение” ШИМ сигнала можно менять “суммарное” напряжение (интегрированное) за некоторый период. Чем больше заполнение ШИМ, тем выше напряжение, но не выше напряжения, которое мы “ШИМим”:
При помощи ШИМ сигнала можно даже модулировать сложные аналоговые сигналы, например – синусоиду. На картинке ниже показан ШИМ (снизу) и этот же ШИМ после фильтров:
Вот таким образом кстати и работают инвертеры DC-AC. Возвращаясь к свойствам ШИМ сигнала, их всего два: частота (frequency) и заполнение (duty), с ними мы разобрались. Давайте перейдём к генерации ШИМ при помощи Arduino.
Arduino и ШИМ
В уроке про функции времени я рассказывал, что у микроконтроллера есть так называемые счётчики, которые считают “пинки” от тактового генератора (кварца). Данные счётчики как раз и генерируют ШИМ сигнал, т.е. само вычислительное ядро микроконтроллера в этом не участвует. Помимо расчётов, даже вывод сигнала с ноги МК ложится на плечи счётчика. Это очень важно понимать, потому что ШИМ сигнал не тормозит выполнение кода, так как его генерацией занимается буквально “другая железка”. На платах UNO/Nano/Pro Mini у нас есть три таймера-счётчика, у каждого таймера есть по два выхода на пины МК, то есть у нас есть 2*3=6 пинов, способных генерировать ШИМ сигнал. Для генерации ШИМ у нас есть готовая функция analogWrite(pin, duty)
- pin – пин, являющийся выводом таймера. Для Нано/Уно это пины D3, D5, D6, D9, D10, D11. На некоторых платах они помечены * звёздочкой, а вообще для определения ШИМ пинов на любой другой модели Ардуино достаточно загуглить распиновку
- duty – заполнение ШИМ сигнала. По умолчанию все “выходы” ШИМ у нас 8-битные, то есть duty может принимать значение с “разрешением” 8 бит, а это 0-255
Совместим эти знания с прошлым уроком и попробуем менять яркость светодиода, подключенного через резистор к пину D3. Потенциометр подключен к пину A0
void setup() { } void loop() { // ШИМ на 3 пин, 1023/4 = 255 — перевели диапазон analogWrite(3, analogRead(0) / 4); delay(10); }
Примечание:
- Делать ШИМ пин как выход через pinMode() необязательно, т.к. это уже встроено в analogWrite() (код ядра, строка ~100)
- Задержка здесь задаёт период чтения сигнала с потенциометра и установку нового значения ШИМ
Рассмотренный пример меняет яркость светодиода в зависимости от положения рукоятки потенциометра. Пару слов о “стандартном” ШИМ сигнале – мы получаем его с такими настройками, какие нам даёт библиотека Arduino.h, а настройки эти сильно занижены по сравнению с возможностями Arduino. Про “улучшение” ШИМ мы поговорим позже, а сейчас давайте глянем на характеристики ШИМ “из коробки”:
Таймер | Пины | Частота | Разрешение |
Timer 0 | D5 и D6 | 976 Гц | 8 бит (0-255) |
Timer 1 | D9 и D10 | 488 Гц | 8 бит (0-255) |
Timer 2 | D3 и D11 | 488 Гц | 8 бит (0-255) |
Это весьма плачевные цифры, особенно по частоте. Все таймеры приведены под одну гребёнку, чтобы пользователь не думал не гадал и лишнюю документацию не изучал. К изменению частоты и разрядности ШИМ мы вернёмся в отдельном уроке, а пока что можете посмотреть данный урок в видео варианте.
1Общие сведенияо широтно-импульсной модуляции
Цифровые выводы Arduino могут выдавать только два значения: логический 0 (LOW, низкий уровень) и логическую 1 (HIGH, высокий). На то они и цифровые. Но есть у Ардуино «особые» выводы, которые обозначаются PWM. Их иногда обозначают волнистой чертой «~» или обводят кружочками или ещё как-то выделяют среди прочих. PWM расшифровывается как Pulse-width modulation или широтно-импульсная модуляция, ШИМ.
Обозначение выходов с ШИМ на Arduino Leonardo
Широтно-импульсно модулированный сигнал – это импульсный сигнал постоянной частоты, но переменной скважности (соотношение длительности импульса и периода его следования). Из-за того, что большинство физических процессов в природе имеют инерцию, то резкие перепады напряжения от 1 к 0 будут сглаживаться, принимая некоторое среднее значение. С помощью задания скважности можно менять среднее напряжение на выходе ШИМ.
Если скважность равняется 100%, то всё время на цифровом выходе Arduino будет напряжение логическая «1» или 5 вольт. Если задать скважность 50%, то половину времени на выходе будет логическая «1», а половину – логический «0», и среднее напряжение будет равняться 2,5 вольтам. Ну и так далее.
Принцип работы широтно-импульсной модуляции (ШИМ)
В программе скважность задаётся не в процентах, а числом от 0 до 255. Например, команда analogWrite(10, 64) скажет микроконтроллеру подать на цифровой PWM выход №10 сигнал со скважностью 25%.
Выводы Arduino с функцией широтно-импульсной модуляции работают на частоте около 500 Гц. Значит, период следования импульсов – около 2 миллисекунд, что и отмеряют зелёные вертикальные штрихи на рисунке. Получается, что мы можем сымитировать аналоговый сигнал на цифровом выходе! Интересно, правда?!
Как же мы можем использовать ШИМ? Применений масса! Например, управлять яркостью светодиода, скоростью вращения двигателя, током транзистора, звуком из пьезоизлучателя и т.д.…
Важные страницы
- Набор GyverKIT – большой стартовый набор Arduino моей разработки, продаётся в России
- Каталог ссылок на дешёвые Ардуины, датчики, модули и прочие железки с AliExpress у проверенных продавцов
- Подборка библиотек для Arduino, самых интересных и полезных, официальных и не очень
- Полная документация по языку Ардуино, все встроенные функции и макросы, все доступные типы данных
- Сборник полезных алгоритмов для написания скетчей: структура кода, таймеры, фильтры, парсинг данных
- Видео уроки по программированию Arduino с канала “Заметки Ардуинщика” – одни из самых подробных в рунете
- Поддержать автора за работу над уроками
- Обратная связь – сообщить об ошибке в уроке или предложить дополнение по тексту ([email protected])
4.8 / 5 ( 13 голосов )
3Пример скетча с ШИМ
Откроем из примеров скетч «Fade»: Файл Образцы 01.Basics Fade.
Открываем скетч для Arduino с использованием ШИМ
Немного изменим его и загрузим в память Arduino.
int ledPin = 3; // объявляем пин, управляющий светодиодом int brightness = 0; // переменная для задания яркости int fadeAmount = 5; // шаг изменения яркости
void setup() {
pinMode(ledPin, OUTPUT);
}void loop() {
analogWrite(ledPin, brightness); // устанавливаем яркость brightness на выводе ledPin brightness += fadeAmount; // изменяем значение яркости /* при достижении границ 0 или 255 меняем направление изменения яркости */ if (brightness == 0 || brightness == 255) { fadeAmount = -fadeAmount; // изменяем знак шага } delay(30); // задержка для большей видимости эффекта
}
Схема проекта
Схема для демонстрации использования ШИМ в Raspberry Pi представлена на следующем рисунке.
Как показано на схеме, мы подключили светодиод между контактами PIN35 (GPIO19) и PIN39 (ground). Поскольку, как мы уже рассмотрели ранее, через контакт нельзя пропускать ток более 15mA, то последовательно со светодиодом мы подключили резистор (сопротивлением 220 Ом или 1 кОм).
Примеры использования ШИМ на Ардуино
Широкополосная широтно-импульсная модуляция является способом кодирования напряжения на фиксированную несущую частоту. Он обычно используется для радиоуправляемых устройств. Каждый тип схемы модуляции имеет свои преимущества и недостатки.
AM-модуляция была первым типом модуляции, используемой для радиопередач. Самая простая схема модуляции для реализации требует только одного транзистора или усилителя вакуумной трубки, как это было сделано в первые дни с момента создания радио.
С необходимостью цифровой связи был изобретен новый метод модуляции – ШИМ. Этот метод обладает той же помехоустойчивостью, что и радиоволны. Самая большая разница – простота и цифровая природа модуляции. Вместо того, чтобы изменять частоту модуляции с напряжением, выход просто включается и выключается с фиксированной частотой. Процент времени включения пропорционален сигнальному напряжению.
Индивидуальные задания
- Измените третий пример так, чтобы после плавного увеличения яркости, светодиоды гасли плавно.
- Подберите соотношение яркости светодиодов так, чтобы добиться белого свечения светодиода.
- Сделайте из шилда лампу настроения. Цвета должны случайным образом переливаться. Организуйте основной цикл так, чтобы сначала случайным образом выбирался номер вывода, а потом он плавно зажигался и гас. Для этого можно использовать функцию random(min,max). Для работы с ней объявите переменную int pin=0; и в цикле void loop() вызовите эту функцию pin=random(9,12);. Она запишет в переменную pin значение от 9 до 11.
Остальные статьи цикла можно найти здесь.
Мы будем очень рады, если вы поддержите наш ресурс и посетите магазин наших товаров shop.customelectronics.ru.
Практические ограничения
Прежде чем мы закончим, я должен отметить, что эти идеализированные симуляции не раскрывают основного источника неидеальной производительности ЦАП базе ШИМ, а именно ненадежных и, следовательно, непредсказуемых напряжений высокого и низкого логических уровней. Напряжение на аналоговом выходе прямо пропорционально амплитуде цифрового ШИМ сигнала, и, таким образом, изменения реальных напряжений высокого и низкого логических уровней ШИМ сигнала приведут к соответствующим изменениям выходного напряжения ЦАП. Эта проблема особенно актуальна для приложений с питанием от батареек; если микроконтроллер питается напрямую от батареи, напряжение высокого логического уровня по мере разряда батареи будет постепенно уменьшаться. Однако даже при стабилизированном питании вы можете не знать точное напряжение питания – стабилизатор с точностью ±2% означает, что точность выходного напряжения ЦАП будет (в лучшем случае) ±2%. И даже если у вас очень точный стабилизатор напряжения, и нет значительных отклонений в напряжении питания, вызванных разрядом батареи или изменениями условий окружающей среды, тем не менее, на реальные напряжения высокого и низкого логических уровней может влиять рабочее состояние устройства, генерирующего ШИМ сигнал (обычно микроконтроллер). Одним из способов решения этой проблемы является использование внешней буферной микросхемы, которая поможет ШИМ сигналу поддерживать предсказуемые уровни напряжения, но в этот момент вы снова находитесь на компромиссной территории – вы потратите 40 с небольшим центов на буферную микросхему или 71 цент на крошечный 8-разрядный ЦАП?
Типы вентиляторов постоянного тока
Существует три основных типа вентиляторов постоянного тока (они же кулеры): двухпроводные, трехпроводные и четырехпроводные.
- Двухпроводной вентилятор имеет два контакта – питание и заземление. Этим вентилятором можно управлять либо путем изменения напряжения постоянного тока, либо с помощью управляющего сигнала ШИМ.
- У трехпроводного вентилятора есть сигнал тахометра, который показывает скорость вращения. Этим вентилятором также можно управлять, изменяя напряжение постоянного тока или используя низкочастотный управляющий сигнал ШИМ.
- Четырехпроводной вентилятор имеет специальный вход PWM, который можно использовать для управления скоростью.
Работа схемы и программы
Схема устройства представлена на следующем рисунке.
Схема собрана на макетной плате. Хотя практически всем кнопкам присущ эффект «дребезга контактов» в данном случае не стоит беспокоиться о нем – нам он не помешает.
Управлять ШИМ модуляцией в плате Arduino очень просто в отличие, к примеру, от использования ШИМ в микроконтроллерах ATMEGA, в которых для выполнения этой задачи необходимо конфигурировать различные регистры и делать другие разнообразные установки – в Arduino всего этого делать не нужно.
По умолчанию все необходимые заголовочные файлы и все регистры, необходимые для работы с ШИМ, сконфигурированы программной средой ARDUINO IDE, нам просто нужно вызвать соответствующую функцию, указав ей в качестве параметра номер контакта, на котором необходимо сконфигурировать ШИМ-сигнал.
То есть, чтобы сформировать ШИМ сигнал на соответствующем контакте платы Arduino, необходимо сделать две вещи:
1. pinMode(ledPin, OUTPUT) 2. analogWrite(pin, value)
Сначала нам необходимо выбрать номер контакта для ШИМ из шести возможных, имеющихся для этой цели в Arduino, после этого мы должны сконфигурировать этот контакт для работы на вывод данных.
После этого мы должны сгенерировать ШИМ сигнал на конкретном контакте Arduino с помощью функции “analogWrite(pin, value)”. Здесь переменная ‘pin’ обозначает номер контакта, на котором необходимо формировать сигнал ШИМ, в нашем случае этот будет контакт 3. А переменная value обозначает требуемый цикл занятости ШИМ, она может принимать значения от 0 (сигнал всегда выключен) до 255 (сигнал всегда включен). Мы будем увеличивать и уменьшать значение этой переменной с помощью кнопок, присутствующих на схеме.