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

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


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

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

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


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

При использовании аппаратного 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    327
Только что, Mendex сказал:

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

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

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


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

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

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

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

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


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

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

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

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


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

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

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

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


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

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

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

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

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

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


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

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

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

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

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

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

Войти

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

Войти сейчас


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

    • Автор: MolodoyElectrik
      Всем привет.
      Пишу скетч для ардуины, нужно чтоб 1 светодиод мигал постоянно, и 4 светодиода включались и выключались поочередно. Все должно происходить в одно время разумеется и Delay здесь не катит. Вот пример как должно быть только с delay:
       
      Сделал такой скетч:
      Тот который 1 светодиод мигает все хорошо, а вот с 4, которые должны подряд включаться какая то лажа) Где напортачил?
      Предыдущую тему не в том разделе создал, удалите пожалуйста. 
    • Гость izakom
      Автор: Гость izakom
      Добрый день,
      Никак не могу, подключить АЦП к микроконтроллеру. Будет здраво, если кто-нибудь сможет подсказать где моя ошибка или хотя бы где ее искать.
      Я подключаю ADS1240 к arduino UNO. Описание АЦП слишком тяжелое, поэтому прикрепляю ссылку
      http://www.ti.com/lit/ds/sbas173f/sbas173f.pdf
      Также во вложении прикрепил 2 схемы подключения, которые побывал.
      Контроллер общается с АЦП по SPI, где D10 -SS, D11 - MOSI, D12 - MISO, D13 - SCLK.

      Сейчас моя задача, измерять напряжение на потенциометре с достаточной точностью. 
      К сожалению внутренний АЦП arduino 10 разрядный, поэтому пытаюсь подключить внешний.

      Также прикрепляю программу, при помощи которой пытаюсь снимать показания. Но к сожалению на контроллер приходит только "0".
      Схема_2.pdf
      Схема_1.pdf
      Тестова программа.txt
      Схема_2.pdf
      Схема_1.pdf
      Тестова программа.txt
    • Гость Роман
      Автор: Гость Роман
      Собираю диммер с использованием микроконтроллера ардуино по следующей схеме:

      Оптрон использую МОС3020. Диммер не заработал. Начал проверять мультиметром:
      1. На J1 входе напряжение 220В
      2. На t1 и t2 ножках симистора напряжение 220В
      3. С PC814 с ножек 3 - 4 напряжение есть (1.2В - 1.8В), это уходит в ардуино
      4. С ардуино на МОС3020 на ножки 1 - 2 тоже напряжение подается (1.2В - 1.8В). А вот уже с 4 - 6 ножки оптрона МОС3020 напряжение снять не могу

      Схема должна быть рабочей, потому что другие люди по ней вроде как собирают устройство. Пайку проверил, вроде все нормально припаял.
      Собственно у меня ряд вопросов:
      1. Можно ли как-то проверить оптрон без выпайки? Или нужно выпаивать и проверять?
      2. Правильно ли я локализировал проблему или мой ход мыслей вообще неправильный?
      3. Как вообще правильно проверять такие схемы, если что-то не работает?
    • Автор: St.Vicarius
      Сил моих нет!
      Идея: нажимаю кнопку - сервопривод поворачивается и зажигаются 4 светодиода.
      Реализация: Arduino mini pro прошито скетчем и оно работает так как задумано, т.е. когда нажимаю кнопочку, то крутится сервопривод, но диоды не зажигаются, хотя скетч рабочий. Проблема скорее всего в светодиодной конструкции.
      Подозрения: Сама светодиодная конструкция собрана так 
      <img src="http://cxem.net/calc_img/ledcalc/3229b2097055972050d15a8ab2b30433.png?1522782146"><br><a href="http://cxem.net/calc/ledcalc.php">Расчёт резистора светодиода</a> И ко всему этому я подключил транзистор кт815г. На базу транзистора идет сигнал от Ардуино. Я думал, что этот сигнал заставит транзистор "открыться" и пропустить ток от кроны к которой эти диоды подключены. Но нет, светодиоды не горят почему то.
      Сама схема из светодиодов без транзистора рабочая.
      Вопрос: Что же я неправильно сделал? Первый раз имею дело с транзистором. 
  • Сообщения

    • Чем старше становлюсь, тем больше всё бесит!!! Я буду очень злой бабкой… .Возможно, даже куплю ружьё (c)
    •  Какого ответа еще можно было ожидать, наверное - только такого  Ключевое слово "угадать"  Классическая оговорка по Фрейду  Конечно не может. Более того ОМ вообще звучать не может (как и любой другой усилитель). Никак. Ни хорошо, ни плохо. Усилитель всего лишь усиливает электрический сигнал.  Зачем? Лично я уже знаю каков будет исход данного "сравнения" 
    • В том, то и дело, что никому ничего не должны. Прогрев зависит от тепловых токов.  То есть тепловые токи к полюсам меньше, чем к экватору. Причина - в термо-электрических-магнитных явлениях.
    • солнце греет поверхность, а потом нагревается воздух! все! и не надо нести чушь.
    • Слово "климат" имеет своё значение. 1. Ядро Земли создаёт тепловую статическую картину. 2. А перемещение воздушных масс создают "климат" - динамическую картину, то есть зиму и лето (если кратко). Для начала надо знать как работает закон Фурье. Вы этого не знаете. Отсюда все Ваши проблемы.   Судя по речи - излагает типичный чайник. Или попросту - провокатор. Никого не надо банить. С троллями у меня есть опыт общения. Голословно не надо утверждать. Ставьте опыт. Отчёт о нём пишите на форуме. Обсудим Ваши экспериментальные способности.
    • Меняя приведённое сопротивление Вы меняете наклон нагрузочной прямой.  Само собой будет меняться THD. Это даже без учёта искажений вносимых ТВЗ. Вот только одной и той де выходной мощности быть не может.   Вы либо не умеете её посчитать, либо вводите нас в заблуждение.  И потом получить с одной 2А3 4 ватта выходной мощности, это надо загнать её в достаточно тяжёлый режим. При её не очень демократичной цене это мягко говоря не самое мудрое решение. 
    • @LepekhinV А правильно ли проводилось сравнение? Лично я более менее правильное сравнение у себя проводил с ОМ2,5 и Холтоном - на слух разницы почти нет.  "Почему усилители звучат по-разному: сравнительное прослушивание усилителей" Я тут ОМ2,7 (2х80 вт, 4 ом) строю, в корпусе, двойное моно. Как доделаю - могу выслать грузовой компанией проверенному пользователю данного форума для адекватного и правильного сравнения   (бесплатно и естессно с возвратом :D)