极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 19930|回复: 6

arduino读取音频信号实时显示在8*8点阵上

[复制链接]
发表于 2015-3-24 11:16:59 | 显示全部楼层 |阅读模式
      论坛很多朋友都玩过8*8的双色led点阵,如果加个麦克风模块在一起会有什么效果呢?
用麦克风实现对音频信号的采集,进行傅里叶变换,实时显示在iic点阵屏上。
      这里需要用到几个库,其中fft就是快速傅里叶变换(Fast Fourier Transform),是离散傅里叶变换的快速算法,也可用于计算离散傅里叶变换的逆变换,有广泛的应用,如频谱分析、滤波器设计、以及音频数据压缩等。

1.所需要的原件
  ocrobot mango 一块
  ocrobot microphone 模块 一个
  OCROBOT 红绿双色 I2C点阵模块 一个
  杜邦线 9根
  面包板 一块
  usb线一根


2.需要用到的库
Adafruit_GFX
Adafruit_LEDBackpack
fft
将这三个库下载好,解压放在libraries目录下


3.接线
麦克风
vcc - 3.3v
gnd -gnd
out - A0


8*8点阵
scl - scl
sda - sda  
vcc - 5v
gnd - gnd

mango板
3.3v - aref




4.代码

  1. /*
  2. PICCOLO is a tiny Arduino-based audio visualizer.

  3. Hardware requirements:
  4. - Most Arduino or Arduino-compatible boards (ATmega 328P or better).
  5. - Adafruit Bicolor LED Matrix with I2C Backpack (ID: 902)
  6. - Adafruit Electret Microphone Amplifier (ID: 1063)
  7. - Optional: battery for portable use (else power through USB)
  8. Software requirements:
  9. - elm-chan's ffft library for Arduino

  10. Connections:
  11. - 3.3V to mic amp+ and Arduino AREF pin <-- important!
  12. - GND to mic amp-
  13. - Analog pin 0 to mic amp output
  14. - +5V, GND, SDA (or analog 4) and SCL (analog 5) to I2C Matrix backpack

  15. Written by Adafruit Industries.  Distributed under the BSD license --
  16. see license.txt for more information.  This paragraph must be included
  17. in any redistribution.

  18. ffft library is provided under its own terms -- see ffft.S for specifics.
  19. */

  20. // IMPORTANT: FFT_N should be #defined as 128 in ffft.h.

  21. #include <avr/pgmspace.h>
  22. #include <ffft.h>
  23. #include <math.h>
  24. #include <Wire.h>
  25. #include <Adafruit_GFX.h>
  26. #include <Adafruit_LEDBackpack.h>

  27. // Microphone connects to Analog Pin 0.  Corresponding ADC channel number
  28. // varies among boards...it's ADC0 on Uno and Mega, ADC7 on Leonardo.
  29. // Other boards may require different settings; refer to datasheet.
  30. #ifdef __AVR_ATmega32U4__
  31. #define ADC_CHANNEL 7
  32. #else
  33. #define ADC_CHANNEL 0
  34. #endif

  35. int16_t       capture[FFT_N];    // Audio capture buffer
  36. complex_t     bfly_buff[FFT_N];  // FFT "butterfly" buffer
  37. uint16_t      spectrum[FFT_N/2]; // Spectrum output buffer
  38. volatile byte samplePos = 0;     // Buffer position counter

  39. byte
  40.   peak[8],      // Peak level of each column; used for falling dots
  41.   dotCount = 0, // Frame counter for delaying dot-falling speed
  42.   colCount = 0; // Frame counter for storing past column data
  43. int
  44.   col[8][10],   // Column levels for the prior 10 frames
  45.   minLvlAvg[8], // For dynamic adjustment of low & high ends of graph,
  46.   maxLvlAvg[8], // pseudo rolling averages for the prior few frames.
  47.   colDiv[8];    // Used when filtering FFT output to 8 columns

  48. /*
  49. These tables were arrived at through testing, modeling and trial and error,
  50. exposing the unit to assorted music and sounds.  But there's no One Perfect
  51. EQ Setting to Rule Them All, and the graph may respond better to some
  52. inputs than others.  The software works at making the graph interesting,
  53. but some columns will always be less lively than others, especially
  54. comparing live speech against ambient music of varying genres.
  55. */
  56. static const uint8_t PROGMEM
  57.   // This is low-level noise that's subtracted from each FFT output column:
  58.   noise[64]={ 8,6,6,5,3,4,4,4,3,4,4,3,2,3,3,4,
  59.               2,1,2,1,3,2,3,2,1,2,3,1,2,3,4,4,
  60.               3,2,2,2,2,2,2,1,3,2,2,2,2,2,2,2,
  61.               2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,4 },
  62.   // These are scaling quotients for each FFT output column, sort of a
  63.   // graphic EQ in reverse.  Most music is pretty heavy at the bass end.
  64.   eq[64]={
  65.     255, 175,218,225,220,198,147, 99, 68, 47, 33, 22, 14,  8,  4,  2,
  66.       0,   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  67.       0,   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  68.       0,   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 },
  69.   // When filtering down to 8 columns, these tables contain indexes
  70.   // and weightings of the FFT spectrum output values to use.  Not all
  71.   // buckets are used -- the bottom-most and several at the top are
  72.   // either noisy or out of range or generally not good for a graph.
  73.   col0data[] = {  2,  1,  // # of spectrum bins to merge, index of first
  74.     111,   8 },           // Weights for each bin
  75.   col1data[] = {  4,  1,  // 4 bins, starting at index 1
  76.      19, 186,  38,   2 }, // Weights for 4 bins.  Got it now?
  77.   col2data[] = {  5,  2,
  78.      11, 156, 118,  16,   1 },
  79.   col3data[] = {  8,  3,
  80.       5,  55, 165, 164,  71,  18,   4,   1 },
  81.   col4data[] = { 11,  5,
  82.       3,  24,  89, 169, 178, 118,  54,  20,   6,   2,   1 },
  83.   col5data[] = { 17,  7,
  84.       2,   9,  29,  70, 125, 172, 185, 162, 118, 74,
  85.      41,  21,  10,   5,   2,   1,   1 },
  86.   col6data[] = { 25, 11,
  87.       1,   4,  11,  25,  49,  83, 121, 156, 180, 185,
  88.     174, 149, 118,  87,  60,  40,  25,  16,  10,   6,
  89.       4,   2,   1,   1,   1 },
  90.   col7data[] = { 37, 16,
  91.       1,   2,   5,  10,  18,  30,  46,  67,  92, 118,
  92.     143, 164, 179, 185, 184, 174, 158, 139, 118,  97,
  93.      77,  60,  45,  34,  25,  18,  13,   9,   7,   5,
  94.       3,   2,   2,   1,   1,   1,   1 },
  95.   // And then this points to the start of the data for each of the columns:
  96.   * const colData[]  = {
  97.     col0data, col1data, col2data, col3data,
  98.     col4data, col5data, col6data, col7data };

  99. Adafruit_BicolorMatrix matrix = Adafruit_BicolorMatrix();

  100. void setup() {
  101.   uint8_t i, j, nBins, binNum, *data;

  102.   memset(peak, 0, sizeof(peak));
  103.   memset(col , 0, sizeof(col));

  104.   for(i=0; i<8; i++) {
  105.     minLvlAvg[i] = 0;
  106.     maxLvlAvg[i] = 512;
  107.     data         = (uint8_t *)pgm_read_word(&colData[i]);
  108.     nBins        = pgm_read_byte(&data[0]) + 2;
  109.     binNum       = pgm_read_byte(&data[1]);
  110.     for(colDiv[i]=0, j=2; j<nBins; j++)
  111.       colDiv[i] += pgm_read_byte(&data[j]);
  112.   }

  113.   matrix.begin(0x70);

  114.   // Init ADC free-run mode; f = ( 16MHz/prescaler ) / 13 cycles/conversion
  115.   ADMUX  = ADC_CHANNEL; // Channel sel, right-adj, use AREF pin
  116.   ADCSRA = _BV(ADEN)  | // ADC enable
  117.            _BV(ADSC)  | // ADC start
  118.            _BV(ADATE) | // Auto trigger
  119.            _BV(ADIE)  | // Interrupt enable
  120.            _BV(ADPS2) | _BV(ADPS1) | _BV(ADPS0); // 128:1 / 13 = 9615 Hz
  121.   ADCSRB = 0;                // Free run mode, no high MUX bit
  122.   DIDR0  = 1 << ADC_CHANNEL; // Turn off digital input for ADC pin
  123.   TIMSK0 = 0;                // Timer0 off

  124.   sei(); // Enable interrupts
  125. }

  126. void loop() {
  127.   matrix.setRotation(3);
  128.   uint8_t  i, x, L, *data, nBins, binNum, weighting, c;
  129.   uint16_t minLvl, maxLvl;
  130.   int      level, y, sum;

  131.   while(ADCSRA & _BV(ADIE)); // Wait for audio sampling to finish

  132.   fft_input(capture, bfly_buff);   // Samples -> complex #s
  133.   samplePos = 0;                   // Reset sample counter
  134.   ADCSRA |= _BV(ADIE);             // Resume sampling interrupt
  135.   fft_execute(bfly_buff);          // Process complex data
  136.   fft_output(bfly_buff, spectrum); // Complex -> spectrum

  137.   // Remove noise and apply EQ levels
  138.   for(x=0; x<FFT_N/2; x++) {
  139.     L = pgm_read_byte(&noise[x]);
  140.     spectrum[x] = (spectrum[x] <= L) ? 0 :
  141.       (((spectrum[x] - L) * (256L - pgm_read_byte(&eq[x]))) >> 8);
  142.   }

  143.   // Fill background w/colors, then idle parts of columns will erase
  144.   matrix.fillRect(0, 0, 8, 3, LED_RED);    // Upper section
  145.   matrix.fillRect(0, 3, 8, 2, LED_YELLOW); // Mid
  146.   matrix.fillRect(0, 5, 8, 3, LED_GREEN);  // Lower section

  147.   // Downsample spectrum output to 8 columns:
  148.   for(x=0; x<8; x++) {
  149.     data   = (uint8_t *)pgm_read_word(&colData[x]);
  150.     nBins  = pgm_read_byte(&data[0]) + 2;
  151.     binNum = pgm_read_byte(&data[1]);
  152.     for(sum=0, i=2; i<nBins; i++)
  153.       sum += spectrum[binNum++] * pgm_read_byte(&data[i]); // Weighted
  154.     col[x][colCount] = sum / colDiv[x];                    // Average
  155.     minLvl = maxLvl = col[x][0];
  156.     for(i=1; i<10; i++) { // Get range of prior 10 frames
  157.       if(col[x][i] < minLvl)      minLvl = col[x][i];
  158.       else if(col[x][i] > maxLvl) maxLvl = col[x][i];
  159.     }
  160.     // minLvl and maxLvl indicate the extents of the FFT output, used
  161.     // for vertically scaling the output graph (so it looks interesting
  162.     // regardless of volume level).  If they're too close together though
  163.     // (e.g. at very low volume levels) the graph becomes super coarse
  164.     // and 'jumpy'...so keep some minimum distance between them (this
  165.     // also lets the graph go to zero when no sound is playing):
  166.     if((maxLvl - minLvl) < 8) maxLvl = minLvl + 8;
  167.     minLvlAvg[x] = (minLvlAvg[x] * 7 + minLvl) >> 3; // Dampen min/max levels
  168.     maxLvlAvg[x] = (maxLvlAvg[x] * 7 + maxLvl) >> 3; // (fake rolling average)

  169.     // Second fixed-point scale based on dynamic min/max levels:
  170.     level = 10L * (col[x][colCount] - minLvlAvg[x]) /
  171.       (long)(maxLvlAvg[x] - minLvlAvg[x]);

  172.     // Clip output and convert to byte:
  173.     if(level < 0L)      c = 0;
  174.     else if(level > 10) c = 10; // Allow dot to go a couple pixels off top
  175.     else                c = (uint8_t)level;

  176.     if(c > peak[x]) peak[x] = c; // Keep dot on top

  177.     if(peak[x] <= 0) { // Empty column?
  178.       matrix.drawLine(x, 0, x, 7, LED_OFF);
  179.       continue;
  180.     } else if(c < 8) { // Partial column?
  181.       matrix.drawLine(x, 0, x, 7 - c, LED_OFF);
  182.     }

  183.     // The 'peak' dot color varies, but doesn't necessarily match
  184.     // the three screen regions...yellow has a little extra influence.
  185.     y = 8 - peak[x];
  186.     if(y < 2)      matrix.drawPixel(x, y, LED_RED);
  187.     else if(y < 6) matrix.drawPixel(x, y, LED_YELLOW);
  188.     else           matrix.drawPixel(x, y, LED_GREEN);
  189.   }

  190.   matrix.writeDisplay();

  191.   // Every third frame, make the peak pixels drop by 1:
  192.   if(++dotCount >= 3) {
  193.     dotCount = 0;
  194.     for(x=0; x<8; x++) {
  195.       if(peak[x] > 0) peak[x]--;
  196.     }
  197.   }

  198.   if(++colCount >= 10) colCount = 0;
  199. }

  200. ISR(ADC_vect) { // Audio-sampling interrupt
  201.   static const int16_t noiseThreshold = 4;
  202.   int16_t              sample         = ADC; // 0-1023

  203.   capture[samplePos] =
  204.     ((sample > (512-noiseThreshold)) &&
  205.      (sample < (512+noiseThreshold))) ? 0 :
  206.     sample - 512; // Sign-convert for FFT; -512 to +511

  207.   if(++samplePos >= FFT_N) ADCSRA &= ~_BV(ADIE); // Buffer full, interrupt off
  208. }
