【雕爷学编程】Arduino动手做(149)---MAX9814咪头传感器模块3

37款传感器与执行器的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的,这里准备逐一动手尝试系列实验,不管成功(程序走通)与否,都会记录下来—小小的进步或是搞不掂的问题,希望能够抛砖引玉。

 

【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)
实验一百四十九:MAX9814麦克风放大器模块 MIC话筒声音放大/咪头传感器

 

【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)

  实验一百四十九:MAX9814麦克风放大器模块 MIC话筒声音放大/咪头传感器

项目测试:测量噪音水平(以dB为单位)

Arduino实验开源代码

 

/*

【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)

  实验一百四十九:MAX9814麦克风放大器模块 MIC话筒声音放大/咪头传感器

 项目测试:测量噪音水平(以dB为单位)

 模块接线:

 MAX9814 Arduino

 VCC    5V

 GND    GND

 OUT     A0

*/

const int MIC = 0; //MAX9814麦克风放大器输出连接到引脚 A0

int adc;

int dB, PdB; //将保存每次从麦克风读取的值的变量

void setup() {

 Serial.begin(9600); //将波特率设置为 9600,以便我们可以检查麦克风在串行监视器上获得的值

 pinMode(13, OUTPUT); //LED灯接入D13脚,并设置为输出

}

void loop() {

 PdB = dB; //在此处存储 dB 的前一个

 adc = analogRead(MIC); //从放大器读取 ADC 值

 //Serial.println (adc);//打印 ADC 用于初始计算

 dB = (adc + 83.2073) / 11.003; //使用回归值将 ADC 值转换为 dB

 if (PdB != dB)

  Serial.print ("dB ");

  Serial.println (dB);

 if (dB > 50) //当dB值大于50时,点亮LED灯

 {

  digitalWrite(13, HIGH);  // 打开 LED(HIGH 是电压电平)

  delay(500);        // 等一下,延时500毫秒

  digitalWrite(13, LOW);

 }

 delay(100);

}

  

实验串口绘图器返回情况截图
注意:项目的目的不是准确测量dB,而是仅提供尽可能接近实际值的值。

 

 

实验串口绘图器返回情况截图之二

项目测试:测量噪音水平(以dB为单位)
实验场景图

 

项目实验:简易测量环境的噪音水平(以dB为单位)

https://v.youku.com/v_show/id_XNTE2OTc3MzI1Mg==.html?spm=a2hcb.playlsit.page.1 (实验视频36秒)

 

简单校对,在手机应用宝上搜索——分贝噪声仪,安装1-2款APP

 

 

下载安装了《分贝噪声测试》

 

还有《分贝测量仪》

 

校正后实验程序

 

/*

【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)

  实验一百四十九:MAX9814麦克风放大器模块 MIC话筒声音放大/咪头传感器

 项目测试:测量噪音水平(以dB为单位)

 模块接线:

 MAX9814 Arduino

 VCC    5V

 GND    GND

 OUT     A0

*/

const int MIC = 0; //MAX9814麦克风放大器输出连接到引脚 A0

int adc;

int dB, PdB; //将保存每次从麦克风读取的值的变量

void setup() {

 Serial.begin(9600); //将波特率设置为 9600,以便我们可以检查麦克风在串行监视器上获得的值

 pinMode(13, OUTPUT); //LED灯接入D13脚,并设置为输出

}

void loop() {

 PdB = dB; //在此处存储 dB 的前一个

 adc = analogRead(MIC); //从放大器读取 ADC 值

 //Serial.println (adc);//打印 ADC 用于初始计算

 dB = (adc + 83.2073) / 8.083; //使用回归值将 ADC 值转换为 dB

 if (PdB != dB)

  Serial.print ("dB ");

  Serial.println (dB);

 if (dB > 55) //当dB值大于55时,点亮LED灯

 {

  digitalWrite(13, HIGH);  // 打开 LED(HIGH 是电压电平)

  delay(500);        // 等一下,延时500毫秒

  digitalWrite(13, LOW);

 }

 delay(100);

}

  

实验串口输出情况

 

 实验串口绘图器绘图输出

【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)

  实验一百四十九:MAX9814麦克风放大器模块 MIC话筒声音放大/咪头传感器

 项目之九:Arduino 的小型音频可视化

Arduino实验开源代码

 

