Перейти к содержанию

Анализатор спектра на arduino


Рекомендуемые сообщения

В общем ребят тема такая. Хотелось бы сделать многополосный анализатор спектра на ленте WS2812B + arduino 
Было забугорное видео с инструкцией но его удалили. Осталась только картинка и скетч от готового анализатора. 
Из за недостатка знаний сам построить не могу. Поэтому прошу более прошареных умов.

image.png.1d60e6c036cc6c90ab2c859ef2838d2d.pngЭтого видео больше нет. Но выглядел анализатор именно так. 

Code Repository:
https://www.dropbox.com/sh/g3qraziuimksdho/AADwkqKRP3JmV9tQyGD_z2jga?dl=0

Строго не судите. Это моё первое обращение на форуме.

Посоветуйте как реализовать этот проект

 

#define PIXELS 600  // Number of pixels in the string
 
// These values depend on which pin your string is connected to and what board you are using 
// More info on how to find these at http://www.arduino.cc/en/Reference/PortManipulation
 
#define PIXEL_PORT  PORTD  // Port of the pin the pixels are connected to
#define PIXEL_DDR   DDRD   // Port of the pin the pixels are connected to
#define PIXEL_BIT   6      // Bit of the pin the pixels are connected to
#define NUM_COLS    30     // Number of columns in our neopixel matrix
#define NUM_ROWS    20     // Number of rows in our neopixel matrix
 
// These are the timing constraints taken mostly from the WS2812 datasheets 
// These are chosen to be conservative and avoid problems rather than for maximum throughput 
 
#define T1H  900    // Width of a 1 bit in ns
#define T1L  600    // Width of a 1 bit in ns
 
#define T0H  400    // Width of a 0 bit in ns
#define T0L  900    // Width of a 0 bit in ns
 
#define RES 6000    // Width of the low gap between bits to cause a frame to latch
 
// Here are some convience defines for using nanoseconds specs to generate actual CPU delays
 
#define NS_PER_SEC (1000000000L)          // Note that this has to be SIGNED since we want to be able to check for negative values of derivatives
 
#define CYCLES_PER_SEC (F_CPU)
 
#define NS_PER_CYCLE ( NS_PER_SEC / CYCLES_PER_SEC )
 
#define NS_TO_CYCLES(n) ( (n) / NS_PER_CYCLE )
 
 
// My spectrum analyzer produces a rainbow effect as amplitudes increase
// This is a lookup table of sorts for the appropriate color of a specific amplitude (RGB)
// I found the values online in RGB format so I left them that way and corrected for it later...
uint8_t Rainbow[60] = {0xbf, 0x00, 0xff,
                      0x7f, 0x00, 0xff,
                      0x40, 0x00, 0xff,
                      0x00, 0x00, 0xff,
                      0x00, 0x40, 0xff,
                      0x00, 0x7f, 0xff,
                      0x00, 0xbf, 0xff,
                      0x00, 0xff, 0xff,
                      0x00, 0xff, 0xbf,
                      0x00, 0xff, 0x80,
                      0x00, 0xff, 0x40,
                      0x00, 0xff, 0x00,
                      0x40, 0xff, 0x00,
                      0x80, 0xff, 0x00,
                      0xbf, 0xff, 0x00,
                      0xff, 0xff, 0x00,
                      0xff, 0xbf, 0x00,
                      0xff, 0x80, 0x00,
                      0xff, 0x40, 0x00,
                      0xff, 0x00, 0x00};
                         
// Actually send a bit to the string. We must to drop to asm to enusre that the complier does
// not reorder things and make it so the delay happens in the wrong place.
 
