Captação de Frequência
Autor: Física Experimental - Arduino | Publicado: 2012-05-08T06:38:00-07:00

Para fazermos a captação de frequência, usamos um código já disponível no blog&nbsp;http://labduino.blogspot.com.br/search/label/FFT%20com%20o%20Arduino, lá você encontrará uma pasta zipada com dois códigos e uma biblioteca e um slide mostrando sua utilização.
Além do arduino, também foi usado o programa Processing para exibir as frequências captadas:






Códigos usados para o experimento:



Processing:





// Feel Free to edit these variables ///////////////////////////

String &nbsp;xLabel = "Frequency";

String &nbsp;yLabel = "Values";

String &nbsp;Heading = "Arduino FFT";

String &nbsp;URL = "01/02/2010";

float Vcc = 255.0; &nbsp; &nbsp;// the measured voltage of your usb&nbsp;

int NumOfVertDivisions=5; &nbsp; &nbsp; &nbsp;// dark gray

int NumOfVertSubDivisions=10; &nbsp;// light gray



int NumOfBars=64; &nbsp; &nbsp;// you can choose the number of bars, but it can cause issues &nbsp;

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // since you should change what the arduino sends

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;

// if these are changed, backgroung image has problems&nbsp;

// a plain background solves the problem

int ScreenWidth = 800, ScreenHeight=600;

/////////////////////////////////////////////////////////



// &nbsp;Serial port stuff ///////////////////////

import processing.serial.*;

Serial myPort; &nbsp; &nbsp; &nbsp; &nbsp;

boolean firstContact = false;&nbsp;

int[] serialInArray = new int[NumOfBars];

int serialCount = 0;

///////////////////////////////////////////////



int LeftMargin=100;

int RightMArgin=80;

int TextGap=50;

int GraphYposition=80;&nbsp;

float BarPercent = 0.4;



int value;



PFont font;

PImage bg;



int temp;

float yRatio = 0.58;

int BarGap, BarWidth, DivisounsWidth;

int[] bars = new int[NumOfBars];



void setup(){



&nbsp; bg = loadImage("BG.jpg");&nbsp;



&nbsp; /// NB SETTINGS ////////////////////////////////////////////////////////

&nbsp; myPort = new Serial(this, "COM10", 57600);&nbsp;

&nbsp; ////////////////////////////////////////////////////////////////////////



&nbsp; DivisounsWidth = (ScreenWidth-LeftMargin-RightMArgin)/(NumOfBars);&nbsp;

&nbsp; BarWidth = int(BarPercent*float(DivisounsWidth));

&nbsp; BarGap = DivisounsWidth - BarWidth;



&nbsp; size(ScreenWidth,ScreenHeight);

&nbsp; font = createFont("Arial",12);



&nbsp; textAlign(CENTER);

&nbsp; textFont(font);

}



void draw(){



// &nbsp;background(bg); &nbsp; &nbsp; // My one used a background image, I've&nbsp;

&nbsp; background(250); &nbsp; &nbsp; &nbsp;// commented it out and put a plain colour&nbsp;



&nbsp; // &nbsp;Headings(); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Displays bar width, Bar gap or any variable.&nbsp;

&nbsp; Axis();

&nbsp; Labels();

&nbsp; PrintBars();

// &nbsp;Line();

// &nbsp;Dots();&nbsp;

}



// Send Recieve data //

void serialEvent(Serial myPort) {



&nbsp; // read a byte from the serial port:

&nbsp; int inByte = myPort.read();



&nbsp; if (firstContact == false) {

&nbsp; &nbsp; if (inByte == 'A') {&nbsp;

&nbsp; &nbsp; &nbsp; myPort.clear(); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// clear the serial port buffer

&nbsp; &nbsp; &nbsp; firstContact = true; &nbsp; &nbsp; // you've had first contact from the microcontroller

&nbsp; &nbsp; &nbsp; myPort.write('A'); &nbsp; &nbsp; &nbsp; // ask for more

&nbsp; &nbsp; }&nbsp;

&nbsp; }&nbsp;

&nbsp; else {

&nbsp; &nbsp; // Add the latest byte from the serial port to array:

&nbsp; &nbsp; serialInArray[serialCount] = inByte;

&nbsp; &nbsp; serialCount++;



&nbsp; &nbsp; // If we have 6 bytes:

&nbsp; &nbsp; if (serialCount &gt; NumOfBars -1 ) {



for (int x=0;x&lt;NumOfBars;x++){

&nbsp; &nbsp;&nbsp;

&nbsp; bars[x] = int (yRatio*(ScreenHeight)*(serialInArray[x]/256.0));



}



&nbsp; &nbsp; &nbsp; // Send a capital A to request new sensor readings:

&nbsp; &nbsp; &nbsp; myPort.write('A');

&nbsp; &nbsp; &nbsp; // Reset serialCount:

&nbsp; &nbsp; &nbsp; serialCount = 0;

&nbsp; &nbsp; }

&nbsp; }

}



