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

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

 

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

 

 

【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 150 // 灵敏度

#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(80.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();

}

  

Arduino实验场景图

 

项目三十二:使用FFT库的迷你音乐频谱仪(声谱可视化器)(完整测试视频2分41秒)

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

 

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

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

  项目三十三:Arduino OLED 频谱分析仪

  Arduino实验开源代码

 

/*

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

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

 项目三十三:Arduino OLED 频谱分析仪

 实验接线方法: max9814接A0

 oled模块  Ardunio Uno

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

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

 SDA---------A4

 SCL ------- A5

*/

#include <fix_fft.h>          

#include <ssd1306.h>          

#include <nano_engine.h>        

// These are user-adjustable

#define LOG_OUTPUT         // Uncomment to enable logarithmic output (exchanges absolute resoluton for more readable output; may require different below params)

#define SAMPLING_FREQUENCY 15000 // Sampling frequency (Actual max measured frequency captured is half)

#define TIME_FACTOR 2       // Smoothing factor (lower is more dynamic, higher is smoother) ranging from 1 to 10+

#define SCALE_FACTOR 15      // Direct scaling factor (raise for higher bars, lower for shorter bars)

#ifdef LOG_OUTPUT

const float log_scale = 64. / log(64. / SCALE_FACTOR + 1.);  // Attempts to create an equivalent to SCALE_FACTOR for log function

#endif

const float coeff = 1. / TIME_FACTOR;             // Time smoothing coefficients (used to factor in previous data)

const float anti_coeff = (TIME_FACTOR - 1.) / TIME_FACTOR;

const unsigned int sampling_period_us = round(1000000 * (2.0 / SAMPLING_FREQUENCY)); // Sampling period (doubled to account for overclock)

int8_t data[64], buff[32];                   // used to store FFT input/output and past data

unsigned long microseconds;                  // used for timekeeping

int summ, avg;                         // used for DC bias elimination

NanoEngine<TILE_32x32_MONO> engine;              // declares nanoengine

void setup()

{

 OSCCAL = 240; // Overclocks the MCU to around 30 MHz, set lower if this causes instability, raise if you can/want

 ADCSRA &= ~(bit (ADPS0) | bit (ADPS1) | bit (ADPS2));    // clear ADC prescaler bits

 ADCSRA |= bit (ADPS2);                   // sets ADC clock in excess of 10kHz

 ADCSRA |= bit (ADPS0);

 ssd1306_128x64_i2c_init();                 // initializes OLED

 ssd1306_clearScreen();                   // clears OLED

 engine.begin();                       // inititalizes nanoengine

};

void loop()

{

 summ = 0;

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

  microseconds = micros();

  data[i] = ((analogRead(A0)) >> 2) - 128;            // Fitting analogRead data (range:0 - 1023) to int8_t array (range:-128 - 127)

  summ += data[i];

  while (micros() < (microseconds + sampling_period_us)) {    // Timing out uC ADC to fulfill sampling frequency requirement

  }

 }

 // Eliminating remaining DC component (produces usable data in FFT bin #0, which is usually swamped by DC bias)

 avg = summ / 64;

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

  data[i] -= avg;

 }

 fix_fftr(data, 6, 0);               // Performing real FFT

 // Time smoothing by user-determined factor and user-determined scaling

 for (int count = 0; count < 32; count++) {

  if (data[count] < 0) data[count] = 0;                     // Eliminating negative output of fix_fftr

#ifdef LOG_OUTPUT

  else data[count] = log_scale * log((float)(data[count] + 1));         // Logarithmic function equivalent to SCALING_FACTOR*log2(x+1)

#else

  else data[count] *= SCALE_FACTOR;                       // Linear scaling up according to SCALE_FACTOR

#endif

  data[count] = (float)buff[count] * anti_coeff + (float)data[count] * coeff;  // Smoothing by factoring in past data

  buff[count] = data[count];                          // Storing current output as next frame's past data

  if (data[count] > 63) data[count] = 63;                    // Capping output at screen height

 }

 // Output to SSD1306 using nanoengine canvas from library

 engine.refresh();                        // Mark entire screen to be refreshed

 engine.canvas.clear();                     // Clear canvas as previous data

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

  engine.canvas.drawVLine(i * 4, 31 - (data[i] + 1), 31); // Draw to canvas data for lower-leftest sector (FFT bins 0 - 7, lower half)

 }

 engine.canvas.blt(0, 32);                    // Outputs canvas to OLED with an offset (x pixels, y pixels)

 engine.canvas.clear();

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

  if (data[i] > 31) engine.canvas.drawVLine(i * 4, 31 - (data[i] - 31), 31); // Draw to canvas data for upper-leftest sector (FFT bins 0 - 7, upper half)

 }

 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); // FFT bins 8 - 15, lower half

 }

 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); // FFT bins 9 - 15, upper half

 }

 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); // FFT bins 16 - 23, lower half

 }

 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); // FFT bins 16 - 23, upper half

 }

 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); // FFT bins 24 - 31, lower half

 }

 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); // FFT bins 24 - 31, upper half

 }

 engine.canvas.blt(96, 0);

}

  