void sendBit( bool bitVal ) {
   
    if (  bitVal ) {        // 0 bit
       
    asm volatile (
      "sbi %[port], %[bit] \n\t"        // Set the output bit
      ".rept %[onCycles] \n\t"                                // Execute NOPs to delay exactly the specified number of cycles
      "nop \n\t"
      ".endr \n\t"
      "cbi %[port], %[bit] \n\t"                              // Clear the output bit
      ".rept %[offCycles] \n\t"                               // Execute NOPs to delay exactly the specified number of cycles
      "nop \n\t"
      ".endr \n\t"
      ::
      [port]    "I" (_SFR_IO_ADDR(PIXEL_PORT)),
      [bit]   "I" (PIXEL_BIT),
      [onCycles]  "I" (NS_TO_CYCLES(T1H) - 2),    // 1-bit width less overhead  for the actual bit setting, note that this delay could be longer and everything would still work
      [offCycles]   "I" (NS_TO_CYCLES(T1L) - 2)     // Minimum interbit delay. Note that we probably don't need this at all since the loop overhead will be enough, but here for correctness
 
    );
                                   
    } else {          // 1 bit
 
    // **************************************************************************
    // This line is really the only tight goldilocks timing in the whole program!
    // **************************************************************************
 
 
    asm volatile (
      "sbi %[port], %[bit] \n\t"        // Set the output bit
      ".rept %[onCycles] \n\t"        // Now timing actually matters. The 0-bit must be long enough to be detected but not too long or it will be a 1-bit
      "nop \n\t"                                              // Execute NOPs to delay exactly the specified number of cycles
      ".endr \n\t"
      "cbi %[port], %[bit] \n\t"                              // Clear the output bit
      ".rept %[offCycles] \n\t"                               // Execute NOPs to delay exactly the specified number of cycles
      "nop \n\t"
      ".endr \n\t"
      ::
      [port]    "I" (_SFR_IO_ADDR(PIXEL_PORT)),
      [bit]   "I" (PIXEL_BIT),
      [onCycles]  "I" (NS_TO_CYCLES(T0H) - 2),
      [offCycles] "I" (NS_TO_CYCLES(T0L) - 2)
 
    );
       
    }
     
    // Note that the inter-bit gap can be as long as you want as long as it doesn't exceed the 5us reset timeout (which is A long time)
    // Here I have been generous and not tried to squeeze the gap tight but instead erred on the side of lots of extra time.
    // This has thenice side effect of avoid glitches on very long strings becuase 
 
     
}  
 
   
void sendByte( uint8_t sByte ) {
     
    for( unsigned char bit = 0 ; bit < 8 ; bit++ ) {
       
      sendBit( bitRead( sByte , 7 ) );                // Neopixel wants bit in highest-to-lowest order
                                                      // so send highest bit (bit #7 in an 8-bit byte since they start at 0)
      sByte <<= 1;                                    // and then shift left so bit 6 moves into 7, 5 moves into 6, etc
       
    }           
} 
 
/*
  The following three functions are the public API:
   
  ledSetup() - set up the pin that is connected to the string. Call once at the begining of the program.  
  setBrightness(byte) - changes the brightness of the neopixels (0(low)->255(high))
  setMatrix(*byte, byte[]) - Converts a byte array of amplitudes into appropriate pixel orientation for matrix
  clear() - writes 0's to all pixels to clear the matrix
  show(*byte) - push updated pixel data to the matrix 
   
*/
 
 
/************ledSetup()******************/
/// Description: declare which i/o pin will be sending data
///              * Must be called prior to using neopixels
/// Parameters: NONE
/// Return: NONE
/****************************************/
void ledSetup() {
   
  bitSet( PIXEL_DDR , PIXEL_BIT );
   
}
 
/************setBrightness()******************/
/// Description: changes brightness of neopixels
///              * If not called, defaults to 255
/// Parameters: value - value between 0-255 to signify fraction of 100% brightness
/// Return: NONE
/*********************************************/
uint8_t Brightness = 255;
void setBrightness(uint8_t value)  {
  Brightness = value;
  return;
}
 
/************setMatrix()******************/
/// Description: Takes a NUM_COLS-long byte-array consisting of
///              amplitudes for each column of the matrix, and 
///              populates the pixels array accordingly
/// Parameters: Bars - byte array of new amplitudes
///             pixels - byte array that will hold data for each pixel
/// Return: NONE
/*****************************************/
void setMatrix(uint8_t * Bars, uint8_t pixels[])  {
  uint16_t k = 0;
  // Scan column by column populating each pixel row by row
  for(int i = 0; i < NUM_COLS; i++) {
    for(int j = 0; j <  NUM_ROWS; j++) {  // For even valued columns, scan from bottom to top of column
      if(j <= (uint8_t)Bars[i])  {        // If the row we are looking at is less than the amplitude in question
        pixels[k++] = Rainbow[j*3+1];     // then the neopixel should be active with the color found in the color lookup table above
        pixels[k++] = Rainbow[j*3];       // ******* Make sure that your values are in GRB format!!!! ********
        pixels[k++] = Rainbow[j*3+2];
      }
      else  {                             // If the current row is greater than the amplitude in question
        pixels[k++] = 0;                  // leave the pixel blank
        pixels[k++] = 0;
        pixels[k++] = 0;
      }
    }
    i++;                                  // Each loop will actually examine 2 columns rather than just one...
    for(int j = NUM_ROWS-1; j >= 0; j--) {// because odd valued columns were wired upside-down for convenience
      if(j <= (uint8_t)Bars[i])  {        // So rather than scanning bottom to top, scan top to bottom now
        pixels[k++] = Rainbow[j*3+1];     // since the pixels array will be fed into the neopixels serially
        pixels[k++] = Rainbow[j*3];       // you'll need this column to be placed backwards in the array...
        pixels[k++] = Rainbow[j*3+2];
      }
      else  {
        pixels[k++] = 0;
        pixels[k++] = 0;
        pixels[k++] = 0;
      }
    }
  }
   
  return;
}
 
