前一段入手了Fermion:全向MEMS麦克风模块(SEN0487),这款模块非常简单能够直接输出模拟信号。简单之处在于无需外部元件进行放大,当没有检测到声音时,输出电压在1.5V左右浮动,在说话时通过ADC采样可以很容易看到声音的波形。 
首先跑了一下WIKI 给出的示例文件,使用 Arduino 自带的串口绘图工具查看了一下波形:
可以看到内部自带了滤波,敏感度也不错。

- #include <arduinoFFT.h>
- #include "DFRobot_OLED12864.h"
-
- // 12864 OLED 配置
- #define I2C_addr 0x3c
- #define pin_SPI_cs D2
-
- #define SAMPLES 1024 // Must be a power of 2
- #define SAMPLING_FREQ 40000 // Hz, must be 40000 or less due to ADC conversion time. Determines maximum frequency that can be analysed by the FFT Fmax=sampleF/2.
- #define AMPLITUDE 1000 // Depending on your audio source level, you may need to alter this value. Can be used as a 'sensitivity' control.
- #define AUDIO_IN_PIN A0 // Signal in on this pin
-
- #define NOISE 500 // Used as a crude noise filter, values below this are ignored
- const uint8_t kMatrixWidth = 16; // Matrix width
- const uint8_t kMatrixHeight = 16; // Matrix height
-
- #define NUM_BANDS 16 // To change this, you will need to change the bunch of if statements describing the mapping from bins to bands
-
- #define BAR_WIDTH (kMatrixWidth / (NUM_BANDS - 1)) // If width >= 8 light 1 LED width per bar, >= 16 light 2 LEDs width bar etc
- #define TOP (kMatrixHeight - 0) // Don't allow the bars to go offscreen
-
- DFRobot_OLED12864 OLED(I2C_addr, pin_SPI_cs);
-
- // Sampling and FFT stuff
- unsigned int sampling_period_us;
- byte peak[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // The length of these arrays must be >= NUM_BANDS
- int oldBarHeights[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- int bandValues[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- double vReal[SAMPLES];
- double vImag[SAMPLES];
- unsigned long newTime;
-
- arduinoFFT FFT = arduinoFFT(vReal, vImag, SAMPLES, SAMPLING_FREQ);
-
- void setup() {
- Serial.begin(115200);
-
- OLED.init();
- // OLED.flipScreenVertically();
-
- sampling_period_us = round(1000000 * (1.0 / SAMPLING_FREQ));
- }
-
- unsigned long int Elsp1;
- int h[16];
-
- void loop() {
-
- // Reset bandValues[]
- for (int i = 0; i < NUM_BANDS; i++) {
- bandValues[i] = 0;
- }
-
- // Sample the audio pin
- for (int i = 0; i < SAMPLES; i++) {
- newTime = micros();
- vReal[i] = analogRead(AUDIO_IN_PIN); // A conversion takes about 9.7uS on an ESP32
- vImag[i] = 0;
- while ((micros() - newTime) < sampling_period_us) {
- /* chill */
- }
- }
-
- // Compute FFT
- FFT.DCRemoval();
- FFT.Windowing(FFT_WIN_TYP_HAMMING, FFT_FORWARD);
- FFT.Compute(FFT_FORWARD);
- FFT.ComplexToMagnitude();
-
- // Analyse FFT results
- for (int i = 2; i < (SAMPLES / 2); i++) { // Don't use sample 0 and only first SAMPLES/2 are usable. Each array element represents a frequency bin and its value the amplitude.
- if (vReal[i] > NOISE) { // Add a crude noise filter
-
- //16 bands, 12kHz top band
- if (i <= 2 ) bandValues[0] += (int)vReal[i];
- if (i > 2 && i <= 3 ) bandValues[1] += (int)vReal[i];
- if (i > 3 && i <= 5 ) bandValues[2] += (int)vReal[i];
- if (i > 5 && i <= 7 ) bandValues[3] += (int)vReal[i];
- if (i > 7 && i <= 9 ) bandValues[4] += (int)vReal[i];
- if (i > 9 && i <= 13 ) bandValues[5] += (int)vReal[i];
- if (i > 13 && i <= 18 ) bandValues[6] += (int)vReal[i];
- if (i > 18 && i <= 25 ) bandValues[7] += (int)vReal[i];
- if (i > 25 && i <= 36 ) bandValues[8] += (int)vReal[i];
- if (i > 36 && i <= 50 ) bandValues[9] += (int)vReal[i];
- if (i > 50 && i <= 69 ) bandValues[10] += (int)vReal[i];
- if (i > 69 && i <= 97 ) bandValues[11] += (int)vReal[i];
- if (i > 97 && i <= 135) bandValues[12] += (int)vReal[i];
- if (i > 135 && i <= 189) bandValues[13] += (int)vReal[i];
- if (i > 189 && i <= 264) bandValues[14] += (int)vReal[i];
- if (i > 264 ) bandValues[15] += (int)vReal[i];
- }
- }
-
- // Process the FFT data into bar heights
- for (byte band = 0; band < NUM_BANDS; band++) {
-
- // Scale the bars for the display
- int barHeight = bandValues[band] / AMPLITUDE;
- if (barHeight > TOP) barHeight = TOP;
-
- // Small amount of averaging between frames
- barHeight = ((oldBarHeights[band] * 1) + barHeight) / 2;
-
- // Move peak up
- if (barHeight > peak[band]) {
- peak[band] = min(TOP, barHeight);
- }
- h[band] = barHeight;
-
- // Save oldBarHeights for averaging later
- oldBarHeights[band] = barHeight;
-
- }
-
- if (millis() - Elsp1 > 60) {
- for (byte band = 0; band < NUM_BANDS; band++)
- if (peak[band] > 0) peak[band] -= 1;
-
- Elsp1 = millis();
- }
- /*
- //直接输出 FFT 结果
- for (int i=0;i<16;i++) {
- if (bandValues[i]<16) {Serial.print(" ");}
- Serial.print(bandValues[i],HEX);
- Serial.print(" ");
- }
- Serial.println("");
- */
-
- // 擦除上一次
- OLED.clear();
- for (int i = 0; i < 16; i++) {
- OLED.fillRect(8 * (16-i), 0, 8, 4 * h[i]);
- OLED.fillRect(8 * (16-i), peak[i]*4, 8, 3);
- }
-
- for (int i = 0; i < 16; i++) {
- Serial.print(h[i], HEX);
- Serial.print("");
- }
- Serial.println("");
- /*
- for (int i = 0; i < 16; i++) {
- Serial.print(peak[i], HEX);
- Serial.print("");
- }
- Serial.println("");
- */
-
- // 显示当前
- OLED.display();
- }
复制代码
最终成品的测试视频:
参考:

|