You are on page 1of 6

2020/9/12 Project#20 OLED Spectrum Analyzer using Fixed-point FFT; FHT on free-running mode - myscratchbooks

Search t his sit e

Home
Home > Arduino Projects >
Arduino Projects
Project#00
Arduino + Project#20 OLED Spectrum Analyzer using Fixed-
Proteus +
Fritzing
Project#01
point FFT; FHT on free-running mode
Cy lon's Ey e
Project#02
External Facts about sound:
Interrupt
Human hearing is 20 Hz to 20 KHz.
Project#03
Photoresistor
Input from http://www.seaindia.in/blog/human-v oice-frequency -range/
Project#04 Fundamental frequency for a ty pical adult male cov ers 100Hz to 900Hz,
Solar Tracker
and ty pical adult female is 350Hz to 3KHz
Project#05
Using LM3 5 /
LM3 4 For a 16 MHz Arduino the ADC clock is set to 16 MHz/128 = 125 KHz.Each conv ersion in AVR takes 13 ADC clocks so
Project#06
125 KHz /13 = 9615 Hz.
Using I2 C 8-bit
IO Expander
PCF857 4 /
MCP2 3 008
Project#07
Using DS1 8B2 0
/ DS1 8S2 0
Project#08
Using DHT2 2
Project#09 US-
1 00 Ultrasonic
sensor
Project#1 0
Sharp GP2 D02
Infrared
Ranging Sensor
Project#1 1
Infrared speed
sensor m odule
(applied on DIY
anem om eter)
Project#1 2
Dem onstrates
use of ADXL3 4 5
Project#1 3
Wireless Wii
Nunchuck
control on Pan
& Tilt
Project#1 4
Fusion
IMU3 000 with
ADXL3 4 5
Project#1 5 Code:
Experim ent on
Gearm otor with
Encoder 1 /*
Project#1 6 2 * Arduino Spectrum Analizer
DHT-2 2 and 3 * https://www.youtube.com/watch?v=5RmQJtE61zE
HC-06 4 * learnelectronics
Bluetooth 5 * 27 April 2017
Project#1 7 6 * black magic stolen from CBM80Amiga
Sonic Radar 7 *
Using US-1 00 8 * code modified from: https://www.dropbox.com/sh/m6c40pu99fqxb5b/AABAQTv67pbYOl6gNozWwDNLa/spec
Project#1 8 9 *
OLED Com pass 10 * Fix_FFT library available @ https://github.com/kosme/fix_fft
LSM3 03 DLH 11 * A library for implementing fixed-point in-place Fast Fourier Transform on Arduino.
(applied on DIY 12 * It sacrifices precision and instead it is way faster than floating-point implementations.
wind Vane) 13 *
Project#1 9 14 * Facts:
Using 15 * Human hearing is 20 Hz to 20 KHz.
MAX9 81 2 16 * http://www.seaindia.in/blog/human-voice-frequency-range/
Microphone 17 * Fundamental frequency for a typical adult male covers 100Hz to 900Hz,
Am plifier
18 * and typical adult female is 350Hz to 3KHz
m easure dB,
19 *
dB-SPL, OLED
20 *
VU Meter
Project #20
21 */
22
OLED
23
Spect rum
24 #include "fix_fft.h" // library to perfom the fixed-point in-pl
Analy zer
using Fixed- 25 //#include <SPI.h> // SPI library 翻译
https://sites.google.com/site/myscratchbooks/home/projects/proejct-20-oled-spectrum-analizer-using-max9812-microphone-amplifier 1/6
2020/9/12 Project#20 OLED Spectrum Analyzer using Fixed-point FFT; FHT on free-running mode - myscratchbooks
point FFT; 26 #include <Wire.h> // I2C library for OLED
FHT on free- 27 #include <Adafruit_GFX.h> // graphics library for OLED
running mode 28 #include <Adafruit_SSD1306.h> // OLED driver
Project#2 1 29
Create own PCB 30 #define OLED_RESET 4 // OLED reset, not hooked up but required
shield 31 Adafruit_SSD1306 display(OLED_RESET); // declare instance of OLED library called
chipKIT Tutorials 32
and Projects 33 // https://arduino.stackexchange.com/questions/699/how-do-i-know-the-sampling-frequency
34 // http://www.dellascolto.com/bitwise/2017/05/25/audio-spectrum-analyzer/
IMU List (last
35 // For a 16 MHz Arduino the ADC clock , default (prescaler=128) fs=9615 Hz=> fmax =fs/2
// if FFT_N=128, (9615 /2)/(128/2) = 75 hz per bin
update:
06 /1 6 /2 01 9 ) 36
37 // if FFT_N=256, (9615/2)/(266/2) = 37.6 hz per bin
Links
38 const int FFT_N =256; // The Arduino Uno does not have enough m
Math
39 // many samples you will get a larger reso
Microcontroller 40 // set FFT_N to 256 by using an Arduino Me
Phy sics 41 char im[FFT_N], data[FFT_N]; // variables for the FFT
PIC1 6 F87 7 A 42 char x = 0, ylim = 60; // variables for drawing the graphics
Projects 43 int i = 0, val,fall; //counters
Raspberry Pi2 /Pi3 44 int dropMax = 0;
Projects 45 int curMax;
Sit emap 46
47 void setup()
48 {
49 //Serial.begin(9600); // serial comms for debuging
50 display.begin(SSD1306_SWITCHCAPVCC,0x3C); // begin OLED @ hex addy 0x3C
51 display.setTextSize(1); // set OLED text size to 1 (1-6)
52 display.setTextColor(WHITE); // set text color to white
53 display.clearDisplay(); // clear display
54 analogReference(DEFAULT); // Use default (5v) aref voltage.
55 };
56
57 void loop()
58 {
59 int mini=1024, maxi=0; // set minumum & maximum ADC values
60 for
(i = 0; i < FFT_N; i++) { // take 128 or 256 point fft samples
61 val = analogRead(A0); // get audio from Analog 0
62 data[i] = val / 4 - 128; // the reason it is divided by 4 and subtr
63 // So because analogRead returns 0-1023, d
64 // scale from 10 bit (0-1023) to 8 bit (0-
65 im[i] = 0; //
66 if(val>maxi) maxi=val; //capture maximum level
67 if(val<mini) mini=val;
68 //if(fall<mini) mini=fall; //capture minimum level
69 };
70
71
72 /*
73 Performs foward or inverse Fourier transform.
74 // fix_fft (char fr[], char fi[], int m, int inverse)
75 // fr is a real data set,
76 // fi is the imaginary data set, im at 0 here
77 // the 3rd parameter m, then there are 2 ^ m 'bins'; if m = 7 then so 128; only the first hal
78 // m is log2(n) where n (FFT_N) is number of data points (log2 (128) = 7), (log2 (256) = 8)
79 // 0 is set for forward transform. 1 would be inverse transform. Apparently inverse does not
80 */
81
82 fix_fft(data, im, 8, 0); // perform the FFT on data for log2 (256)
83 //fix_fft(data, im, 7, 0); // perform the FFT on data for log2 (128
84
85 // /* display graphic, un-comment here
86
87 display.clearDisplay(); // clear display
88 // result array is a bin.
89 // interessted in the absolute value of the transformation
90 // The number of bins you get is half the amount of samples spanning the frequency range f
91 // the first half of array elements contain the real values after fix_fft
92 // In the end we get N/2 bins, each covering a frequency range of sampling_rate/N Hz.
93 for (i = 1; i < FFT_N/2; i++) { // full spectrum; here 4.
94 // 1st bin = 37.5Hz, 2nd b
95 // change for loop values
96 // ex: for (i = 1; i < 64
97 int dat = sqrt(data[i] * data[i] + im[i] * im[i]); // filter out noise and hu
98 dat = (2-dat/60)*dat; // multiplication factor m
99 display.drawLine(i*2 + x, ylim, i*2 + x, ylim - dat, WHITE); // if using FFT_N=128; draw ba
100 //display.drawLine(i + x, ylim, i + x, ylim - dat, WHITE); // if using FFT_N=256; d
101 };
102 display.setCursor(0,0); // set cursor to top of scre
103 display.print("->Spectrum Analyzer<-"); // print title to buffer
104 display.display(); // show the buffer
105
106 // */ display graphic, un-comment here
107
108
109 /* // Another display graphic, un-comment here
110 // *
111 // *
112 // *
113 //
114 //
115 // code from http://www.dellascolto.com/bitwise/category/arduino/page/2/
116

https://sites.google.com/site/myscratchbooks/home/projects/proejct-20-oled-spectrum-analizer-using-max9812-microphone-amplifier 2/6
2020/9/12 Project#20 OLED Spectrum Analyzer using Fixed-point FFT; FHT on free-running mode - myscratchbooks
117 display.clearDisplay(); //clear display
118 // the first 32 array elements contain the real values after fix_fft
119 for (i = 1; i < FFT_N/2; i++) {
120 int dat = sqrt(data[i] * data[i] + im[i] * im[i]); //filter out noise and hum
121 dat = (2-dat/60)*dat; // multiplication factor make
122 display.drawLine(0,63,128,63,WHITE); // baseline
123 // the +5 ensures that the background noise becomes invisible over the full width
124 // display.fillRect(i*4 + x, ylim-dat+5, 2, 63-ylim+dat, WHITE); // if FFT_N=64, draw b
125 display.fillRect(i + x, ylim-dat+5, 2, 63-ylim+dat, WHITE); // if FFT_N=256, draw
126 };
127 display.setCursor(0,0); //set cursor to top of screen
128 curMax=(dropMax+2*min((maxi-mini)/4-12,128))/3; // weighted average between new and old va
129 display.fillRect(0,0,curMax,3,WHITE);
130 if (dropMax>curMax+4) {
131 dropMax=dropMax-3;
132 display.fillRect(dropMax-4,0,3,3,WHITE);
133 } else {
134 dropMax=curMax;
135 }
136 display.display(); //show the buffer
137
138 */ // Another display graphic, un-comment here
139
140
141 }; // end of loop()