Arduino实验场景图

 

项目三十三:Arduino OLED 频谱分析仪(视频,法语版《因为爱情》3分12秒)

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

 

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

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

  项目三十四:八位音乐反应式 LED 灯条

  Arduino实验开源代码

 

/*

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

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

 项目三十四:八位音乐反应式 LED 灯条

 实验接线方法: max9814接A0

 oled模块  Ardunio Uno

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

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

 SDA---------A4

 SCL ------- A5

*/

#include <Adafruit_NeoPixel.h>

#include <math.h>

#define N_PIXELS 8

#define MIC_PIN  A0

#define LED_PIN  6

#define SAMPLE_WINDOW  5

#define PEAK_HANG 24

#define PEAK_FALL 4

#define INPUT_FLOOR 10

#define INPUT_CEILING 50

byte peak = 16;

unsigned int sample;

byte Count = 0;

byte HangCount = 0;

Adafruit_NeoPixel strip = Adafruit_NeoPixel(N_PIXELS, LED_PIN, NEO_GRB + NEO_KHZ800);

void setup() {

 Serial.begin(9600);

 analogReference(EXTERNAL);

 strip.setBrightness(22);

 strip.show();

 strip.begin();

}

float fscale( float originalMin, float originalMax, float newBegin, float newEnd, float inputValue, float curve) {

 float OriginalRange = 0;

 float NewRange = 0;

 float zeroRefCurVal = 0;

 float normalizedCurVal = 0;

 float rangedValue = 0;

 boolean invFlag = 0;

 if (curve > 10) curve = 10;

 if (curve < -10) curve = -10;

 curve = (curve * -.1) ;

 curve = pow(10, curve);

 if (inputValue < originalMin) {

  inputValue = originalMin;

 }

 if (inputValue > originalMax) {

  inputValue = originalMax;

 }

 OriginalRange = originalMax - originalMin;

 if (newEnd > newBegin) {

  NewRange = newEnd - newBegin;

 }

 else

 {

  NewRange = newBegin - newEnd;

  invFlag = 1;

 }

 zeroRefCurVal = inputValue - originalMin;

 normalizedCurVal = zeroRefCurVal / OriginalRange;  // normalize to 0 - 1 float

 Serial.print(OriginalRange, DEC);

 Serial.print("  ");

 Serial.print(NewRange, DEC);

 Serial.print("  ");

 Serial.println(zeroRefCurVal, DEC);

 Serial.println();

 delay(10); 

 if (originalMin > originalMax ) {

  return 0;

 }

 if (invFlag == 0) {

  rangedValue = (pow(normalizedCurVal, curve) * NewRange) + newBegin;

 }

 else

 {

  rangedValue = newBegin - (pow(normalizedCurVal, curve) * NewRange);

 }

 return rangedValue;

}

