В этой статье мы рассмотрим принципы использования широтно-импульсной модуляции (ШИМ) в плате Arduino на основе схемы регулирования силы свечения светодиода.
Принципы работы широтно-импульсной модуляции (ШИМ)
Рассмотрим схему, изображенную на следующем рисунке. Как мы выясним, управляя скважностью модуляции ШИМ (PWM) можно регулировать силу свечения светодиода.
Если на представленном рисунке выключатель будет замкнут на протяжении некоторого времени, то на протяжении этого же времени лампочка будет гореть. Если переключатель будет замкнут в течение 8ms и будет разомкнут 2ms в течение интервала 10ms, тогда лампочка будет гореть только в течение интервала 8ms. В рассмотренном примере можно сказать, что среднее выходное напряжение (на лампочке) будет составлять 80% от напряжения батареи.
В другом случае выключатель замыкается на 5ms и размыкается на эти же самые 5ms в течение интервала 10ms, таким образом среднее напряжение на лампочке будет составлять 50% от напряжения батареи. Принято говорить, что если напряжение батареи 5В и цикл занятости составляет 50%, то среднее напряжение на оконечном устройстве (лампочке) будет составлять 2.5В.
В третьем рассмотренном на рисунке случае цикл занятости (duty cycle) составляет 20% и поэтому среднее напряжение на оконечном устройстве (лампочке) будет составлять 20% от напряжения батареи.
Более красочно принципы работы ШИМ показаны на следующих рисунках.
Рассмотрим какие возможности в плане ШИМ имеет плата Arduino.
Как показано на рисунке, плата Arduino UNO имеет 6 каналов ШИМ (по англ. – PWM, Pulse Width Modulation). Мы можем использовать ШИМ на любом из этих 6 контактов. В этом проекте мы будем использовать контакт 3 (PIN3).
Также достаточно наглядно работа ШИМ в практической задаче представлена в следующей статье - вентилятор на Arduino Uno, управляемый с помощью температуры.
Необходимые компоненты
- Плата Arduino Uno (купить на AliExpress).
- Конденсатор 100 мкФ (купить на AliExpress).
- Резистор 10 кОм (2 шт.) (купить на AliExpress).
- Светодиод (купить на AliExpress).
- Кнопка (2 шт.).
- Источник питания с напряжение 5 В.
Реклама: ООО "АЛИБАБА.КОМ (РУ)" ИНН: 7703380158
Работа схемы и программы
Схема устройства представлена на следующем рисунке.
Схема собрана на макетной плате. Хотя практически всем кнопкам присущ эффект "дребезга контактов" в данном случае не стоит беспокоиться о нем – нам он не помешает.
Управлять ШИМ модуляцией в плате Arduino очень просто в отличие, к примеру, от использования ШИМ в микроконтроллерах ATMEGA, в которых для выполнения этой задачи необходимо конфигурировать различные регистры и делать другие разнообразные установки – в Arduino всего этого делать не нужно.
По умолчанию все необходимые заголовочные файлы и все регистры, необходимые для работы с ШИМ, сконфигурированы программной средой ARDUINO IDE, нам просто нужно вызвать соответствующую функцию, указав ей в качестве параметра номер контакта, на котором необходимо сконфигурировать ШИМ-сигнал.
То есть, чтобы сформировать ШИМ сигнал на соответствующем контакте платы Arduino, необходимо сделать две вещи:
1. pinMode(ledPin, OUTPUT)
2. analogWrite(pin, value)
Сначала нам необходимо выбрать номер контакта для ШИМ из шести возможных, имеющихся для этой цели в Arduino, после этого мы должны сконфигурировать этот контакт для работы на вывод данных.
После этого мы должны сгенерировать ШИМ сигнал на конкретном контакте Arduino с помощью функции “analogWrite(pin, value)”. Здесь переменная ‘pin’ обозначает номер контакта, на котором необходимо формировать сигнал ШИМ, в нашем случае этот будет контакт 3. А переменная value обозначает требуемый цикл занятости ШИМ, она может принимать значения от 0 (сигнал всегда выключен) до 255 (сигнал всегда включен). Мы будем увеличивать и уменьшать значение этой переменной с помощью кнопок, присутствующих на схеме.
Исходный код программы
Далее приведен исходный код программы с комментариями, поясняющими смысл отдельных команд.
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 |
volatile int i=0; // объявляем переменную целого типа для хранения коэффициента заполнения ШИМ void setup() { pinMode(3, OUTPUT); // контакт 3 на вывод данных pinMode(0, INPUT);// контакт 0 на ввод данных pinMode(1, INPUT);// контакт 1 на ввод данных } void loop() { analogWrite(3, i); // функция для генерации ШИМ на контакте 3, где i может принимать значения от 0 до 255 if (digitalRead(0)==LOW) { if (i<255) { i++; // если кнопка, подключенная к pin0, нажата и коэффициент заполнения ШИМ меньше 255 delay(30); } } if (digitalRead(1)==LOW) { if (i>0) { i--;// если кнопка, подключенная к pin1, нажата и коэффициент заполнения ШИМ больше 0 delay(30); } } } |
Да сделал так ,но например я включаю зажигание и у меня при нажатие кнопки вперед рулевая коловка не выезжает пока не нажмешь кнопку назад и после этого ана рабатает вперед и назад и также вверх и вниз тоже нужно тажать кнопку вниз а потом начинает работать вверх и так все работает пока схему не обесточишь
Ну можно еще вывод переменных в окно монитора последовательной связи добавить если вы уж до конца хотите разобраться в логике работы своей программы
Частота ШИМа в ардуино, имеющем 16-мегагерцовый (!!!) процессор, крайне мала - всего сотни герц(!!!)
Ни для чего осмысленного, кроме моргания светодиодом, или управления нагревательной спиралью, это не годится.
В самом процессоре, конечно, есть возможность увеличения частоты ШИМа во многие разы, но для начинающих это тайна за семью печатями, поэтому многие, поигравшись, охладевают к такому радиоконструктору.
А жаль.
Было бы очень полезно в статье осветить вопрос и задания более высоких частот ШИМу, с примерами программ, и не только для Уно, но и для других, более современных плат (Arduino Due, Мега 2560, Леонардо, и др.)
Спасибо, учту ваше замечание. При возможности доработаю статью. Но вместо дорогих предложенных вами плат можно также использовать дешёвую STM32 Blue Pill, программируется она точно также с помощью Arduino IDE, а возможности ШИМ в ней уже получше
Здравствуйте, хотел сделать понижающий преобразователь DC-DC на ШИМ из Arduino с 220в до 40в. Почему-то на всех DC-DC преобразователях используются трансформаторы. Получиться ли сделать на ШИМе из Arduino?
Добрый вечер. Да, можно с помощью ШИМ без трансформатора такой конвертер сделать, но тогда в схеме будет нужен MOSFET транзистор. У нас на сайте есть подобный проект - понижающий преобразователь напряжения постоянного тока на Arduino. Только он с 12 В до более низкого напряжения понижает, а вот насчет 220 В я уже не уверен. Не очень силен в этой тематике. Скорее всего, в схему придется добавить дополнительные элементы. Но, я думаю, принцип понижения напряжения с помощью ШИМ вы из представленной статьи поймете.
Трансформатор обеспечивает гальваническую развязку от сети 220В, что очень важно в целях электробезопасности.
Безтрансформаторную схему, конечно, можно соорудить, но вы всегда рискуете получить удар током, что опасно для жизни.
Я бы не советовал экономить на трансформаторе
Здравствуйте.Надо подключить дополнительные кнопки: 1)при нажатии лампа светится с максимальной мощностью. 2) при нажатии лампа не светится
Здравствуйте, проблем нет. Добавьте эти две строчки в программу.
if (digitalRead(5)==LOW) i=255;
if (digitalRead(6)==LOW) i=0;
В соответствии с этими строчками кнопки необходимо подключить к контактам 5 и 6.
Здравствуйте!Написал скетч по вашему примеру только duty должно быть фиксированно,но почему то выполняется только по аналоговым входам А1,А3 а когда подаю землю на А0,А2 на выходах 5,6 нету pwm.
Суть дела в том что имеется контроллер двигателя рулевой колонки и изменением Duty меняется направление вращения двигателя
volatile int i=0;
void setup()
{
pinMode(6, OUTPUT); // контакт 5 на вывод данных
pinMode(5, OUTPUT); // контакт 6 на вывод данных
pinMode(A0, INPUT_PULLUP);// контакт A0 на ввод данных
pinMode(A1, INPUT_PULLUP);// контакт A1 на ввод данных
pinMode(A2, INPUT_PULLUP);// контакт A2 на ввод данных
pinMode(A3, INPUT_PULLUP);// контакт A3 на ввод данных
}
void loop()
{
analogWrite(6,i);
if (digitalRead(A0)==LOW) i=127;
delay(30);
if (digitalRead(A0)==HIGH)i=0;
delay(30);
if (digitalRead(A1)==LOW)i=135;
delay(30);
if (digitalRead(A1)==HIGH) i=0;
delay(30);
analogWrite(5,i);
if (digitalRead(A2)==LOW) i=127;
delay(30);
if (digitalRead(A2)==HIGH) i=0;
delay(30);
if (digitalRead(A3)==LOW) i=135;
delay(30);
if (digitalRead(A3)==HIGH) i=0;
delay(30);
}
Добрый день. У вас как то немного странно реализован алгоритм управления ШИМ сигналом на контактах 5 и 6. Я бы на вашем месте, чтобы не путаться, завел две переменные для управления коэффициентом заполнения ШИМ сигнала - одна для управления на контакте 5, а другая - для управления на контакте 6. Ну и можно попробовать подключить кнопки к другим контактам чтобы попытаться выявить проблему.
в симуляторе тоже самое,если поменять местами аналоговые входы то происходит тоже самое,может приведете пример как правильно реализовать переменные для управления контактами? просто новичок в этом и уже два месяца ничего не получается
сделал вот так ,тоже самое
volatile int i=0;
volatile int b=0;
void setup()
{
pinMode(6, OUTPUT); // контакт 5 на вывод данных
pinMode(5, OUTPUT); // контакт 6 на вывод данных
pinMode(A0, INPUT_PULLUP);// контакт A0 на ввод данных
pinMode(A1, INPUT_PULLUP);// контакт A1 на ввод данных
pinMode(A2, INPUT_PULLUP);// контакт A2 на ввод данных
pinMode(A3, INPUT_PULLUP);// контакт A3 на ввод данных
}
void loop()
{
analogWrite(6,i);
if (digitalRead(A0)==LOW) i=127;
delay(30);
if (digitalRead(A0)==HIGH)i=0;
delay(30);
if (digitalRead(A1)==LOW)i=135;
delay(30);
if (digitalRead(A1)==HIGH) i=0;
delay(30);
analogWrite(5,b);
if (digitalRead(A2)==LOW) b=127;
delay(30);
if (digitalRead(A2)==HIGH) b=0;
delay(30);
if (digitalRead(A3)==LOW) b=135;
delay(30);
if (digitalRead(A3)==HIGH) b=0;
delay(30);
}
и выполняется только для А0 и А2,если поменять местами с А0 на А1 а А2 с А3 то где уже выполняется А1 и А3
Сделал для каждой кнопки свой канал так все работает,то есть А0-D3,A1-D9,A2-D10,A3-D11
То есть у вас все получилось из того что вы хотели сделать? С одним каналом изначально у вас просто логика была запутана. Можно было конечно исхитриться и сделать это с одним каналом, но поскольку в вашем проекте нет дефицита контактов платы Ардуино, то проще и логичнее, конечно, сделать с двумя каналами