本帖最后由 littlehao 于 2024-12-11 20:21 编辑
【Follow me第二季第4期】任务汇总
作为一名理工科学渣,很有幸可以参与到得捷和EEWORLD联合举办的Follow me活动。以前简单接触过ESP8266开发板,也只是停留在调试一些基础的功能,这次申请的Arduino Nano RP2040 Connect也是第一次接触,接下来我会按照要求详情介绍任务完成情况,如有论述不当还请大家见谅并及时指正,谢谢!
任务介绍以及实现进度
物料名称: Arduino® Nano RP2040 Connect (搭载功能丰富的Raspberry Pi RP2040微控制器,将其融入到Nano尺寸封装中。充分利用双核32位Arm® Cortex®-M0+处理器,通过U-blox® Nina W102模块实现蓝牙和WiFi连接,集速度计、陀螺仪、RGB LED和麦克风于一体)
实物图片:
任务汇总:Blink三色LED/串口打印、IMU六轴数据打印、打印PDM麦克风收音数据和音频波形、通过LED颜色变化显示PDM麦克风声音大小
- 任务一:搭建环境并开启第一步Blink三色LED / 串口打印Hello DigiKey & EEWorld!;
- 任务二:学习IMU基础知识,调试IMU传感器,通过串口打印六轴原始数据;
- 任务三:学习PDM麦克风技术知识,调试PDM麦克风,通过串口打印收音数据和音频波形。
- 任务四:通过RGB LED不同颜色、亮度显示PDM麦克风收到的声音大小;
任务一:搭建环境并开启第一步Blink三色LED / 串口打印Hello DigiKey & EEWorld!;
所需元件: RGB LED
在数据手册P11可以看到Nina W102模块提供WIFI和蓝牙连接,其中RGB LED也由该模块控制,使LED在数字状态为High时关闭,Low时打开。
3.4 Wi-Fi®/Bluetooth® Connectivity
Wi-Fi® and Bluetooth® connectivity is provided by the Nina W102 (U2) module. The Nano RP2040 Connect only has 4 analog pins, and the Nina is used to extend that to the full eight as is standard in the Arduino Nano form factor with another 4 12-bit analog inputs (A4-A7). Additionally, the common anode RGB LED is also controlled by the Nina W-102 module such that the LED is off when the digital state is HIGH and on when the digital state is LOW. The internal PCB antenna in the module eliminates the need for an external antenna. The Nina W102 module also includes a dual core Xtensa LX6 CPU that can also be programmed independently of the RP2040 through the pads under the board using SWD.
从下图的原理图中也可以看出,需要引用 WiFiNINA 库才能调用LED。实现三色闪烁效果需LEDR&LEDG&LEDB循环输出低电平。
流程图:
代码片段及功能展示:
#Blink三色LED
#include <WiFiNINA.h>
#define led1 LEDR
#define led2 LEDG
#define led3 LEDB
void setup(){
//设置串口打印后续Print
Serial.begin(9600);
//设置引脚输出模式
pinMode(led1,OUTPUT);
pinMode(led2,OUTPUT);
pinMode(led3,OUTPUT);
}
void loop(){
//高低电平控制开关,灯光闪烁延迟200ms
digitalWrite(led1,LOW);
digitalWrite(led2,HIGH);
delay(200);
digitalWrite(led2,LOW);
digitalWrite(led3,HIGH);
delay(200);
digitalWrite(led3,LOW);
digitalWrite(led1,HIGH);
delay(200);
//打印
Serial.println("Hello DigiKey & EEWorld!");
delay(1000);
}
#串口打印Hello DigiKey & EEWorld
任务二:学习IMU基础知识,调试IMU传感器,通过串口打印六轴原始数据;
所需元件:LSM6DSOX IMU
IMU是采用惯性定律原理实现的,通过LSM6DSOX这个六轴IMU提供了一组3D陀螺仪和3D加速计。
3.5 6-Axis
IMU It is possible to obtain 3D gyroscope and 3D accelerometer data from the LSM6DSOX 6-axis IMU (U9). In addition to providing such data, it is also possible to do machine learning on the IMU for gesture detection.
- 加速度计是一种用于测量加速度的机电设备。这些力可能是静态的,例如重力的连续力,或者像许多移动设备一样,动态的,用于感应运动或振动。
- 陀螺仪传感器是一种可以测量和保持物体的方向和角速度的设备。陀螺仪比加速度计更先进,因为它们可以测量物体的倾斜和横向,而加速度计只能测量其线性运动。
流程图:
代码片段及功能展示:
#include <Arduino_LSM6DSOX.h>
float acc_x, acc_y, acc_z; //定义加速度坐标轴
float gyro_x, gyro_y, gyro_z; //定义角速度坐标轴
int update_flag;
void setup() {
Serial.begin(9600);
while (!Serial);
if (!IMU.begin()) {
Serial.println("Failed to initialize IMU!");
while (1);
}
Serial.print("Accelerometer sample rate = ");
Serial.print(IMU.accelerationSampleRate());
Serial.println(" Hz");
Serial.print("GYro sample rate = ");
Serial.print(IMU.gyroscopeSampleRate());
Serial.println(" Hz");
}
void loop() {
if (IMU.accelerationAvailable()) {
IMU.readAcceleration(acc_x, acc_y, acc_z);
update_flag = 1;
}
if (IMU.gyroscopeAvailable()) {
IMU.readGyroscope(gyro_x, gyro_y, gyro_z);
update_flag = 1;
}
if (update_flag) {
update_flag = 0;
Serial.print("Acceleration_X = ");
Serial.print(acc_x);
Serial.print('\t');
Serial.print("Acceleration_Y = ");
Serial.print(acc_y);
Serial.print('\t');
Serial.print("Acceleration_Z = ");
Serial.print(acc_z);
Serial.print('\n');
Serial.print("Gyroscope_X = ");
Serial.print(gyro_x);
Serial.print('\t');
Serial.print("Gyroscope_Y = ");
Serial.print(gyro_y);
Serial.print('\t');
Serial.print("Gyroscope_Z = ");
Serial.print(gyro_z);
Serial.print('\n');
}
delay(1000);
}
任务三:学习PDM麦克风技术知识,调试PDM麦克风,通过串口打印收音数据和音频波形。
所需元件:MP34DT06JTR 麦克风
MP34DT06JTR 传感器是一种超小型麦克风,它使用 PDM(pulse density mdulation, 脉冲密度调制)来表示具有二进制信号的模拟信号。
电容式麦克风(Condenser Micphone):根据电容两片隔板间距离的改变来产生电压变化。当声波进入麦克风,振膜产生振动,使得振动膜和基板之间的距离会随着振动而改变,于是基板间的电容会变,根据Q=C*V(电容式麦克风中电容极板的电压会维持一个定值)得到变化的电荷量Q。MEMS麦克风包含一个第二半导体芯片,该芯片充当音频前置放大器,用于将MEMS不断变化的电容转换为电信号。如果首选模拟输出信号,则可向用户提供音频前置放大器的输出。不过,如果需要数字输出信号,则在该音频前置放大器的同一芯片上集成了一个模数转换器 (ADC)。脉冲密度调制 (PDM) 是用于MEMS麦克风数字编码的传统格式,只需一条数据线和一个时钟便可实现通信。
流程图:
代码片段及功能展示:
#include <PDM.h>
// 默认输出信道
static const char channels = 1;
// 默认PCM输出频率
static const int frequency = 24000;
// 用于读取样本的缓冲区,每个样本为16位
short sampleBuffer[512];
// 读取的音频样本数
volatile int samplesRead;
void setup() {
Serial.begin(115200);
while (!Serial);
// 配置数据接收回调
PDM.onReceive(onPDMdata);
if (!PDM.begin(channels, frequency)) {
Serial.println("Failed to start PDM!");
while (1);
}
}
void loop() {
// 等待读取样本
if (samplesRead) {
// 将样本打印到串行监视器或绘图仪
for (int i = 0; i < samplesRead; i++) {
if(channels == 2) {
Serial.print("L:");
Serial.print(sampleBuffer[i]);
Serial.print(" R:");
i++;
}
Serial.println(sampleBuffer[i]);
}
// 清除读取计数
samplesRead = 0;
}
delay(10);
}
void onPDMdata() {
// 获取PDM缓存可读字节数
int bytesAvailable = PDM.available();
// 将缓存读取到Buff中
PDM.read(sampleBuffer, bytesAvailable);
// 16-bit, 2 bytes per sample
samplesRead = bytesAvailable / 2;
}
任务四:通过RGB LED不同颜色、亮度显示PDM麦克风收到的声音大小;
所需元件:PDM库&WIFININA库
通过RGB LED不同颜色、亮度来达到显示PDM麦克风收到的声音不同大小的目的。
数字音频部分,计算声音/音量/振幅(音量或振幅)采用均方根法(RMS,Root Mean Square),计算采样值的平方平均再开方,能更稳定地反映声音的大小。
(参考Netseye帖子)
代码片段及功能展示:
根据音量等级,设置 LED 的颜色或亮度。例如:
#include <PDM.h>
#include <WiFiNINA.h>
// 默认输出通道数
static const char channels = 1;
// 默认 PCM 输出频率
static const int frequency = 20000;
// 用于读取样本的缓冲区,每个样本是 16 位
short sampleBuffer[512];
// 已读取的音频样本数量
volatile int samplesRead;
void setup() {
Serial.begin(115200); // 初始化串口通信
while (!Serial);
// 设置LED 引脚输出
pinMode(LEDR, OUTPUT);
pinMode(LEDG, OUTPUT);
pinMode(LEDB, OUTPUT);
// 配置数据回调函数
PDM.onReceive(onPDMdata);
if (!PDM.begin(channels, frequency)) {
Serial.println("Failed to start PDM!");
while (1); // 启动失败
}
}
void loop() {
// 等待读取样本
if (samplesRead) {
float rms = getRMSAmplitude(sampleBuffer, samplesRead);
controlLEDs(rms);
Serial.println(rms);
samplesRead = 0;
}
}
// 查询可用字节数,从 PDM 麦克风读取数据到样本缓冲区
void onPDMdata() {
int bytesAvailable = PDM.available();
PDM.read(sampleBuffer, bytesAvailable);
samplesRead = bytesAvailable / 2;
}
//均方根法(RMS,Root Mean Square)它计算采样值的平方平均再开方,能更稳定地反映声音的大小
float getRMSAmplitude(short *buffer, int length) {
long sum = 0;
for (int i = 0; i < length; i++) {
sum += (long)buffer[i] * buffer[i]; // 计算平方和
}
float rms = sqrt(sum / (float)length); // 计算平方平均值并开方
return rms;
}
//峰值振幅法(Peak Amplitude)计算采样数据中的最大或最小振幅,取绝对值的最大值。
// int16_t getMaxAmplitude(short *buffer, int length) {
// int16_t maxAmplitude = 0;
// for (int i = 0; i < length; i++) {
// int16_t amplitude = abs(buffer[i]);
// if (amplitude > maxAmplitude) {
// maxAmplitude = amplitude;
// }
// }
// return maxAmplitude; // 返回最大振幅
// }
void controlLEDs(float rms) {
// rms<500红色LED亮起
if (rms < 500) {
digitalWrite(LEDR, HIGH);
digitalWrite(LEDG, LOW);
digitalWrite(LEDB, LOW);
}
// 500<rms<1500绿色LED亮起
else if (rms < 1500) {
digitalWrite(LEDR, LOW);
digitalWrite(LEDG, HIGH);
digitalWrite(LEDB, LOW);
}
// 1500<rms<3000蓝色LED亮起
else if (rms < 3000) {
digitalWrite(LEDR, LOW);
digitalWrite(LEDG, LOW);
digitalWrite(LEDB, HIGH);
}
// rms>3000LED全亮
else {
digitalWrite(LEDR, HIGH);
digitalWrite(LEDG, HIGH);
digitalWrite(LEDB, HIGH);
}
}
心得体会&总结
感谢 DigiKey 和 EEWorld 对 【Follow me第二季第4期】活动的支持,感谢微信群友们和论坛小伙伴们的陪伴和无私帮助。本次活动依靠 Arduino Nano RP2040 Connect 开发板完成了四个任务,更加充分地理解了WiFi、IMU 、PDM 等模块的应用。而且代码所用到的函数基本上都封装即用,只需要调用对应的库函数对于我这种初学者十分友善。希望 Follow me 活动可以继续办下去,以后还有机会能参与进来和大家一起共同进步、成长。
|