/*

【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)

  实验一百四十九:MAX9814麦克风放大器模块 MIC话筒声音放大/咪头传感器

 项目之九:Arduino 的小型音频可视化

 模块接线:

 - 3.3V 至麦克风放大器 + 和 Arduino AREF 引脚 <-- 重要!

 MAX9814 Arduino

 VCC    3.3V

 GND    GND

 OUT     A0

 VK16k33  UNO

 VIN    5V

 GND    GND

 SCL    A5

 SDA    A4

*/

// 重要提示:FFT_N 应该在 ffft.h 中 #defined 为 128。

#include <avr/pgmspace.h>

#include <ffft.h>

#include <math.h>

#include <Wire.h>

#include <Adafruit_GFX.h>

#include <Adafruit_LEDBackpack.h>

// Microphone connects to Analog Pin 0. Corresponding ADC channel number

// varies among boards...it's ADC0 on Uno and Mega, ADC7 on Leonardo.

// Other boards may require different settings; refer to datasheet.

#ifdef __AVR_ATmega32U4__

#define ADC_CHANNEL 7

#else

#define ADC_CHANNEL 0

#endif

int16_t    capture[FFT_N];  // Audio capture buffer

complex_t   bfly_buff[FFT_N]; // FFT "butterfly" buffer

uint16_t   spectrum[FFT_N / 2]; // Spectrum output buffer

volatile byte samplePos = 0;   // Buffer position counter

byte

peak[8],   // Peak level of each column; used for falling dots

   dotCount = 0, // Frame counter for delaying dot-falling speed

   colCount = 0; // Frame counter for storing past column data

int

col[8][10],  // Column levels for the prior 10 frames

  minLvlAvg[8], // For dynamic adjustment of low & high ends of graph,

  maxLvlAvg[8], // pseudo rolling averages for the prior few frames.

  colDiv[8];  // Used when filtering FFT output to 8 columns

/*

 These tables were arrived at through testing, modeling and trial and error,

 exposing the unit to assorted music and sounds. But there's no One Perfect

 EQ Setting to Rule Them All, and the graph may respond better to some

 inputs than others. The software works at making the graph interesting,

 but some columns will always be less lively than others, especially

 comparing live speech against ambient music of varying genres.

*/

static const uint8_t PROGMEM

// This is low-level noise that's subtracted from each FFT output column:

noise[64] = { 8, 6, 6, 5, 3, 4, 4, 4, 3, 4, 4, 3, 2, 3, 3, 4,

       2, 1, 2, 1, 3, 2, 3, 2, 1, 2, 3, 1, 2, 3, 4, 4,

       3, 2, 2, 2, 2, 2, 2, 1, 3, 2, 2, 2, 2, 2, 2, 2,

       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 4

      },

      // These are scaling quotients for each FFT output column, sort of a

      // graphic EQ in reverse. Most music is pretty heavy at the bass end.

eq[64] = {

 255, 175, 218, 225, 220, 198, 147, 99, 68, 47, 33, 22, 14, 8, 4, 2,

 0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,

 0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,

 0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0

},

// When filtering down to 8 columns, these tables contain indexes

// and weightings of the FFT spectrum output values to use. Not all

// buckets are used -- the bottom-most and several at the top are

// either noisy or out of range or generally not good for a graph.

col0data[] = { 2, 1, // # of spectrum bins to merge, index of first

        111,  8

       },      // Weights for each bin

       col1data[] = { 4, 1, // 4 bins, starting at index 1

               19, 186, 38,  2

             }, // Weights for 4 bins. Got it now?

             col2data[] = { 5, 2,

                     11, 156, 118, 16,  1

                    },

                    col3data[] = { 8, 3,

                            5, 55, 165, 164, 71, 18,  4,  1

                          },

                      col4data[] = { 11, 5,

                             3, 24, 89, 169, 178, 118, 54, 20,  6,  2,  1

                            },

                        col5data[] = { 17, 7,

                               2,  9, 29, 70, 125, 172, 185, 162, 118, 74,

                               41, 21, 10,  5,  2,  1,  1

                              },

                          col6data[] = { 25, 11,

                                 1,  4, 11, 25, 49, 83, 121, 156, 180, 185,

                                 174, 149, 118, 87, 60, 40, 25, 16, 10,  6,

                                 4,  2,  1,  1,  1

                                },

                            col7data[] = { 37, 16,

                                   1,  2,  5, 10, 18, 30, 46, 67, 92, 118,

                                   143, 164, 179, 185, 184, 174, 158, 139, 118, 97,

                                   77, 60, 45, 34, 25, 18, 13,  9,  7,  5,

                                   3,  2,  2,  1,  1,  1,  1

                                  },

                              // And then this points to the start of the data for each of the columns:

* const colData[] = {

 col0data, col1data, col2data, col3data,

 col4data, col5data, col6data, col7data

};

Adafruit_BicolorMatrix matrix = Adafruit_BicolorMatrix();

void setup() {

 uint8_t i, j, nBins, binNum, *data;

 memset(peak, 0, sizeof(peak));

 memset(col , 0, sizeof(col));

 for (i = 0; i < 8; i++) {

  minLvlAvg[i] = 0;

  maxLvlAvg[i] = 512;

  data     = (uint8_t *)pgm_read_word(&colData[i]);

  nBins    = pgm_read_byte(&data[0]) + 2;

  binNum    = pgm_read_byte(&data[1]);

  for (colDiv[i] = 0, j = 2; j < nBins; j++)

   colDiv[i] += pgm_read_byte(&data[j]);

 }

 matrix.begin(0x70);

 // Init ADC free-run mode; f = ( 16MHz/prescaler ) / 13 cycles/conversion

 ADMUX = ADC_CHANNEL; // Channel sel, right-adj, use AREF pin

 ADCSRA = _BV(ADEN) | // ADC enable

      _BV(ADSC) | // ADC start

      _BV(ADATE) | // Auto trigger

      _BV(ADIE) | // Interrupt enable

      _BV(ADPS2) | _BV(ADPS1) | _BV(ADPS0); // 128:1 / 13 = 9615 Hz

 ADCSRB = 0;        // Free run mode, no high MUX bit

 DIDR0 = 1 << ADC_CHANNEL; // Turn off digital input for ADC pin

 TIMSK0 = 0;        // Timer0 off

 sei(); // Enable interrupts

}

void loop() {

 uint8_t i, x, L, *data, nBins, binNum, weighting, c;

 uint16_t minLvl, maxLvl;

 int   level, y, sum;

 while (ADCSRA & _BV(ADIE)); // Wait for audio sampling to finish

 fft_input(capture, bfly_buff);  // Samples -> complex #s

 samplePos = 0;          // Reset sample counter

 ADCSRA |= _BV(ADIE);       // Resume sampling interrupt

 fft_execute(bfly_buff);     // Process complex data

 fft_output(bfly_buff, spectrum); // Complex -> spectrum

 // Remove noise and apply EQ levels

 for (x = 0; x < FFT_N / 2; x++) {

  L = pgm_read_byte(&noise[x]);

  spectrum[x] = (spectrum[x] <= L) ? 0 :

         (((spectrum[x] - L) * (256L - pgm_read_byte(&eq[x]))) >> 8);

 }

 // Fill background w/colors, then idle parts of columns will erase

 matrix.fillRect(0, 0, 8, 3, LED_RED);  // Upper section

 matrix.fillRect(0, 3, 8, 2, LED_YELLOW); // Mid

 matrix.fillRect(0, 5, 8, 3, LED_GREEN); // Lower section

 // Downsample spectrum output to 8 columns:

 for (x = 0; x < 8; x++) {

  data  = (uint8_t *)pgm_read_word(&colData[x]);

  nBins = pgm_read_byte(&data[0]) + 2;

  binNum = pgm_read_byte(&data[1]);

  for (sum = 0, i = 2; i < nBins; i++)

   sum += spectrum[binNum++] * pgm_read_byte(&data[i]); // Weighted

  col[x][colCount] = sum / colDiv[x];          // Average

  minLvl = maxLvl = col[x][0];

  for (i = 1; i < 10; i++) { // Get range of prior 10 frames

   if (col[x][i] < minLvl)   minLvl = col[x][i];

   else if (col[x][i] > maxLvl) maxLvl = col[x][i];

  }

  // minLvl and maxLvl indicate the extents of the FFT output, used

  // for vertically scaling the output graph (so it looks interesting

  // regardless of volume level). If they're too close together though

  // (e.g. at very low volume levels) the graph becomes super coarse

  // and 'jumpy'...so keep some minimum distance between them (this

  // also lets the graph go to zero when no sound is playing):

  if ((maxLvl - minLvl) < 8) maxLvl = minLvl + 8;

  minLvlAvg[x] = (minLvlAvg[x] * 7 + minLvl) >> 3; // Dampen min/max levels

  maxLvlAvg[x] = (maxLvlAvg[x] * 7 + maxLvl) >> 3; // (fake rolling average)

  // Second fixed-point scale based on dynamic min/max levels:

  level = 10L * (col[x][colCount] - minLvlAvg[x]) /

      (long)(maxLvlAvg[x] - minLvlAvg[x]);

  // Clip output and convert to byte:

  if (level < 0L)   c = 0;

  else if (level > 10) c = 10; // Allow dot to go a couple pixels off top

  else        c = (uint8_t)level;

  if (c > peak[x]) peak[x] = c; // Keep dot on top

  if (peak[x] <= 0) { // Empty column?

   matrix.drawLine(x, 0, x, 7, LED_OFF);

   continue;

  } else if (c < 8) { // Partial column?

   matrix.drawLine(x, 0, x, 7 - c, LED_OFF);

  }

  // The 'peak' dot color varies, but doesn't necessarily match

  // the three screen regions...yellow has a little extra influence.

  y = 8 - peak[x];

  if (y < 2)   matrix.drawPixel(x, y, LED_RED);

  else if (y < 6) matrix.drawPixel(x, y, LED_YELLOW);

  else      matrix.drawPixel(x, y, LED_GREEN);

 }

 matrix.writeDisplay();

 // Every third frame, make the peak pixels drop by 1:

 if (++dotCount >= 3) {

  dotCount = 0;

  for (x = 0; x < 8; x++) {

   if (peak[x] > 0) peak[x]--;

  }

 }

 if (++colCount >= 10) colCount = 0;

}