void loop() {

 unsigned long startMillis = millis();

 float peakToPeak = 0;

 unsigned int signalMax = 0;

 unsigned int signalMin = 1023;

 unsigned int c, y;

 while (millis() - startMillis < SAMPLE_WINDOW)

 {

  sample = analogRead(MIC_PIN);

  if (sample < 1024)

  {

   if (sample > signalMax)

   {

    signalMax = sample;

   }

   else if (sample < signalMin)

   {

    signalMin = sample;

   }

  }

 }

 peakToPeak = signalMax - signalMin;

 for (int i = 0; i <= strip.numPixels() - 1; i++) {

  strip.setPixelColor(i, Wheel(map(i, 0, strip.numPixels() - 1, 30, 150)));

 }

 c = fscale(INPUT_FLOOR, INPUT_CEILING, strip.numPixels(), 0, peakToPeak, 2);

 if (c < peak) {

  peak = c;

  HangCount = 0;

 }

 if (c <= strip.numPixels()) {

  drawLine(strip.numPixels(), strip.numPixels() - c, strip.Color(0, 0, 0));

 }

 y = strip.numPixels() - peak;

 strip.setPixelColor(y - 1, Wheel(map(y, 0, strip.numPixels() - 1, 30, 150)));

 strip.show();

 if (HangCount > PEAK_HANG) {

  if (++Count >= PEAK_FALL) {

   peak++;

   Count = 0;

  }

 }

 else {

  HangCount++;

 }

}

void drawLine(uint8_t from, uint8_t to, uint32_t c) {

 uint8_t fromTemp;

 if (from > to) {

  fromTemp = from;

  from = to;

  to = fromTemp;

 }

 for (int i = from; i <= to; i++) {

  strip.setPixelColor(i, c);

 }

}

uint32_t Wheel(byte WheelPos) {

 if (WheelPos < 85) {

  return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);

 }

 else if (WheelPos < 170) {

  WheelPos -= 85;

  return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);

 }

 else {

  WheelPos -= 170;

  return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);

 }

}

  

实验串口返回情况

 

Arduino实验场景图

 

项目三十四:八位音乐反应式 LED 灯条

(实验视频)

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


【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)
实验一百四十九:MAX9814麦克风放大器模块 MIC话筒声音放大/咪头传感器
项目三十五:十六位音乐反应式 LED 灯条
实验接线方法: max9814接A0
oled模块 Ardunio Uno
GND---------GND接地线
VCC---------5V 接电源
SDA---------A4
SCL ------- A5

实验开源代码

 

/*
  【Arduino】168种传感器模块系列实验(资料代码+图形编程+仿真编程)
  <span style="background-color: rgb(255, 255, 255);">实验一百五十九:MAX9814麦克风放大器模块 MIC话筒声音放大/咪头传感器</span>
  项目三十五:十六位音乐反应式 LED 灯条
  实验接线方法: max9814接A0
  oled模块    Ardunio Uno
  GND---------GND接地线
  VCC---------5V 接电源
  SDA---------A4
  SCL ------- A5
*/

#include <Adafruit_NeoPixel.h>
#include <math.h>
#define N_PIXELS  16
#define MIC_PIN   A0
#define LED_PIN    6
#define SAMPLE_WINDOW   5
#define PEAK_HANG 24
#define PEAK_FALL 4
#define INPUT_FLOOR 10
#define INPUT_CEILING 50
byte peak = 16;
unsigned int sample;

byte Count = 0;
byte HangCount = 0;

Adafruit_NeoPixel strip = Adafruit_NeoPixel(N_PIXELS, LED_PIN, NEO_GRB + NEO_KHZ800);

void setup() {
  Serial.begin(9600);
  analogReference(EXTERNAL);
  strip.setBrightness(22);
  strip.show();
  strip.begin();
}

