VU метр на адресной ленте WS 2812

Falcon689

✩✩✩✩✩✩✩
1 Апр 2021
10
0
Всем привет, задумал сделать простенькую цветомузыку на адресной ленте, 2 вертикальные шкалы VU метра и горизонтальная около метра просто с мигающими диодами. Про готовые варианты Алекса и чип и дип знаю, как надоест развлекаться сделаю на них. Собственно хочу чтобы на VU метре диоды подсвечивались тусклым цветом(типа задник) а при работе шкалы цвет менялся на яркую шкалу, куда шкала не дошла-там сохраняется задник. при отсутствии сигнала просто статичный задник во всю ленту. Собственно проблема следующая, не работает задник без сигнала. Если сигнал есть, даже минимальный (на потенциометре проверил) зажигается шкала, все что не занято шкалой подсвечено цветом задника. А вот статичный задник появляется при первом включении и навсегда пропадает после подачи сигнала и срабатывания шкалы, сигнал пропал - все потухло. Подскажите плиз как исправить, желательно развернуто и доходчиво, а то я не очень хорошо разбираюсь в написании кода. собственно код прилагаю.
З.Ы. в коде отмечены 3 блока, первый отвечает за рост шкалы при увеличении уровня сигнала, второй за падение шкалы и заливку свободных от нее диодов фоном, третий за статичный фон покоя. Если из кода выкинуть "второй блок" то статичный задник корректно работает, а вот шкала перестает падать, она поднимается и остается статичной пока сигнал не упадет на 0.
C++:
#define STRIP_PIN 12 // пин ленты
#define NUMLEDS 27 // число диодов в ленте
#define COLOR_DEBTH 3 // глубина цвета
#define CRT_OFF
#define STRIP_TYPE LED_WS2812
#include <microLED.h> // подключаем библиотеку
#define AUDIO_IN A0 //вход звука
#define LOW_VAL 18 //нижний порог звука
#define HI_VAL 670 //верхний порог звука
#define EXT 1.1
#define SMOOTH 0.3
microLED<NUMLEDS, STRIP_PIN, -1, STRIP_TYPE, ORDER_GRB, CLI_AVER> strip; //инициализируем ленту
int val=0,val2=0,val3=0,x=0; //обьявляем переменные
uint32_t timer; //обьявляем таймер

void setup()
{
  Serial.begin(9600); //включаем порт
  strip.setBrightness(255); //яркость ленты
  strip.clear(); //очищаем ленту
  strip.show(); //обновляем ленту
  delay(1);
}

void loop()
{
    mGradient< 4 > myGrad;  // создать градиент с именем myGrad на 4 точки
    myGrad.colors[0] = mGreen;// указываем цвет каждой точки
    myGrad.colors[1] = mGreen;
    myGrad.colors[2] = mOrange;
    myGrad.colors[3] = mRed;
    if(millis()-timer>1)
    {
      timer=millis();                                           
      val2=0;                                                                         
      val=analogRead(AUDIO_IN); //читаем вход аудио 
      if(val2<val)val2=val;
      val2=map(val2,LOW_VAL,HI_VAL,0,500);
      val2=constrain(val2,0,500);
      val3=val2 * SMOOTH + val3 * (1 - SMOOTH);
      
      x=map(val3,15,495,0,NUMLEDS); //масштабируем уровень звука в номер светодиода
      x=constrain(x,0,NUMLEDS);
      Serial.print(val); //отправляем всякое в порт для мониторинга
      Serial.print("\t");
      Serial.print(val2);
      Serial.print("\t");
      Serial.print(val3);
      Serial.print("\t");
      Serial.println(x);
    }
    if(val3>LOW_VAL) //если текущий уровень звука превышает минимальный порог
    {
    for(int i=0;i<=x;i++) //для диодов от 1 и до Х
    {
      strip.set(i,myGrad.get(i,NUMLEDS)); //заливаем ленту градиентом, шкала растет (блок 1)
      strip.setBrightness(255);
      strip.show(); //обновляем ленту
    }
    for(int i=NUMLEDS;i>x+1;i--) //вот эта фигня заливает фоном все что не занято самой шкалой и позволяет шкале плавно падать(назовем блок 2)
    {
      strip.set(i,mWheel8(200,5)); //заливаем ленту сплошным цветом-подложкой
      strip.show(); //обновляем ленту
    }
    }
     else
  {
    for(int i=0;i<NUMLEDS;i++)      //а вот это должно заливать всю шкалу цветом когда сигнала нет(назовем блок 3)
    {                               //оно и работает, заливает шкалу цветом при старте
      strip.set(i,mWheel8(200,5)); //но после прихода сигнала и срабатывания шкалы больше не работает
      strip.show();                //пробовал и else if(val3<LOW_VAL), и разные числа подставлял вместо LOW_VAL, один фиг
                                   //а вот если из кода выкинуть блок 2, то это все работает, но пропадает уменьшение шкалы, она только растет и полностью исчезает
    }                              //но фон при этом работает корректно.
    }
}
 

