Цветомузыка на WS2812B и ардуино для ПК

Опубликовал | 21.11.2017
Здравствуйте

Мне давно хотелось сделать цветомузыку (далее ЦМУ), но хотелось сделать так, чтобы работы при этом было как можно меньше. Увидел на ali ленту WS2812B и решил вот, это то что надо, ни каких 220В, ни каких тиристоров, симисторов и т.п…

Основные принципы работы данной ЦМУ:
— Обработка звука и формирование цветомузыкальных программ осуществляется моей программой для ПК.
— Управление состоянием светодиодов ленты осуществляет модуль arduino по командам из программы.
— Для воспроизведения музыки может использоваться любой программный плеер, например WinAmp, AIMP, ITUNES, Windows Media и т.п. или аппаратный плеер имеющий линейный выход.

Для управления лентой я написал программу для ПК. Ссылка для скачивания программы. Программа не имеет ограничений и может использоваться в личных целях всеми желающими.

Для минимального комплекта ЦМУ, с непосредственным подключением к USB ПК, нужна лишь светодиодная лента с WS2812B, arduino nano (или аналогичная), три проводника и мини USB кабель для подключения платы arduino к одному из USB портов ПК. В данном варианте количество активных (работающих) светодиодов ограничено 19 по одному на каждую цветовую полосу программы ЦМУ. Ограничение введено для предотвращения перегрузки USB порта.

Скетч модуля arduino при непосредственном подключении ЦМУ к USB порту компьютера:

Дополнительная информация
  #include <Adafruit_NeoPixel.h>     #define ledPin 13       // светодиод на плате arduino  #define stripPin 2      // выход управления светодиодной лентой  #define stripLed 30     // количество светодиодов в ленте  #define bandPass 19     // число полос ЦМУ (используемых светодиодов)    // Parameter 1 = number of pixels in strip  // Parameter 2 = Arduino pin number (most are valid)  // Parameter 3 = pixel type flags, add together as needed:  //   NEO_KHZ800  800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)  //   NEO_KHZ400  400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)  //   NEO_GRB     Pixels are wired for GRB bitstream (most NeoPixel products)  //   NEO_RGB     Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)  Adafruit_NeoPixel strip = Adafruit_NeoPixel(stripLed, stripPin, NEO_GRB + NEO_KHZ800);    const uint32_t PROGMEM    colorTab[]={        0xFF0000,0xFF1100,0xFF2200,0xFF3300,0xFF4400,0xFF5500,0xFF6600,0xFF7700,0xFF8800,0xFF9900,0xFFAA00,0xFFBB00,0xFFCC00,0xFFDD00,0xFFEE00,0xFFFF00,  //красный - жёлтый        0xFFFF00,0xEEFF00,0xDDFF00,0xCCFF00,0xBBFF00,0xAAFF00,0x99FF00,0x88FF00,0x77FF00,0x66FF00,0x55FF00,0x44FF00,0x33FF00,0x22FF00,0x11FF00,0x00FF00,  //жёлтый — зелёный        0x00FF00,0x00FF11,0x00FF22,0x00FF33,0x00FF44,0x00FF55,0x00FF66,0x00FF77,0x00FF88,0x00FF99,0x00FFAA,0x00FFBB,0x00FFCC,0x00FFDD,0x00FFEE,0x00FFFF,  //зелёный — циан (голубой)        0x00FFFF,0x00EEFF,0x00DDFF,0x00CCFF,0x00BBFF,0x00AAFF,0x0099FF,0x0088FF,0x0077FF,0x0066FF,0x0055FF,0x0044FF,0x0033FF,0x0022FF,0x0011FF,0x0000FF,  //голубой — синий        0x0000FF,0x1100FF,0x2200FF,0x3300FF,0x4400FF,0x5500FF,0x6600FF,0x7700FF,0x8800FF,0x9900FF,0xAA00FF,0xBB00FF,0xCC00FF,0xDD00FF,0xEE00FF,0xFF00FF,  //синий — пурпур (маджента)        0xFF00FF,0xFF00EE,0xFF00DD,0xFF00CC,0xFF00BB,0xFF00AA,0xFF0099,0xFF0088,0xFF0077,0xFF0066,0xFF0055,0xFF0044,0xFF0033,0xFF0022,0xFF0011,0xFF0000}; //маджента — красный    typedef union{      struct {        uint8_t b,g,r,w;      };      uint32_t dw;  } TColor;    typedef union{      struct {        uint8_t b0,b1;      };      uint16_t w;  } TWord;    char inStr[64];       // a string to hold incoming data  char rcvString[64];   // a string to hold incoming data  uint8_t inCounter = 0;  boolean stringComplete = false;  // whether the string is complete    void setup() {    // initialize serial:    strip.begin();    strip.show(); // Initialize all pixels to 'off'    Serial.begin(115200);    // reserve 32 bytes for the inputString:    pinMode(ledPin, OUTPUT);  }    void loop() {    // print the string when a newline arrives:    if (stringComplete) {      stringComplete = false;      compare();      rcvString[2]=0;      Serial.println(rcvString);   }  }    void compare() {            switch (rcvString[0]) {        case 'r': {          zmu();          break;        }        case 'c':{          strip.clear();          strip.show();          break;        }      }  }      //  SerialEvent  void serialEvent() {    uint8_t i;        while (Serial.available()) {      // get the new byte:      char inChar = (char)Serial.read();      if (inChar != char(254)) {       inStr[inCounter++] = inChar;       if (inChar == char(255)) {         i=0;         while (inStr[i]!=char(255)) {           rcvString[i]=inStr[i];           i++;         }         rcvString[i]=inStr[i];         stringComplete = true;         inCounter = 0;          // clear the input string:       }      } else inCounter = 0;      // clear the input string:     }  }    void zmu() {    TColor cl;    TWord akk;    uint8_t n,i,k;      for(i=0; i<bandPass; i++) {        cl.dw = pgm_read_dword(&colorTab[96*i/bandPass]);        akk.w = cl.r * rcvString[i+1];        akk.w = akk.b1 * akk.b1;         cl.r = akk.b1;        akk.w = cl.g * rcvString[i+1];        akk.w = akk.b1 * akk.b1;         cl.g = akk.b1;        akk.w = cl.b * rcvString[i+1];        akk.w = akk.b1 * akk.b1;         cl.b = akk.b1;        strip.setPixelColor(i, cl.dw);    }    strip.show();  }  

Для максимального, беспроводного варианта, дополнительно потребуется ещё одна плата arduino, два радио модуля nRF24L01 с платами адаптеров, блок питания 5В на мощность соответствующую вашей ленте. Оба модуля nRF24L01 подключаются к платам arduino идентично. Подключение осуществляется по типовой схеме к цифровым выводам D9,D10,D11,D12,D13 или другим при соответствующем изменении заголовков конфигурации в скетче. Типовые схемы включения nRF24L01 есть в интернете. Вход управления светодиодной лентой Din (Din на ленте) заведён на цифровой выход D2 платы arduino.

При беспроводном подключении к ПК один из модулей arduino c модулем nRF24L01 подключается к USB порту ПК (при подключении драйвером выполняется преобразование USB<->COM). Указанный модуль принимает по СОМ порту пакеты от программы ЦМУ и через радио модуль nRF24L01 транслирует их по радиоканалу к контроллеру ленты. Радио модуль nRF24L01 контроллера ленты по радио каналу принимает пакеты поступившие от контроллера подключённого к ПК. Модуль arduino контроллера ленты получает принятые пакеты от nRF24L01 и устанавливает светодиоды ленты в требуемое состояние.

Скетч модуля подключаемого к ПК:

Дополнительная информация
  #include <SPI.h>        // Подключаем библиотеку для работы с шиной SPI  #include <nRF24L01.h>   // Подключаем файл настроек из библиотеки RF24  #include <RF24.h>       // Подключаем библиотеку для работы с nRF24L01+  RF24    radio(9, 10);   // Создаём объект radio для работы с библиотекой RF24, указывая номера выводов nRF24L01+ (CE, CSN)    char    rfData[32];     // Создаём массив для передачи данных  uint8_t rfCounter = 0;  char    serData[40];   // a string to hold incoming data  uint8_t serCounter = 0;  boolean stringComplete = false;    void setup(){      Serial.begin(115200);      radio.begin();                                      // Инициируем работу nRF24L01+      radio.setChannel(5);                                // Указываем канал передачи данных (от 0 до 127), 5 - значит передача данных осуществляется на частоте 2,405 ГГц (на одном канале может быть только 1 приёмник и до 6 передатчиков)      radio.setDataRate     (RF24_1MBPS);                 // Указываем скорость передачи данных (RF24_250KBPS, RF24_1MBPS, RF24_2MBPS), RF24_1MBPS - 1Мбит/сек      radio.setPALevel      (RF24_PA_HIGH);               // Указываем мощность передатчика (RF24_PA_MIN=-18dBm, RF24_PA_LOW=-12dBm, RF24_PA_HIGH=-6dBm, RF24_PA_MAX=0dBm)      radio.openWritingPipe (0x1234567890LL);             // Открываем трубу с идентификатором 0x1234567890 для передачи данных (на ожном канале может быть открыто до 6 разных труб, которые должны отличаться только последним байтом идентификатора)  }    void loop(){    uint8_t i;          if (rfCounter>0) {        radio.write(&rfData[0],32);        rfCounter=0;        Serial.write(rfData,32);      }  }    //  SerialEvent  void serialEvent() {    uint8_t i;        while (Serial.available()) {      // get the new byte:      char inChar = (char)Serial.read();      if (inChar != char(254)) {       if (inChar == char(255)) {         for(i=0; i<32; i++) rfData[i]=serData[i];         rfCounter = 32;         serCounter = 0;          // clear the input string:       }       else serData[serCounter++] = inChar;      } else serCounter = 0;      // clear the input string:     }  }  

