Ёлочная гирлянда из arduino, светодиодов WS2811 и старого блока питания от компьютера

Ответить
Сергей
Сообщения: 5
Зарегистрирован: Вт ноя 28, 2017 6:58 pm

Ёлочная гирлянда из arduino, светодиодов WS2811 и старого блока питания от компьютера

Сообщение Сергей » Вт ноя 28, 2017 8:18 pm

Новый год приближался, а старые гирлянды все как то кончились. Стоимость гирлянд в супермаркетах и на рынках не радует, да и стандартные, однотипные схемы мигания приелись. Хотелось чего-то волшебного, сказочного...

Дабы не томить, покажу сразу что в итоге получилось:


ws2811_36.jpg
Гирлянда IP67 (для улицы):http://s.click.aliexpress.com/e/f6EIAIi
По проще и дешевле для дома: http://s.click.aliexpress.com/e/f6y7EmM

Пару лет назад пришлось справлять этот волшебный праздник с обычной китайской гирляндой из лампочек накаливания, которые от старости выцвели и светили стрёмным жёлтым цветом. И была найдена зависимость: какая гирлянда - такой и новый год.

Год назад (перед 2016 нг) заказал с китаю гирлянду в 100 диодов с чипами ws2811, Ехала долго, думал не успеет, но мне повезло - гирлянда приехала до нового года. По быстрому отрыл старый БП от компа ватт на 250, выдрал лишние провода и заменил вспухшие кондёры, почистил естественно и перепаял 80мм вентилятор с 12в на 5в чтоб меньше жужжал, предварительно смазав его литолом. Впихал туда ардуину, кнопочки, крутилочки... Мигает! ))

Ёлка у меня искуственная но высокая и пышная, прикинул по вышине - 25 диодов получилось в самый раз, поэтому гирлянда была распилена на 4 куска по 25 диодов. (позже я добавил ещё 4 таких куска, но об этом потом)

Всверлил в корпус БП 3 кнопки и три крутилки, одна крутилка регулирует яркость гирлянды, вторая скорость еффектов, третья будет менять скорость смены цвета в радуге, ну или ещё чего на неё повешать - не знаю.

Кнопка из 3х задействована одна. Она переключает эффекты и записывает в ЕЕПРОМ, для того, чтобы при включении показывался ранее выбраный эффект. На две другие пока думаю чего навешать. можно например ночной режим - яркость на минимум, скорость на минимум, эффект радуга. Или можно определённые, самые любимые эффекты на них повешать.

Из эффектов пока 6 штук из библтотеки FastLED и ещё несколько самопальных :) В том числе "снегопад"

Зачем запихал в такую большую коробку? Потому что старых БП от компа у меня много :) . И сейчас будут подключаться 100 диодов (4 обрезка по 25шт) это на полной яркости белого цвета почти 6А, К следующему новому году наверно добавлю ещё 4 таких обрезка, будет уже 12А. Тот БП что я использовал выдаёт 18А по 5в линии, тоесть ещё запас на 4 обрезка по 25 диодов останется.

А теперь как я туда чего запихивал, высверливал и протачивал...

Нашёл свободное место, подальше от высокочастотных и силовых узлов (разъём 220 не в счет :) )

ws2811_05.jpg
ws2811_05.jpg (68.76 КБ) 11464 просмотра

К тому же будет доступ к USB разъёму.

ws2811_06.jpg
ws2811_06.jpg (67.87 КБ) 11464 просмотра

Для органов управления так же найдено место, подальше от всего опасного...

ws2811_07.jpg
ws2811_07.jpg (78.67 КБ) 11464 просмотра
ws2811_08.jpg
ws2811_08.jpg (93.04 КБ) 11464 просмотра
ws2811_09.jpg
ws2811_09.jpg (111.7 КБ) 11464 просмотра

Сверлить тонкую жестянку, так чтобы было аккуратно - не очень получается (позже приноровился - подставляя разделочную доску)

ws2811_10.jpg
ws2811_10.jpg (89.48 КБ) 11464 просмотра
ws2811_11.jpg
ws2811_11.jpg (104.64 КБ) 11464 просмотра