kostyamat

★★★★★★✩
29 Окт 2019
1,098
632
Задник/передник - офигенная терминология. Речь идет о фоне, я правильно понял?
Почему бы вам просто, в начале loop, циклом for, не закрасить всю ленту "задником", а потом накладывать все остальное, поверху? Лента работает как защелка, если новые данные не приходили, она будет светится последним цветом, пока питание с нее не снять. Из этого и исходите.

Ещё вопрос: принципиально в loop каждый раз массив градиента создавать? Может его вне loop ввынести?
 

Falcon689

✩✩✩✩✩✩✩
1 Апр 2021
10
0
Избыточное цитирование
Задник/передник - офигенная терминология. Речь идет о фоне, я правильно понял?
Почему бы вам просто, в начале loop, циклом for, не закрасить всю ленту "задником", а потом накладывать все остальное, поверху? Лента работает как защелка, если новые данные не приходили, она будет светится последним цветом, пока питание с нее не снять. Из этого и исходите.

Ещё вопрос: принципиально в loop каждый раз массив градиента создавать? Может его вне loop ввынести?
Спасибо за совет, так тоже пробовал, не работает(всмысле сначала закрасить а потом накладывать все остальное)почему то, при val3==0 гаснет вся лента полностью, хотя strip.clear() прописан только в сетапе. Градиент если он прописан вне лупа из лупа не вызывается, пишет что переменная myGrad не обьявлена. Попробую написать заливку шкалы градиентом как отдельную функцию, внутри которой будет создаваться градиент. Хотя по сути разницы не будет, функция будет постоянно вызываться, градиент создаваться.
З.Ы. повторил тот же код с использованием библиотеки fastLED, там задники работают, но только пока все одноцветное и одной яркости, тоесть цвета указаны как CRGB::Red для шкалы и CRGB::Green. При указании фонового цвета в формате CHSV почему то ломается математика в 40 строке и переменная val3 начинает принимать большие рандомные значения, как положительные, так и отрицательные, хаотично меняющиеся. А еще фастлед для меня слишком сложная и я не понимаю как мне сделать там такой же градиент как в микроледе, чтобы переход от зеленого к красному был от 1 до последнего диода, но зажигались только те, которые соответствуют текущей громкости. В общем пока решил проблему тем, что не даю val3 падать до 0, строчкой if(val3<10)val3=10 В целом работает, результат меня устраивает.
 

bort707

★★★★★★✩
21 Сен 2020
3,058
910
как определять функции - так и не разобрались?
 

Falcon689

✩✩✩✩✩✩✩
1 Апр 2021
10
0
@bort707, разобрался, это не совсем то ,что нужно, в функции градиента фастледа можно указать с какого по какой диод и от какого к какому цвету сделать градиент, а вот сколько диодов при этом зажечь не укажешь, нет такого параметра, тоесть если указать от 1 до 27 загорится все 27 с градиентом, только толку то, оно к переменной х не привязано. а если сказать от 1 до х, то конечный цвет градиента будет на диоде х, где нибудь в середине шкалы. Алекс Гайвер в своей цветомузыке для VU метра создает палитру, а потом заливает ей массив доидов .
 

kostyamat

★★★★★★✩
29 Окт 2019
1,098
632
C++:
static const mGradient< 4 > myGrad;  // создать градиент с именем myGrad на 4 точки
    myGrad.colors[0] = mGreen;// указываем цвет каждой точки
    myGrad.colors[1] = mGreen;
    myGrad.colors[2] = mOrange;
    myGrad.colors[3] = mRed;