Скетч модуля ленты:

  #include <SPI.h>                   // Подключаем библиотеку  для работы с шиной SPI  #include <nRF24L01.h>              // Подключаем файл настроек из библиотеки RF24  #include <RF24.h>                  // Подключаем библиотеку  для работы с nRF24L01+  #include <Adafruit_NeoPixel.h>    #define stripPin 2       // выход управления светодиодной лентой  #define stripLed 120     // количество светодиодов в ленте  #define bandPass 19      // полосовых фильтров = цветов = групп светодиодов  #define ledDist stripLed/bandPass  // количество светодиодов на цвет  #define LedtoColor 4  // LedtoColor < или = ledDist - количество активных светодиодов на цвет, если у вас пока нет блока питания который тянет всю ленту (как у меня)     // Parameter 1 = number of pixels in strip  // Parameter 2 = Arduino pin number (most are valid)  // Parameter 3 = pixel type flags, add together as needed:  //   NEO_KHZ800  800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)  //   NEO_KHZ400  400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)  //   NEO_GRB     Pixels are wired for GRB bitstream (most NeoPixel products)  //   NEO_RGB     Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)  Adafruit_NeoPixel strip = Adafruit_NeoPixel(stripLed, stripPin, NEO_GRB + NEO_KHZ800);    RF24      radio(9, 10);    // Создаём объект radio   для работы с библиотекой RF24, указывая номера выводов nRF24L01+ (CE, CSN)    const uint32_t PROGMEM    colorTab[]={        0xFF0000,0xFF1100,0xFF2200,0xFF3300,0xFF4400,0xFF5500,0xFF6600,0xFF7700,0xFF8800,0xFF9900,0xFFAA00,0xFFBB00,0xFFCC00,0xFFDD00,0xFFEE00,0xFFFF00,  //красный - жёлтый        0xFFFF00,0xEEFF00,0xDDFF00,0xCCFF00,0xBBFF00,0xAAFF00,0x99FF00,0x88FF00,0x77FF00,0x66FF00,0x55FF00,0x44FF00,0x33FF00,0x22FF00,0x11FF00,0x00FF00,  //жёлтый — зелёный        0x00FF00,0x00FF11,0x00FF22,0x00FF33,0x00FF44,0x00FF55,0x00FF66,0x00FF77,0x00FF88,0x00FF99,0x00FFAA,0x00FFBB,0x00FFCC,0x00FFDD,0x00FFEE,0x00FFFF,  //зелёный — циан (голубой)        0x00FFFF,0x00EEFF,0x00DDFF,0x00CCFF,0x00BBFF,0x00AAFF,0x0099FF,0x0088FF,0x0077FF,0x0066FF,0x0055FF,0x0044FF,0x0033FF,0x0022FF,0x0011FF,0x0000FF,  //голубой — синий        0x0000FF,0x1100FF,0x2200FF,0x3300FF,0x4400FF,0x5500FF,0x6600FF,0x7700FF,0x8800FF,0x9900FF,0xAA00FF,0xBB00FF,0xCC00FF,0xDD00FF,0xEE00FF,0xFF00FF,  //синий — пурпур (маджента)        0xFF00FF,0xFF00EE,0xFF00DD,0xFF00CC,0xFF00BB,0xFF00AA,0xFF0099,0xFF0088,0xFF0077,0xFF0066,0xFF0055,0xFF0044,0xFF0033,0xFF0022,0xFF0011,0xFF0000}; //маджента — красный          typedef union{      struct {        uint8_t b,g,r,w;      };      uint32_t dw;  } TColor;    typedef union{      struct {        uint8_t b0,b1;      };      uint16_t w;  } TWord;          char rfData[32];           // Буфер команды  uint8_t ledPtr = 0;    void setup(){      // initialize serial:      Serial.begin(115200);      strip.begin();      strip.show(); // Initialize all pixels to 'off'        radio.begin();                              // Инициируем работу nRF24L01+  //    radio.setAutoAck(false);        radio.setChannel(5);                        // Указываем канал приёма данных (от 0 до 127), 5 - значит приём данных осуществляется на частоте 2,405 ГГц (на одном канале может быть только 1 приёмник и до 6 передатчиков)      radio.setDataRate     (RF24_1MBPS);         // Указываем скорость передачи данных (RF24_250KBPS, RF24_1MBPS, RF24_2MBPS), RF24_1MBPS - 1Мбит/сек      radio.setPALevel      (RF24_PA_HIGH);       // Указываем мощность передатчика (RF24_PA_MIN=-18dBm, RF24_PA_LOW=-12dBm, RF24_PA_HIGH=-6dBm, RF24_PA_MAX=0dBm)      radio.openReadingPipe (1, 0x1234567890LL);  // Открываем 1 трубу с идентификатором 0x1234567890 для приема данных (на ожном канале может быть открыто до 6 разных труб, которые должны отличаться только последним байтом идентификатора)        radio.startListening  ();                   // Включаем приемник, начинаем прослушивать открытые трубы  }    void loop(){        if(radio.available()){      // Если в буфере имеются принятые данные, то получаем номер трубы, по которой они пришли, по ссылке на переменную pipe        radio.read(&rfData, 32);  // Приём команды        cmdExecute();             }  }    void cmdExecute() {            switch (rfData[0]) {        case 'r': {          zmu();          break;        }        case 'c':{          strip.clear(); strip.show(); break;        }      }  }      void zmu() {    TColor cl;    TWord akk;    uint16_t r,g,b;    uint8_t n,i,k,j;      for(i=0; i<bandPass; i++) {        cl.dw = pgm_read_dword(&colorTab[96*i/bandPass]);        j=rfData[i+1];        akk.w = cl.r * j;        akk.w = akk.b1 * akk.b1;         cl.r = akk.b1;        akk.w = cl.g * j;        akk.w = akk.b1 * akk.b1;         cl.g = akk.b1;        akk.w = cl.b * j;        akk.w = akk.b1 * akk.b1;         cl.b = akk.b1;        cl.dw = strip.Color(cl.r, cl.g, cl.b);        n=i*ledDist;        for(k=0; k<LedtoColor; k++) strip.setPixelColor(n+k, cl.dw);    }    strip.show();  }  