Паяем выходы, те что пойдут на гирлянды. Для безопасности делаем это через резистор. Советуют 470 ом, но у меня были в наличии на 330, сойдёт...

ws2811_12.jpg
ws2811_12.jpg (107.86 КБ) 11464 просмотра
ws2811_15.jpg
ws2811_15.jpg (109.01 КБ) 11464 просмотра

Распаял кнопки и переменники. Кнопки замыкают на массу и используется внутренняя подтяжка к плюсу, поэтому лишних резисторов не ставим. Все переменники (лучше на 10к, но не особо важно, можно даже на 1к воткнуть) подключены одним концом на массу, другие концы все в кучу и через 200 ом резистор (ну вдруг там чего замкнёт) на +5в, паралельно переменникам напаял кондёр (100мкф и 0.1мкф) , чтоб сильно цифры не скакали. Ползунки переменников идут в ардуино на аналоговые входы.

ws2811_17.jpg
ws2811_17.jpg (110.57 КБ) 11464 просмотра
ws2811_19.jpg
ws2811_19.jpg (78.73 КБ) 11464 просмотра
ws2811_20.jpg
ws2811_20.jpg (89.14 КБ) 11464 просмотра

Подаём питание... И поскольку очень много говорят про всякие там помехи и фильтры - поставил пару кондёров (100мкф и 0.1мкф) Не потому что я чегото там просчитал, а просто у меня есть кондёры только 100мкф и 0.1мкф :D

ws2811_21.jpg
ws2811_21.jpg (79.96 КБ) 11464 просмотра

Всё паялось обычным 40вт паялом, без всякого заземления со вставленой в панель ардуиной и как ни странно, всё работает :)

ws2811_22.jpg
ws2811_22.jpg (90.99 КБ) 11464 просмотра

Был написан скетч по быстрому на базе библиотеки FastLED и весело отпразднован новый год. После чего, гирлянда вместе с ёлкой были упрятаны в коробку и отправлены в дальний угол ожидать следующего нового года.

И вот "на горизонте" обозначился очередной 2017 новый год. заказана и уже доставлена ещё одна гирлянда из 100 диодов с чипами WS2811. Досталась прошлогодняя гирлянда и работы продолжились...

Было решено заменить самопальные разъёмы на нормальные типа "Джек". Был так же докуплен провод и термоусадка.

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

ws2811_23.jpg
ws2811_23.jpg (99.42 КБ) 11464 просмотра
ws2811_24.jpg
ws2811_24.jpg (75.08 КБ) 11464 просмотра
ws2811_25.jpg
ws2811_25.jpg (108.36 КБ) 11464 просмотра
ws2811_26.jpg
ws2811_26.jpg (112.25 КБ) 11045 просмотров
ws2811_27.jpg
ws2811_27.jpg (44.14 КБ) 11045 просмотров
ws2811_28.jpg
ws2811_28.jpg (88.55 КБ) 11045 просмотров

Готово! Теперь надо паять к ним провода...

В прошлом году гирлянд было 4, распаял на 6, но в задумке было 8, поэтому допаиваем недостающие 2 провода с резисторами.

ws2811_29.jpg
ws2811_29.jpg (94.77 КБ) 11045 просмотров
ws2811_26.jpg
ws2811_27.jpg

И припаиваем это всё к джекам, не забывая надевать термоусадки (я на плюс забыл одеть)...

ws2811_28.jpg
ws2811_29.jpg

Вычитал также что надо конденсатор ближе к гирляндам поставить, под руку попался 1000мкф х 25в. Паяю его прямо к джекам.

ws2811_30.jpg

Чтоб провода не лезли к вентелятору и высоковольтной части БП - фиксирую их бумажным скотчем и для верности - клеющим пистолетом.

ws2811_31.jpg
ws2811_32.jpg
ws2811_33.jpg

Собираем корпус

ws2811_34.jpg
ws2811_36.jpg
ws2811_37.jpg

Припаивал провода метра по полтора от джека до куска гирлянды, закрывая все стыки термоусадкой

ws2811_39.jpg

