【Follow me第二季第4期】-任务4:选做任务一(非必做):通过RGB LED不同颜色、亮...
[复制链接]
由于任务3是PDM麦克风相关任务,所以本次选择的可选任务是通过LED显示麦克风收到声音大小。
本次任务是在任务3 的基础上,结合任务1,对代码进行修改。
主要思路是对麦克风的取值进行存储,然后控制LED灯亮度。本次只用到红灯和绿灯。
观测到任务3中,麦克风采集的数据有两个问题;
1、麦克风采集到的声音波动非常大,不利于LED的控制,如下图(图片来自任务3的内容);
2、采集到的数值会出现负值。
所以需要对采集到的数值进行处理。
本次处理的方式是,先求绝对值,将负值变为正值,再进行滑动平均滤波。
全部带码如下:
#include "PDM.h"
#include "WiFiNINA.h"
#define Led1 LEDR
#define Led2 LEDG
#define Led3 LEDB
#define MAX_SIZE 10
int head = 0;
int tail = 0;
int count = 0;
int queue[MAX_SIZE];
static const char channels = 1;
static const int frequncy = 24000;
short sampleBuffer[512];
volatile int samplesRead;
int LEDR_Value;
int LEDG_Value;
double MIC_Value;
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
pinMode(Led1, OUTPUT);
pinMode(Led2, OUTPUT);
PDM.onReceive(onPDMdata);
if(!PDM.begin(channels,frequncy))
{
Serial.println("Failed to start PDM!!!");
while(1);
}
}
void loop() {
// put your main code here, to run repeatedly:
if(samplesRead)
{
for(int i = 0; i < samplesRead; i++)
{
//Serial.println(sampleBuffer[i]);
MIC_Value=get_sliding_average(sampleBuffer[i]);
Serial.println(MIC_Value);
LEDR_Value=map(MIC_Value, 1, 3000, 1, 255);
LEDG_Value=map(MIC_Value, 1, 3000, 255, 1);
// analogWrite(Led1 ,LEDR_Value);
// analogWrite(Led2 ,LEDG_Value);
analogWrite(Led2 ,LEDR_Value);
analogWrite(Led1 ,LEDG_Value);
}
samplesRead=0;
}
delay(1);
}
void onPDMdata(){
int bytesAvailable = PDM.available();
PDM.read(sampleBuffer,bytesAvailable);
samplesRead = bytesAvailable / 2;
}
void enqueue(int value) {
if ((tail + 1) % MAX_SIZE == head) {
// 队列已满,需要先移除一个元素
head = (head + 1) % MAX_SIZE;
}
queue[tail] = value;
tail = (tail + 1) % MAX_SIZE;
count++;
}
int dequeue() {
int value = queue[head];
head = (head + 1) % MAX_SIZE;
count--;
return value;
}
double get_sliding_average(int new_value) {
static int init = 1;
if (init) {
// 初始化添加MAX_SIZE-1个0,保证头尾指针不会相遇
for (int i = 0; i < MAX_SIZE - 1; i++) {
enqueue(0);
}
init = 0;
}
// 添加新的样本值
enqueue(sqrt(new_value * new_value));
// 计算滑动平均值
double sum = 0;
for (int i = 0; i < count; i++) {
sum += queue[(head + i) % MAX_SIZE];
}
return sum / count;
}
滑动平均滤波函数中,直接对采集到的数值进行取绝对值;
在主程序中,通过映射,将数值转换为1-255,控制LEDR和LEDG;当声音小的时候,绿灯亮,声音大的时候,红灯亮。
下面看一下演示视频。
|