Output (capture from):

Another graphic display (capture from):

Next, set the prescaler to 32, so that the bandwidth to 19.2KHz; near to the human hearing 20 KHz.
Using FHT (Fast Hartley Transformation) on free-running mode.

https://sites.google.com/site/myscratchbooks/home/projects/proejct-20-oled-spectrum-analizer-using-max9812-microphone-amplifier 3/6
2020/9/12 Project#20 OLED Spectrum Analyzer using Fixed-point FFT; FHT on free-running mode - myscratchbooks

ADMUX (ADC Multiplexer And Selection Register)

ADLAR bit :

When ADLAR = 0,

When ADLAR = 1 , giv es the left adjusted result (used for 8 bit results)

ADCSRA (ADC Control and Status Register)

ADEN: ADC Enable bit, this bit m ust be set to 1 for turning ADC on.

ADSC: ADC Start Conv ersion bit, this bit is set to 1 to start ADC conv ersion,
as soon as conv ersion is com pleted this bit is set back to 0 by the hardware.

ADAT E: ADC Auto T rigger Enable, this bit is set to 1 to enable auto triggering of ADC conv ersion.

ADIF: ADC Interrupt Flag, this bit is set to 1 when ADC conv ersion gets com plete.

https://sites.google.com/site/myscratchbooks/home/projects/proejct-20-oled-spectrum-analizer-using-max9812-microphone-amplifier 4/6
2020/9/12 Project#20 OLED Spectrum Analyzer using Fixed-point FFT; FHT on free-running mode - myscratchbooks
and the data is written to the result registers (ADCL/ADCH).
T o clear it back to zero y ou need to write a 1 to it.

