Mendex

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

12 сообщений в этой теме

Mendex    0

В общем ребят тема такая. Хотелось бы сделать многополосный анализатор спектра на ленте 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

Поделиться сообщением


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

Быстрый заказ печатных плат

Полный цикл производства PCB по низким ценам!

  • x
    мм
Заказать Получить купон на $5.00
Zahar    14

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
ARV    278

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Mendex    0
В 23.08.2017 в 22:06, Zahar сказал:

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
proffelec    2

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Mendex    0
В 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 и собирался делать данный проект. 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
ARV    278
Только что, Mendex сказал:

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Morroc    3

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

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

Изменено пользователем Morroc

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
ARV    278
Только что, Morroc сказал:

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Mendex    0
9 часов назад, ARV сказал:

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
ARV    278
36 минут назад, Mendex сказал:

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

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

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

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

Поделиться сообщением


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

Создайте аккаунт или войдите в него для комментирования

Вы должны быть пользователем, чтобы оставить комментарий

Создать аккаунт

Зарегистрируйтесь для получения аккаунта. Это просто!

Зарегистрировать аккаунт

Войти

Уже зарегистрированы? Войдите здесь.

Войти сейчас


  • Похожие публикации

    • Автор: MDobroch
      Доброго времени суток уважаемые форумчане!
      Обращаюсь по такому вопросу, собираю схему генератора звука на Arduino основываясь на следующей статье : http://www.instructables.com/id/Arduino-Audio-Output/
      Данная схема призвана сформировать синусоидальный сигнал определенной частоты используя 8 цифровых выходов Ардуино,  Собранном на резисторах ЦАП, фильтре и паре операционных усилителей. К сожалению в данной теме указано, что качество сигнала при использовании резисторов намного ниже чем при использовании 8 битного ЦАПа в формате готовой микросхемы. Также данное решение разрабатывалось для работы с 1 частотой. 
      Техническое задание :
      Необходима схема, работающая на двух частотах. Стабильность частоты, ровно как и качество сигнала на выходе -  крайне важны !!!   Потребителем данного сигнала будут 2 телефона подключенные к этому "генератору" посредством двух аудио кабелей. 
      Проблема:
      К сожалению я не сильно опытен в схемотехнике - являюсь программистом. Но данное решение необходимо разработать для одного проекта.
      Вопрос:
      1) Как по вашему мнение усложнится схема, для выполнения технического задания описанного выше?
      2) Какие компоненты необходимо добавить в схему? (Какую модель ЦАП нужно выбрать?)  
      3) Возможна ли вообще выдача стабильной частоты на 2 телефона при помощи ардуино или лучше выбрать для реализации данного задания другую платформу?
      4) Возможно среди форумчан есть желающие разработать подобное решение за не разумное материальное вознаграждение? Данный вариант тоже можем обсудить. 
       
      Благодарю за ответы и желаю хорошего дня!
    • Автор: Whitefoot
      Добрый день. Собрал лазерный сигнализатор задевания сетки для игры в пинг-понг теперь хочу пойти дальше и сделать дисплей для вывода счета. Иначе приходится считать все самому, а если кто-нибудь придет и отвлечет, так счет сразу из головы вылетает. Хочу сделать все как можно проще, но при этом чтобы не было примитивно. У меня есть запысы плат Arduino Nano V3 328 16M 5V CH340G, которые я как-то по распродаже заказывал из китая, потому хочу использовать одну и приделать к ней дисплей. Пока думаю в двух направляниях. 1й - купить где-нибудь на авито сломаный планшет с целым экраном, достать дисплейный модуль и переделать его для работы с ардуиной. 2й - собрать из всетодиодов большой экран на 4 цифры, каждая цифра по 7 сегментов. Вопрос у меня по второму варианту. Подскажите пожалуйста схемы подобных дисплеев. Еще желательно чтобы упраление шло по I2C интерфейсу, чтобы кучу выводов не задйствовать, но можно и более примитивно. Спасибо.
    • Автор: draco
      помогите, пожалуйста, решить мою проблему:
      имеется arduino mega2560 (китайская)
      после приобретения я работал только с цифровыми входами
       
      сегодня решил сделать dc вольтметр, пришлось задействовать аналоговый вход
      в процессе отладки выяснил, что на всех входах (проверял в цикле) постоянно значение 1023 (или 5v в зависимости от интерпретации кода) и при подаче напряжения и без
      тестовое напряжение никогда не превышало 5в
       
      что с платой, или что я делаю не так?
    • Автор: winice
      Подскажите как можно сделать программку на андроид для обмена данными с контроллером?
      Например дергать выводами arduino со смарта по wi-fi (само собой через соответствующий шилд) 
      Накидать кнопок ползунков... и задать им соответствие каким-то байтам в памяти контроллера. 
      С разработкой на андроид связываться не хочется)))
    • Автор: megauserr895877
      Добрый день уважаемые!
      хотелось бы вашего совета по блоку питания!
      Суть проблемы такова, имеется прибор на Arduino с 3 датчиками и несколькими кнопками (если быть совсем честным и точным это контроллер джойстика). У большинства народа и у меня в частности этот прибор имеет нестабильности в работе датчиков, так как собственного питания ардуины на датчики хватает с некоторым натягом и более того, склонен я думать что питание ардуины от USB имеет "некоторые" проблемы с помехами и скачками питания- отчего возникают шумы в показаниях. Решение проблемы я вижу в 3 вариантах: 1 шумы датчиков, 2 шумы контроллера, 3 шумы источника питания. Не вдаваясь, пока что, в первые две, хочу решить 3 проблему.
      Моя цель собрать или купить готовый блок, модуль или комплектующие и собрать сетевой(желательно безтрансформаторный-трудно добыть, еще сложней перемотать) качественный блок питания с стабилизированным DC напряжением 5 V на небольшую мощность- 200-500 mA
      Возможно я параноик и питание ардуины стабильно и все "затыки" в первых 2 моментах,
      возможно для датчиков хватит стандартного ардуиновского внешнего подключаемого питалова...
      возможно блок питания от мобилки с лихвой заменит по качеству и всему прочему большинство самоделок,
      возможно и  взять какой нить 9 вольтовый зарядник и стабилизировать его какой нибудь 7805 или AMS1117( но 7805 это печка а не стаб- у меня батарея есть квартиру греть, а 1117 какие то подозрительные милипусичные и обвязка на смд меня смущает- будет ли оно ловить внешние помехи и отдавать их в выходное напряжение да и смысл, если они же в ардуиновской питалке стоят?)
      но я же параноик... и потому прошу совета Отцов:
      пару схемок:
      одну простую и надежную как автомат Михаила Тимофеевича
      и вторую что-нить экстравагантно шизофреничное а ля золотые транзисторы навесным монтажом в корпусе оклеенном серебряными пулями крестами, чесноком и святой водой, с наклейкой HighEnd и обмотанное кабелем ODIN или Sommer
      Ну или валенков, что суету попусту развел , вот только в гугл не отправляйте, видели там-знаем