У меня 120 светодиодов в ленте, но используются пока 19*4=76. Мой блок питания не тянет больше. Куплю источник питания мощней зажгу все.

Пока есть только цветомузыка, но к новому году постараюсь добавить какие нибудь дополнительные световые эффекты. Новая программа будет доступна по той же ссылке. Работу цветомузыки вы можете посмотреть на видео в конце статьи.

Для работы программы ЦМУ нужно настроить два подключения:
1. к COM порту ПК, порту к которому подключён модуль arduino;
2. к источнику звука.
Работа начинается после нажатия на кнопку старт.

В простейшем случае в качестве источника звука может выступать микрофон ПК или ноутбука. Недостатком данного метода является влияние на цветовую программу внешних звуков и шума.

Второй вариант получение аудио потока непосредственно с музыкального плеера. Для этого необходимо перехватить аудио поток с программы плеера к выходному звуковому устройству (динамикам ПК или звуковому выходу). Для этого можно использовать драйвер и программу «виртуальный аудио кабель». В интернете есть несколько вариантов «виртуального аудио кабеля» и вы можете выбрать подходящий к вашему оборудованию.
Для моей конфигурации потребовался простой «виртуальный аудио кабель» с одним входом и одним выходом.
Я использую «виртуальный аудио кабель» который вы можете скачать по ссылке.
Установите на ПК программное обеспечение «виртуальный аудио кабель». В настройках звуковых устройств ПК выберите выходное звуковое устройство «виртуальный аудио кабель» и установите для него — использовать по умолчанию.

После данной настройки все аудио потоки со всех программ будут направляться на вход «виртуального аудио кабеля». В программе цветомузыки установите в качестве источника звука (звукового устройства) выход «виртуального аудио кабеля».
Окно программы цветомузыки:

Программа ЦМУ готова к работе.

Мой вариант подключения.
У меня аудио ресивер с airplay и проигрыватель я естественно использую c поддержкой airplay ITUNES. Кроме того ITUNES умеет выводить звук одновременно и на аудио ресивер и на ПК как показано ниже

Звуковой поток поступающий на ПК попадает на устройство по умолчанию, то есть на вход «виртуального аудио кабеля», а его выход служит источником звука в программе цветомузыки.
Если вы пользуетесь другим музыкальным плеером и/или у вас нет усилителя или аудио ресивера с airplay вам понадобится «виртуальный аудио кабель» умеющий коммутировать аудио поток на несколько устройств. Один из выходов вы должны подать на ваше выходное звуковое устройство (выход звуковой карты или динамики ПК), а другой должны указать в качестве источника звука в программе цветомузыки.

Третий вариант потребует наличия или изготовления аудио кабеля. Вы можете использовать линейный вход вашей звуковой карты в качестве источника звука в программе ЦМУ. В этом случае вы можете использовать любой внешний источник звука (аудио плеер, MP3 плеер и т.п. ) имеющий линейный выход.

С «виртуальным аудио кабелем» с разветвителем и вариантом изготовления кабеля вам придётся разбираться самим, мне эти варианты не понадобились. Возможно есть другие варианты организации источника звука для программы ЦМУ.

Профиль для установки светодиодной ленты или другой вариант крепления светодиодной ленты выбирается из ваших желаний.

Примеры работы ЦМУ:

Пишу очень редко. Мало опыта. Сильно не ругайте.

Добавить в избранное +12 +19

(c) 2017 Источник материала

Рекламные ссылки