float fscale( float originalMin, float originalMax, float newBegin, float newEnd, float inputValue, float curve) {

  float OriginalRange = 0;
  float NewRange = 0;
  float zeroRefCurVal = 0;
  float normalizedCurVal = 0;
  float rangedValue = 0;
  boolean invFlag = 0;

  if (curve > 10) curve = 10;
  if (curve < -10) curve = -10;

  curve = (curve * -.1) ;
  curve = pow(10, curve);

  if (inputValue < originalMin) {
    inputValue = originalMin;
  }
  if (inputValue > originalMax) {
    inputValue = originalMax;
  }

  OriginalRange = originalMax - originalMin;

  if (newEnd > newBegin) {
    NewRange = newEnd - newBegin;
  }
  else
  {
    NewRange = newBegin - newEnd;
    invFlag = 1;
  }

  zeroRefCurVal = inputValue - originalMin;
  normalizedCurVal  =  zeroRefCurVal / OriginalRange;   // normalize to 0 - 1 float

  Serial.print(OriginalRange, DEC);
  Serial.print("   ");
  Serial.print(NewRange, DEC);
  Serial.print("   ");
  Serial.println(zeroRefCurVal, DEC);
  Serial.println();
  delay(10); 

  if (originalMin > originalMax ) {
    return 0;
  }

  if (invFlag == 0) {
    rangedValue =  (pow(normalizedCurVal, curve) * NewRange) + newBegin;
  }
  else
  {
    rangedValue =  newBegin - (pow(normalizedCurVal, curve) * NewRange);
  }
  return rangedValue;
}

void loop() {
  unsigned long startMillis = millis();
  float peakToPeak = 0;

  unsigned int signalMax = 0;
  unsigned int signalMin = 1023;
  unsigned int c, y;

  while (millis() - startMillis < SAMPLE_WINDOW)
  {
    sample = analogRead(MIC_PIN);
    if (sample < 1024)
    {
      if (sample > signalMax)
      {
        signalMax = sample;
      }
      else if (sample < signalMin)
      {
        signalMin = sample;
      }
    }
  }
  peakToPeak = signalMax - signalMin;

  for (int i = 0; i <= strip.numPixels() - 1; i++) {
    strip.setPixelColor(i, Wheel(map(i, 0, strip.numPixels() - 1, 30, 150)));
  }

  c = fscale(INPUT_FLOOR, INPUT_CEILING, strip.numPixels(), 0, peakToPeak, 2);

  if (c < peak) {
    peak = c;
    HangCount = 0;
  }
  if (c <= strip.numPixels()) {
    drawLine(strip.numPixels(), strip.numPixels() - c, strip.Color(0, 0, 0));
  }

  y = strip.numPixels() - peak;
  strip.setPixelColor(y - 1, Wheel(map(y, 0, strip.numPixels() - 1, 30, 150)));
  strip.show();

  if (HangCount > PEAK_HANG) {
    if (++Count >= PEAK_FALL) {
      peak++;
      Count = 0;
    }
  }
  else {
    HangCount++;
  }
}

void drawLine(uint8_t from, uint8_t to, uint32_t c) {
  uint8_t fromTemp;
  if (from > to) {
    fromTemp = from;
    from = to;
    to = fromTemp;
  }
  for (int i = from; i <= to; i++) {
    strip.setPixelColor(i, c);
  }
}

