W tym artykule zaprezentuje oraz wytłumaczę jak możemy zbudować własny układ odbiornika audio ze spectrum. Do wykonania modelu wykorzystałem wymieniony wyżej mikrofon ze wzmacniaczem MAX9814. W modelu również zostały wykorzystane kilka nigdy wcześniej nie używanych przez nas bibliotek (takich jak np. fix_fft) , których działanie również mam zamiar pokazać.
Spis treści
- Krótki opis Mikrofonu
- Specyfikacja
- Podłączenie układu
- Program
- Pliki do pobrania (w tym biblioteki)
Krótki opis
Mikrofon o zakresie od 20Hz do 20kHz. Częstotliwość dźwięku jest pobierana przez układ dzięki napięciom na analogowym pinie Arduino. A następnie dzięki bibliotece fix_fft zamieniana na odpowiedni zakres dźwiękowy który można następnie wyświetlić na oledzie.
Specyfikacja
- Napięcie zasilania: od 2,7 V do 5,5 V
- Wyjście: 2 Vpp dla 1,25 V bias
- Zakres częstotliwości: od 20 Hz do 20 kHz
- Programowalna wartość Attack/Release ratio
- Automatyczne wzmocnienie
- Maksymalna wartość wzmocnienia: 40 dB / 50 dB / 60 dB (domyślnie)
- Wymiary: 26 x 14 mm
Połączenie układu
Elementy:
- Arduino Mega/Uno/Nano
- Mikrofon Moduł MAX9814
- Oled 128×64
- Rezystkor 0.25W 10kΩ 5%
- Płytka stykowa
- 4x kable stykowe (mes-żęń)
- 3xkable stykowe (męs)
Arduino -> Oled:
- A5(SDA) -> SDA
- A4(SCL) -> SCL
- GND -> GND
- 5V -> VCC
Arduino -> Mikrofon (wpinamy mikrofon do płytki stykowej)
- 5V – VCC
- GND – GND
- A0 – OUT (+rezystor)
Program
- Definicja zmiennych i załączenie biblioteka. Utworzenie obiektu biblioteki NanoEngine.
#include <fix_fft.h> #include <ssd1306.h> #include <nano_engine.h> #define SAMPLING_FREQUENCY 15000 #define TIME_FACTOR 3 #define SCALE_FACTOR 12 #ifdef LOG_OUTPUT const float log_scale = 64./log(64./SCALE_FACTOR + 1.); #endif const float coeff = 1./TIME_FACTOR; const unsigned int sampling_period_us = round(1000000 * (2.0 / SAMPLING_FREQUENCY)); int8_t data[64], buff[32]; unsigned long microseconds; int summ, avg; NanoEngine<TILE_32x32_MONO> engine;
2. Funkcja void setup(). Przypisanie wartości dla zmiennych oraz aktywacja oled i działania obiektu engine.
void setup() { OSCCAL = 240; ADCSRA &= ~(bit (ADPS0) | bit (ADPS1) | bit (ADPS2)); ADCSRA |= bit (ADPS2); ADCSRA |= bit (ADPS0); ssd1306_128x64_i2c_init(); ssd1306_clearScreen(); engine.begin(); }
3. Funkcja void loop(). Funkcje for zajmują się zmianą wysokości słupków mocy. Natomiast obiekt engine redukcją szumów.
void loop() { summ = 0; for (int i = 0; i < 64; i++) { microseconds = micros(); data[i] = ((analogRead(A0)) >> 2) - 128; summ += data[i]; while (micros() < (microseconds + sampling_period_us)) { } } avg = summ/64; for (int i = 0; i < 64; i++){ data[i] -= avg; } fix_fftr(data, 6, 0); for(int count = 0; count < 32; count++){ if(data[count] < 0) data[count] = 0; #ifdef LOG_OUTPUT else data[count] = log_scale*log((float)(data[count]+1)); #else else data[count] *= SCALE_FACTOR; #endif data[count] = (float)buff[count] * anti_coeff + (float)data[count] * coeff; buff[count] = data[count]; if(data[count] > 63) data[count] = 63; } engine.refresh(); engine.canvas.clear(); for(int i = 0; i < 8; i++){ engine.canvas.drawVLine(i*4,31-(data[i]+1),31); } engine.canvas.blt(0,32); engine.canvas.clear(); for(int i = 0; i < 8; i++){ if(data[i] > 31) engine.canvas.drawVLine(i*4,31-(data[i]-31),31); } engine.canvas.blt(0,0); engine.canvas.clear(); for(int i = 8; i < 16; i++){ engine.canvas.drawVLine((i-8)*4,31-(data[i]+1),31); } engine.canvas.blt(32,32); engine.canvas.clear(); for(int i = 8; i < 16; i++){ if(data[i] > 31) engine.canvas.drawVLine((i-8)*4,31-(data[i]-31),31); } engine.canvas.blt(32,0); engine.canvas.clear(); for(int i = 16; i < 24; i++){ engine.canvas.drawVLine((i-16)*4,31-(data[i]+1),31); } engine.canvas.blt(64,32); engine.canvas.clear(); for(int i = 16; i < 24; i++){ if(data[i] > 31) engine.canvas.drawVLine((i-16)*4,31-(data[i]-31),31); } engine.canvas.blt(64,0); engine.canvas.clear(); for(int i = 24; i < 32; i++){ engine.canvas.drawVLine((i-24)*4,31-(data[i]+1),31); } engine.canvas.blt(96,32); engine.canvas.clear(); for(int i = 24; i < 32; i++){ if(data[i] > 31) engine.canvas.drawVLine((i-24)*4,31-(data[i]-31),31); } engine.canvas.blt(96,0); }