/////// Display any variables for testing here//////////////

void Headings(){

&nbsp; fill(0 );

&nbsp; text("BarWidth",50,TextGap ); &nbsp;&nbsp;

&nbsp; text("BarGap",250,TextGap ); &nbsp;

&nbsp; text("DivisounsWidth",450,TextGap );

&nbsp; text(BarWidth,100,TextGap ); &nbsp; &nbsp;

&nbsp; text(BarGap,300,TextGap ); &nbsp; &nbsp;

&nbsp; text(DivisounsWidth,520,TextGap );

}



void PrintBars(){&nbsp;



&nbsp; int c=0;

&nbsp; for (int i=0;i&lt;NumOfBars;i++){

&nbsp; &nbsp;

&nbsp; &nbsp; fill((0xe4+c),(255-bars[i]+c),(0x1a+c));

&nbsp; &nbsp; stroke(90);

&nbsp; &nbsp; rect(i*DivisounsWidth+LeftMargin, &nbsp; ScreenHeight-GraphYposition, &nbsp; BarWidth, &nbsp; -bars[i]);

&nbsp; &nbsp; fill(0x2e,0x2a,0x2a);

// &nbsp; &nbsp;text(float(bars[i])/(yRatio*(ScreenHeight))*Vcc, &nbsp; i*DivisounsWidth+LeftMargin+BarWidth/2, &nbsp; ScreenHeight-bars[i]-5-GraphYposition );

// &nbsp; &nbsp;text("A", &nbsp; i*DivisounsWidth+LeftMargin+BarWidth/2 -5, &nbsp; ScreenHeight-GraphYposition+20 );

// &nbsp; &nbsp;text(i, &nbsp; i*DivisounsWidth+LeftMargin+BarWidth/2 +5, &nbsp; ScreenHeight-GraphYposition+20 );

&nbsp; }

}



void Axis(){



&nbsp; strokeWeight(1);

&nbsp; stroke(220);

&nbsp; for(float x=0;x&lt;=NumOfVertSubDivisions;x++){



&nbsp; &nbsp; int bars=(ScreenHeight-GraphYposition)-int(yRatio*(ScreenHeight)*(x/NumOfVertSubDivisions));

&nbsp; &nbsp; line(LeftMargin-15,bars,ScreenWidth-RightMArgin-DivisounsWidth+50,bars);

&nbsp; }

&nbsp; strokeWeight(1);

&nbsp; stroke(180);

&nbsp; for(float x=0;x&lt;=NumOfVertDivisions;x++){



&nbsp; &nbsp; int bars=(ScreenHeight-GraphYposition)-int(yRatio*(ScreenHeight)*(x/NumOfVertDivisions));

&nbsp; &nbsp; line(LeftMargin-15,bars,ScreenWidth-RightMArgin-DivisounsWidth+50,bars);

&nbsp; }

&nbsp; strokeWeight(2);

&nbsp; stroke(90);

&nbsp; line(LeftMargin-15, ScreenHeight-GraphYposition+2, ScreenWidth-RightMArgin-DivisounsWidth+50, ScreenHeight-GraphYposition+2);

&nbsp; line(LeftMargin-15,ScreenHeight-GraphYposition+2,LeftMargin-15,GraphYposition+80);

&nbsp; strokeWeight(1);

}



void Labels(){

&nbsp; textFont(font,18);

&nbsp; fill(50);

&nbsp; rotate(radians(-90));

&nbsp; text(yLabel,-ScreenHeight/2,LeftMargin-45);

&nbsp; textFont(font,10);

&nbsp; for(float x=0;x&lt;=NumOfVertDivisions;x++){



&nbsp; &nbsp; int bars=(ScreenHeight-GraphYposition)-int(yRatio*(ScreenHeight)*(x/NumOfVertDivisions));

&nbsp; &nbsp; text(round(x),-bars,LeftMargin-20);

&nbsp; }



&nbsp; textFont(font,18);

&nbsp; rotate(radians(90)); &nbsp;

&nbsp; text(xLabel,LeftMargin+(ScreenWidth-LeftMargin-RightMArgin-50)/2,ScreenHeight-GraphYposition+40);

&nbsp; textFont(font,24);

&nbsp; fill(50);

&nbsp; text(Heading,LeftMargin+(ScreenWidth-LeftMargin-RightMArgin-50)/2,70);

&nbsp; textFont(font);



&nbsp; fill(150);

&nbsp; text(URL,ScreenWidth-RightMArgin-40,ScreenHeight-15);

&nbsp; textFont(font);



}



