RSS блога
Подписка
Цветомузыка на WS2812B и ардуино для ПК
Здравствуйте
Мне давно хотелось сделать цветомузыку (далее ЦМУ), но хотелось сделать так, чтобы работы при этом было как можно меньше. Увидел на ali ленту WS2812B и решил вот, это то что надо, ни каких 220В, ни каких тиристоров, симисторов и т.п…
Основные принципы работы данной ЦМУ:
— Обработка звука и формирование цветомузыкальных программ осуществляется моей программой для ПК.
— Управление состоянием светодиодов ленты осуществляет модуль arduino по командам из программы.
— Для воспроизведения музыки может использоваться любой программный плеер, например WinAmp, AIMP, ITUNES, Windows Media и т.п. или аппаратный плеер имеющий линейный выход.
Для управления лентой я написал программу для ПК. Ссылка для скачивания программы. Программа не имеет ограничений и может использоваться в личных целях всеми желающими.
Для минимального комплекта ЦМУ, с непосредственным подключением к USB ПК, нужна лишь светодиодная лента с WS2812B, arduino nano (или аналогичная), три проводника и мини USB кабель для подключения платы arduino к одному из USB портов ПК. В данном варианте количество активных (работающих) светодиодов ограничено 19 по одному на каждую цветовую полосу программы ЦМУ. Ограничение введено для предотвращения перегрузки USB порта.
Скетч модуля arduino при непосредственном подключении ЦМУ к USB порту компьютера:
Для максимального, беспроводного варианта, дополнительно потребуется ещё одна плата 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 и устанавливает светодиоды ленты в требуемое состояние.
Скетч модуля подключаемого к ПК:
Скетч модуля ленты:
У меня 120 светодиодов в ленте, но используются пока 19*4=76. Мой блок питания не тянет больше. Куплю источник питания мощней зажгу все.
Пока есть только цветомузыка, но к новому году постараюсь добавить какие нибудь дополнительные световые эффекты. Новая программа будет доступна по той же ссылке. Работу цветомузыки вы можете посмотреть на видео в конце статьи.
Для работы программы ЦМУ нужно настроить два подключения:
1. к COM порту ПК, порту к которому подключён модуль arduino;
2. к источнику звука.
Работа начинается после нажатия на кнопку старт.
В простейшем случае в качестве источника звука может выступать микрофон ПК или ноутбука. Недостатком данного метода является влияние на цветовую программу внешних звуков и шума.
Второй вариант получение аудио потока непосредственно с музыкального плеера. Для этого необходимо перехватить аудио поток с программы плеера к выходному звуковому устройству (динамикам ПК или звуковому выходу). Для этого можно использовать драйвер и программу «виртуальный аудио кабель». В интернете есть несколько вариантов «виртуального аудио кабеля» и вы можете выбрать подходящий к вашему оборудованию.
Для моей конфигурации потребовался простой «виртуальный аудио кабель» с одним входом и одним выходом.
Я использую «виртуальный аудио кабель» который вы можете скачать по ссылке.
Установите на ПК программное обеспечение «виртуальный аудио кабель». В настройках звуковых устройств ПК выберите выходное звуковое устройство «виртуальный аудио кабель» и установите для него — использовать по умолчанию.
После данной настройки все аудио потоки со всех программ будут направляться на вход «виртуального аудио кабеля». В программе цветомузыки установите в качестве источника звука (звукового устройства) выход «виртуального аудио кабеля».
Окно программы цветомузыки:
Программа ЦМУ готова к работе.
Мой вариант подключения.
У меня аудио ресивер с airplay и проигрыватель я естественно использую c поддержкой airplay ITUNES. Кроме того ITUNES умеет выводить звук одновременно и на аудио ресивер и на ПК как показано ниже
Звуковой поток поступающий на ПК попадает на устройство по умолчанию, то есть на вход «виртуального аудио кабеля», а его выход служит источником звука в программе цветомузыки.
Если вы пользуетесь другим музыкальным плеером и/или у вас нет усилителя или аудио ресивера с airplay вам понадобится «виртуальный аудио кабель» умеющий коммутировать аудио поток на несколько устройств. Один из выходов вы должны подать на ваше выходное звуковое устройство (выход звуковой карты или динамики ПК), а другой должны указать в качестве источника звука в программе цветомузыки.
Третий вариант потребует наличия или изготовления аудио кабеля. Вы можете использовать линейный вход вашей звуковой карты в качестве источника звука в программе ЦМУ. В этом случае вы можете использовать любой внешний источник звука (аудио плеер, MP3 плеер и т.п. ) имеющий линейный выход.
С «виртуальным аудио кабелем» с разветвителем и вариантом изготовления кабеля вам придётся разбираться самим, мне эти варианты не понадобились. Возможно есть другие варианты организации источника звука для программы ЦМУ.
Профиль для установки светодиодной ленты или другой вариант крепления светодиодной ленты выбирается из ваших желаний.
Примеры работы ЦМУ:
Добавил схемы
Добавил скетч для варианта подключения к USB с внешним источником питания 5В (на большое количество светодиодов > 30).
Заключительная версия программы.
Мне давно хотелось сделать цветомузыку (далее ЦМУ), но хотелось сделать так, чтобы работы при этом было как можно меньше. Увидел на 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,j;
for(i=0; i<bandPass; i++) {
cl.dw = pgm_read_dword(&colorTab[96*i/bandPass]);
j = rcvString[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);
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 плеер и т.п. ) имеющий линейный выход.
С «виртуальным аудио кабелем» с разветвителем и вариантом изготовления кабеля вам придётся разбираться самим, мне эти варианты не понадобились. Возможно есть другие варианты организации источника звука для программы ЦМУ.
Профиль для установки светодиодной ленты или другой вариант крепления светодиодной ленты выбирается из ваших желаний.
Примеры работы ЦМУ:
Добавил схемы
Добавил скетч для варианта подключения к USB с внешним источником питания 5В (на большое количество светодиодов > 30).
#include <Adafruit_NeoPixel.h>
#define ledPin 13 // светодиод на плате arduino
#define stripPin 2 // выход управления светодиодной лентой
#define stripLed 60 // количество светодиодов в ленте
#define bandPass 19 // число полос ЦМУ (используемых светодиодов)
#define ledDist 3 // Число светодиодов на цвет bandPass*ledDist=3*19 должно быть меньше stripLed=60
#define LedtoColor 3 // Число активных светодиодов на цвет должно быть меньше или равно ledDist=3
// 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,j;
for(i=0; i<bandPass; i++) {
cl.dw = pgm_read_dword(&colorTab[96*i/bandPass]);
j = rcvString[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();
}
Заключительная версия программы.
Самые обсуждаемые обзоры
+79 |
4345
153
|
+62 |
4495
75
|
За что тут ругать?
Молодец!
*задумался*
Стоящий обзор. Тоже руки зачесались сделать, к томуже всё имеется и смонтировано.
Я забабахал подсветку в карниз и со смартфона управляю ею, там разные цвета и прочее, надо бобавить микрофон и подправить код.
Обзор хороший,
сейчас нигде такого не найти
правда я первый раз слышу про такой экран
что-то типа такого с таким же эффектом
cccr.listbb.ru/viewtopic.php?p=3526&sid=3b44042d5e990f84fd49dd5afbb10718#p3526
только это был заводской конструктор
вот такой вот точно было экран и лампочки на 13в с цветными колпаками
экран не впечатлил и его яркость
так что либо потолок, либо тюль какая на окне или матовое оргстекло с подсветкой в торец
с фонарями сейчас как раз все просто
вот какая штука еще была не выпущена
forum.astrakhan.ru/topic/73205-%D0%B0%D1%83%D0%B4%D0%B8%D0%BE%D1%82%D0%B5%D1%85%D0%BD%D0%B8%D0%BA%D0%B0-%D1%81%D1%81%D1%81%D1%80/?page=2&tab=comments#comment-1470969
дизайн мегакрутой просто
Поскольку ламповый завод в советские времена этих палочек выкидывал немеряно, все делали цветомузыку из них, изредка встречающиеся конструкции без них вызывали недоумение и мысли о криворукости изготовителя.
Экран получается действительно обалденным, особенно если там 3-4 слоя палочек.
Неистово плюсую.
но хочется такое же только чтоб звук с аудиовыхода брало, никто не видел?
И чего минусить. не понятно… ( обнулил )
На первый взгляд ничего особо сложного все запихать в микроконтроллер нет. Для управления WS2812 вовсе не требуется сожрать практически 100% CPU, как это сейчас обычно делают. Незначительное усложнение (1 корпус 74HC74), и накладные расходы на загрузку ленты сокращаются до этак 10...15% (при 16 MHz тактовой, ATmega). Дальше берем какой-нибудь малозатратную реализацию спектроанализатора и все ограничивается лишь фантазией. И свободным временем, к сожалению…
Можно было выводить и 24-битный цвет (даже быстрее получалось), но 1800 байт из 2048 были заняты «экраном», что не оставляло места для какой-либо программы управления этим «экраном». Да и с учетом гаммы 2.2 и баланса белого, там получается по 4 реальных бита на каждый цвет максимум.
Это при каком количестве диодов и какой частоте вывода информации на них?
А расходы — посчитал на собственно время загрузки ленты. 300 шт — примерно 9 ms, т.е. из можно обновлять больше 100 раз в секунду. 600 — соответственно вдвое реже. Сейчас глянул код — не, пожалуй слегка приврал, если гнать готовые 24 бита, что скорее 20% (16 MHz тактовой), а перекодировка палитры и еще добавит, так что будет ближе к 30%. Но это если непрерывно грузим цепочку, без пауз.
У меня еще был код параллельного вывода сразу на 5 линий, он как раз занимал менее 20% при 600 диодах, не использовал аппаратных последовательных контроллеров, не требовал вообще никаких внешних активных деталей, но и не был совместим с прерываниями, поэтому практического применения тоже не нашел.
два плюса ушло.
тут собственно такие светодиоды и не нужны, достаточно мелкасхемы для частотного фильтра и контроллера для шима на 4 канала, хотя мелкасхема раскладывает на 7 каналов и стоит в музцентрах для анализатора спектра
самое смотрибельное из всех экранов
куда уж проще… я ох… дорогая редакция. :)
Если можно, схемку подключения всех модулей (Структурную).
Модули уже заказал.
Делаем в школу на Новый год.
Спасибо.
Для второго варианта
#define stripLed 60 // количество светодиодов в ленте
#define bandPass 19 // полосовых фильтров = цветов = групп светодиодов
#define ledDist stripLed/bandPass // количество светодиодов на цвет
#define LedtoColor ledDist
У меня всякие радуги на 288 светиков работали от 1,5 А зарядника от телефона, плюс ещё плисина от этого же питания работала…
За песню «Овощевоз» отдельное спасибо! ;)
Плюсую…
Инфа из прошлого столетия о соответствии цветов частотам в ЦМУ:
ВЧ — синий
СЧ1 — зеленый
СЧ2- желтый
НЧ — красный
фон (отсутствие сигнала) — белый
и добавить количество светодиодов на цвет LedtoColor.
Например 3:
#define ledDist stripLed/bandPass // количество led на цвет для данной ленты
#define LedtoColor 3 // всего светодиодов 3*19=57
LedtoColor должно быть меньше или равно ledDist = stripLed/bandPass
j=rfData[i+1];
надо заменить на
j=rcvString[i+1];
так как входной массив в первой версии имеет другое имя.
красный-зеленый-синий-зеленый-красный (типа симметрично, думаю будет красиво)
mysku.club/blog/aliexpress/49938.html
Вот такие хороши как гирлянда:
Для них купил линзы-рассеиватели (менее $2 за 100), ими прикрою. Пайку и обратную сторону можно обработать «Plastik 71».
Зато уже распаяно, похоже на гирлянду и отлично управляется.
и нашёл вот какие: https://aliexpress.com/item/item/50Pcs-Black-Wire-DC5V-WS2811-with-3pin-JST-connectors-Dream-Color-RGB-Strings-Node-LED-Pixels/32219637999.html
Наверное можно и с прозрачными проводами найти.
Можно ссылку?
Ищите «5050 SMD LEDS»
Вот пример:
ebay.com/itm/142286663718
Если будет матовая — вместо светорассеивателя будет работать.
Прочитал обзор полностью, ни фига не понял но понравилось.
Закинул темку в закладки, руки дойдут скопирую может.
Единственно напрягает привязка к ПК. Обычный аудио вход не помешал бы.
вот готовое с дмх512 управлением, есть прога dmxcontrol, там есть модуль светомузыки
надо только купить дмх радиомодули или адаптер
вот сравнение
www.youtube.com/watch?v=HqWMQ5E9d4g
и изменил параметры stripLed:
#define stripLed 19 // количество светодиодов в ленте.
Итог: Не работает как положено моргают все 19 диодов на красный спектр (в ритм басов).
Может автор подскажет- какие еще нужно сделать изменения в программе?
Вставьте строку
cl.dw = strip.Color(cl.r, cl.g, cl.b);
перед
strip.setPixelColor(n+k, cl.dw);
Получится код.
Основной исходник подправил.
Вот Ваш новый код, изменен только > #define stripLed 19.
Проверьте у себя свой код с #define stripLed 19…
Проверяли напрямую от USB?
На 19 диодов?
Но, с «виртуальным аудио кабелем» не могу разобраться- звук или в динамики, или на светодиоды, одновременно не получается.
Но все же мне кажется побаловаться несколько раз.
Тут была тема, как делали амбилайт с помощью ардуино на ТВ.
Тоже сделал, но посмотрел пару фильмов и снял.
Плюсанул!
Отличная статья!
Как раз под «Новый Год».
Буду делать!
Прошу прощения за негатив, но опишу как есть:
— гемор с настройкой захвата звука (у меня по цифре идет на ресивер),
— тормознутая программа в которой кстати отсутствует кнопка СЕРНУТЬ
— Нету регулировки чувствительности или яркости, ибо есть сильная зависимость от громкости, а это дико неудобно.
Но это все мелочи, самое главное: музыка и свет живут своей жизнью. На хорошие басовые удары толком нету отклика какой-то группы светодиодов. Вроде все мерцает, но соотнести это с ритмом никак не получается. Запустил генератор синуса, так там на определенных частотах начинает мерцать вся линейка, причем по разному:
21Hz — мерцает где то посередине и в правой части линейки (я то думал слева низкие частоты, справа высокие)
на 50 вообще вся горит в пол накала и ничего не моргает, при этом на 49 и 51 плавно расходится туда-сюда одинаково в режиме двутавр и радуга, короче дальше даже описывать не буду, нету соответствия частотам от слова совсем. И в музыке так же.
До упомянутого DiskoLux как до луны, правда последний стоит как лунный камень.
Да, знаю что заминусите, но какая то фигня а не светомузыка, хотя автор молодец, я и такое не способен создать ;)
Уровень входного сигнала уменьшите. Если у вас сигнал входит в ограничение это даёт резкие фронты с широким спектром. Регулировки усиления в программе нет. Кнопочку свернуть добавлю, но для программы из второй части статьи. Может за счёт большого числа полос нет явно выраженных привязок к инструментам (барабанам) мало светиков на красный. Объедините выходы как вам надо или сделайте разное количество светиков на разные части спектра. Я весь проект написал за четыре дня и дал вам инструмент. Составление цветовых программ естественно займёт намного больше времени. И я надеюсь что если этим будут заниматься несколько человек, читателей муськи, и выкладывать свои удачные цветомузыкальные программы, то каждый подберёт себе такие программы какие нужны ему. Но писать их надо для ардуино что достаточно просто даже для не имеющих профессионального образования в области программирования и спектрального анализа. Я писал статью для тех кто хочет что то аналогичное сделать для себя, но в силу отсутствия знаний и опыта не мог этого сделать. Теперь это будет сделать намного проще.
Эх, попробую конечно с привязками разобраться, но тяжко будет…
Еще такой вопрос: В программе AmbiBox можно добавлять Плагины, не проще было туда это запихнуть? (Я не программист, по этому не знаю разницы)
Основная цель всех моих работ заинтересовать моего ребёнка. Смотреть на ютубе Галилео, про машины, про технические новинки и т.п. ему нравится, а что то делать сам не хочет. Надо оторвать его от планшета.
Версию новую скачайте.
mysku.club/blog/diy/59692.html
По вашей ленте, не зная типа ленты, ничего сказать не могу. У меня нет и не было 12В лент, однозначно надо будет что-то городить, минимум согласование.
Например:
0xFF0000 R=255(0xFF), G=0, B=0 (0 цвет красный)
0x00FF00 R=0, G=255(0xFF), B=0 (32 цвет зелёный)
0x00FF00 R=0, G=0, B=255(0xFF) (64 цвет синий)
последняя строка градации серого
или в программе радуга
написать новую строку вычисления цвета
Здесь же можно при уменьшении суммы амплитуд (magn[]) зажигать фоновый цвет, например жёлтый
Новый автономный вариант цветомузыки
Общие принципы понятны:
[регулируемый усилитель] -> [детектор] ->[ НЧ фильтр] -> управление регулируемым усилителем
Вы, если не прослушали композицию ранее, не знаете почему уровень упал. Может это началась новая композиция, а может так автор этой композиции задумал. Исходя из этого и необходимо выбрать параметры блоков системы.
Я пытался в его скеч перенисти ком порт. Чтобы не ардуино занималась обработкой
звука а пк. Ну и сделать радиопередачю и режимы переключались на ик пульту. Я ему писал но он молчит. Сам передеделал но когда звук молчит полоска моргает и хоть убейся. Время мало до Нового года хочется сделать но мозгов не хватает))) а там и уровень звука атоматический
Сейчас у меня другой проект цветомузыки.
Группа
Видео
#define AUTO_GAIN 1 // автонастройка по громкости (экспериментальная функция)
#define VOL_THR 0 // порог тишины (ниже него отображения на матрице не будет)
#define LOW_PASS 0 // нижний порог чувствительности шумов (нет скачков при отсутствии звука)
#define DEF_GAIN 250 // максимальный порог по умолчанию (при GAIN_CONTROL игнорируется)
#define FHT_N 256 // ширина спектра х2
// вручную забитый массив тонов, сначала плавно, потом круче
byte posOffset[16] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
// — НАСТРОЙКИ — // — ПИНЫ — #define AUDIO_IN 0 // пин, куда подключен звук
#define POT_PIN 7 // пин потенциометра настройки
// — ПИНЫ — // — БИБЛИОТЕКИ — #define LOG_OUT 1
//#include <FHT.h> // преобразование Хартли
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#define printByte(args) write(args);
double prevVolts = 100.0;
// — БИБЛИОТЕКИ — #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
// — АВТОВЫБОР ОПРЕДЕЛЕНИЯ ДИСПЛЕЯ — // Если кончается на 4Т — это 0х27. Если на 4АТ — 0х3f
#if (DRIVER_VERSION)
LiquidCrystal_I2C lcd(0x27, 16, 2);
#else
LiquidCrystal_I2C lcd(0x3f, 16, 2);
#endif
// — АВТОВЫБОР ОПРЕДЕЛЕНИЯ ДИСПЛЕЯ — // — ПОЛОСОЧКИ — byte v1[8] = {0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b11111};
byte v2[8] = {0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b11111, 0b11111};
byte v3[8] = {0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b11111, 0b11111, 0b11111};
byte v4[8] = {0b00000, 0b00000, 0b00000, 0b00000, 0b11111, 0b11111, 0b11111, 0b11111};
byte v5[8] = {0b00000, 0b00000, 0b00000, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111};
byte v6[8] = {0b00000, 0b00000, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111};
byte v7[8] = {0b00000, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111};
byte v8[8] = {0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111};
// — ПОЛОСОЧКИ — byte gain = DEF_GAIN; // усиление по умолчанию
unsigned long gainTimer;
byte maxValue, maxValue_f;
float k = 0.1;
uint8_t readData[32];
uint8_t inStr[32];
uint8_t magn[20] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
uint8_t inCounter = 0;
boolean inComplete = false;
void setup() {
Serial.begin(115200);
lcd.init();
lcd.backlight();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(" ");
lcd.setCursor(0, 1);
lcd.print(" ");
lcdChars(); // подхватить коды полосочек
}
void loop() {
uint8_t i;
while (Serial.available()) {
// get the new byte:
uint8_t inChar = (uint8_t)Serial.read();
if (inChar != 253) {
inStr[inCounter++] = inChar;
if (inChar == 254) {
i=0;
while (inStr[i]!=254) {
readData[i]=inStr[i];
i++;
}
readData[i]=inStr[i];
inCounter = 0; // Устанавливаем счётчик принятых символов на начало входного буфера
inComplete = true;
}
} else inCounter = 0; // Устанавливаем счётчик принятых символов на начало входного буфера
}
// если разрешена ручная настройка уровня громкости
for (int pos = 0; pos < 16; pos++) { // для окошек дисплея с 0 по 15
// найти максимум из пачки тонов
if (readData[posOffset[pos]] > maxValue) maxValue = readData[posOffset[pos]]; //fht_log_out
lcd.setCursor(pos, 0);
// преобразовать значение величины спектра в диапазон 0..15 с учётом настроек
int posLevel = map(readData[posOffset[pos]], LOW_PASS, gain, 0, 15);
posLevel = constrain(posLevel, 0, 15);
if (posLevel > 7) { // если значение больше 7 (значит нижний квадратик будет полный)
lcd.printByte(posLevel — 8); // верхний квадратик залить тем что осталось
lcd.setCursor(pos, 1); // перейти на нижний квадратик
lcd.printByte(7); // залить его полностью
} else { // если значение меньше 8
lcd.print(" "); // верхний квадратик пустой
lcd.setCursor(pos, 1); // нижний квадратик
lcd.printByte(posLevel); // залить полосками
}
}
if (AUTO_GAIN) {
maxValue_f = maxValue * k + maxValue_f * (1 — k);
if (millis() — gainTimer > 1500) { // каждые 1500 мс
// если максимальное значение больше порога, взять его как максимум для отображения
if (maxValue_f > VOL_THR) gain = maxValue_f;
// если нет, то взять порог побольше, чтобы шумы вообще не проходили
else gain = 100;
gainTimer = millis();
}
}
}
void lcdChars() {
lcd.createChar(0, v1);
lcd.createChar(1, v2);
lcd.createChar(2, v3);
lcd.createChar(3, v4);
lcd.createChar(4, v5);
lcd.createChar(5, v6);
lcd.createChar(6, v7);
lcd.createChar(7, v8);
}
github.com/juraspb/MusicToColor
и я этим проектом с того времени больше не занимаюсь.
Сделал новый проект:
sites.google.com/view/musical-leds
есть группа
vk.com/club171670176
Юрий