/************Clear()*********************/
/// Description: Send all 0s to the matrix
/// Parameters: NONE
/// Return: NONE
/****************************************/
void Clear()  {
  cli();                                // Turn off all interrupts while we send data to the matrix
  for(int i = 0; i < PIXELS; i++) {
    sendByte(0);
    sendByte(0);
    sendByte(0);
  }
  sei();                                // All of the data is sent so we can turn back on interrupts
  // By sending creating a specifically timed delay, the neopixels will know that we are done sending data
  _delay_us( (RES / 1000UL) + 1);       // Round up since the delay must be _at_least_ this long (too short might not work, too long not a problem)
}
 
// Just wait long enough without sending any bits to cause the pixels to latch and display the last sent frame
 
/************show()******************/
/// Description: "Refresh" the neopixel matrix with
///               updated values 
///               * Should be called once the pixel array
///                 is updated and ready to be pushed
/// Parameters: pixels - the byte array containing values for all the pixels
/// Return: NONE
/************************************/
void show(uint8_t * pixels) {
  cli();                                              // Turn off all interrupts while we send new data
  for(int i = 0; i < PIXELS*3; i++) {
    if(pixels[i] != 0 && Brightness != 0)  {  
      sendByte(((Brightness * pixels[i]) >> 8) + 1);  // This is when we take pixel brightness into account
    }
    else  {
      sendByte(0);
    }
  }
  sei();                                              // All data is sent so we can turn interrupts back on
  // By sending creating a specifically timed delay, the neopixels will know that we are done sending data
  _delay_us( (RES / 1000UL) + 1);       // Round up since the delay must be _at_least_ this long (too short might not work, too long not a problem)
  return;
}

 

Изменено пользователем Mendex
Ссылка на комментарий
Поделиться на другие сайты

Реклама: ООО ТД Промэлектроника, ИНН: 6659197470, Тел: 8 (800) 1000-321

20% скидка на весь каталог электронных компонентов в ТМ Электроникс!

Акция "Лето ближе - цены ниже", успей сделать выгодные покупки!

Плюс весь апрель действует скидка 10% по промокоду APREL24 + 15% кэшбэк и бесплатная доставка!

Перейти на страницу акции

Реклама: ООО ТМ ЭЛЕКТРОНИКС, ИНН: 7806548420, info@tmelectronics.ru, +7(812)4094849

При использовании аппаратного SPI обмен с WS2812 получается гораздо проще и надежнее, чем при ассемблерном подсчете тактов и дрыгоногом. Не знаю, как с Ардуиной этот финт прокатит, но для отдельно взятого контроллера рекомендую именно аппаратный SPI.

Если забанить всех, кто набрался смелости думать независимо, здорово будет на форуме - как на кладбище: тишина, птички поют...

Ссылка на комментарий
Поделиться на другие сайты

Выбираем схему BMS для заряда литий-железофосфатных (LiFePO4) аккумуляторов

Обязательным условием долгой и стабильной работы Li-FePO4-аккумуляторов, в том числе и производства EVE Energy, является применение специализированных BMS-микросхем. Литий-железофосфатные АКБ отличаются такими характеристиками, как высокая многократность циклов заряда-разряда, безопасность, возможность быстрой зарядки, устойчивость к буферному режиму работы и приемлемая стоимость. Но для этих АКБ очень важен контроль процесса заряда и разряда для избегания воздействия внешнего зарядного напряжения после достижения 100% заряда. Инженеры КОМПЭЛ подготовили список таких решений от разных производителей. Подробнее>>

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