Arduino:





/*

This Example acquire analog signal from A0 of Arduino, and Serial out to Processing application to visualize.

Tested with preamplified audio data. Take a look at http://www.youtube.com/watch?v=drYWullBWcI



Analog signal is captured at 9.6 KHz, 64 spectrum bands each 150Hz which can be change from adcInit()

Load the this file to Arduio, run Processing application.



Original Fixed point FFT library is from ELM Chan, http://elm-chan.org/works/akilcd/report_e.html

Ported to the library and demo codes are from AMurchick http://arduino.cc/forum/index.php/topic,37751.0.html

Processing code is from boolscott http://boolscott.wordpress.com/2010/02/04/arduino-processing-analogue-bar-graph-2/

*/



#include &lt;stdint.h&gt;

#include &lt;ffft.h&gt;



#define &nbsp;IR_AUDIO &nbsp;0 // ADC channel to capture



volatile &nbsp;byte &nbsp;position = 0;

volatile &nbsp;long &nbsp;zero = 0;



int16_t capture[FFT_N];   /* Wave captureing buffer */

complex_t bfly_buff[FFT_N];  /* FFT buffer */

uint16_t spektrum[FFT_N/2];  /* Spectrum output buffer */



void setup()

{

&nbsp; Serial.begin(57600);

&nbsp; adcInit();

&nbsp; adcCalb();

&nbsp; establishContact(); &nbsp;// send a byte to establish contact until Processing respon

}



void loop()

{

&nbsp; if (position == FFT_N)

&nbsp; {

&nbsp; &nbsp; fft_input(capture, bfly_buff);

&nbsp; &nbsp; fft_execute(bfly_buff);

&nbsp; &nbsp; fft_output(bfly_buff, spektrum);



&nbsp; &nbsp; for (byte i = 0; i &lt; 64; i++){

&nbsp; &nbsp; &nbsp; Serial.print(spektrum[i],BYTE);

&nbsp; &nbsp; }

&nbsp; &nbsp;position = 0;

&nbsp; }

}



void establishContact() {

&nbsp;while (Serial.available() &lt;= 0) {

&nbsp; &nbsp; &nbsp; Serial.print('A', BYTE); &nbsp; // send a capital A

&nbsp; &nbsp; &nbsp; delay(300);

&nbsp; }

}



// free running ADC fills capture buffer

ISR(ADC_vect)

{

&nbsp; if (position &gt;= FFT_N)

&nbsp; &nbsp; return;

&nbsp;&nbsp;

&nbsp; capture[position] = ADC + zero;

&nbsp; if (capture[position] == -1 || capture[position] == 1)

&nbsp; &nbsp; capture[position] = 0;



&nbsp; position++;

}

void adcInit(){

&nbsp; /* &nbsp;REFS0 : VCC use as a ref, IR_AUDIO : channel selection, ADEN : ADC Enable, ADSC : ADC Start, ADATE : ADC Auto Trigger Enable, ADIE : ADC Interrupt Enable, &nbsp;ADPS : ADC Prescaler &nbsp;*/

&nbsp; // free running ADC mode, f = ( 16MHz / prescaler ) / 13 cycles per conversion&nbsp;

&nbsp; ADMUX = _BV(REFS0) | IR_AUDIO; // | _BV(ADLAR);&nbsp;

// &nbsp;ADCSRA = _BV(ADSC) | _BV(ADEN) | _BV(ADATE) | _BV(ADIE) | _BV(ADPS2) | _BV(ADPS1) //prescaler 64 : 19231 Hz - 300Hz per 64 divisions

&nbsp; ADCSRA = _BV(ADSC) | _BV(ADEN) | _BV(ADATE) | _BV(ADIE) | _BV(ADPS2) | _BV(ADPS1) | _BV(ADPS0); // prescaler 128 : 9615 Hz - 150 Hz per 64 divisions, better for most music

&nbsp; sei();

}

void adcCalb(){

&nbsp; Serial.println("Start to calc zero");

&nbsp; long midl = 0;

&nbsp; // get 2 meashurment at 2 sec

&nbsp; // on ADC input must be NO SIGNAL!!!

&nbsp; for (byte i = 0; i &lt; 2; i++)

&nbsp; {

&nbsp; &nbsp; position = 0;

&nbsp; &nbsp; delay(100);

&nbsp; &nbsp; midl += capture[0];

&nbsp; &nbsp; delay(900);

&nbsp; }

&nbsp; zero = -midl/2;

&nbsp; Serial.println("Done.");

}