В этом уроке мы создадим гирлянду из 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;} // Хорда от синего к зелёному, через голубой }
Обсуждение