【雕爷学编程】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

  实验开源代码

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
/*
 
【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实验开源代码

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
/*
 
【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实验开源代码

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
/*
 
 【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

实验开源代码

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
/*
  【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实验开源代码

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
/*
  【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 @   行者花雕  阅读(180)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· spring官宣接入deepseek,真的太香了~
点击右上角即可分享
微信分享提示