ISR(ADC_vect) { // Audio-sampling interrupt

 static const int16_t noiseThreshold = 4;

 int16_t       sample     = ADC; // 0-1023

 capture[samplePos] =

  ((sample > (512 - noiseThreshold)) &&

   (sample < (512 + noiseThreshold))) ? 0 :

  sample - 512; // Sign-convert for FFT; -512 to +511

 if (++samplePos >= FFT_N) ADCSRA &= ~_BV(ADIE); // Buffer full, interrupt off

}

  实验场景图  动态图

项目之九:Arduino 的小型音频可视化 (49秒视频)

https://v.youku.com/v_show/id_XNTgwNTE5NTU0OA==.html?spm=a2hcb.playlsit.page.1

 

【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)

  实验一百四十九:MAX9814麦克风放大器模块 MIC话筒声音放大/咪头传感器

  项目十六:使用FFT库的迷你音乐频谱仪(声谱可视化器)

  实验接线方法: max9814接A0

  oled模块  Ardunio Uno

  GND---------GND接地线

  VCC---------5V 接电源

  SDA---------A4

  SCL ------- A5

/*

【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)

  实验一百四十九:MAX9814麦克风放大器模块 MIC话筒声音放大/咪头传感器 

 项目十六:使用FFT库的迷你音乐频谱仪(声谱可视化器)

 实验接线方法: max9814接A0

 oled模块  Ardunio Uno

 GND---------GND接地线

 VCC---------5V 接电源

 SDA---------A4

 SCL ------- A5

*/

#include "arduinoFFT.h"

#include <Adafruit_GFX.h>

#include <Adafruit_SSD1306.h>

#define SAMPLES 64 // power of 2

#define SAMPLING_FREQ 8000 // 12 kHz Fmax = sampleF /2 

#define AMPLITUDE 100 // 灵敏度

#define FREQUENCY_BANDS 14

#define SCREEN_WIDTH 128

#define SCREEN_HEIGHT 32

#define BARWIDTH 11

#define BARS 11

#define ANALOG_PIN A0

#define OLED_RESET   -1 // 重置引脚 #(如果共享 Arduino 重置引脚,则为 -1)

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

double vImag[SAMPLES];

double vReal[SAMPLES];

unsigned long sampling_period_us;

arduinoFFT fft = arduinoFFT(vReal, vImag, SAMPLES, SAMPLING_FREQ);

//调整参考以去除背景噪声

float reference = log10(60.0);

double coutoffFrequencies[FREQUENCY_BANDS];

void setup() {

 // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally

 if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x32

  for (;;); // Don't proceed, loop forever

 }

 // Setup display

 display.clearDisplay();

 display.display();

 display.setRotation(0);

 display.invertDisplay(false);

 sampling_period_us = (1.0 / SAMPLING_FREQ ) * pow(10.0, 6);

 // 计算截止频率,以对数标度为基数 POt

 double basePot = pow(SAMPLING_FREQ / 2.0, 1.0 / FREQUENCY_BANDS);

 coutoffFrequencies[0] = basePot;

 for (int i = 1 ; i < FREQUENCY_BANDS; i++ ) {

  coutoffFrequencies[i] = basePot * coutoffFrequencies[i - 1];

 }

 // 绘制虚线以分离频段

 for (int i = 0; i < BARS - 1 ; i++) {

  for (int j = 0; j < SCREEN_HEIGHT ; j += 4) {

   display.writePixel((i + 1)*BARWIDTH + 2 , j, SSD1306_WHITE );

  }

 }

 display.drawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SSD1306_WHITE);

}