Чтоб было за что вешать гирлянду на ёлку (или ещё куда нибудь) из больших канцелярских скрепок сделал крючки, а из оставшихся проводов-хвостиков сделал петельки, куда и вставил скрепки

ws2811_40.jpg

Подошло время для скетча... Первая версия была переработана, инициализация лент была запихана в массив, вызов эффектов был переделан под использование этого массива, что дало возможность делать горизонтальные эффекты. Сделал 1-2 эффекта простых (между лентами) и после нескольких дней обдумывания изобретён эффект "снегопад". Если бы вместо гирлянд были ленты с высокой плотностью диодов, то эффект можно было назвать "капающие сосульки", а на гирлянде только "снегопад" :) Для меня версия скетча "v2 рабочая", вам нужно его рассматривать как "преальфа" :)

Библиотеку FastLED качаем здесь

Ну и сам скетч (делал всё в arduino IDE):

Код: Выделить всё

#include <EEPROM.h>
#include "FastLED.h"
const int bright_rezistor_pin = A7; // Резистор регулировки яркости (10к)
const int rainbowspeed_rezistor_pin = A6; // Резистор регулировки скорости смены цвета в радуге (10к)
const int fps_rezistor_pin = A5; // Общая скорость эффектов (кадров в секунду) (10к)
const int btn_changeeffect_pin = 2; // Кнопка смены эффектов
const int btn_2_pin = 3; // Резерв
const int btn_3_pin = 4; // Резерв

int bright_rezistor = 400; // Стартовое значение резистора яркости
int fps_rezistor = 400; // Стартовое значение резистора скорости еффектов (fps)

int btn_changeeffect_flag = 0;
int btn_changeeffect_state = HIGH;
int last_btn_changeeffect_state = HIGH;
long last_btn_changeeffect_debounce_time = 0;
const int debounceDelay = 80;
byte current_effect = 0;
const int eeprom_addr = 4;

int pos1 = 0;
int color_x = 0;

FASTLED_USING_NAMESPACE
#if FASTLED_VERSION < 3001000
#error "Requires FastLED 3.1 or later; check github for latest code."
#endif

#define DATA_PIN_1  5  // Определяем пин для ленты #1
#define DATA_PIN_2  6  // Определяем пин для ленты #2
#define DATA_PIN_3  7  // Определяем пин для ленты #3
#define DATA_PIN_4  8  // Определяем пин для ленты #4
#define DATA_PIN_5  9  // Определяем пин для ленты #5
#define DATA_PIN_6  10 // Определяем пин для ленты #6
#define DATA_PIN_7  11 // Определяем пин для ленты #7
#define DATA_PIN_8  12 // Определяем пин для ленты #8

#define LED_TYPE    WS2811
#define COLOR_ORDER RGB
#define NUM_LEDS    25
#define NUM_STRIPS  8
CRGB leds[NUM_STRIPS][NUM_LEDS];

#define BRIGHTNESS         150  // Стартовое значение яркости
#define FRAMES_PER_SECOND  1   // Стартовое значение скорости эффектов