В 23.08.2017 в 22:06, Zahar сказал:

Я как раз сейчас работаю с этими ледями.
А что конкретно ты не понимаешь?

Как реализовать этот проект. Что куда подключить. Возможно лучше было бы использовать  какой нить shield. например тот же Spectrum Shield  который имеет вход и выход 3.5. 

Ссылка на комментарий
Поделиться на другие сайты

Могу посоветовать модуль WS2812B. Вот ссылка https://www.chipdip.ru/product/ws2812b.  По поводу проекта можете глянуть здесь: http://arduino.ru/projects/analizator-spektra-zvuka-na-arduino или здесь http://kazus.ru/forums/showthread.php?t=107805. Если будет полезно, поставьте "одобряю" (наведите на лайк и нажмите зелёную стрелку).

Ссылка на комментарий
Поделиться на другие сайты

  • 2 недели спустя...
В 28.08.2017 в 10:07, proffelec сказал:

Могу посоветовать модуль WS2812B. Вот ссылка https://www.chipdip.ru/product/ws2812b.  По поводу проекта можете глянуть здесь: http://arduino.ru/projects/analizator-spektra-zvuka-na-arduino или здесь http://kazus.ru/forums/showthread.php?t=107805. Если будет полезно, поставьте "одобряю" (наведите на лайк и нажмите зелёную стрелку).

Обыскал уже весь инет в поисках именно готового решения. Увы не нашёл. Именно на ленте из  WS2812 и собирался делать данный проект. 

Ссылка на комментарий
Поделиться на другие сайты

Только что, Mendex сказал:

Обыскал уже весь инет в поисках именно готового решения.

А что мне будет, если я вам сделаю готовое решение? ;) Только готовое - это прошил и работает, а не ардуиновский скетч...

Если забанить всех, кто набрался смелости думать независимо, здорово будет на форуме - как на кладбище: тишина, птички поют...

Ссылка на комментарий
Поделиться на другие сайты

Там вроде в трех файлах и так готовое решение если оно, конечно, вообще рабочее.

Как реализовать ? Ну это... соединить проводами детали, залить скетч, запустить processing с анализатором и убедиться что он по нужному serial-порту видит ардуину. Без компа это не работает если что... сам анализатор спектра на компе в processing, ардуина тут только мигает лампочками.

Изменено пользователем Morroc
Ссылка на комментарий
Поделиться на другие сайты

Только что, Morroc сказал:

Без компа это не работает если что...

Но можно сделать и без компа. Качество будет немножко похуже, но для мигалки вполне приемлемое.

Если забанить всех, кто набрался смелости думать независимо, здорово будет на форуме - как на кладбище: тишина, птички поют...

Ссылка на комментарий
Поделиться на другие сайты

9 часов назад, ARV сказал:

А что мне будет, если я вам сделаю готовое решение? ;) Только готовое - это прошил и работает, а не ардуиновский скетч...

Само готовое устройство меня не так сильно интересует, как возможность отредактировать код под свои нужды. Что то поменять, что то добавить в этом весь фетишь. К том же проект задумывался как "открытый" чтобы любой желающий мог повторить подобное чудо. Так как готов поспорить что желающих будет много. 

Ссылка на комментарий
Поделиться на другие сайты

36 минут назад, Mendex сказал:

Что то поменять, что то добавить в этом весь фетишь.

Ну дело-то вот в чем: я делаю свой проект, и он примерно на 99% пересекается с тем, что вы возжелали, а именно использует FFT-анализ для управления светодиодами WS2812. Я тоже не планирую делать секрет из своего кода, но до полного завершения работы публиковать не собираюсь. Поэтому если вам очень-очень надо, я могу доработать свой код под ваши хотелки и дать готовое решение, а потом, спустя какое-то время, вы наравне со всеми получите доступ к моим исходникам и сможете править их под свои нужды сколько угодно. Только я работаю с Си, а ардуиновские скетчи - это С++.

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

Вот это я и имел ввиду, предлагая свои услуги: надо быстро - заинтересуйте меня. Не надо - ждите...

Если забанить всех, кто набрался смелости думать независимо, здорово будет на форуме - как на кладбище: тишина, птички поют...

Ссылка на комментарий
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Ответить в этой теме...

×   Вставлено с форматированием.   Восстановить форматирование

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

Загрузка...
  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу
×
×
  • Создать...