ADIE: ADC Interrupt Enable, this bit is set to 1 if we want to activ ate the ADC conv ersion com plete
interrupt.

DIDR0 is used to disable the digital input buffers on PC0 to PC5. When set, the corresponding PINC v alue will be set
to 0.

Code:

/*
fht_adc.pde
guest openmusiclabs.com 9.5.12
example sketch for testing the fht library.
it takes in data on ADC0 (Analog0) and processes them
with the fht. the data is sent out over the serial
port at 115.2kb. there is a pure data patch for
visualizing the data.
// http://wiki.openmusiclabs.com/wiki/ArduinoFHT
//
*/
// https://cassiopeia.hk/spectrumanalyser/
//#define OCT_NORM 0 // 0: no normalisation, more high freq 1: divided by number of bins, less
//#define OCTAVE 1
// https://github.com/ayavilevich/ArduinoSoundLevelMeter/blob/master/ArduinoSoundLevelMeter.ino
//#define LIN_OUT8 1 // use the linear byte output function
#define LOG_OUT 1 // use the log output function
#include <FHT.h> // include the library
#define FHT_N 256 // set to 256 point fht
#include <Wire.h> // I2C library for OLED
#include <Adafruit_GFX.h> // graphics library for OLED
#include <Adafruit_SSD1306.h> // OLED driver
#define OLED_RESET 4 // OLED reset, not hooked up but required by li
Adafruit_SSD1306 display(OLED_RESET); // declare instance of OLED library called disp
char x = 0, ylim = 60; // variables for drawing the graphics
const int noise_level = 60; // set 0 will have background noise spectrum d
void setup() {
//Serial.begin(115200); // use the serial port
display.begin(SSD1306_SWITCHCAPVCC,0x3C); // begin OLED @ hex addy 0x3C
display.setTextSize(1); // set OLED text size to 1 (1-6)
display.setTextColor(WHITE); // set text color to white
display.clearDisplay(); // clear display
analogReference(DEFAULT); // Use default (5v) aref voltage.
setFreeRunMode();
}