复制代码



5.效果





本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复

使用道具 举报

发表于 2015-4-3 15:12:02 | 显示全部楼层
感觉好给力~~~~~~~~
回复 支持 反对

使用道具 举报

发表于 2016-4-19 23:26:23 | 显示全部楼层
我都用的是ocrobot mega328-u开发板,用了上面的程序灯全部都亮了,但是它的音频效果是是相反的,高音的时候就灯降下去。请问一下怎么改能让它不要全部的灯亮,还有音频效果不要相反呢
回复 支持 反对

使用道具 举报

发表于 2016-4-20 11:27:31 | 显示全部楼层
哇,这个棒,回头仿制下!
回复 支持 反对

使用道具 举报

发表于 2016-8-24 13:59:47 | 显示全部楼层
下载是出现错误,不知道什么原因,用的UNO3的板子
回复 支持 反对

使用道具 举报

发表于 2016-8-24 14:02:05 | 显示全部楼层
FFT_N was not declared in this scope
回复 支持 反对

使用道具 举报

发表于 2016-8-24 14:15:46 | 显示全部楼层
解决了,原来是电脑里版本装的太多
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则 需要先绑定手机号

Archiver|联系我们|极客工坊

GMT+8, 2024-4-26 09:18 , Processed in 0.047150 second(s), 26 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表