uint32_t Wheel(byte WheelPos) {
  if (WheelPos < 85) {
    return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
  }
  else if (WheelPos < 170) {
    WheelPos -= 85;
    return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  }
  else {
    WheelPos -= 170;
    return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
}

  

Arduino实验场景图

 

项目三十五:十六位音乐反应式 LED 灯条(实验视频)
https://v.youku.com/v_show/id_XNTgwODQ4Njk2MA==.html?spm=a2hcb.playlsit.page.1

 

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

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

项目四十:十六位音乐频谱灯条

Arduino实验开源代码

 

/*
  【Arduino】168种传感器模块系列实验(资料代码+图形编程+仿真编程)
  实验六十一:直条16位 WS2812B 5050 RGB LED内置全彩驱动彩灯模块
  项目四十:十六位音乐频谱灯条
*/

#include "FastLED.h"

#define OCTAVE 1 //   // Group buckets into octaves  (use the log output function LOG_OUT 1)
#define OCT_NORM 0 // Don't normalise octave intensities by number of bins
#define FHT_N 256 // set to 256 point fht
#include <FHT.h> // include the library
//int noise[] = {204,188,68,73,150,98,88,68}; // noise level determined by playing pink noise and seeing levels [trial and error]{204,188,68,73,150,98,88,68}


// int noise[] = {204,190,108,85,65,65,55,60}; // noise for mega adk
int noise[] = {204,195,100,90,85,80,75,75}; // noise for NANO
//int noise[] = {204,198,100,85,85,80,80,80};
float noise_fact[] = {15, 7, 1.5, 1, 1.2, 1.4, 1.7,3}; // noise level determined by playing pink noise and seeing levels [trial and error]{204,188,68,73,150,98,88,68}
float noise_fact_adj[] = {15, 7, 1.5, 1, 1.2, 1.4, 1.7,3}; // noise level determined by playing pink noise and seeing levels [trial and error]{204,188,68,73,150,98,88,68}


#define LED_PIN     6
#define LED_TYPE    WS2812
#define COLOR_ORDER GRB


// Params for width and height
const uint8_t kMatrixWidth = 8;
const uint8_t kMatrixHeight = 8;//----------was 27
//#define NUM_LEDS (kMatrixWidth * kMatrixHeight)
#define NUM_LEDS    64

CRGB leds[NUM_LEDS];

int counter2=0;



void setup() { 
Serial.begin(9600);
  delay(1000);
  FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );
  
  FastLED.setBrightness (33);
  fill_solid(leds, NUM_LEDS, CRGB::Black); 
  FastLED.show();    
// TIMSK0 = 0; // turn off timer0 for lower jitter
  ADCSRA = 0xe5; // set the adc to free running mode
  ADMUX = 0x40; // use adc0
  DIDR0 = 0x01; // turn off the digital input for adc0

}




