Программный шим на любом выводе arduino. Arduino проекты

21.02.2019

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

ШИМ

Гениально определение ШИМ сформулировано в Википедии , поэтому я просто скопипащу его оттуда: "ШИМ - приближение желаемого сигнала (многоуровневого или непрерывного) к действительным бинарным сигналам (с двумя уровнями - вкл / выкл ), так, что, в среднем, за некоторый отрезок времени, их значения равны. <...> ШИМ есть импульсный сигнал постоянной частоты и переменной скважности, то есть отношения периода следования импульса к его длительности. С помощью задания скважности (длительности импульсов) можно менять среднее напряжение на выходе ШИМ . "


Теперь разберемся, что это значит. Пусть есть обычный такой прямоугольный сигнал:




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


Если у нас максимальное напряжение равно 5 В, то напряжение, получаемое на выходе ШИМ равно скважность умножить на 5 В (и делить на 100% чтобы формал-nazi не привязывались):


Arduino позволяет записать на ШИМ-выход значение от 0 до 255, а это значит, что мы можем получить напряжение с дискретностью примерно 20 мВ.


Трехцветный светодиод

Вот он, четырехногий красавец:


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

Если подать на длинную ногу +5В, а на все остальные 0В, то получится белый свет (умоляю, предохраняйтесь - ставьте ограничивающие резисторы!). Насколько он белый, можно судить по следующему видео:


Но получать белый цвет на нем как раз-таки неинтересно. Посмотрим, как заставить его переливаться разными цветами.

ШИМ на Arduino

Частота ШИМ на Arduino - примерно 490 Гц. На плате Arduino UNO выводы, которые могут быть использованы для ШИМ - 3,5,6, 9, 10 и 11. На плате к этому есть подсказка - шелкографией перед номерами ШИМ-выводов есть тильда или диез.

Нет ничего проще, чем управлять ШИМ на Arduino! Для этого используется одна единственная функция analogWrite(pin, value) , где pin - номер вывода, а value - значение от 0 до 255. При этом ничего не надо писать в void setup() !

Подробнее про это на английском языке можно почитать и .

Совсем немного работаем

Сделаем так, чтобы светодиод переливался разными цветами. Пусть один цвет плавно гаснет, в то время как другой разгорается. Поочередно будем менять пару цветов, и цвет будет переходить по кругу из красного в зеленый, из зеленого в синий, из синего в красный.

Соберем незамысловатую схему:


И напишем незамысловатый код:

//обзываем выводы соответственно цвету
int REDpin = 9;
int GREENpin = 10;
int BLUEpin = 11;

void setup (){}

void loop (){
for (int value = 0 ; value <= 255; value +=1) {
//яркость красного уменьшается
analogWrite (REDpin, value);
//яркость зеленого увеличивается
analogWrite (GREENpin, 255-value);
//синий не горит
analogWrite (BLUEpin, 255);
//пауза
delay (30);
}

for (int value = 0 ; value <= 255; value +=1) {
//красный не горит
analogWrite (REDpin, 255);
//яркость зеленого уменьшается
analogWrite (GREENpin, value);
//яркость синего увеличивается
analogWrite (BLUEpin, 255-value);
//пауза
delay (30);
}

for (int value = 0 ; value <= 255; value +=1) {
//яркость красного увеличивается
analogWrite (REDpin, 255-value);
//зеленый не горит
analogWrite (GREENpin, 255);
//яркость синего уменьшается
analogWrite (BLUEpin, value);
//пауза
delay (30);
}
}

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

Функция analogWrite(), так же как и digitalWrite(), содержит в скобках два аргумента и работает по тому же словесному принципу: "куда, что". Главным различием является возможность записи широкого диапазона значений вместо привычного LOW или HIGH. Это и позволит нам регулировать яркость светодиода. Главное замечание, которое необходимо учитывать, это то, что данная функция работает только на определенных контактах. Эти контакты обозначены символом "~". Этот символ означает, что это PWM-контакт. PWM (pulse-width modulation) звучит по-русски как ШИМ (широтно-импульсная модуляция). Принцип работы основан на изменении длительности импульса. Графически это можно изобразить так:

Давайте попробуем разобраться как это работает, рассмотрев простой пример. Для этого необходимо подключить светодиод к PWM-контакту через резистор номиналом 150 Ом и "зашить" в Arduino простенькую программу. Схема подключения и код скетча представлены ниже:


void setup()
{
pinMode(led,OUTPUT);
}