void setup() {
  Serial.begin(9600); // Для отладки
  
  pinMode(bright_rezistor_pin, INPUT);
  pinMode(rainbowspeed_rezistor_pin, INPUT);
  pinMode(fps_rezistor_pin, INPUT);
  
  pinMode(btn_changeeffect_pin, INPUT);
  digitalWrite(btn_changeeffect_pin, HIGH); // Используем встроенную верхнюю подтяжку
  pinMode(btn_2_pin, INPUT);
  digitalWrite(btn_2_pin, HIGH); // Используем встроенную верхнюю подтяжку
  pinMode(btn_3_pin, INPUT);
  digitalWrite(btn_3_pin, HIGH); // Используем встроенную верхнюю подтяжку
  
  delay(1000); // 3 second delay for recovery
  
  // tell FastLED about the LED strip configuration
  FastLED.addLeds<LED_TYPE,DATA_PIN_1,COLOR_ORDER>(leds[0], NUM_LEDS).setCorrection(TypicalLEDStrip);
  FastLED.addLeds<LED_TYPE,DATA_PIN_2,COLOR_ORDER>(leds[1], NUM_LEDS).setCorrection(TypicalLEDStrip);
  FastLED.addLeds<LED_TYPE,DATA_PIN_3,COLOR_ORDER>(leds[2], NUM_LEDS).setCorrection(TypicalLEDStrip);
  FastLED.addLeds<LED_TYPE,DATA_PIN_4,COLOR_ORDER>(leds[3], NUM_LEDS).setCorrection(TypicalLEDStrip);
  FastLED.addLeds<LED_TYPE,DATA_PIN_5,COLOR_ORDER>(leds[4], NUM_LEDS).setCorrection(TypicalLEDStrip);
  FastLED.addLeds<LED_TYPE,DATA_PIN_6,COLOR_ORDER>(leds[5], NUM_LEDS).setCorrection(TypicalLEDStrip);
  FastLED.addLeds<LED_TYPE,DATA_PIN_7,COLOR_ORDER>(leds[6], NUM_LEDS).setCorrection(TypicalLEDStrip);
  FastLED.addLeds<LED_TYPE,DATA_PIN_8,COLOR_ORDER>(leds[7], NUM_LEDS).setCorrection(TypicalLEDStrip);

  // set master brightness control
  FastLED.setBrightness(BRIGHTNESS);
  current_effect = EEPROM.read(eeprom_addr);
}


// List of patterns to cycle through.  Each is defined as a separate function below.
typedef void (*SimplePatternList[])();
SimplePatternList gPatterns = { rainbow, rainbowWithGlitter, confetti, sinelon, juggle, bpm, horizont_2, snow_2 };

uint8_t gCurrentPatternNumber = 0; // Index number of which pattern is current
uint8_t gHue = 0; // rotating "base color" used by many of the patterns
  
void loop()
{
  bright_rezistor = map(analogRead(bright_rezistor_pin), 0, 985 ,10 ,255);
  fps_rezistor = map(analogRead(fps_rezistor_pin), 0, 985 ,5 ,255);
  
  // Городим жуткую защиту от дребезга для кнопки переключения эффектов...
  int btn_changeeffect_reading = digitalRead(btn_changeeffect_pin);
  if(btn_changeeffect_reading != last_btn_changeeffect_state){
    last_btn_changeeffect_debounce_time = millis();
  }
  if((millis() - last_btn_changeeffect_debounce_time) > debounceDelay) {
    if(btn_changeeffect_reading != btn_changeeffect_state) {
      btn_changeeffect_state = btn_changeeffect_reading;
      if(btn_changeeffect_state == LOW && btn_changeeffect_flag == 0){ // Если кнопка нажата...
        current_effect ++; // Увиличиваем номер эффекта
        EEPROM.write(eeprom_addr, current_effect); // Записываем номер эффекта в ЭСППЗУ
        btn_changeeffect_flag = 1;
        if(current_effect > 9){      // Если номер эффекта превышает существующее
          current_effect = 0;        // то отсчет начинается с нуля
        }
      }
      if(btn_changeeffect_state == HIGH && btn_changeeffect_flag == 1){
        btn_changeeffect_flag = 0;
      }
    }
  }
  last_btn_changeeffect_state = btn_changeeffect_reading;
  
  FastLED.setBrightness(bright_rezistor);
  //Serial.println(current_effect);
  //delay(1);
  if(current_effect == 0){
    EVERY_N_SECONDS( 10 ) { nextPattern(); } // change patterns periodically
    gPatterns[gCurrentPatternNumber]();
  }
  if(current_effect == 1){
    rainbow();
  }
  if(current_effect == 2){
    rainbowWithGlitter();
  }
  if(current_effect == 3){
    confetti();
  }
  if(current_effect == 4){
    sinelon();
  }
  if(current_effect == 5){
    juggle();
  }
  if(current_effect == 6){
    bpm();
  }
  if(current_effect == 7){
    horizont_2();
  }
  if(current_effect == 8){
    snow_1();
  }
  if(current_effect == 9){
    snow_2();
  }

  // send the 'leds' array out to the actual LED strip
  FastLED.show();  
  // insert a delay to keep the framerate modest
  FastLED.delay(1000/fps_rezistor); 

  // do some periodic updates
  EVERY_N_MILLISECONDS( 1 ) { gHue++; } // slowly cycle the "base color" through the rainbow
}

