Hi!
I want to create an audio specter analyzer with information output to a serial port (not to LED board) for testing work of an audio device. So I bought MAX9814 audio sensor and connected it to arduino. After I used arduinoFFT.h library and chose third example of library.
#include "arduinoFFT.h"
arduinoFFT FFT = arduinoFFT(); /* Create FFT object */
/*
These values can be changed in order to evaluate the functions
*/
#define CHANNEL A0
const uint16_t samples = 64; //This value MUST ALWAYS be a power of 2
const double samplingFrequency = 100; //Hz, must be less than 10000 due to ADC
unsigned int sampling_period_us;
unsigned long microseconds;
/*
These are the input and output vectors
Input vectors receive computed results from FFT
*/
double vReal[samples];
double vImag[samples];
#define SCL_INDEX 0x00
#define SCL_TIME 0x01
#define SCL_FREQUENCY 0x02
#define SCL_PLOT 0x03
void setup()
{
sampling_period_us = round(1000000*(1.0/samplingFrequency));
Serial.begin(115200);
while(!Serial);
Serial.println("Ready");
}
void loop()
{
/*SAMPLING*/
microseconds = micros();
for(int i=0; i<samples; i++)
{
vReal[i] = analogRead(CHANNEL);
vImag[i] = 0;
while(micros() - microseconds < sampling_period_us){
//empty loop
}
microseconds += sampling_period_us;
}
/* Print the results of the sampling according to time */
Serial.println("Data:");
PrintVector(vReal, samples, SCL_TIME);
FFT.Windowing(vReal, samples, FFT_WIN_TYP_HAMMING, FFT_FORWARD); /* Weigh data */
Serial.println("Weighed data:");
PrintVector(vReal, samples, SCL_TIME);
FFT.Compute(vReal, vImag, samples, FFT_FORWARD); /* Compute FFT */
Serial.println("Computed Real values:");
PrintVector(vReal, samples, SCL_INDEX);
Serial.println("Computed Imaginary values:");
PrintVector(vImag, samples, SCL_INDEX);
FFT.ComplexToMagnitude(vReal, vImag, samples); /* Compute magnitudes */
Serial.println("Computed magnitudes:");
PrintVector(vReal, (samples >> 1), SCL_FREQUENCY);
double x = FFT.MajorPeak(vReal, samples, samplingFrequency);
Serial.println(x, 6); //Print out what frequency is the most dominant.
while(1); /* Run Once */
// delay(2000); /* Repeat after delay */
}
void PrintVector(double *vData, uint16_t bufferSize, uint8_t scaleType)
{
for (uint16_t i = 0; i < bufferSize; i++)
{
double abscissa;
/* Print abscissa value */
switch (scaleType)
{
case SCL_INDEX:
abscissa = (i * 1.0);
break;
case SCL_TIME:
abscissa = ((i * 1.0) / samplingFrequency);
break;
case SCL_FREQUENCY:
abscissa = ((i * 1.0 * samplingFrequency) / samples);
break;
}
Serial.print(abscissa, 6);
if(scaleType==SCL_FREQUENCY)
Serial.print("Hz");
Serial.print(" ");
Serial.println(vData[i], 4);
}
Serial.println();
}
So, I get a frequency response function. The next step to increase sampling rate, because analogRead() function has sampling rate 9,6 KHz, so with using FFT analogRead can analyze frequencies up to 5Khz.
I found this method to increase sampling rate via registers
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
void setup()
{
sbi(ADCSRA, ADPS2);
cbi(ADCSRA, ADPS1);
cbi(ADCSRA, ADPS0);
But the code didn’t compile. I check the data sheet, and it turned out that there are no such registers on my board. I tried to use registers in data sheet first, second and I tried to add code with control registers
ADC0.CTRLC |= ADC_PRESC_DIV32_gc;
ADC0.CTRLA |= ADC_ENABLE_bm;
it’s compiled, but converted data still was wrong. I tried to add
ADC0.MUXPOS = ADC_MUXPOS_AIN6_gc;
to address command to pin A0, but pin A0 doesn’t have ADC0 number (page 18 on the first data sheet), so can i increase sample rate for A0 pin on my UNO Wi-Fi? Or I need to buy new arduino (if so, tell me please which one is better to choose)? Or something like that link.
Also, if I can change sample frequency, can I use analogRead after this?
I understand little about the work of registers and have known arduino not so long ago, so describe your answers more detailed. Thanks in advance, I’m glad for any help.