void loop()
{
for(int i=0; i<=255; i++)
{
analogWrite(led,i);
delay(10);
}
for(int i=255; i>=0; i--)
{
analogWrite(led,i);
delay(10);
}
}


Думаю, что в целом код понятен, но необходимо уделить немного внимания циклу for(). Существует такое понятие как разрешение. Поскольку мы работаем с 8-битным разрешением (это будет рассмотрено несколько позднее), то минимальному значению будет соответствовать 0, а максимальному - 255. В конце каждой итерации мы установили временную задержку в 10мс.

Давайте вернемся к схеме из предыдущего урока и попробуем сделать аналогичную гирлянду с использованием функции analogWrite().


int buttonPin = 2;
int pins = {3,5,6,9,10,11};

boolean lastButton = LOW;
boolean currentButton = LOW;
boolean enable = false;

void setup()
{
pinMode(buttonPin, INPUT);
for(int mode = 0; mode <= 5; mode++) pinMode(pins, OUTPUT);
}

boolean debounce(boolean last)
{
boolean current = digitalRead(buttonPin);
if(last != current)
{
delay(5);
current = digitalRead(buttonPin);
}
return current;
}

void loop()
{
currentButton = debounce(lastButton);
if(lastButton == LOW && currentButton == HIGH)
{
enable = !enable;
}

If(enable == true)
{
for (int i=0; i<=5; i++)
{
for (int brightness = 0; brightness <= 255; brightness++)
{
delay(1);
}
delay(40);
}
for (int i=0; i<=5; i++)
{
for (int brightness = 255; brightness >= 0; brightness--)
{
analogWrite(pins[i], brightness);
delay(1);
}
delay(40);
}
}

If(enable == false)
{
for(int i = 0; i <= 5; i++) digitalWrite(pins[i], LOW);
}

LastButton = currentButton;
}


Визуально скетч стал несколько сложнее. На самом деле здесь все просто и давайте в этом разберемся. Нам необходимо идентифицировать все подключенные светодиоды, но вместо привычного int led мы используем массив, каждый элемент которого является PWM-контактом на Arduino. В теле функции void setup() мы тоже поступили хитрым образом. "Перечислять" все контакты мы доверили циклу for(), с каждой итерацией которого производится конфигурация соответствующего контакта на OUTPUT. Переходим к функции void loop(). Функция debounce() и начальное условие if() остается без изменений. У нас по-прежнему идет проверка уровней двух переменных: предыдущее значение (изначально LOW) и текущее состояние кнопки. При выполнении этих условий значение переменной enable инвертируется. Учитывая это, мы добавили еще два простых условия if(). Если enable = true, то гирлянда включается, плавностью "перетекания" которой управляет цикл for(). Если же enable = false, то все светодиоды выключены. По окончанию условий переменная lastButton принимает текущее состояние кнопки.
Тестируя нашу программу, мы заметили, что все работает не должным образом. Помните, в прошлом уроке мы сделали поправку, что при большом значении временной задержки кнопка срабатывает по её истечению? В прошлом примере, при включенной гирлянде, суммарная задержка в теле функции void loop() составляла 85мс. Это давало нам возможность успеть "попасть" в определенной отрезок времени. В данном скетче, при том же условии, задержка отличается в несколько раз. Возможно, при желании выключить гирлянду напрашивается слово "прервать". Это и будет являться решением данной задачи!

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

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

Функция analogWrite(), так же как и digitalWrite(), содержит в скобках два аргумента и работает по тому же словесному принципу: "куда, что". Главным различием является возможность записи широкого диапазона значений вместо привычного LOW или HIGH. Это и позволит нам регулировать яркость светодиода. Главное замечание, которое необходимо учитывать, это то, что данная функция работает только на определенных контактах. Эти контакты обозначены символом "~". Этот символ означает, что это PWM-контакт. PWM (pulse-width modulation) звучит по-русски как ШИМ (широтно-импульсная модуляция). Принцип работы основан на изменении длительности импульса. Графически это можно изобразить так:

Давайте попробуем разобраться как это работает, рассмотрев простой пример. Для этого необходимо подключить светодиод к PWM-контакту через резистор номиналом 150 Ом и "зашить" в Arduino простенькую программу. Схема подключения и код скетча представлены ниже:


void setup()
{
pinMode(led,OUTPUT);
}

void loop()
{
for(int i=0; i<=255; i++)
{
analogWrite(led,i);
delay(10);
}
for(int i=255; i>=0; i--)
{
analogWrite(led,i);
delay(10);
}
}