int oldHeight[20];

int oldMax[20];

double maxInFreq;

void loop() {

 // 采样

 for (int i = 0; i < SAMPLES; i++) {

  unsigned long newTime = micros();

  int value = analogRead(ANALOG_PIN);

  vReal[i] = value;

  vImag[i] = 0;

  while (micros() < (newTime + sampling_period_us)) {

   yield();

  }

 }

 // 计算 FFT

 fft.DCRemoval();

 fft.Windowing(FFT_WIN_TYP_HAMMING, FFT_FORWARD);

 fft.Compute(FFT_FORWARD);

 fft.ComplexToMagnitude();

 double median[20];

 double max[20];

 int index = 0;

 double hzPerSample = (1.0 * SAMPLING_FREQ) / SAMPLES; //

 double hz = 0;

 double maxinband = 0;

 double sum = 0;

 int count = 0;

 for (int i = 2; i < (SAMPLES / 2) ; i++) {

  count++;

  sum += vReal[i];

  if (vReal[i] > max[index] ) {

   max[index] = vReal[i];

  }

  if (hz > coutoffFrequencies[index]) {

   median[index] = sum / count;

   sum = 0.0;

   count = 0;

   index++;

   max[index] = 0;

   median[index] = 0;

  }

  hz += hzPerSample;

 }

 // 计算每个频段的中值和最大值

 if ( sum > 0.0) {

  median[index] = sum / count;

  if (median[index] > maxinband) {

   maxinband = median[index];

  }

 }

 int bar = 0;

 for (int i = FREQUENCY_BANDS - 1; i >= 3; i--) {

  int newHeight = 0;

  int newMax = 0;

  // 计算实际分贝

  if (median[i] > 0 && max[i] > 0 ) {

   newHeight = 20.0 * (log10(median[i] ) - reference);

   newMax = 20.0 * (log10(max[i] ) - reference);

  }

  // 调整最小和最大级别

  if (newHeight < 0 || newMax < 0) {

   newHeight = 1;

   newMax = 1;

  }

  if (newHeight >= SCREEN_HEIGHT - 2) {

   newHeight = SCREEN_HEIGHT - 3;

  }

  if (newMax >= SCREEN_HEIGHT - 2) {

   newMax = SCREEN_HEIGHT - 3;

  }

  int barX = bar * BARWIDTH + 5;

  // 删除旧水平中位数

  if (oldHeight[i] > newHeight) {

   display.fillRect(barX, newHeight + 1, 7, oldHeight[i], SSD1306_BLACK);

  }

  // 删除旧的最大级别

  if ( oldMax[i] > newHeight) {

   for (int j = oldMax[i]; j > newHeight; j -= 2) {

    display.drawFastHLine(barX , j, 7, SSD1306_BLACK);

   }

  }

  // 绘制新的最大级别

  for (int j = newMax; j > newHeight; j -= 2) {

   display.drawFastHLine(barX , j, 7, SSD1306_WHITE);

  }

  // 绘制新的级别中位数

  display.fillRect(barX , 1, 7, newHeight, SSD1306_WHITE);

  oldMax[i] = newMax;

  oldHeight[i] = newHeight;

  bar++;

 }

 display.drawFastHLine(0 , SCREEN_HEIGHT - 1, SCREEN_WIDTH, SSD1306_WHITE);

 display.display();

}

  

实验场景图

 

项目十六:使用FFT库的迷你音乐频谱仪(声谱可视化器)(视频67秒)

https://v.youku.com/v_show/id_XNTgwNzU4NDQwOA==.html?spm=a2hcb.playlsit.page.1

 

项目十六:使用FFT库的迷你音乐频谱仪(声谱可视化器)(测试视频113秒)

https://v.youku.com/v_show/id_XNTgwNzYwODA2OA==.html?spm=a2hcb.playlsit.page.1

 

posted @ 2023-07-14 09:19  行者花雕  阅读(245)  评论(0编辑  收藏  举报