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    463

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

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


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

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

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

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


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

Найдите миллионы труднодоступных

электронных компонентов

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    463
Только что, Mendex сказал:

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

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

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


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

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

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

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

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


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

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

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

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


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

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

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

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


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

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

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

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

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

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


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

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

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

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

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

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

Войти

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

Войти сейчас


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

    • Автор: ренат07
      помогите дописать программу
      в долгу не останусь естественно 
      взял текст программы для управления ШГ и интернета 
      все работает красиво 
      но мне нужно что бы работало ни всегда, а при определённых условиях 
      то есть что бы "кнопкой" включения бодр определённое положение реостата 
      подскажите пожалуйста 
      спасибо большое 
    • Автор: ренат07
      у меня есть такой мини проект по вентиляции автомобиля 
      Короче, есть шаговый двигатель установленный регулировки заслонки воздушного дефлектора
      основа программы для шагового двигателя была взята с интернета
      так вот, в самом авто есть электронная заслонка печки отвечающая за направление потока воздуха и для определения положения заслонки блоком управления, внутри заслонки стоит простой реостат
       так вот в чем вопрос как сделать чтобы программа управления ШГ запускалась при про определенном напряжении с реостата ? 
      помогите пожалуйста, постораюсь не остаться в долгу  
    • Автор: Dandan He
      Здравствуйте, Уважаемые форумчане!
      TOMTOP – интернет-магазин, специализирующийся на продажах товаров китайского производства. Магазин TOMTOP не является новичком на рынке – он был основан ещё в 2004 году. К 2017 году портал завоевал репутацию заботливого и ответственного торговца высококачественной продукции, а также получил признание такого «гиганта» продаж, как Alibaba. В 2006 году Alibaba пожаловала продавцу TOMTOP статус «золотого поставщика» — очень почётный для азиатского рынка.
      Доступные способы оплаты
      Российским покупателям магазин TOMTOP даёт возможность оплачивать товары множеством способов:
      С банковских карт Visa и MasterCard. Оплата происходит через защищённый сервер платежей Alipay – риск того, что деньги попадут к мошенникам и не дойдут до продавца, сведён к нулю.
      Посредством PayPal. Именно этот способ оплаты считается наиболее безопасным — покупатель, прибегнувший к услугам PayPal, может быть уверен: если он вдруг станет жертвой мошенников, ему вернут деньги. Однако сервис PayPal неудобен для оплаты дорогостоящих товаров — если сумма единовременного платежа превосходит 1000 $, платёж наверняка будет задержан на несколько дней для проверки транзакции.
      С электронных кошельков. TOMTOP ведёт сотрудничество с 3-мя ведущими отечественными платёжными системами – QIWI, Яндекс.Деньги, WebMoney. Комиссия при оплате с кошельков перечисленных систем не берётся.
      Доставка товара
      Покупатель вправе выбрать один из 2-х способов доставки: почтовая (дёшево и сердито) или экспресс (для тех, кому срочно). Доставка посредством авиапочты является бесплатной – в этом плане магазин TOMTOP «заткнул за пояс» даже площадку AliExpress, которая в 2017 году за пересылку многих товаров в Россию стала требовать деньги.
      Стоимость экспресс-доставки зависит от того, какого рода товар и с какого склада он отправляется. За быструю доставку гаджета с китайского склада покупателю придётся заплатить порядка 4 тыс. рублей. Экспресс-доставка смартфона / планшета со склада, размещённого в России, обойдётся примерно в 1 тыс. рублей. Если речь идёт о каком-либо мелком и дешёвом товаре (например, о светодиодной Wi-Fi лампочке), экспресс-доставка с отечественного склада может оказаться бесплатной.
       
      Основной сайт: https://www.tomtop.com/
      Служба поддержки: service@tomtop.com
      ПАРТНЕРСКАЯ ПРОГРАММА : https://www.tomtop.com/help/affiliate-program.html
      Как присоединиться к нашей партнерской программе?
      Выберите партнерские сети и зарегистрируйтесь как партнер или издатель.
      Найдите идентификатор программы Tomtop.
      Подать заявку, чтобы присоединиться к нам и ждать нашего одобрения.
      Получите наши ссылки для продвижения и просмотра комиссионных.

    • Автор: Alexander1997
      Доброго времени суток. Понадобилось сделать несложное меню.  Меню построено следующим образом - имеется главный пункт и 4 подпункта. Попасть в нужный подпункт можно только через главное меню. Вот примерный вид главного меню.

      Блок схема меню

       
      Конструкция кода
      typedef struct { uint8_t menu;// uint8_t submenu;// MAIN_MENU, MENU_MANUAL, MENU_AUTO, MENU_SETUP, MENU_START }menuItem; typedef struct Selection { unsigned char id; //Номер меню/подменю unsigned char ent_f : 4; //Флаг входа в подменю unsigned char esc_f : 4; //Флаг выхода из подменю }SL; enum switchVariants : byte { // Определения для переключателя пунктов меню; MAIN_MENU, MENU_MANUAL, MENU_AUTO, MENU_SETUP, MENU_START }; switchVariants switchPointer = MAIN_MENU; // С чего начнем цикл int main (void) { while(1) { } } Посоветуйте как организовать вход и выход из меню? Для этого завел два флага ent и esc. Но как их связать голову ломаю.
    • Автор: Yon
      Нарыл код в нете для FM радио на Ардуино на базе EM5807M.  Залил это дело в Atmega8, все заработало, сделал простой выбор стаций.
      А кто знает как управлять програмно громкостью, басами, стерео/моно  и др. Используемая часть кода ниже.