#define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0]))

void nextPattern()
{
  // add one to the current pattern number, and wrap around at the end
  gCurrentPatternNumber = (gCurrentPatternNumber + 1) % ARRAY_SIZE( gPatterns);
}

void rainbow(){
  // FastLED's built-in rainbow generator
  for(int i=0; i < NUM_STRIPS; i++){
    fill_rainbow( leds[i], NUM_LEDS, gHue, 7);
  }
}

void rainbowWithGlitter(){
  // built-in FastLED rainbow, plus some random sparkly glitter
  rainbow();
  addGlitter(80);
}

void addGlitter( fract8 chanceOfGlitter){
  if( random8() < chanceOfGlitter) {
    for(int i=0; i < NUM_STRIPS; i++){
      leds[i][ random16(NUM_LEDS) ] += CRGB::White;
    }
  }
}

void confetti(){
  // random colored speckles that blink in and fade smoothly
  for(int i=0; i < NUM_STRIPS; i++){
    fadeToBlackBy( leds[i], NUM_LEDS, 10);
  }
  int pos = random16(NUM_LEDS);
  for(int i=0; i < NUM_STRIPS; i++){
    leds[i][pos] += CHSV( gHue + random8(64), 200, 255);
  }
}

void sinelon(){
  // a colored dot sweeping back and forth, with fading trails
  for(int i=0; i < NUM_STRIPS; i++){
    fadeToBlackBy( leds[i], NUM_LEDS, 20);
  }
  int pos = beatsin16(13,0,NUM_LEDS);
  for(int i=0; i < NUM_STRIPS; i++){
    leds[i][pos] += CHSV( gHue, 255, 192);
  }
}

void bpm(){
  // colored stripes pulsing at a defined Beats-Per-Minute (BPM)
  uint8_t BeatsPerMinute = 62;
  CRGBPalette16 palette = PartyColors_p;
  uint8_t beat = beatsin8( BeatsPerMinute, 64, 255);
  for( int ii = 0; ii < NUM_LEDS; ii++) { //9948
    for(int i=0; i < NUM_STRIPS; i++){
      leds[i][ii] = ColorFromPalette(palette, gHue+(ii*2), beat-gHue+(ii*10));
    }
  }
}

void juggle(){
  // eight colored dots, weaving in and out of sync with each other
  for(int i=0; i < NUM_STRIPS; i++){
    fadeToBlackBy( leds[i], NUM_LEDS, 20);
  }
  byte dothue = 0;
  for( int ii = 0; ii < 8; ii++) {
    for(int i=0; i < NUM_STRIPS; i++){
      leds[i][beatsin16(ii+7,0,NUM_LEDS)] |= CHSV(dothue, 200, 255);
    }
    dothue += 32;
  }
}

void horizont_2(){
  for(int i=0; i < NUM_STRIPS; i++){
    fadeToBlackBy( leds[i], NUM_LEDS, 100);
  }
  if(pos1 > NUM_STRIPS-1) {pos1 = 0; color_x = color_x+1;}
  if(color_x > 3) color_x = 0;
  CRGB color[] = {CRGB(255, 0, 0), CRGB(0, 255, 0), CRGB(0, 0, 255), CRGB(255, 255, 255),
                  CRGB(255, 0, 255), CRGB(0, 255, 255), CRGB(255, 255, 0), CRGB(255, 150, 150)};
  for (int i=0; i <= NUM_LEDS-1; i++){
    leds[pos1][i] = color[color_x];
  }
  pos1 = pos1+1;
}

