Как обычно. Вот, и кнопка, и ик приёмник, и блютуз, и всё одновременно:
Спойлер
/////////////////////////////////////
/// примеры для ws2812b на ESP32
//голосовое управление и ик управление (плюс кнопка)
////////////////////////////////////
#include "BluetoothSerial.h"
#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
#endif
#define KN 27 // под кнопку
#define plus 17 //
#define minus 25 //
int IK_PIN = 26; //Пин подключения выходного сигнала с ИК-приёмника
#include "Adafruit_NeoPixel.h"
#define line_ 96 //число пикселей в ленте
#define max_eff 23 //общее число эффектов
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};
BluetoothSerial SerialBT;
String inputString;// строки данных
byte komanda_=0;//
//
///RGB
void setup() {
pinMode (KN, INPUT_PULLUP);// кнопка управления
pinMode(plus,OUTPUT);//
digitalWrite(plus,HIGH);// плюс питания ик приёмника
pinMode(minus,OUTPUT);//
digitalWrite(minus,LOW);// минус питания ик приёмника
pinMode(IK_PIN, INPUT); // ir recv
attachInterrupt(26, irread, FALLING);
SerialBT.begin("ESP32test"); //НАЗВАНИЕ БЛЮТУЗ МОДУЛЯ
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= max_eff;}//
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);CheckSerial();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=5;G=1;B=5;}else{R=7;G=7;B=1;}} }//<-разбегание от центра поочерёдное полосы синеватого и сиреневого цветов - подобие волны->
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=15;G=2;B=0;}else{R=7;G=2;B=2;}} }//<-разбегание от центра поочерёдное полосы зеленоватого и оранжевого цветов - подобие волны->
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;if(in==it||in+1==it||in+2==it||in+3==it){R=0;G=0;B=0;}}//радужное движение групп по 16 пикселей с добавкой оранжевого 2 вариант
break;
case 20:
if(it<line_/2){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<line_/2){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:
if(it<line_/4){if(abs(in-random(0,line_))<6){R=3;G=6;B=9;}else{R=1;G=2;B=3;}} //отрисовка пикселей ёлки
if(it>=line_/4&&it<line_/2){if(abs(in-random(0,line_))<6){R=6;G=9;B=3;}else{R=2;G=3;B=1;}}
if(it>=line_/2&&it<line_*3/4){if(abs(in-random(0,line_))<6){R=6;G=12;B=0;}else{R=2;G=4;B=0;}}
if(it>=line_*3/4&&it<line_){if(abs(in-random(0,line_))<6){R=3;G=9;B=6;}else{R=1;G=3;B=2;}}
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;
case 23:
R=2+it%2;G=2+it%2;B=2+it%2;
if(random(0,abs(line_/2-it)+2)==0) {R=2;G=5;B=0;}
if(random(0,abs(line_/2-it)+2)==0) {R=3;G=2;B=0;}
if(random(0,abs(line_/2-it)+2)==0) {R=1;G=0;B=5;}
break;
default:
{ R=0;G=0;B=0;}//выключаем пиксели если не выбран эффект
}
}
/////////////////////////////////////////
//ФУНКЦИИ ПРИЁМА И ОБРАБОТКИ КОМАНД-ДАННЫХ
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<7){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;}
//
}
//////////////////////////////////////////////////////////////
/////////////////////////////////////////////////
// функция временной задержки с проверкой кнопки управления
void delay_(int T1)
{
static bool FL_KN=true;
Y1=millis();
while(millis()-Y1<T1){
if(digitalRead(KN)==HIGH&&!FL_KN){FL_KN=true;delay(200);}//
if(digitalRead(KN)==LOW&&FL_KN){//
delay(200);
if(digitalRead(KN)==HIGH){
FL_=false;
effekt++;//выбор - номер эффекта
if(effekt> max_eff){effekt=1;}
t=100;M=5;cvet=0;delay(200);
}
else{
delay(200);
if(digitalRead(KN)==HIGH){
cvet++;if(cvet>5){cvet=0;}//выбор компонент цвета
}
else{
t=t+30;if(t>210){t=30;}//выбор длительности паузы между кадрами в эффекте
FL_KN=false;
}
}
}
}
}
////////////////////////////////////////////////
/////////////////////////////////////////
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> max_eff){effekt=1;}
break;
case 0x1451AE:
effekt--;//выбор - номер эффекта
if(effekt<1){effekt= max_eff;}
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);
}
}
//////////////////////////////////////////////