void loop() {
while
(1) { // reduces jitter
cli(); // no for TIMING
// unsigned long start_time = micros(); // yes for TIMING
for (int i = 0 ; i < FHT_N ; i++) { // save 128 samples
while (!(ADCSRA & 0x10)); // wait for adc to be ready (ADIF)
ADCSRA = 0xf5; // restart adc
byte m = ADCL; // fetch adc data, the ADCL register first because readin
byte j = ADCH;
int k = (j << 8) | m; // form into an int
k -= 0x0200; // form into a signed int
k <<= 6; // form into a 16b signed int
fht_input[i] = k; // put real data into bins
}

// Serial.println(micros()-start_time); // yes for TIMING


fht_window(); // window the data for better frequency response
fht_reorder(); // reorder the data before doing the fht
fht_run(); // process the data in the fht
// fht_mag_octave(); // take the output of the fht
fht_mag_log(); // take the output of the fht
// fht_mag_lin8(); // take the output of the fht
sei(); // no for TIMING
// Serial.write(255); // send a start byte
// Serial.write(fht_log_out, FHT_N/2); // send out the data
// OLED display
display.clearDisplay(); // clear display
for (int i=2; i< FHT_N; i+=1) { // output even bins because oled is
// i=2, because i've noise on first
// If FHT_N=128, then use for (int
int dat = max((fht_log_out[i] - noise_level) / 4, 0); // scale the height
display.drawLine(i + x, ylim, i + x, ylim-dat, WHITE); // draw bar graphics for freq
https://sites.google.com/site/myscratchbooks/home/projects/proejct-20-oled-spectrum-analizer-using-max9812-microphone-amplifier 5/6
2020/9/12 Project#20 OLED Spectrum Analyzer using Fixed-point FFT; FHT on free-running mode - myscratchbooks

}
display.setCursor(0,0); // set cursor to top of scree
display.print("->Spectrum Analyzer<-"); // print title to buffer
display.display();

} // end while
} // end loop
void setFreeRunMode() {
TIMSK0 = 0; // turn off timer0 for lower jitter
ADCSRA = 0xE5; // "ADC Enable", "ADC Start Conversion", "ADC Auto Trigge
// 0xE4, 16 prescaler
// 0xE6, 64 prescaler
ADMUX = 0x40; // b0100 0000; use adc0, right-align, use the full 10 bit
DIDR0 = 0x01; // turn off the digital input for adc0
}

登录 | 最近的网站活动 | 举报滥用行为 | 打印页面 | 由 Google 协作平台强力驱动

https://sites.google.com/site/myscratchbooks/home/projects/proejct-20-oled-spectrum-analizer-using-max9812-microphone-amplifier 6/6

You might also like