void horizont_3(){
  for(int i=0; i < NUM_STRIPS; i++){
    fadeToBlackBy( leds[i], NUM_LEDS, 100);
  }
  if(pos1 > NUM_STRIPS-1) pos1 = 0;
  for (int i=0; i <= NUM_LEDS-1; i++){
    leds[pos1][i] = CHSV( gHue, 255, 192);
  }
  pos1 = pos1+1;
}
void snow_1(){
  if(pos1 > NUM_LEDS*2-1) pos1 = 0;
  for(int i=0; i < NUM_STRIPS; i++){
    fadeToBlackBy( leds[i], NUM_LEDS, 50);
  }
  for(int i=0; i < NUM_STRIPS; i++){
    leds[i][NUM_LEDS-pos1/2-1] = CRGB(255, 255, 255);
  }
  pos1 = pos1+1;
}

struct snow_line{   // объявляем структуру для ленты снега
    byte pos;
    long end_time;
    int  start_delay;
} type;
snow_line snow_2_vars[NUM_STRIPS];
void snow_2(){  
  for(int i=0; i < NUM_STRIPS; i++){
    fadeToBlackBy( leds[i], NUM_LEDS, 40);
  }
  
  for(byte i=0; i < NUM_STRIPS; i++){
    if(snow_2_vars[i].pos > NUM_LEDS*2-1){   // Если дошли до конца ленты то...
      snow_2_vars[i].pos = 0;              // Сбрасываем позицию на ноль
      snow_2_vars[i].end_time = millis();  // Записываем время окончания эффекта
      
    }
    if(snow_2_vars[i].pos == 0){           //  Если задана нулевая позиция - значит начало, то...
      snow_2_vars[i].start_delay = random(10, 3000);    // Генерируем врменную задержку запуска эффекта (до 3х секунд)
    }
    if(millis() > snow_2_vars[i].end_time+snow_2_vars[i].start_delay){  // Если вышла задержка перед запуском эффекта, запускаем...
      leds[i][NUM_LEDS-snow_2_vars[i].pos/2-1] = CRGB(255, 255, 200);
      snow_2_vars[i].pos++; 
    }
  }
}
Сейчас близится 2018 новый год, ёлку с гирляндой ещё не доставал. Достану, может ещё чего подделаю.

Празднуйте новый год весело! :)
Вложения
ws2811_36.jpg
ws2811_36.jpg (91.32 КБ) 11539 просмотров
ws2811_01.jpg
ws2811_01.jpg (84.68 КБ) 11464 просмотра
ws2811_02.jpg
ws2811_02.jpg (73.72 КБ) 11464 просмотра
ws2811_03.jpg
ws2811_03.jpg (71.05 КБ) 11045 просмотров
ws2811_04.jpg
ws2811_04.jpg (64.2 КБ) 11045 просмотров
ws2811_05.jpg
ws2811_05.jpg (68.76 КБ) 11045 просмотров
ws2811_06.jpg
ws2811_06.jpg (67.87 КБ) 11045 просмотров
ws2811_07.jpg
ws2811_07.jpg (78.67 КБ) 11045 просмотров
ws2811_08.jpg
ws2811_08.jpg (93.04 КБ) 11045 просмотров
ws2811_09.jpg
ws2811_09.jpg (111.7 КБ) 11045 просмотров
ws2811_10.jpg
ws2811_10.jpg (89.48 КБ) 11045 просмотров
ws2811_11.jpg
ws2811_11.jpg (104.64 КБ) 11045 просмотров
ws2811_12.jpg
ws2811_12.jpg (107.86 КБ) 11045 просмотров
ws2811_15.jpg
ws2811_15.jpg (109.01 КБ) 11045 просмотров
ws2811_17.jpg
ws2811_17.jpg (110.57 КБ) 11045 просмотров
ws2811_21.jpg
ws2811_21.jpg (79.96 КБ) 11045 просмотров
ws2811_22.jpg
ws2811_22.jpg (90.99 КБ) 11045 просмотров
ws2811_23.jpg
ws2811_23.jpg (99.42 КБ) 11045 просмотров
ws2811_24.jpg
ws2811_24.jpg (75.08 КБ) 11045 просмотров
ws2811_03.jpg
ws2811_03.jpg (71.05 КБ) 11464 просмотра
ws2811_04.jpg
ws2811_04.jpg (64.2 КБ) 11464 просмотра