Думаю, что в целом код понятен, но необходимо уделить немного внимания циклу for(). Существует такое понятие как разрешение. Поскольку мы работаем с 8-битным разрешением (это будет рассмотрено несколько позднее), то минимальному значению будет соответствовать 0, а максимальному - 255. В конце каждой итерации мы установили временную задержку в 10мс.

Давайте вернемся к схеме из предыдущего урока и попробуем сделать аналогичную гирлянду с использованием функции analogWrite().


int buttonPin = 2;
int pins = {3,5,6,9,10,11};

boolean lastButton = LOW;
boolean currentButton = LOW;
boolean enable = false;

void setup()
{
pinMode(buttonPin, INPUT);
for(int mode = 0; mode <= 5; mode++) pinMode(pins, OUTPUT);
}

boolean debounce(boolean last)
{
boolean current = digitalRead(buttonPin);
if(last != current)
{
delay(5);
current = digitalRead(buttonPin);
}
return current;
}

void loop()
{
currentButton = debounce(lastButton);
if(lastButton == LOW && currentButton == HIGH)
{
enable = !enable;
}

If(enable == true)
{
for (int i=0; i<=5; i++)
{
for (int brightness = 0; brightness <= 255; brightness++)
{
delay(1);
}
delay(40);
}
for (int i=0; i<=5; i++)
{
for (int brightness = 255; brightness >= 0; brightness--)
{
analogWrite(pins[i], brightness);
delay(1);
}
delay(40);
}
}

If(enable == false)
{
for(int i = 0; i <= 5; i++) digitalWrite(pins[i], LOW);
}

LastButton = currentButton;
}


Визуально скетч стал несколько сложнее. На самом деле здесь все просто и давайте в этом разберемся. Нам необходимо идентифицировать все подключенные светодиоды, но вместо привычного int led мы используем массив, каждый элемент которого является PWM-контактом на Arduino. В теле функции void setup() мы тоже поступили хитрым образом. "Перечислять" все контакты мы доверили циклу for(), с каждой итерацией которого производится конфигурация соответствующего контакта на OUTPUT. Переходим к функции void loop(). Функция debounce() и начальное условие if() остается без изменений. У нас по-прежнему идет проверка уровней двух переменных: предыдущее значение (изначально LOW) и текущее состояние кнопки. При выполнении этих условий значение переменной enable инвертируется. Учитывая это, мы добавили еще два простых условия if(). Если enable = true, то гирлянда включается, плавностью "перетекания" которой управляет цикл for(). Если же enable = false, то все светодиоды выключены. По окончанию условий переменная lastButton принимает текущее состояние кнопки.
Тестируя нашу программу, мы заметили, что все работает не должным образом. Помните, в прошлом уроке мы сделали поправку, что при большом значении временной задержки кнопка срабатывает по её истечению? В прошлом примере, при включенной гирлянде, суммарная задержка в теле функции void loop() составляла 85мс. Это давало нам возможность успеть "попасть" в определенной отрезок времени. В данном скетче, при том же условии, задержка отличается в несколько раз. Возможно, при желании выключить гирлянду напрашивается слово "прервать". Это и будет являться решением данной задачи!

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

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

analogWrite

Скважность это отношение периода следования импульсов к их длительности. На рисунке – чем больше мгновенное значение управляющего сигнала, тем меньше скважность импульсов ШИМ-сигнала. Этот способ модуляции широко применяется в технике ввиду того, что позволяет произвольное среднедействующее значение средствами цифровых устройств. Этот способ применим в тех случаях, когда необходимо, например, плавно регулировать яркость свечения лампы, температуры нагревателя, скорость вращения мотора постоянного тока и так далее.
Arduino имеет встроенную функцию для формирования ШИМ-сигнала – analogWrite(pin,value) . У этой функции два параметра: pin – номер вывода, на котором формируется сигнал; value – относительное значение скважности импульсов.
Value может принимать значения от 0 до 255. Причем максимальная скважность получается при 0 (а среднедействующее значение минимально), а минимальная при 255 (среднедействующее максимально). Функция analogWrite может работать только с выводами 9, 10 и 11 (на нашей плате с микроконтроллером Atmega8). Соответственно, только такие значения может принимать переменная pin .
Если использовать эту функцию для управления другим выводом (0-8, 12, 13), то при значения скважности от 0 до 127 на выводе будет низкий уровень напряжения, а при 128-255 – высокий.

Подготовка к работе

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