В этом уроке мы создадим гирлянду из Trema-модулей NeoPixel. Каждый модуль состоит из четырёх адресных светодиодов и имеет один вход и один выход. Модули можно соединять друг с другом (выход одного модуля подключается ко входу другого), получив гирлянду из модулей. Управление цветами каждого светодиодов, происходит с использованием всего одного вывода Arduino.
Собираемая нами схема состоит из 30 модулей (количество указывается в скетче), по 4 адресных светодиода в каждом, значит всего 120 светодиодов. Каждый светодиод может потреблять до 45 мА (при белом свечении), значит вся гирлянда может потреблять до 5,4 А (120 x 45 мА). Разумеется это максимум и по алгоритму скетча мы его не достигнем, но для сборки гирлянды потребуются провода с большим сечением, как у проводов из набора МАМА-МАМА 20AWG.
Меняя значения четырёх констант скетча Вы можете изменить: номер вывода Arduino, количество используемых Trema-модулей NeoPixel, количество модулей между шарами и время на которое будет устанавливаться очередное состояние гирлянды.
Нам понадобится:
- Arduino Uno х 1шт.
- Trema модуль - NeoPixel x 30шт.
- Trema Shield x 1шт.
- Набор проводов МАМА-МАМА x 5шт.
Для реализации проекта нам необходимо установить библиотеку:
- iarduino_NeoPixel для работы с адресными светодиодами.
О том как устанавливать библиотеки, Вы можете ознакомиться на странице Wiki - Установка библиотек в Arduino IDE.
Видео:
Схема подключения:
Все используемые в уроке Trema-модули NeoPixel соединены друг c другом, а первый модуль гирлянды можно подключить к любому выводу Arduino. Номер вывода указывается в скетче (в примере используется вывод D7). Чем больше модулей в гирлянде, тем больше тока она потребляет, по этому в схеме используется внешний стабилизированный источник питания на 5 В постоянного тока.
Алгоритм работы:
Работа адресных светодиодов:
- На выходе Arduino формируется последовательность импульсов:
- короткий импульс означает, что бит равен 0.
- длинный импульс означает, что бит равен 1.
- Светодиод подключенный первым к выводу Arduino «берёт» себе первые сформированные 24 бита (3 байта) указывающие яркость трёх цветов GBR. А все остальные биты светодиод пропускает, передавая их на свой выход, к которому подключён вход следующего светодиода.
- Второй светодиод, так же, «берёт» себе первые полученные им 24 бита (3 байта) которые пропустил первый светодиод. Но на самом деле это вторые 3 байта которые сформировались на выходе Arduino, т.к. первые 3 байта «забрал» первый светодиод.
- Как только импульсы перестали формироваться на выходе Arduino, светодиоды ждут до 50 мкс, после чего устанавливают полученный (взятый из потока данных) ими цвет.
- Светодиоды находящиеся в модуле подключённом первым к выводу Arduino имеют номера 0-3, в следующем 4-7 и т.д.
Работа с библиотекой iarduino_NeoPixel:
- После подключения библиотеки нужно объявить объект, указав номер вывода Arduino и количество используемых светодиодов.
- В коде setup() необходимо инициировать работу с адресными светодиодами вызвав функцию begin() объекта библиотеки.
- Вызывая функцию setColor(№,R,G,B) объекта библиотеки, можно установить любой цвет для любого светодиода, но эта функция не передаёт цвет светодиоду, а сохраняет его в памяти. Номер светодиода должен находиться в пределах от 0 до 65534, а каждое из значений составляющих цвет (RGB) в пределах от 0 до 255. Если вместо номера указать NeoPixelAll, то цвет установится для всех светодиодов.
- Вызов функции write() объекта библиотеки приведёт к передачи всех установленных ранее цветов во все используемые светодиоды. Именно после вызова данной функции светодиоды меняют свои цвета.
Все функции библиотеки iarduino_NeoPixel описаны в разделе Wiki - Адресные светодиоды, модули NeoPixel.
Работа скетча:
- В начале скетча определены четыре константы pinNum, modSum, modShift и durationState. Меняя их значение Вы можете изменить: номер вывода Arduino, количество используемых Trema-модулей NeoPixel, количество модулей между шарами и время на которое будет устанавливаться очередное состояние гирлянды (в секундах).
- Далее подключается библиотека iarduino_NeoPixel, объявляется объект библиотеки, а также используемые переменные и функции.
- Код loop() состоит из оператора switch() в котором выполняется только тот участок кода, который совпадает с номером состояния в переменной garlandState. А после оператора switch() имеется код который меняет значение переменной garlandState через каждые durationState секунд.
- В конце кода определены три функции:
- Функция setColorModule(№,R,G,B) выполняет то же самое что и функция setColor(№,R,G,B) объекта библиотеки iarduino_NeoPixel, но принимает не номер светодиода, а номер Trema-модуля NeoPixel, устанавливая цвет для всех его светодиодов.
- Функция setColorBall(№,R,G,B) выполняет то же самое что и функция setColor(№,R,G,B) объекта библиотеки iarduino_NeoPixel, но принимает не номер светодиода, а номер шара с Trema-модулем NeoPixel, устанавливая цвет для всех его светодиодов.
- Функция getColorDeg(угол) принимает одно значение - угол, но не в градусах от 0 до 360, а в виде значения от 0 до 255. Если нарисовать радужный круг с переливом цветов (зелёный > красный > синий), то функция возвращает цвет (в переменные colR, colG и colB) на который указывает угол из центра этого круга.
Код программы:
/* Скетч для работы гирлянды состоящей из Trema-модулей NeoPixel.
* Общее количество используемых Trema-модулей указывается в константе modSum.
* Номер вывода Arduino к которому подключена гирлянда указывается в константе pinNum.
* Гирлянда состоит из чередующихся игрушек (Trema-модулей в шарах) и Trema-модулей без шаров.
* Между каждым шаром должно быть одинаковое количество Trema-модулей (указывается в константе modShift).
* Гирлянда не может начинаться с шара.
* Состояние гирлянды (режим её работы) постоянно меняется через время указанное в константе durationState (в секундах).
*/
const uint8_t pinNum = 7; // Определяем константу с указанием № вывода Arduino, к которому подключена гирлянда
const uint16_t modSum = 30; // Определяем константу с указанием количества Trema-модулей NeoPixel в гирлянде
const uint8_t modShift = 2; // Определяем константу с указанием количества Trema-модулей между шарами с Trema-модулями
const uint8_t durationState = 6; // Определяем константу с указанием количества секунд через которое будут меняться состояние гирлянды (режимы её работы)
#include <iarduino_NeoPixel.h> // Подключаем библиотеку iarduino_NeoPixel для работы со светодиодами NeoPixel
iarduino_NeoPixel led(pinNum,(modSum*4)); // Объявляем объект led указывая (№ вывода Arduino с гирляндой, количество светодиодов в гирлянде)
uint8_t garlandState=0; // Определяем переменную хранящую состояние гирлянды
uint32_t setTimeState; // Объявляем переменную для хранения времени последнего изменения состояния гирлянды
uint16_t ballSum=modSum/(modShift+1); // Определяем переменную хранящую количество шаров в гирлянде
uint8_t colR,colG,colB; // Определяем переменные которые будут использоваться для получения результирующего цвета
uint8_t i=0, j=0; // Определяем переменные которые будут использоваться в разных участках кода по разному
void setColorModule(uint16_t, uint8_t, uint8_t, uint8_t); // Объявляем функцию устанавливающую цвет для всех светодиодов на одном Trema-модуле (№_Trema-модуля, R, G, B)
void setColorBall (uint16_t, uint8_t, uint8_t, uint8_t); // Объявляем функцию устанавливающую цвет для Trema-модулей в шарах (№_шара, R, G, B)
void getColorDeg (uint8_t); // Объявляем функцию возвращающую цвет в переменные colR,colG,colB по градусу (градус от 0 до 255)
void setup(){led.begin();} // В функции setup выполняется только инициализация работы с адресными светодиодами
void loop(){
switch(garlandState){ // В зависимости от значения переменной garlandState, будет выполняться только один участок оператора switch
case 0: // Все шары гирлянды зажигаются одним из цветов радуги
if(i==0 ){i=42; }else // i=60° (0 ... 42 ... 255 = 0° ... 60° ... 360°)
if(i==42 ){i=85; }else // i=120° (0 ... 85 ... 255 = 0° ... 120° ... 360°)
if(i==85 ){i=127;}else // i=180° (0 ... 127 ... 255 = 0° ... 180° ... 360°)
if(i==127){i=170;}else // i=240° (0 ... 170 ... 255 = 0° ... 240° ... 360°)
if(i==170){i=212;}else // i=300° (0 ... 212 ... 255 = 0° ... 300° ... 360°)
if(i==212){i=0; } // i=360° (0 ... 255 ... 255 = 0° ... 360° ... 360°)
getColorDeg(i); // Получаем цвет в переменные colR,colG,colB по градусу i
setColorBall(NeoPixelAll,colR,colG,colB); // Устанавливаем цвет colR,colG,colB для всех шаров гирлянды
led.write(); delay(1000); // Записываем установленные цвета и ждём 1 секунду
break;
case 1: // Вся гирлянда зажигается одним из цветов радуги
if(i==0 ){i=42; }else // i=60° (0 ... 42 ... 255 = 0° ... 60° ... 360°)
if(i==42 ){i=85; }else // i=120° (0 ... 85 ... 255 = 0° ... 120° ... 360°)
if(i==85 ){i=127;}else // i=180° (0 ... 127 ... 255 = 0° ... 180° ... 360°)
if(i==127){i=170;}else // i=240° (0 ... 170 ... 255 = 0° ... 240° ... 360°)
if(i==170){i=212;}else // i=300° (0 ... 212 ... 255 = 0° ... 300° ... 360°)
if(i==212){i=0; } // i=360° (0 ... 255 ... 255 = 0° ... 360° ... 360°)
getColorDeg(i); // Получаем цвет в переменные colR,colG,colB по градусу i
setColorModule(NeoPixelAll,colR,colG,colB); // Устанавливаем цвет colR,colG,colB для всех Trema-модулей
led.write(); delay(1000); // Записываем установленные цвета и ждём 1 секунду
break;
case 2: // Случайные шары включаются случайным цветом
i=random(3); // Определяем какой из трех составляющих цветов будет отсутствовать R, G, или B
if(i==0){colR=0;}else{colR=random(0xFF);} // Определяем случайное значение для переменной colR
if(i==1){colG=0;}else{colG=random(0xFF);} // Определяем случайное значение для переменной colG
if(i==2){colB=0;}else{colB=random(0xFF);} // Определяем случайное значение для переменной colB
setColorBall(random(ballSum),colR,colG,colB); // Устанавливаем цвет colR,colG,colB для случайного шара
led.write(); delay(50); // Записываем установленные цвета и ждём 50 миллисекунд
break;
case 3: // Случайные модули включаются случайным цветом
i=random(3); // Определяем какой из трех составляющих цветов будет отсутствовать R, G, или B
if(i==0){colR=0;}else{colR=random(0xFF);} // Определяем случайное значение для переменной colR
if(i==1){colG=0;}else{colG=random(0xFF);} // Определяем случайное значение для переменной colG
if(i==2){colB=0;}else{colB=random(0xFF);} // Определяем случайное значение для переменной colB
setColorModule(random(modSum),colR,colG,colB); // Устанавливаем цвет colR,colG,colB для случайного Trema-модуля
led.write(); delay(10); // Записываем установленные цвета и ждём 10 миллисекунд
break;
case 4: // Шрапнель одного из цветов радуги, которые будут меняться через каждые 20j
if(j>=20 ){j=0; // Если переменная j >= 20, то сбрасываем j и меняем градус i:
if(i==0 ){i=42; }else // i=60° (0 ... 42 ... 255 = 0° ... 60° ... 360°)
if(i==42 ){i=85; }else // i=120° (0 ... 85 ... 255 = 0° ... 120° ... 360°)
if(i==85 ){i=127;}else // i=180° (0 ... 127 ... 255 = 0° ... 180° ... 360°)
if(i==127){i=170;}else // i=240° (0 ... 170 ... 255 = 0° ... 240° ... 360°)
if(i==170){i=212;}else // i=300° (0 ... 212 ... 255 = 0° ... 300° ... 360°)
if(i==212){i=0; }} // i=360° (0 ... 255 ... 255 = 0° ... 360° ... 360°)
getColorDeg(i); // Получаем цвет в переменные colR,colG,colB по градусу i
led.setColor(NeoPixelAll,0,0,0); // Гасим цвета для всех светодиодов
led.setColor(random(modSum*4),colR,colG,colB); // Устанавливаем включённый цвет для первого случайного светодиода
led.setColor(random(modSum*4),colR,colG,colB); // Устанавливаем включённый цвет для второго случайного светодиода
led.setColor(random(modSum*4),colR,colG,colB); // Устанавливаем включённый цвет для третьего случайного светодиода
led.setColor(random(modSum*4),colR,colG,colB); // Устанавливаем включённый цвет для четвёртого случайного светодиода
led.setColor(random(modSum*4),colR,colG,colB); // Устанавливаем включённый цвет для пятого случайного светодиода
led.write(); delay(50); // Записываем установленные цвета и ждём 50 миллисекунд
j++; // Увеличиваем переменную j. Как только она станет равна 20, то сменится цвет
break;
case 5: // Шрапнель из случайных цветов
i=random(3); // Определяем какой из трех составляющих цветов будет отсутствовать R, G, или B
if(i==0){colR=0;}else{colR=random(0xFF);} // Определяем случайное значение для переменной colR
if(i==1){colG=0;}else{colG=random(0xFF);} // Определяем случайное значение для переменной colG
if(i==2){colB=0;}else{colB=random(0xFF);} // Определяем случайное значение для переменной colB
led.setColor(NeoPixelAll,0,0,0); // Гасим цвета для всех светодиодов
led.setColor(random(modSum*4),colR,colG,colB); // Устанавливаем включённый цвет для первого случайного светодиода
led.setColor(random(modSum*4),colR,colG,colB); // Устанавливаем включённый цвет для второго случайного светодиода
led.setColor(random(modSum*4),colR,colG,colB); // Устанавливаем включённый цвет для третьего случайного светодиода
led.setColor(random(modSum*4),colR,colG,colB); // Устанавливаем включённый цвет для четвёртого случайного светодиода
led.setColor(random(modSum*4),colR,colG,colB); // Устанавливаем включённый цвет для пятого случайного светодиода
led.write(); delay(50); // Записываем установленные цвета и ждём 50 миллисекунд
break;
case 6: // Все шары гирлянды одновременно переливаются всеми цветами радуги
getColorDeg(i); // Получаем цвет в переменные colR,colG,colB по градусу i
setColorBall(NeoPixelAll,colR,colG,colB); // Устанавливаем цвет colR,colG,colB для всех шаров
led.write(); delay(5); // Записываем установленные цвета и ждём 5 миллисекунды
i++; // Увеличиваем градус i
break;
case 7: // Вся гирлянда одновременно переливается всеми цветами радуги
getColorDeg(i); // Получаем цвет в переменные colR,colG,colB по градусу i
setColorModule(NeoPixelAll,colR,colG,colB); // Устанавливаем цвет colR,colG,colB для всех модулей
led.write(); delay(5); // Записываем установленные цвета и ждём 5 миллисекунды
i++; // Увеличиваем градус i
break;
case 8: // Все шары гирлянды переливаются всеми цветами радуги
for(uint16_t k=0; k<ballSum; k++){ // Проходим по всем шарам в гирлянде
i=((uint16_t)(k*256/ballSum)+j); // Определяем градус i для очередного шара на спектре цветов со смещением j
getColorDeg(i); // Получаем цвет в переменные colR,colG,colB по градусу i
setColorBall(k,colR,colG,colB); // Устанавливаем цвет colR,colG,colB для очередного шара
} led.write(); delay(2); // Записываем установленные цвета и ждём 2 миллисекунды
j++; // Смещаем спектр цветов для всех шаров
break;
case 9: // Вся гирлянда переливается всеми цветами радуги
for(uint16_t k=0; k<modSum; k++){ // Проходим по всем модулям в гирлянде
i=((uint16_t)(k*256/modSum)+j); // Определяем градус i для очередного модуля на спектре цветов со смещением j
getColorDeg(i); // Получаем цвет в переменные colR,colG,colB по градусу i
setColorModule(k,colR,colG,colB); // Устанавливаем цвет colR,colG,colB для очередного модуля
} led.write(); delay(2); // Записываем установленные цвета и ждём 2 миллисекунды
j++; // Смещаем спектр цветов для всех модулей
break;
}
// Меняем состояние работы гирлянды
if(millis()>setTimeState+(uint32_t)durationState*1000){ // Если с последнего изменения состояния прошло более чем durationState сек, то..
setColorModule(NeoPixelAll,0,0,0); led.write(); i=0; j=0; // Гасим все модули и обнуляем переменные i и j
garlandState++; if(garlandState>9){garlandState=0;} // Устанавливаем следующее состояние. Строку можно заменить на: garlandState=random(10);
setTimeState=millis(); // Сохраняем время смены состояния
}
}
// Функция устанавливающая цвет для всех светодиодов на одном Trema-модуле
void setColorModule(uint16_t n, uint8_t r, uint8_t g, uint8_t b){ // аргументы функции: (№_Trema-модуля, R, G, B)
if(n!=NeoPixelAll){for(int i=0; i<4; i++){led.setColor((n*4+i),r,g,b);}} // Устанавливаем цвет для каждого из 4 светодиодов Trema-модуля с номером n
else { led.setColor( n ,r,g,b); } // Устанавливаем цвет для всех светодиодов гирлянды
}
// Функция устанавливающая цвет для Trema-модулей находящихся в шарах
void setColorBall(uint16_t n, uint8_t r, uint8_t g, uint8_t b){ // аргументы функции: (№_шара, R, G, B)
if(n!=NeoPixelAll){setColorModule((n*(modShift+1)+modShift),r,g,b);} // Устанавливаем цвет для Trema-модуля находящегося в шаре с номером n
else {for(int i=modShift; i<30; i+=(modShift+1)){setColorModule(i,r,g,b);}} // Устанавливаем цвет для всех Trema-модулей находящихся в шарах
}
// Функция возвращает цвет в переменные colR,colG,colB по градусу n
void getColorDeg(uint8_t n){ // аргументы функции: (градус n от 0 до 255)
if(n<85) { colB=0; colR=n*3; colG=255-colR;}else // Хорда от зелёного к красному, через жёлтый
if(n<170){n-=85; colG=0; colB=n*3; colR=255-colB;}else // Хорда от красного к синему , через фиолетовый
{n-=170; colR=0; colG=n*3; colB=255-colG;} // Хорда от синего к зелёному, через голубой
}


Обсуждение