Мне давно хотелось сделать цветомузыку (далее ЦМУ), но хотелось сделать так, чтобы работы при этом было как можно меньше. Увидел на 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();
}
A ку202?
Стоящий обзор. Тоже руки зачесались сделать, к томуже всё имеется и смонтировано.
Я забабахал подсветку в карниз и со смартфона управляю ею, там разные цвета и прочее, надо бобавить микрофон и подправить код.
Обзор хороший,
Неееее. С тиристорамы это уже другой уровень. Со стартёрами от дневных ламп всё гораздо проще. Стартёру на выходы припаивался кондёр на 10мкФ и эта конструкция последовательно в цепь с простой лампой накаливания. Такая хрень конечно к музыке вообще никакого отношения не имела, просто лихорадочно мигала в такт попавшего под напряжение неумелого электрика. Ессесенно таких конструкций, с разным цветом ламп, было несколько. На школьном дискаче прокатывало на ура!
В ЮТ или его приложении была статья про разные способы изготовления экранов. Еще один — засыпать битого автомобильного стекла между двух листов оконного стекла. ( в наши дни это проблемно)
Экран — это не то. Это тогда было в диковинку. А сейчас огромный экран есть в каждом доме (телевизор), достаточно сделать цветомузыко с выходом HDMI и можно рисовать что угодно. Но это не то. Настоящая цветомузыка должна иметь отдельные цветные фонари, а не экран или ленту.
Эти палочки шли для изготовления ламп накаливания, сам такие собирал в отходах производства лампового завода.
Поскольку ламповый завод в советские времена этих палочек выкидывал немеряно, все делали цветомузыку из них, изредка встречающиеся конструкции без них вызывали недоумение и мысли о криворукости изготовителя.
Экран получается действительно обалденным, особенно если там 3-4 слоя палочек.
На первый взгляд ничего особо сложного все запихать в микроконтроллер нет. Для управления WS2812 вовсе не требуется сожрать практически 100% CPU, как это сейчас обычно делают. Незначительное усложнение (1 корпус 74HC74), и накладные расходы на загрузку ленты сокращаются до этак 10...15% (при 16 MHz тактовой, ATmega). Дальше берем какой-нибудь малозатратную реализацию спектроанализатора и все ограничивается лишь фантазией. И свободным временем, к сожалению…
Я делал на 328р инвертированием выхода USART (на одном полевике) и прерываниях (на ассемблере, конечно). В итоге выводил 8-битный цвет (жестко заданная в PM 24-битная палитра на 256 цветов) на 600 светодиодов 50 «кадров» в секунду, и занимало это 49.3% тактов процессора на частоте 16 МГц. Из плюсов — прерывания разрешены и можно было работать с остальными устройствами. Из минусов — были заняты регистры R2-R11, что, скорее всего, не позволяет применять такое решение совместно с каким-либо С компилятором (только асм).
Можно было выводить и 24-битный цвет (даже быстрее получалось), но 1800 байт из 2048 были заняты «экраном», что не оставляло места для какой-либо программы управления этим «экраном». Да и с учетом гаммы 2.2 и баланса белого, там получается по 4 реальных бита на каждый цвет максимум.
Все можно сделать эффективнее. Первоначально я попробовал «склеить» выход USART в режиме SPI (доступный в более свежих кристаллах) и таймер, но возникли некоторые сложности с взаимосинхронизацией (есть неприятная особенность делителя baudrate). Но потом сообразил — сделал просто два одновибратора на 74HC74, на 400 и 800 ns, и их выходы объединил диодным «ИЛИ». Собственно загрузка жрет где-то менее 10% CPU, а вот с палитрой, разворачивая 8-битный код цвет+яркость в 24 бит RGB, немножно больше (поскольку не по таблице, получается накладно). Никаких ограничений по регистрам, прерывания раскрыты большую часть времени, ресурсов должно бы и на FFT хватить.
Клоком USART/SPI. 400 ns — генерирует всегда, 800 ns — когда передается «1», т.е. он берет данные от выхода USART.
А расходы — посчитал на собственно время загрузки ленты. 300 шт — примерно 9 ms, т.е. из можно обновлять больше 100 раз в секунду. 600 — соответственно вдвое реже. Сейчас глянул код — не, пожалуй слегка приврал, если гнать готовые 24 бита, что скорее 20% (16 MHz тактовой), а перекодировка палитры и еще добавит, так что будет ближе к 30%. Но это если непрерывно грузим цепочку, без пауз.
Интересное решение. Да, 50 раз в секунду 600 диодов — это практически в непрерывном режиме, ограничение самого протокола. У меня это занимает 50%, у вас — в два раза меньше.
У меня еще был код параллельного вывода сразу на 5 линий, он как раз занимал менее 20% при 600 диодах, не использовал аппаратных последовательных контроллеров, не требовал вообще никаких внешних активных деталей, но и не был совместим с прерываниями, поэтому практического применения тоже не нашел.
Можно и так сделать, я находил скетчи с работой просто от линейного выхода и от микрофона, пробовал делать от микрофона, реакция не понравилась, а от линейного не стал делать, хотел автономную.
Это нормальный режим работы светодиодов. Яркость каждого из R, G, B светодиодов регулируется с помощью ШИМ, этим задаётся цвет и яркость свечения. При постоянной яркости и цвете скважность постоянна. При изменении яркости или цвета меняется скважность на одном, двух или всех светодиодах и только.
неправильный экран все портит, 3 цвета должны светить в одну точку на белом фоне, чтобы смешиваться и образовывать остальные цвета
тут собственно такие светодиоды и не нужны, достаточно мелкасхемы для частотного фильтра и контроллера для шима на 4 канала, хотя мелкасхема раскладывает на 7 каналов и стоит в музцентрах для анализатора спектра
Для управления лентой я написал программу для ПК. Ссылка для скачивания программы. Программа не имеет ограничений и может использоваться в личных целях всеми желающими.
Очень интересно было бы увидеть её исходник, а не только скетчи для ардуинок.
Если непосредственно к USB порт не потянет.
Для второго варианта
#define stripLed 60 // количество светодиодов в ленте
#define bandPass 19 // полосовых фильтров = цветов = групп светодиодов
#define ledDist stripLed/bandPass // количество светодиодов на цвет
#define LedtoColor ledDist
У вас же белым цветом она и не горит никогда.
У меня всякие радуги на 288 светиков работали от 1,5 А зарядника от телефона, плюс ещё плисина от этого же питания работала…
Мне медведь все уши оттоптал, но и то мне мерещится, что лента не по-русски висит: высокие частоты вроде слева, а низкие справа. Не по феньшую. ;) Или я что-то путаю?
За песню «Овощевоз» отдельное спасибо! ;)
и добавить количество светодиодов на цвет LedtoColor.
Например 3:
#define ledDist stripLed/bandPass // количество led на цвет для данной ленты
#define LedtoColor 3 // всего светодиодов 3*19=57
LedtoColor должно быть меньше или равно ledDist = stripLed/bandPass
Использовал VirtualAudioCable, что бы распаралелить звук, идущий на HDMI и наушники. Не понравилось, что идёт небольшая задержка между источником звука и выводом его на выход.
А есть ли простая реализация для подобной ленты на ESP, классно было бы просто подсветить окно и запитать от павербанка, а по wifi сделать смену режимов… уверен что есть подобные, но поиски пока не увенчались успехами
Такие тоже есть. Они слишком большие.
Для них купил линзы-рассеиватели (менее $2 за 100), ими прикрою. Пайку и обратную сторону можно обработать «Plastik 71».
Зато уже распаяно, похоже на гирлянду и отлично управляется.
Прозрачную термоусадку нарезать сантиметровыми кусками, надеть на провод и усадить. Дешево, быстро, просто.
Если будет матовая — вместо светорассеивателя будет работать.
У ТС потолок шпаклеванный вроде, на натяжном эффект круче был бы наверное.
Прочитал обзор полностью, ни фига не понял но понравилось.
Закинул темку в закладки, руки дойдут скопирую может.
Единственно напрягает привязка к ПК. Обычный аудио вход не помешал бы.
мне кажется, или у ТС RGB программируемые диоды используются как простые одноцветные? какой тогда в них смысл? ту же линейку можно было слепить и обычными разноцветными диодами, разделенными на несколько групп…
Автор же сказал, что не хотел усложнять схему делать кучу проводов, ставить транзисторы на каждую группу и т.п. У ардуины то и 57 шим ножек наверное нету…
Все что вы написали (транзисторы на каждую группу и т.п.) для ленты WS2812B не требуется — у нее в каждом светодиоде уже встроен собственный ШИМ-контроллер и все это дело управляется по одному единственному проводу. Независимое управление цветом и яркостью каждого светодиода осуществляется с одного цифрового пина ардуины.
Собрал вариант номер один (напрямую к USB). Подключил «виртуальный аудио кабель», подключил ленту на 19 диодов
и изменил параметры stripLed:
#define stripLed 19 // количество светодиодов в ленте.
Итог: Не работает как положено моргают все 19 диодов на красный спектр (в ритм басов).
Может автор подскажет- какие еще нужно сделать изменения в программе?
Разобрался- мой косяк в монтаже, извините за беспокойство.
Но, с «виртуальным аудио кабелем» не могу разобраться- звук или в динамики, или на светодиоды, одновременно не получается.
Круто!
Но все же мне кажется побаловаться несколько раз.
Тут была тема, как делали амбилайт с помощью ардуино на ТВ.
Тоже сделал, но посмотрел пару фильмов и снял.
скачал, попробовал:
Прошу прощения за негатив, но опишу как есть:
— гемор с настройкой захвата звука (у меня по цифре идет на ресивер),
— тормознутая программа в которой кстати отсутствует кнопка СЕРНУТЬ
— Нету регулировки чувствительности или яркости, ибо есть сильная зависимость от громкости, а это дико неудобно.
Но это все мелочи, самое главное: музыка и свет живут своей жизнью. На хорошие басовые удары толком нету отклика какой-то группы светодиодов. Вроде все мерцает, но соотнести это с ритмом никак не получается. Запустил генератор синуса, так там на определенных частотах начинает мерцать вся линейка, причем по разному:
21Hz — мерцает где то посередине и в правой части линейки (я то думал слева низкие частоты, справа высокие)
на 50 вообще вся горит в пол накала и ничего не моргает, при этом на 49 и 51 плавно расходится туда-сюда одинаково в режиме двутавр и радуга, короче дальше даже описывать не буду, нету соответствия частотам от слова совсем. И в музыке так же.
До упомянутого DiskoLux как до луны, правда последний стоит как лунный камень.
Да, знаю что заминусите, но какая то фигня а не светомузыка, хотя автор молодец, я и такое не способен создать ;)
В программе есть кнопочка тест(работает до момента старта) по ней прогоняется синус программный от 40 до 22000 Гц. БПФ работает корректно.
Уровень входного сигнала уменьшите. Если у вас сигнал входит в ограничение это даёт резкие фронты с широким спектром. Регулировки усиления в программе нет. Кнопочку свернуть добавлю, но для программы из второй части статьи. Может за счёт большого числа полос нет явно выраженных привязок к инструментам (барабанам) мало светиков на красный. Объедините выходы как вам надо или сделайте разное количество светиков на разные части спектра. Я весь проект написал за четыре дня и дал вам инструмент. Составление цветовых программ естественно займёт намного больше времени. И я надеюсь что если этим будут заниматься несколько человек, читателей муськи, и выкладывать свои удачные цветомузыкальные программы, то каждый подберёт себе такие программы какие нужны ему. Но писать их надо для ардуино что достаточно просто даже для не имеющих профессионального образования в области программирования и спектрального анализа. Я писал статью для тех кто хочет что то аналогичное сделать для себя, но в силу отсутствия знаний и опыта не мог этого сделать. Теперь это будет сделать намного проще.
Возможно в целом я немного резковато отозвался :) Тестировал как раз 2 часть программы, там такой копки нету. С уровнем сигнала я по разному экспериментировал, сложно поймать, тем более громкость я на ПК регулирую, прям совсем не удобно :(
Эх, попробую конечно с привязками разобраться, но тяжко будет…
Еще такой вопрос: В программе AmbiBox можно добавлять Плагины, не проще было туда это запихнуть? (Я не программист, по этому не знаю разницы)
У каждой программы свой интерфейс и с ним надо разбираться. Изучать его ради цветомузыки я не готов. Времени на это уйдёт много. Не все интерфейсы хорошо описаны. С какой нибудь мелочью можно убить неделю, а то и месяц пока не поймёшь почему не работает. В отзывах товарищ на MSGEQ7 так завис, а дело может потом оказаться в какой то мелочи. Я пишу на том что хорошо знаю, что бы не терять время на мелочах.
Основная цель всех моих работ заинтересовать моего ребёнка. Смотреть на ютубе Галилео, про машины, про технические новинки и т.п. ему нравится, а что то делать сам не хочет. Надо оторвать его от планшета.
Подправил. Теперь в версии 2 уровень сигнала в цветомузыкальных программах можно ползунком регулировать. И цвет ленты кликом по соотв. цвету индикаторов включается.
добрый день, у меня программа CMU пишет «соединение не установлено», порт в настройках стоит верный, скетчи грузятся через ардуино IDE, может подскажите решение. Вариант установки через кабель USB, виртуальный кабель установлен
Если COM установлен правильно (скетчи грузятся по этому же порту) всё должно работать. Может у вас программа уже запущена? В трее посмотрите.
Версию новую скачайте.
Простите, вопрос от начинающего. 12 вольтовую ленту с внешнем питанием можно использовать? 60 диодов / метр. И есть ли ограничение во ко-ву диодов в ленте?
Максимальное количество светодиодов 240. Можно включать ленты параллельно. Например 2х240 или 3x240. Мне больше нравится 120. При 240 некоторые динамические программы кажутся слегка затянутыми, пока по всем элементам пробежит.
По вашей ленте, не зная типа ленты, ничего сказать не могу. У меня нет и не было 12В лент, однозначно надо будет что-то городить, минимум согласование.
Не получается переделать эфект уровня звука. Хочется переделать от зеленого- красному и тоже от центра как и с радужной линейкой. Радуга наростающая режет глаза без подсветки фона. Автоуровень уже кто-то сделал или нет? Как его сделать? Без пояснения скетча для меня это оченть трудно. Помогите чем можете. Буду благодарен ) Автор молодец, цветомузыка бомба).
Регулировку уровня звука сделать сложнее. Её надо делать в исходнике на Delphi и лучше с использованием аппаратных средств. Проблем будет не меньше чем без АРУ. Я автоматической регулировкой уровня звука не занимался и чтобы её сделать корректно надо хотя бы пару книжек на эту тему прочитать.
Вы, если не прослушали композицию ранее, не знаете почему уровень упал. Может это началась новая композиция, а может так автор этой композиции задумал. Исходя из этого и необходимо выбрать параметры блоков системы.
Нашёл как решить проблему уровня звука. Плеер AIMP. Заходим настройки эффектов и ставим галочку анализ файла на ленту и звук будет уже сам добавляться или наоборот. Лучше выбрать анализ на альбом. Чтобы музыка не настраевалась вовремя воспроизведения.
столкнулся с такой проблемой. пытался передачю даных по юсб перекинуть в другой скеч. получилось но есть одно но. все спектра звука кроме дата ред [0] показания подскакивают вверх без причины. вчем беда почему так происходит. и причем реско и несенхронно. хаотично
Я вас понял. Вечером скину. Но наперед скажу. Сделал на экране 16 на 2 лсд анализатор спектра на 16 полос и когда плеер выключаеш то большенство полосок прыгают на максимум это на экране еле заметно. Вечером это скеч и скину. И я кстати думал что уровень звука идет например в какомто другом байте например 25 или 26 но нет только спектр от 0 до 19 байта)) Удачного дня всем!)
Я пытался в его скеч перенисти ком порт. Чтобы не ардуино занималась обработкой
звука а пк. Ну и сделать радиопередачю и режимы переключались на ик пульту. Я ему писал но он молчит. Сам передеделал но когда звук молчит полоска моргает и хоть убейся. Время мало до Нового года хочется сделать но мозгов не хватает))) а там и уровень звука атоматический
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();
}
}
}
// — НАСТРОЙКИ — #define DRIVER_VERSION 0 // 0 — маркировка драйвера кончается на 4АТ, 1 — на 4Т
#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(«AlexGyver»);
lcd.setCursor(0, 1);
lcd.print(«SpektrumAnalyzer»);
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; // Устанавливаем счётчик принятых символов на начало входного буфера
}
if (inComplete) {
inComplete=false;
// Здесь по завершению приёма пакета ПК (в темпе поступления от ПК) выполняем все действия по выводу на LCD, так как повторять их много раз не имеет смысла
// Я не знаю сколько по времени занимает вывод на LCD но он не должен превышать времени приёма одного байта(или нескольких байт) от ПК, я точно не помню как
// организован приём данных от UART и есть ли там буферизация, или будут потери данных.
// Вставьте сюда проверку количества принятых байт и если их число меньше 26 значит были пропущены данные
// код отправки пакета из ПК для наглядности
procedure TForm1.setBandPass;
var i:Integer;
begin
SendBuff[0]:=253; // Сброс счётчика, начало команды
for i:=0 to nBandPass-1 do
begin
if zmuBuf[i]>252 then zmuBuf[i]:=255;
SendBuff[i+1]:=zmuBuf[i];
end;
SendBuff[21]:=prog;
SendBuff[22]:=param[prog];
SendBuff[23]:=brightness;
SendBuff[24]:=0;
SendBuff[25]:=254; // Конец передачи команды
FLink.SendBuffer(SendBuff);
rcvAnswer; // Ответ
end;
// если есть пропуски, значит надо как то по другому организовывать приём данных от UART
// или по прерываниям, или вставлять проверку принятия байта после каждой операции с LCD
// например весь while (Serial.available()) {...} вынести в отдельную функцию и вызывать её
// в процессе вывода на дисплей
// если разрешена ручная настройка уровня громкости
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);
}
Добрый день. Дайте исходники цму5 или любую версию вашей программы для Delfi… Попробую реализовать регулятор уровня для каждой из полос. В это есть беда что надо на плеере эквалайзер перестраивать чтоб стало мигать как надо. А звук в итоге сильно меняется и слушать уже неприятно. Или может быть вы уже это сделали??
Исходники этого проекта с весны прошлого года доступны на Github: github.com/juraspb/MusicToColor
и я этим проектом с того времени больше не занимаюсь.
За что тут ругать?
Молодец!
*задумался*
Стоящий обзор. Тоже руки зачесались сделать, к томуже всё имеется и смонтировано.
Я забабахал подсветку в карниз и со смартфона управляю ею, там разные цвета и прочее, надо бобавить микрофон и подправить код.
Обзор хороший,
сейчас нигде такого не найти
правда я первый раз слышу про такой экран
что-то типа такого с таким же эффектом
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.me/blog/aliexpress/49938.html
Вот такие хороши как гирлянда:
Для них купил линзы-рассеиватели (менее $2 за 100), ими прикрою. Пайку и обратную сторону можно обработать «Plastik 71».
Зато уже распаяно, похоже на гирлянду и отлично управляется.
и нашёл вот какие: aliexpress.com/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.me/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
Юрий