void loop()
{
Попробуйте вот так сделать.
 

Falcon689

✩✩✩✩✩✩✩
1 Апр 2021
10
0
Избыточное цитирование
C++:
static const mGradient< 4 > myGrad;  // создать градиент с именем myGrad на 4 точки
    myGrad.colors[0] = mGreen;// указываем цвет каждой точки
    myGrad.colors[1] = mGreen;
    myGrad.colors[2] = mOrange;
    myGrad.colors[3] = mRed;

void loop()
{
Попробуйте вот так сделать.
Выдает ошибку 'myGrad' does not name a type
 

bort707

★★★★★★✩
21 Сен 2020
3,058
910
в функции градиента фастледа можно указать с какого по какой диод и от какого к какому цвету сделать градиент, а вот сколько диодов при этом зажечь не укажешь, нет такого параметра, тоесть если указать от 1 до 27 загорится все 27 с градиентом, только толку то, оно к переменной х не привязано. а если сказать от 1 до х, то конечный цвет градиента будет на диоде х, где нибудь в середине шкалы.
эта проблема решается элементарно - сначала создаете полный градиент, а потом гасите не нужные диоды, сами-то не догадались?
 

Falcon689

✩✩✩✩✩✩✩
1 Апр 2021
10
0
Хм, мне кажется не будет плавности работы шкалы, я попробую, спасибо за идею.
 

bort707

★★★★★★✩
21 Сен 2020
3,058
910
Хм, мне кажется не будет плавности работы шкалы, я попробую, спасибо за идею.
почему вам так кажется? думаете будут заметны частичные засветки?
А Вы создавайте градиент на всю длину, потом гасите все диоды. что больше X - и только потом делайте show() на ленту.
Все будет выглядеть так, будто вы сразу создали нужную картинку.
 
  • Лойс +1
Реакции: kostyamat

Falcon689

✩✩✩✩✩✩✩
1 Апр 2021
10
0
Избыточное цитирование
почему вам так кажется? думаете будут заметны частичные засветки?
А Вы создавайте градиент на всю длину, потом гасите все диоды. что больше X - и только потом делайте show() на ленту.
Все будет выглядеть так, будто вы сразу создали нужную картинку.
Это вообще не работает. Вот код:
C++:
#include "FastLED.h"
#define NUMLEDS 27 // Указываем, какое количество пикселей у нашей ленты.
#define LED_PIN 12 // Указываем, к какому порту подключен вход ленты DIN.
#define AUDIO_IN A0
#define STRIP_TYPE WS2812B
#define LOW_VAL 18 //нижний порог звука
#define HI_VAL 759 //верхний порог звука
#define EXT 1.1
#define SMOOTH 0.3
int val=0,val2=0,val3=0,x=0; //обьявляем переменные
uint32_t timer,timer2; //обьявляем таймер
CRGB strip[NUMLEDS]; // Создаем переменную strip для управления нашей лентой.

void setup()
{
  Serial.begin(9600);
  FastLED.addLeds<STRIP_TYPE, LED_PIN, GRB>(strip, NUMLEDS).setCorrection(TypicalLEDStrip); // Добавляем ленту
  FastLED.setBrightness(255); //настройка яркости
 
}


void loop()
{
   if(millis()-timer>10)
    {
      timer=millis();
      val2=0;
      val=analogRead(AUDIO_IN); //читаем вход аудио
      if(val2<val)val2=val;
      val2=map(val2,LOW_VAL,HI_VAL,0,500);
      val2=constrain(val2,0,500);
      val2=pow(val2,EXT);
      val3=val2 * SMOOTH + val3 * (1 - SMOOTH);
      x=map(val3,0,472,0,NUMLEDS); //масштабируем уровень звука в номер светодиода
      x=constrain(x,0,NUMLEDS);
      Serial.print(val); //отправляем всякое в порт для мониторинга
      Serial.print("\t");
      Serial.print(val2);
      Serial.print("\t");
      Serial.print(val3);
      Serial.print("\t");
      Serial.println(x);
    }
    for(int i=0;i<x;i++)
    {
    fill_gradient_RGB (strip,NUMLEDS,CRGB::Green,CRGB::Green,CRGB::Orange,CRGB::Red);
    }
    FastLED.show();
    
}
Все ожидаемо, статичный градиент на 4 цвета, диод RX мигает, данные в порт идут, переменные реагируют на уровень звука, все ровно.
Добавляю одну строчку (47-ю):
C++:
#include "FastLED.h"
#define NUMLEDS 27 // Указываем, какое количество пикселей у нашей ленты.
#define LED_PIN 12 // Указываем, к какому порту подключен вход ленты DIN.
#define AUDIO_IN A0
#define STRIP_TYPE WS2812B
#define LOW_VAL 18 //нижний порог звука
#define HI_VAL 759 //верхний порог звука
#define EXT 1.1
#define SMOOTH 0.3
int val=0,val2=0,val3=0,x=0; //обьявляем переменные
uint32_t timer,timer2; //обьявляем таймер
CRGB strip[NUMLEDS]; // Создаем переменную strip для управления нашей лентой.

void setup()
{
  Serial.begin(9600);
  FastLED.addLeds<STRIP_TYPE, LED_PIN, GRB>(strip, NUMLEDS).setCorrection(TypicalLEDStrip); // Добавляем ленту
  FastLED.setBrightness(255); //настройка яркости
 
}


void loop()
{
   if(millis()-timer>10)
    {
      timer=millis();
      val2=0;
      val=analogRead(AUDIO_IN); //читаем вход аудио
      if(val2<val)val2=val;
      val2=map(val2,LOW_VAL,HI_VAL,0,500);
      val2=constrain(val2,0,500);
      val2=pow(val2,EXT);
      val3=val2 * SMOOTH + val3 * (1 - SMOOTH);
      x=map(val3,0,472,0,NUMLEDS); //масштабируем уровень звука в номер светодиода
      x=constrain(x,0,NUMLEDS);
      Serial.print(val); //отправляем всякое в порт для мониторинга
      Serial.print("\t");
      Serial.print(val2);
      Serial.print("\t");
      Serial.print(val3);
      Serial.print("\t");
      Serial.println(x);
    }
    fill_gradient_RGB (strip,NUMLEDS,CRGB::Green,CRGB::Green,CRGB::Orange,CRGB::Red);

    for(int i=NUMLEDS;i>x;i--)strip[i]=CRGB::Blue;
    FastLED.show();
    
}
Итог:первый диод зеленый, остальные синие, что ожидаемо, залился задник,диод RX НЕ МИГАЕТ! никаких данных в монитор не идет, вообще опроса микрофона не происходит, лента ни на что не реагирует, статичный цвет.
 

Falcon689

✩✩✩✩✩✩✩
1 Апр 2021
10
0
А если 47 строку записать вот так:
C++:
for(int i=x;i<NUMLEDS;i++)strip[i]=CRGB::Blue;
то все работает. Я хз почему так.
 

bort707

★★★★★★✩
21 Сен 2020
3,058
910
А если 47 строку записать вот так:
C++:
for(int i=x;i<NUMLEDS;i++)strip[i]=CRGB::Blue;
то все работает. Я хз почему так.
потому что эта строка и вот эта строка
C++:
for(int i=NUMLEDS;i>x;i--)strip[i]=CRGB::Blue;
задают разный диапазон диодов, не замечаете?

И кстати, первый код и тот, про который вы пишете, что "только добавили 47 строку" - отличаются куда больше, чем только добавлением этой строки. Вот смотрите - в первом коде есть цикл for по х (строчки 45-47), а во втором он куда-то исчез (кстати. а зачем он был нужен ?)

Есть масса других вопросов и замечаний по коду, если хотите - можем разобрать. В целом, как мне кажется. вы особо не пытались вникнуть, что тут и как делается. просто копируете разные строчки наобум... в итоге куча ошибок.
 
Изменено:

Falcon689

✩✩✩✩✩✩✩
1 Апр 2021
10
0
Вроде один и тот же, просто в одном случае перебор идет снизу вверх(от х до 27) а в другом сверху вниз(от 27 до х). В любом случае это не обьясняет почему вырубался порт при переборе сверху вниз.
 

bort707

★★★★★★✩
21 Сен 2020
3,058
910
Вроде один и тот же, просто в одном случае перебор идет снизу вверх(от х до 27) а в другом сверху вниз(от 27 до х). В любом случае это не обьясняет почему вырубался порт при переборе сверху вниз.
Плохо у вас с логикой.
Смотрите внимательно - возьмем для примера пределы 0 и 27, тогда первый код перебирает диоды от 27 до 1, а второй - от 0 до 26.
А с учетом того, что в Си массивы нумеруются с нуля, то ваш первый код пытается записать что-то в элемент массива strip[NUMLEDS] - это приводит к неработоспособности программы.
 

Falcon689

✩✩✩✩✩✩✩
1 Апр 2021
10
0
Ага, понял,тоесть массив имеет 27 "ячеек" с 0 по 26, а я попытался записать в ячейку номер 27,которая не существует. Тоесть в таком виде заработало бы
C++:
for(int i=NUMLEDS-1;i=x;i--)strip[i]=CRGB::Blue;
Спасибо за ответы, многое стало понятнее)
 

bort707

★★★★★★✩
21 Сен 2020
3,058
910
в таком виде заработало бы
в таком виде тоже нет, условие
i=x;
никуда не годится.
Перебирайте лучше по возрастанию, это проще.

Математику свою еще изучите (строчки 28-35 первого скетча), разберитесь, какая строчка что делает. На мой взгляд там тоже местами бред
написан

PS если будут вопросы - отвечу вечером, ухожу
 

Falcon689

✩✩✩✩✩✩✩
1 Апр 2021
10
0
Математика не моя, я выдрал этот кусок из скетча цветомузыки Алекса Гайвера. Он назвал это фильтром, с ним работает гораздо плавнее. Просто сглаживает резкие скачки сигнала,кмк.