Как рождаются программы
Это будет немного не обычная статья, в ней я попробую не просто показать готовый код, который что-то делает, а покажу как рождается устройство и прошивка для него. Мы рассмотрим логику работы программы и то как эту логику построить.
Сегодня мы с вами будем решать следующую задачу: есть 2 светодиода их надо подключить к Arduino и реализовать возможность регулировать яркость их горения.
Приступим!
Первым делом надо продумать как будет выглядеть наше устройство и что нам понадобится для его реализации, нам надо чем то регулировать яркость светодиодов и видеть в каком режиме сейчас работают светодиоды для этого отлично подходит lcd shield который мы рассматривали в прошлой статье .
Теперь нам осталось подключить светодиоды, для этого отлично подходит так называемый бредборд, это пластиковая штуковина (не знаю как ее по другому назвать) в которую без пайки можно подключить провода от Arduino и другие электронные компоненты, что очень удобно когда ты точно не знаешь как будет выглядеть готовое устройство или схема нужно всего на несколько запусков. Китайцы клепают огромное количество их разновидностей, я лично пользуюсь таким:
Для простоты понимания как он устроен внутри я приложу схему внутренних соединений:
Подключение светодиодов к Arduino
Многие сейчас скажут: что сложного в подключении светодиода, это же лампочка! И будут не правы, светодиод - это далеко не простая лампочка, а полупроводниковый световой прибор. Который питается не напряжением как обычная лампочка, а током и если ток превысит допустимые значения, то светодиод начнет деградировать, его яркость будет уменьшатся что станет заметно через некоторое время, зависящее от мощности протыкаемого тока или, вообще моментально сгорит.
Как избежать порчи светодиода из-за большого тока? Все очень просто: нужно использовать токоограничивающий резистор, который надо рассчитывать для каждого светодиода в зависимости от его характеристик. Расчет резисторов для светодиода - это тема для отдельной статьи и сегодня мы не будем углубляться в эту тему так как скорей всего вы не знаете характеристик светодиода, который вы где-то нашли. На этот случай я использую маленькое правило: если светодиод не яркий, то я запитываю его через резистор сопротивлением от 220 до 400 ом в зависимости от того какой резистор был под рукой. Главное запомнить правило – лучше больше чем меньше. При большем сопротивлении чем требуется светодиоду, он просто будет гореть тусклее нормы.
Теперь надо определится как регулировать яркость светодиода, для этого можно использовать переменные резисторы что в принципе исключит интерактивную регулировку и по этому мы не будем использовать данный способ в этой статье. Мы будем использовать ШИМ реализованный на плате Arduino.
Что такое ШИМ
ШИМ (широтно-импульсная модуляция) – это изменение скважности сигнала на определенном отрезке времени. Шим сигнал имеет следующий вид по сравнению с постоянным сигналом:
На этой картинке 100% рабочего цикла это отсутствие ШИМ как такового, сигнал идет без изменений, как будто вывод просто подключен к 5 вольтам.
0% рабочего цикла это отсутствие какого-либо сигнала, как будто провод никуда не подключен.
Остальные режимы работы - это быстрое переключение режимов работы что заставляет светодиод как бы моргать с большой скоростью не заметной глазу человека (100 раз в секунду) что и заставляет его гореть с не полной яркостью. Arduino в зависимости от версии используемого чипа имеет разное количество ШИМ выходов, на плате они помечены знаком ~ из прошлой статьи мы знаем что это 6 выходов 3, 5, 6, 9, 10, и 11 мы будем использовать 10 и 11 выводы.
Давайте наконец то подключим светодиоды к плате. Надеваем на Arduino наш lcd shield и собираем следующею схему для которой нам понадобится бредборд, 2 светодиода, 2 резистора на 250 ом, и 3-4 провода папа- папа. Схема будет иметь следующий вид:
И не забываем, что у светодиода есть полярность, длинная или кривая (как на схеме) ножка светодиода - это плюс который и подключается через резистор.
На этом я наверно закончу первую часть статьи, во второй части мы займемся именно проработкой логики работы и написанием кода программ. Всем добра!
Потенциометр — это переменный резистор, который при повороте ручки изменяет свое сопротивление.
Что требуется для проекта:
Схема подключения на макетной плате.
Для того, чтобы регулировать яркость светодиода, подключим его к разъему, который поддерживает ШИМ, в нашем случае это цифровой пин 3. Разъемы VCC и GND потенциометра подключаем к рельсе питания и земли макетной платы. Разъем A0 подключаем к аналоговому пину A0.
После удачной сборки схемы загружаем данный скетч:
#define LED 3 #define POT A0 void setup() { pinMode(LED, OUTPUT); //настройка пина в режим выхода pinMode(POT, INPUT); //настройка пина в режим входа } void loop() { //заявляем целочисленные переменные int turn, brightness; //считываем в turn напряжение потенциометра, его значения //будут варьироваться от 0 до 1023 turn = analogRead(POT); //в переменную brightness записываем значение turn, //деленное на 4. Будет принимать значения от 0 до 255 brightness = turn / 4; //включаем светодиод с яркостью, равной значению brightness analogWrite(LED, brightness); }
Теперь попробуем написать код для этой же схемы, но на чистом СИ в среде AtmelStudio 7. Выглядеть это будет так.
#include Теперь попробуем разобраться с этими двумя примерами. Дело в том, что среда Arduino задумывалась для быстрого старта начинающим. Если надо помигать светодиодом или пощелкать реле, то это можно осуществить за считанные минуты. Среда Arduino полностью изолированна от железа микроконтроллера и поэтому в ней все осуществляется через функции, которые написаны разработчиками данного софта. Эти функции и их внутренности сокрыты в недрах программы. Обычному пользователю остается только вызывать нужные функции для настроек аппаратных узлов МК. Казалось бы это намного упрощает программирование. В принципе это так и есть. Поэтому среда и платы Arduino очень популярны среди начинающих любителей проектов на МК. Однако есть и минусы, например те, кто программируют Arduino, не могут запрограммировать микроконтроллеры, которые не поддерживает среда Arduino IDE. Например, запрограммировать любую модель МК Attiny AVR представляется уже невозможным. Да и другие модели Atmega, которых нет в платах Arduino, тоже остаются за бортом. В принципе если проекты не особо сложные, так побаловатся, то и среды Arduino достаточно. Если же надо что то большое и сложное, то тут конечно рулит чистый СИ. Но тогда придется разбираться в регистрах МК, в том как работают те или иные узлы МК. Надо читать документацию, изучить и понимать сам СИ. Однако если у вас уже есть опыт написание скетчей в среде Arduino, то со временем разобраться в СИ тоже будет возможно. Теперь попробуем рассмотреть код на СИ и поймем что это не так страшно. К примеру строка #include DDRC = 0< Эти строки настраивают нужные нам выводы платы Arduino на вход или на выход. PC0
это то же что и А0
на плате, этот вывод надо настроить на вход, так как к ней подключаетя потенциометр. И с этого вывода будет считываться значение АЦП. Регистром ADMUX
и ADCSRA
настраиваем сам узел АЦП в нужный нам режим. В частности настраиваем так что АЦП будет автоматически постоянно считывать значение с вывода А0
и сохранять это значение в регистре ADCH
. В МК есть аппаратные таймеры, это тоже такие узлы которые дают возможность работать с ШИМ выводами, например ШИМ вывод ~3 к которому подключен светодиод, принадлежит внутреннему Timer2
. В Atmega 328 есть еще Timer0
и Timer1
. Так вот с помощью регистров TCCR2A
и TCCR2B
, настроим наш Timer2 на режим FAST_PWM
, это дает нам возможность работать с выводом ~3 платы Arduino. Ну и в главном цикле программы сразу передаем значение из АЦП в наш Timer2
. Делается это одной строчкой OCR2B=ADCH
. Вопрос только в том как залить в нашу ардуину код написанный на СИ в AtmelStudio? Сделать это можно с помощью прямо из среды AtmelStudio. Правда перед этим надо из платы ардуино этим же программатором считать и сохранить загрузчик. Иначе потом плата ардуино не сможет работать со средой Arduino. В любое время можно обратно программатором вернуть загрузчик на место. В этом эксперименте мы добавляем порцию яркости светодиоду одной кнопкой и убавляем другой.
Функция analogWrite() используется для затухания свтодиода и его постепенного включения. AnalogWrite использует широтно-импульсную модуляцию (PWM), которая дает возможность включать/включать цифровой пин с большой скоростью, генерируя эффект затухания. Подключите анод (более длинная, позитивная нога) светодиода к цифровому пину 9 платы Arduino через резистор 220 Ом. Подключите катод (более короткая, нога с отрицательным зарядом) к земле. После объявления 9 пина в качестве ledPin, тело функции setup() можно не наполнять. Функция analogWrite() которую вы будете использовать в главном цикле main, требует два аргумента: один для определения пина, на который будут записываться и второй - для отображения записываемого ШИМ-значения. Для того, чтобы постепенно зажигать и тушить ваш светодиод, постепенно увеличивайте ШИМ значение от 0 до 255, после - опять до 0, чтобы завершить цикл. В скетче ниже, ШИМ-значение используется для переменной под названием brightness. Каждый раз по завершению цикла она увеличивает значение переменной. Если brightness достигает своего предельного значения (0 или 255), fadeAmount меняет свое значение на отрицательное. Другими словами, если fadeAmount равно 5, его значение меняется на -5. При следующей итерации цикла это приводит к изменению переменной brightness. analogWrite() обеспечивает быструю смену ШИМ значения, так что задержка в конце скетча контролирует скорость затухания. Попробуйте изменить значение задержки задержки и отследить, как отработает программа. Данный пример показывает как обеспечить затухание на 9 пине с использованием функции analogWrite(). int led = 9; // пин, к которому подключен светодиод int brightness = 0; // яркость светодиода int fadeAmount = 5; // на сколько увеличить яркость светодиода // функция setup отрабатывает один раз после перезагрузки платы: // объявляет 9 пин в качестве выхода: pinMode(led, OUTPUT); // цикл loop повторяется бесконечно: // устанавливает яркость 9 пина: analogWrite(led, brightness); // изменение яркости на следующей итерации с помощью цикла: brightness = brightness + fadeAmount; // меняет значение затухания на аналогичное с противоположным знаком при граничных значениях: if (brightness == 0 || brightness == 255) { fadeAmount = -fadeAmount ; // задержка в 30 для отслеживания эффекта затухания Теперь же разберемся с многоцветным светодиодом, который часто называют сокращенно: RGB-светодиод
.
RGB — это аббревиатура, которая расшифровывается как: Red — красный, Green — зеленый, Blue — синий. То есть внутри этого устройства размещается сразу три отдельных светодиода. В зависимости от типа, RGB-светодиод может иметь общий катод или общий анод.
подключает заголовочный файл в котором выбирается наш нужный МК. Среда AtmelStudio 7 делает это автоматически при создании нового проекта.СПИСОК ДЕТАЛЕЙ ДЛЯ ЭКСПЕРИМЕНТА
- 1 плата Arduino Uno;
- 1 беспаечная макетная плата;
- 2 тактовых кнопки;
- 1 резистор номиналом 220 Ом;
- 1 светодиод;
- 7 проводов «папа-папа».
ПРИНЦИПИАЛЬНАЯ СХЕМА
СХЕМА НА МАКЕТНОЙ ПЛАТЕ
ОБРАТИТЕ ВНИМАНИЕ
СКЕТЧ
скачать скетч для Arduino IDE
#define PLUS_BUTTON_PIN 2
#define MINUS_BUTTON_PIN 3
#define LED_PIN 9
int brightness = 100;
boolean plusUp = true;
boolean minusUp = true;
void setup()
{
pinMode(LED_PIN, OUTPUT);
pinMode(PLUS_BUTTON_PIN, INPUT_PULLUP);
pinMode(MINUS_BUTTON_PIN, INPUT_PULLUP);
}
void loop()
{
analogWrite(LED_PIN, brightness);
// реагируем на нажатия с помощью функции, написанной нами
plusUp = handleClick(PLUS_BUTTON_PIN, plusUp, +35);
minusUp = handleClick(MINUS_BUTTON_PIN, minusUp, -35);
}
// Собственная функция с 3 параметрами: номером пина с кнопкой
// (buttonPin), состоянием до проверки (wasUp) и градацией
// яркости при клике на кнопку (delta). Функция возвращает
// (англ. return) обратно новое, текущее состояние кнопки
boolean handleClick(int buttonPin, boolean wasUp, int delta)
{
boolean isUp = digitalRead(buttonPin);
if (wasUp && !isUp) {
delay(10);
isUp = digitalRead(buttonPin);
// если был клик, меняем яркость в пределах от 0 до 255
if (!isUp)
brightness = constrain(brightness + delta, 0, 255);
}
return isUp; // возвращаем значение обратно, в вызывающий код
}
ПОЯСНЕНИЯ К КОДУ
ВОПРОСЫ ДЛЯ ПРОВЕРКИ СЕБЯ
ЗАДАНИЯ ДЛЯ САМОСТОЯТЕЛЬНОГО РЕШЕНИЯ
Что вам понадобится для проекта
Схема подключения светодиода к Arduino
Электросхема подключенного к Arduino светодиода
Вариант шилда со светодиодом для Arduino
Описание программы для Arduino
Скетч для Arduino IDE
1. Смешение цветов
Чем RGB-светодиод, лучше трех обычных? Всё дело в свойстве нашего зрения смешивать свет от разных источников, размещенных близко друг к другу. Например, если мы поставим рядом синий и красный светодиоды, то на расстоянии несколько метров их свечение сольется, и глаз увидит одну фиолетовую точку. А если добавим еще и зеленый, то точка покажется нам белой. Именно так работают мониторы компьютеров, телевизоры и уличные экраны.
Матрица телевизора состоит из отдельно стоящих точек разных цветов. Если взять лупу и посмотреть через нее на включенный монитор, то эти точки можно легко увидеть. А вот на уличном экране точки размещаются не очень плотно, так что их можно различить невооруженным глазом. Но с расстояния несколько десятков метров эти точки неразличимы.
Получается, что чем плотнее друг к другу стоят разноцветные точки, тем меньшее расстояние требуется глазу чтобы смешивать эти цвета. Отсюда вывод: в отличие от трех отдельностоящих светодиодов, смешение цветов RGB-светодиода заметно уже на расстоянии 30-70 см. Кстати, еще лучше себя показывает RGB-светодиод с матовой линзой.
2. Подключение RGB-светодиода к Ардуино
Поскольку многоцветный светодиод состоит из трех обычных, мы будем подключать их отдельно. Каждый светодиод соединяется со своим выводом и имеет свой отдельный резистор.
В уроке мы используем RGB-светодиод с общим катодом, так что провод к земле будет только один.
Принципиальная схема
Внешний вид макета
3. Программа для управления RGB-светодиодом
Составим простую программу, которая будет по очереди зажигать каждый из трех цветов.
const byte rPin = 3;
const byte gPin = 5;
const byte bPin = 6;
void setup() {
pinMode(rPin, OUTPUT);
pinMode(gPin, OUTPUT);
pinMode(bPin, OUTPUT);
}
void loop() {
// гасим синий, зажигаем красный
digitalWrite(bPin, LOW);
digitalWrite(rPin, HIGH);
delay(500);
// гасим красный, зажигаем зеленый
digitalWrite(rPin, LOW);
digitalWrite(gPin, HIGH);
delay(500);
// гасим зеленый, зажигаем синий
digitalWrite(gPin, LOW);
digitalWrite(bPin, HIGH);
delay(500);
}
Загружаем программу на Ардуино и наблюдаем результат.
Your browser does not support the video tag.
Немного оптимизируем программу: вместо переменных rPin, gPin и bPin применим массив. Это нам поможет в следующих заданиях.
const byte rgbPins = {3,5,6};
void setup() {
for(byte i=0; i<3; i++)
pinMode(rgbPins[i], OUTPUT);
}
void loop() {
digitalWrite(rgbPins, LOW);
digitalWrite(rgbPins, HIGH);
delay(500);
digitalWrite(rgbPins, LOW);
digitalWrite(rgbPins, HIGH);
delay(500);
digitalWrite(rgbPins, LOW);
digitalWrite(rgbPins, HIGH);
delay(500);
}
4. Семь цветов радуги
Теперь попробуем зажигать одновременно по два цвета. Запрограммируем такую последовательность цветов:
Оранжевый цвет мы для упрощения опустили. Так что, получилось шесть цветов радуги 🙂
const byte rgbPins = {3,5,6};
const byte rainbow = {
{1,0,0}, // красный
{1,1,0}, // жёлтый
{0,1,0}, // зелёный
{0,1,1}, // голубой
{0,0,1}, // синий
{1,0,1}, // фиолетовый
};
void setup() {
for(byte i=0; i<3; i++)
pinMode(rgbPins[i], OUTPUT);
}
void loop() {
// перебираем все шесть цветов
for(int i=0; i<6; i++){
// перебираем три компоненты каждого из шести цветов
for(int k=0; k<3; k++){
digitalWrite(rgbPins[k], rainbow[i][k]);
}
delay(1000);
}
}
В результате работы программы получается:
Your browser does not support the video tag.
5. Плавное изменение цвета
Мы не зря подключили RGB-светодиод к выводам 3, 5 и 6. Как известно, эти выводы позволяют генерировать ШИМ сигнал разной скважности. Другими словами, мы можем не просто включать или выключать светодиод, а управлять уровнем напряжения на нем. Делается это с помощью функции analogWrite
.
Сделаем так, что наш светодиод будет переходить между цветами радуги не скачкообразно, а плавно.
const byte rgbPins = {3,5,6};
int dim = 1;
void setup() {
for(byte i=0; i<3; i++){
pinMode(rgbPins[i], OUTPUT);
}
// начальное состояние - горит красный цвет
analogWrite(rgbPins, 255);
analogWrite(rgbPins, 0);
analogWrite(rgbPins, 0);
}
void loop() {
// гасим красный, параллельно разжигаем зеленый
for(int i=255; i>=0; i--){
analogWrite(rgbPins, i/dim);
analogWrite(rgbPins, (255-i)/dim);
delay(10);
}
// гасим зеленый, параллельно разжигаем синий
for(int i=255; i>=0; i--){
analogWrite(rgbPins, i/dim);
analogWrite(rgbPins, (255-i)/dim);
delay(10);
}
// гасим синий, параллельно разжигаем красный
for(int i=255; i>=0; i--){
analogWrite(rgbPins, i/dim);
analogWrite(rgbPins, (255-i)/dim);
delay(10);
}
}
Переменная dim определяет яркость свечения. При dim = 1 имеем максимальную яркость.
Загружаем программу на Ардуино.
Your browser does not support the video tag.
Задания