void loop() { 
int prev_j[8];
int beat=0;
int prev_oct_j;
int counter=0;
int prev_beat=0;
int led_index=0;
int saturation=0;
int saturation_prev=0;
int brightness=0;
int brightness_prev=0;

 while (1) { // reduces jitter

      cli();  // UDRE interrupt slows this way down on arduino1.0
     
  for (int i = 0 ; i < FHT_N ; i++) { // save 256 samples
      while (!(ADCSRA & 0x10)); // wait for adc to be ready
      ADCSRA = 0xf5; // restart adc
      byte m = ADCL; // fetch adc data
      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
    }
    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()

   // every 50th loop, adjust the volume accourding to the value on A2 (Pot)
    if (counter >= 50) {
      ADMUX = 0x40 | (1 & 0x07); // set admux to look at Analogpin A1 - Master Volume
 

      while (!(ADCSRA & 0x10)); // wait for adc to be ready
      ADCSRA = 0xf5; // restart adc 
  delay(10);      
      while (!(ADCSRA & 0x10)); // wait for adc to be ready
      ADCSRA = 0xf5; // restart adc 
      byte m = ADCL; // fetch adc data
      byte j = ADCH;
      int k = (j << 8) | m; // form into an int
      float master_volume=(k+0.1)/1000 +.75;  // so the valu will be between ~0.5 and 1.---------------------+.75 was .5
  Serial.println (master_volume);


      for (int i=1; i<8; i++) {
          noise_fact_adj[i]=noise_fact[i]*master_volume;
      }

      ADMUX = 0x40 | (0 & 0x07); // set admux back to look at A0 analog pin (to read the microphone input
      counter = 0;
    }
        
    sei();
    counter++;
 
     
    // End of Fourier Transform code - output is stored in fht_oct_out[i].

    // i=0-7 frequency (octave) bins (don't use 0 or 1), fht_oct_out[1]= amplitude of frequency for bin 1
    // for loop a) removes background noise average and takes absolute value b) low / high pass filter as still very noisy
    // c) maps amplitude of octave to a colour between blue and red d) sets pixel colour to amplitude of each frequency (octave)
 
    for (int i = 1; i < 8; i++) {  // goes through each octave. skip the first 1, which is not useful

      int j;      
      j = (fht_oct_out[i] - noise[i]); // take the pink noise average level out, take the asbolute value to avoid negative numbers
      if (j<10) {j=0;}  
      j= j*noise_fact_adj[i];
       
      if (j<10) {j=0;}
      else {  
        j= j*noise_fact_adj[i];
        if (j>180) {
          if (i>=7) {
            beat+=2;
          }
          else {
            beat+=1;
          }
        }
        j=j/30;
        j=j*30; // (force it to more discrete values)
      }
      
      prev_j[i]=j;

//     Serial.print(j);
//     Serial.print(" "); 

 
// this fills in 11 LED's with interpolated values between each of the 8 OCT values 
       if (i>=2) {
        led_index=2*i-3;
        prev_oct_j=(j+prev_j[i-1])/2;
        
        saturation=constrain(j+50, 0,255);//-----------50 was 30
        saturation_prev=constrain(prev_oct_j+50, 0,255);
        brightness=constrain(j, 0,255);
        brightness_prev=constrain(prev_oct_j, 0,255);
if (brightness==255) {
  saturation=50;
  brightness=200;
}
if (brightness_prev==255) {
  saturation_prev=50;
  brightness_prev=200;
}


        for (uint8_t y=0;y<kMatrixHeight;y++){  
          leds[XY(led_index-1,y)] = CHSV(j+y*30,saturation, brightness);        
          if (i>2){         
            prev_oct_j=(j+prev_j[i-1])/2;
            leds[ XY(led_index-2,y)]=CHSV(prev_oct_j+y*30,saturation_prev, brightness_prev);             
          }              
        }
       }
    }
      


      if (beat>=7) {
          fill_solid(leds, NUM_LEDS, CRGB::Gray);          
          FastLED.setBrightness(200);



      }                 
    else {
      if (prev_beat!=beat) {
        FastLED.setBrightness(40+beat*beat*5);
        prev_beat=beat;
      }

    }

    FastLED.show(); 
    if (beat) {
      counter2+=((beat+4)/2-2);
      if (counter2<0) {counter2=1000;}
      if (beat>3 && beat<7) {
         FastLED.delay (20);
      }
      beat=0;
    }

// Serial.println();
 }
}



// Param for different pixel layouts
const bool    kMatrixSerpentineLayout = false;
// Set 'kMatrixSerpentineLayout' to false if your pixels are 
// laid out all running the same way, like this:

// Set 'kMatrixSerpentineLayout' to true if your pixels are 
// laid out back-and-forth, like this:

uint16_t XY( uint8_t x, uint8_t y)
{
  uint16_t i;
  
  if( kMatrixSerpentineLayout == false) {
    i = (y * kMatrixWidth) + x;
  }

  if( kMatrixSerpentineLayout == true) {
    if( y & 0x01) {
      // Odd rows run backwards
      uint8_t reverseX = (kMatrixWidth - 1) - x;
      i = (y * kMatrixWidth) + reverseX;

    } else {
      // Even rows run forwards
      i = (y * kMatrixWidth) + x;

    }
  }
  
  i=(i+counter2)%NUM_LEDS;  
  return i;
}

  

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

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

项目四十:十六位音乐频谱灯条

实验视频剪辑

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

 

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