Нашёл ещё один вариант как мне кажется устойчивый к многократным перемонтажам … и того пока три:
А пенопластовые шарики из подушек или кресел-подушек ?
Нашёл ещё один вариант как мне кажется устойчивый к многократным перемонтажам … и того пока три:
А пенопластовые шарики из подушек или кресел-подушек ?
Селикогель и пенопласт совсем разные хим свойства.
Они непрозрачные
Делал новогоднюю гирлянду на дом из 100 светодиодных модулей.
[https://www.youtube.com/watch?v=UDHte7VaFYU]
Красиво.
/////////////////////////////////////
/// примеры для ws2812b на ESP32
////////////////////////////////////
#define plus 17 //
#define minus 25 //
int IK_PIN = 26; //Пин подключения выходного сигнала с ИК-приёмника
#include "Adafruit_NeoPixel.h"
#define line_ 96 //число пикселей в ленте
uint8_t dataPin = 5;// вывод для подключения
Adafruit_NeoPixel strip = Adafruit_NeoPixel(line_,dataPin , NEO_BRG + NEO_KHZ800);// Создаем переменную strip для управления нашей лентой.
volatile word keycode_ = 0;// переменная хранения кода кнопки
byte R=0; byte G=0; byte B=0;//составляющие цвета пикселя
int t=70;// пауза между кадрами
int effekt=1;// номер эффекта
int M=10;//коэффициент мощности свечения пикселя
long Y=0;//переменная хранения моментов времени
byte cvet=0;//
long Y1=0;//переменная хранения моментов времени
int ti = 0;
int ni = 0;
bool FL_=true;//переключение автоматического режима на управление с пульта ИК
bool FL_show=true;//
//
byte kanal_1[8]={0,24,44,60,74,83,89,95};// выделение светодиодов в группы-каналы
byte kanal_2[8]={4,28,48,63,76,81,88,95};
byte kanal_3[8]={8,31,50,65,77,85,91,95};
byte kanal_4[8]={12,34,52,67,78,87,93,95};
//
///RGB
void setup() {
pinMode(plus,OUTPUT);//
digitalWrite(plus,HIGH);// плюс питания ик приёмника
pinMode(minus,OUTPUT);//
digitalWrite(minus,LOW);// минус питания ик приёмника
pinMode(IK_PIN, INPUT); // ir recv
attachInterrupt(26, irread, FALLING);
strip.begin();
Serial.begin(9600);
}
void loop() {
///
//автоматический перебор программ каждые 30 секунд
if(millis()-Y>30000ul&&FL_){
Y=millis();
t=70*random(1,4);//псевдослучайный выбор длительности паузы между кадрами в эффекте
effekt--; if(effekt==0){effekt=22;}//
M=random(3,11);//псевдослучайный выбор яркости свечения
cvet=random(0,6);//псевдослучайный выбор компонент цвета
}
///
// проигрывание программы эффекта
for ( ti = 0; ti < line_; ti++) {//перебор номеров кадров в ленте
for ( ni = 0; ni < line_; ni++) {//перебор номеров пикселей в ленте
cvet_(ti,ni);// функция определения цвета пикселя в зависимости от его номера в ленте и момента времени (кадра анимации)
if(cvet==0){strip.setPixelColor(ni, R*M, G*M, B*M);}if(cvet==1){strip.setPixelColor(ni, G*M, B*M, R*M);}if(cvet==2){strip.setPixelColor(ni, B*M, R*M, G*M);}
if(cvet==3){strip.setPixelColor(ni, R*M, B*M, G*M);}if(cvet==4){strip.setPixelColor(ni, G*M, R*M, B*M);}if(cvet==5){strip.setPixelColor(ni, B*M, G*M, R*M);}
}
if(FL_show){strip.show();}
// delay_(t);
delay(t);keypressed();
}
///
}
///////////////////////////////////////
void cvet_ (int it,int in){
switch (effekt) {
case 0:
R=0;G=0;B=0;//выключение ёлки
break;
case 1:
R=7;G=1;B=0;
if(in==it){R=0;G=14;B=2;}//бегущий по оранжевой ленте -> цвета бирюзового пиксель ->
break;
case 2:
{ byte mnogo=9; R=5*((in+it%mnogo)%mnogo);G=5*((mnogo-1-(in+it%mnogo)%mnogo));B=0;}// бегущая по ленте <-палитра от зелёного до красного (переход из 9 штук)<-
break;
case 3:
if(in<=it){R=5;G=0;B=10;}else{R=0;G=10;B=0;}// ->полоса фиолетового цвета набегает на полосу зелёного ->
break;
case 4:
if(in%(it+1)==0){R=15;G=15;B=10;}else{R=7;G=1;B=1;}// -> выстрел белыми пикселями с их взаиморазлётом -> на розовом фоне
break;
case 5:
if(in==line_-it||in+1==line_-it||in+2==line_-it||in+3==line_-it||in+4==line_-it){R=15;G=3;B=0;}else{R=0;G=0;B=7;}//бегущий по синей ленте -> цвета оранжевого 5 пикселей ->
break;
case 6:
{ byte mnogo=10; R=5*((in+it%mnogo)%mnogo);G=0;B=5*((mnogo-1-(in+it%mnogo)%mnogo));}// бегущая по ленте <-палитра от синего до красного (переход из 10 штук)<-
break;
case 7:
if(in<=line_-it){R=10;G=10;B=0;}else{R=0;G=7;B=7;}// <-полоса голубого цвета набегает на полосу жёлтого <-
break;
case 8:
if((line_-in)%(it+1)==0){R=15;G=15;B=10;}else{if(in%(it+3)==0){R=10;G=3;B=0;}else{R=0;G=2;B=2;}}// -> выстрел белыми пикселями и оранжевыми с их взаиморазлётом -> на голубом фоне
break;
case 9:
{ byte mnogo=32; R=3;G=1*(mnogo-1-(it%mnogo));B=1*((it%mnogo));t=200;}// плавный переход цвета ленты от "зеленоватого к синеватому"
break;
case 10:
{ byte mnogo=32; R=1*(mnogo-1-(it%mnogo));G=1;B=1*((it%mnogo));t=200;}// плавный переход цвета ленты от "красноватого к синеватому"
break;
case 11:
{ byte mnogo=7; R=0*((mnogo-1-(in+it%mnogo)%mnogo));G=2*((mnogo-1-(in+it%mnogo)%mnogo));B=5*((mnogo-1-(in+it%mnogo)%mnogo));}// бегущая по ленте <-поток метеоров (переход из 7 штук)<-
break;
case 12:
{if(in==it){R=0;G=1;B=0;}if(in+1==it){R=10;G=0;B=0;}if(in+2==it){R=10;G=3;B=0;}if(in+3==it){R=10;G=10;B=0;}if(in+4==it){R=0;G=10;B=0;}
if(in+5==it){R=0;G=10;B=10;}if(in+6==it){R=0;G=0;B=15;}if(in+7==it){R=3;G=0;B=10;} }// бегущая по ленте ->радуга (переход из 7 штук)->
break;
case 13:
{if(in<=line_-it){R=0;G=1;B=0;}if(in+2==line_-it){R=10;G=0;B=0;}if(in+4==line_-it){R=10;G=3;B=0;}if(in+6==line_-it){R=10;G=10;B=0;}if(in+8==line_-it){R=0;G=10;B=0;}
if(in+10==line_-it){R=0;G=10;B=10;}if(in+12==line_-it){R=0;G=0;B=15;}if(in+14==line_-it){R=3;G=0;B=10;} }// бегущая по ленте <-радуга (переход из 7 штук через 1)<-
break;
case 14:
{if(in-2<(line_+2*it)/2&&in+2>(line_-2*it)/2&&it<line_/2){R=0;G=7;B=7;}else{if((in>it||in<line_-it)&&it>=line_/2){R=0;G=7;B=7;}else{R=5;G=1;B=5;}} }//<-разбегание от центра поочерёдное полосы синеватого и сиреневого цветов - подобие волны->
break;
case 15:
{if(in-2<(line_+2*it)/2&&in+2>(line_-2*it)/2&&it<line_/2){R=0;G=7;B=1;}else{if((in>it||in<line_-it)&&it>=line_/2){R=0;G=7;B=1;}else{R=15;G=2;B=0;}} }//<-разбегание от центра поочерёдное полосы зеленоватого и оранжевого цветов - подобие волны->
break;
case 16:
{ if((in>=it-3&&in<=it+3)||(in>=it-3+8&&in<=it+3+8)){R=0;G=0;B=0;}else{ R=2*(it%2);G=2*((it%4)/2);B=2*((it%8)/4);} t=70;}//-> бег тень 6 пикселей, светящиеся 1 пиксель, тень 6 пикселей -> на фоновом радужном переливе
break;
case 17:
if(in%(it/(line_/3)+1)==0){R=random(0,(in+it)%7+2); G=random(0,in%10+2); B=random(0,it%10+2);}if(R==0&&G==0&&B==0){R=5;G=5;B=5;}// рандом пикселей
break;
case 18:
{R=(in/16+it)%2;G=((in/16+it)/2)%2;B=((in/16+it)/4)%2;M=40;if(R==0&&G==0&&B==0){R=7;G=1;B=0;M=5;}t=140;}//радужное движение групп по 16 пикселей с добавкой оранжевого
break;
case 19:
{R=((it+in)/(5))%2;G=(((it+in)/(5))/2)%2;B=(((it+in)/(5))/4)%2;M=40;if(R==0&&G==0&&B==0){R=7;G=1;B=0;M=5;}t=70;}//радужное движение групп по 16 пикселей с добавкой оранжевого 2 вариант
break;
case 20:
if(in%2==0&&it%3==0){R=1;G=2;B=3;}else{R=2;G=3;B=1;}
for( byte w=0;w<8;w++){
if(in==kanal_1[w]||in==kanal_2[w]||in==kanal_3[w]||in==kanal_4[w]){R=1;G=0;B=0;}// маятник эффект
if(it%6==0&&in==kanal_1[w]){R=8;G=5;B=5;}
if(it%6==1&&in==kanal_2[w]){R=8;G=5;B=5;}
if(it%6==2&&in==kanal_3[w]){R=8;G=5;B=5;}
if(it%6==3&&in==kanal_4[w]){R=8;G=5;B=5;}
if(it%6==4&&in==kanal_3[w]){R=8;G=5;B=5;}
if(it%6==5&&in==kanal_2[w]){R=8;G=5;B=5;}
}
break;
case 21:
if(it%4==0){R=1;G=1;B=0;}else{R=2;G=3;B=0;}
if(it<8&&(in==kanal_1[7-it%8]||in==kanal_4[it%8])){R=8;G=5;B=5;}//бегущие точки по каналам
if(it>=8&&it<16&&(in==kanal_2[it%8]||in==kanal_3[7-it%8])){R=8;G=8;B=5;}
if(it>=16&&it<24&&(in==kanal_3[7-it%8]||in==kanal_2[it%8])){R=8;G=8;B=5;}
if(it>=24&&it<32&&(in==kanal_4[it%8]||in==kanal_1[7-it%8])){R=8;G=8;B=5;}
if(it>=32&&it<40&&(in==kanal_1[7-it%8]||in==kanal_4[it%8])){R=8;G=8;B=5;}
if(it>=40&&it<48&&(in==kanal_2[it%8]||in==kanal_3[7-it%8])){R=8;G=8;B=5;}
if(it>=48&&it<56&&(in==kanal_3[7-it%8]||in==kanal_2[it%8])){R=8;G=8;B=5;}
if(it>=56&&it<64&&(in==kanal_4[it%8]||in==kanal_1[7-it%8])){R=8;G=8;B=5;}
if(it>=64&&it<72&&(in==kanal_1[7-it%8]||in==kanal_4[it%8])){R=8;G=8;B=5;}
if(it>=72&&it<80&&(in==kanal_2[it%8]||in==kanal_3[7-it%8])){R=8;G=8;B=5;}
if(it>=80&&it<88&&(in==kanal_3[7-it%8]||in==kanal_2[it%8])){R=8;G=8;B=5;}
if(it>=88&&it<96&&(in==kanal_4[it%8]||in==kanal_1[7-it%8])){R=8;G=8;B=5;}
if(in==it){R=14;G=3;B=0;}//бегущие точки по спирали ёлки
if(in==line_-it){R=3;G=14;B=0;}//
break;
case 22:
R=1;G=2;B=it%5;//отрисовка пикселей ёлки
if(it%16<8){
for( int w=0;w<8;w++){
if(in==kanal_1[w]||in==kanal_2[w]||in==kanal_3[w]||in==kanal_4[w]){R=1;G=0;B=0;}//отрисовка пикселей каналов
if(it%8==w&&(in==kanal_1[w]||in==kanal_2[w]||in==kanal_3[w]||in==kanal_4[w])){R=8;G=5;B=5;}
}
}
else{
for( int w=0;w<8;w++){
if(in==kanal_1[w]||in==kanal_2[w]||in==kanal_3[w]||in==kanal_4[w]){R=1;G=0;B=0;}//отрисовка пикселей каналов
if(w!=0&&(line_-it)%8==w&&(in==kanal_1[w]||in==kanal_2[w]||in==kanal_3[w]||in==kanal_4[w])){R=8;G=5;B=5;}
}
}
break;
default:
{ R=0;G=0;B=0;}//выключаем пиксели если не выбран эффект
}
}
/////////////////////////////////////////
void irread() {
volatile static byte n = 0;
volatile static word keycode = 0;
volatile static unsigned long tm = 0;
volatile static unsigned long last = 0;
tm = micros() - last;
last = micros();
n += 1;
if (tm > 3000) {
keycode = 0;
n = 0;
}
if (n >8&&n<=32) {
if (tm > 1500) {keycode += 1;}
keycode = keycode << 1;
}
if(n==32){keycode_ = keycode;keycode = 0;n=0;}
}
//////////////////////////////////////////
void keypressed() {
if(keycode_!=0){
Serial.println(keycode_, HEX);// печатаем код кнопки
//код по обработке значений keycode_
switch (keycode_) {
case 0x15906E:
effekt++;//выбор - номер эффекта
if(effekt>19){effekt=1;}
break;
case 0x1451AE:
effekt--;//выбор - номер эффекта
if(effekt<1){effekt=22;}
break;
case 0x1550AE:
M=M+2;if(M>10){M=10;}//выбор яркости свечения
break;
case 0x14D12E:
M=M-2;if(M<0){M=1;}//выбор яркости свечения
break;
case 0x15C03E:
cvet++;if(cvet>5){cvet=0;}//выбор компонент цвета
break;
case 0x14A15E:
t=t+30;if(t>210){t=30;}//выбор длительности паузы между кадрами в эффекте
break;
case 0x14817E:
FL_=! FL_;
break;
case 0x15D02E:
FL_show=! FL_show;//переключение с автоматического перебора на ручное эффектов
break;
case 0x15609E:
effekt=0;//выключение ёлки
break;
default:
ti=ni=line_;
}
keycode_ = 0;delay(100);
}
}
//////////////////////////////////////////////
/////////////////////////////////////////////////
// функция временной задержки с проверкой поступающих данных
void delay_(int T1)
{
Y1=millis();
while(millis()-Y1<T1){
// keypressed();
}
}
////////////////////////////////////////////////
Текущая версия.
…Может кто подкинет описание интересных эффектов?
Тут правда своеобразная логика создания эффекта.
case 1:
R=7;G=1;B=0;//фоновая закраска ленты по всем кадрам оранжевым
if(in==it){R=0;G=14;B=2;}//бегущий по ленте -> цвета бирюзового пиксель ->
break;
Ещё бы генерацию эффектов придумать.
Что такое - генерация эффектов?
По типу как я делал в узорах. Там правда проще в логике работы – псевдослучайный набор в четверти узора, а дальше повторение в отражении или повороте.
Переделал на голосовое управление гирлянду. Концепт - отдельные команды: шестнадцать, очень ярко , быстро, цвет пять. Вроде управление не хуже чем при ИК.
//ФУНКЦИИ ПРИЁМА И ОБРАБОТКИ КОМАНД-ДАННЫХ
void CheckSerial()
{
//////////////////////////////////////////////////////////////////////////////
while (SerialBT.available())//считываем строку данных пока они поступают
{
char inChar = (char)SerialBT.read();
if (inChar == '\n') //если окончание строки или запрос на загрузку
{
MakeCmd();//обрабатываем её данной функцией
break;
}
else inputString += inChar;// иначе удлиняем строку на один символ
}
}
/////////////////////////////////////////////////////////////////////////////////
void MakeCmd()
{
int y = inputString.length(); // присваиваем переменной у число символов в строке
String cmd = inputString; // передаём строку другой переменной
inputString = "";//"обнуляем переменную"
//////
// Serial.print(cmd);
if(cmd=="СТОП КАДР"){FL_show=false;//стоп-кадр
}
if(cmd=="ПУСК КАДР"){FL_show=true;//стоп-кадр
}
if(cmd=="АВТОМАТ ДА"){FL_=true;//автоматический перебор
}
if(cmd=="АВТОМАТ НЕТ"){FL_=false;//ручной перебор
}
if(cmd=="ЦВЕТ 0"){ cvet=0;//перебор сочетаний цветов
}
if(cmd=="ЦВЕТ 1"){ cvet=1;//перебор сочетаний цветов
}
if(cmd=="ЦВЕТ 2"){ cvet=2;//перебор сочетаний цветов
}
if(cmd=="ЦВЕТ 3"){ cvet=3;//перебор сочетаний цветов
}
if(cmd=="ЦВЕТ 4"){ cvet=4;//перебор сочетаний цветов
}
if(cmd=="ЦВЕТ 5"){ cvet=5;//перебор сочетаний цветов
}
if(cmd=="ЯРКО"){ M=5;//выбор яркости свечения
}
if(cmd=="ТЕМНО"){ M=3; //выбор яркости свечения
}
if(cmd=="ОЧЕНЬ ЯРКО"){ M=10;//выбор яркости свечения
}
if(cmd=="ОЧЕНЬ ТЕМНО"){ M=1; //выбор яркости свечения
}
if(cmd=="ОЧЕНЬ БЫСТРО"){ t=30;//выбор длительности паузы между кадрами в эффекте
}
if(cmd=="ОЧЕНЬ МЕДЛЕННО"){ t=210;//выбор длительности паузы между кадрами в эффекте
}
if(cmd=="БЫСТРО"){ t=60;//выбор длительности паузы между кадрами в эффекте
}
if(cmd=="МЕДЛЕННО"){ t=100;//выбор длительности паузы между кадрами в эффекте
}
if(cmd=="ВЫКЛЮЧИ"){ effekt=0;//выключение ёлки
}
else{//выбор - номер эффекта
int pos=cmd.toInt();//преобразовать строку в число
if(pos>0&&pos<=23){effekt=pos;}
}
//////
}
//////////////////////////////////////////////////////////////
Но хотелось бы одной фразой (не факт, что так будет удобнее
Типа : Эффект шестнадцать яркость три скорость два цвет четыре
Но как тогда разбирать проще строку? Ведь в ней уже четыре числа надо извлечь.
Моя жена не одобрит такое нововведение
Да почему? В смартфон можно спокойно говорить, он уловит.
Сейчас модно (по жене вижу) наговаривать сообщения. Можно считать это сообщением…ёлке.
Дошло до меня как сделать вместо отдельных команд полное задание ёлке. Надо так:
//ФУНКЦИИ ПРИЁМА И ОБРАБОТКИ КОМАНД-ДАННЫХ
void CheckSerial()
{
//////////////////////////////////////////////////////////////////////////////
while (SerialBT.available())//считываем строку данных пока они поступают
{
char inChar = (char)SerialBT.read();
if (inChar == '\n'||inChar == ' ') //если окончание строки или пробел
{
MakeCmd();//обрабатываем её данной функцией
break;
}
else inputString += inChar;// иначе удлиняем строку на один символ
}
}
/////////////////////////////////////////////////////////////////////////////////
void MakeCmd()
{
int y = inputString.length(); // присваиваем переменной у число символов в строке
String cmd = inputString; // передаём строку другой переменной
inputString = "";//"обнуляем переменную"
//////
// Serial.print(cmd);
if(cmd=="ВЫКЛЮЧИ"){ effekt=0;//выключение ёлки
}
//
if(cmd=="ЭФФЕКТ"||cmd=="EFFECT"){komanda_=1;}
if(cmd=="ЯРКОСТЬ"){komanda_=2;}
if(cmd=="ПАУЗА"){komanda_=3;}
if(cmd=="ЦВЕТ"||cmd=="СВЕТ"){komanda_=4;}
if(cmd=="КАДР"){komanda_=5;}
if(cmd=="АВТОМАТ"){komanda_=6;}
//
int pos=cmd.toInt();//преобразовать строку в число
if(komanda_==1&&pos>0&&pos<=23){effekt=pos;pos=0;komanda_=0;}
if(komanda_==2&&pos>0&&pos<=10){M=pos;pos=0;komanda_=0;}
if(komanda_==3&&pos>=30&&pos<=210){t=pos;pos=0;komanda_=0;}
if(komanda_==4&&pos>0&&pos<6){cvet=pos-1;pos=0;komanda_=0;}
if(komanda_==5&&cmd=="СТОП"){FL_show=false;pos=0;komanda_=0;}
if(komanda_==5&&cmd=="ПУСК"){FL_show=true;pos=0;komanda_=0;}
if(komanda_==6&&cmd=="ДА"){FL_=true;pos=0;komanda_=0;}
if(komanda_==6&&cmd=="НЕТ"){FL_=false;pos=0;komanda_=0;}
//
}
Тогда задание: Эффект четыре, яркость пять, пауза сто, цвет три - будет выполнено сразу.
… Ну иногда распознаватель речи капризничает и выдаёт числа текстом, а не цифрами, путает слова тоже иногда
Ни фига не работают сенсоры вместе с лентой, а только без
Придётся одной кнопкой как то управлять пробовать