【Follow me第二季第4期】Arduino Nano RP2040学习总结+FFT音频灯
[复制链接]
本帖最后由 eew_cT3H5d 于 2024-12-31 22:54 编辑
活动链接:https://www.eeworld.com.cn/huodong/digikey_follow_me_2024_04/
先放最后项目:FFT音频灯,然后在讲述【Follow me第二季第4期】Arduino Nano RP2040学习总结
扩展任务:FFT音频灯项目
项目效果演示:
FFT音频LED灯
效果展示:
程序代码:
程序流程图:
傅里叶FFT变换原理
硬件组成连接框图:
参考来源:
下面进行讲解【Follow me第二季第4期】学习过程
准备工作:
1)开发板介绍
2)安装开发板支持包
3)安装开发板WIFI支持包
4)板载负载驱动引脚
5)开发板数字I/O引脚
6)开发板相关通讯引脚
必做任务一:搭建环境并开启第一步Blink三色LED / 串口打印Hello DigiKey & EEWorld!
程序代码:备注digitalWrite(!digitalRead())不能直接使用
#include <WiFiNINA.h>
void setup() {
Serial.begin(115200);
pinMode(LEDR,OUTPUT);
pinMode(LEDG,OUTPUT);
pinMode(LEDB, OUTPUT);
}
void loop() {
digitalWrite(LEDR, LOW);//0
digitalWrite(LEDG, LOW);//0
digitalWrite(LEDB, LOW);//0
Serial.println("Hello DigiKey & EEWorld!");
delay(200);
digitalWrite(LEDR, HIGH);//1
digitalWrite(LEDG, HIGH);//1
digitalWrite(LEDB, HIGH);//1
Serial.println("Hello DigiKey & EEWorld!");
delay(200);
}
点亮三色LED效果(红、绿、蓝构成白色):
串口接收数据:
程序流程图:
扩展:点亮ws2812数字全彩LED
下载库:
打开案例库:
选择GPIO5作为驱动引脚
程序代码:
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#include <avr/power.h> // Required for 16 MHz Adafruit Trinket
#endif
#define LED_PIN 5
// How many NeoPixels are attached to the Arduino?
#define LED_COUNT 64
Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);
void setup() {
// These lines are specifically to support the Adafruit Trinket 5V 16 MHz.
// Any other board, you can remove this part (but no harm leaving it):
#if defined(__AVR_ATtiny85__) && (F_CPU == 16000000)
clock_prescale_set(clock_div_1);
#endif
// END of Trinket-specific code.
strip.begin(); // INITIALIZE NeoPixel strip object (REQUIRED)
strip.show(); // Turn OFF all pixels ASAP
strip.setBrightness(50); // Set BRIGHTNESS to about 1/5 (max = 255)
}
void loop() {
// Fill along the length of the strip in various colors...
colorWipe(strip.Color(255, 0, 0), 50); // Red
colorWipe(strip.Color( 0, 255, 0), 50); // Green
colorWipe(strip.Color( 0, 0, 255), 50); // Blue
theaterChase(strip.Color(127, 127, 127), 50); // White, half brightness
theaterChase(strip.Color(127, 0, 0), 50); // Red, half brightness
theaterChase(strip.Color( 0, 0, 127), 50); // Blue, half brightness
rainbow(10); // Flowing rainbow cycle along the whole strip
theaterChaseRainbow(50); // Rainbow-enhanced theaterChase variant
}
void colorWipe(uint32_t color, int wait) {
for(int i=0; i<strip.numPixels(); i++) { // For each pixel in strip...
strip.setPixelColor(i, color); // Set pixel's color (in RAM)
strip.show(); // Update strip to match
delay(wait); // Pause for a moment
}
}
void theaterChase(uint32_t color, int wait) {
for(int a=0; a<10; a++) { // Repeat 10 times...
for(int b=0; b<3; b++) { // 'b' counts from 0 to 2...
strip.clear(); // Set all pixels in RAM to 0 (off)
// 'c' counts up from 'b' to end of strip in steps of 3...
for(int c=b; c<strip.numPixels(); c += 3) {
strip.setPixelColor(c, color); // Set pixel 'c' to value 'color'
}
strip.show(); // Update strip with new contents
delay(wait); // Pause for a moment
}
}
}
// Rainbow cycle along whole strip. Pass delay time (in ms) between frames.
void rainbow(int wait) {
for(long firstPixelHue = 0; firstPixelHue < 5*65536; firstPixelHue += 256) {
strip.rainbow(firstPixelHue);
strip.show(); // Update strip with new contents
delay(wait); // Pause for a moment
}
}
// Rainbow-enhanced theater marquee. Pass delay time (in ms) between frames.
void theaterChaseRainbow(int wait) {
int firstPixelHue = 0; // First pixel starts at red (hue 0)
for(int a=0; a<30; a++) { // Repeat 30 times...
for(int b=0; b<3; b++) { // 'b' counts from 0 to 2...
strip.clear(); // Set all pixels in RAM to 0 (off)
for(int c=b; c<strip.numPixels(); c += 3) {
int hue = firstPixelHue + c * 65536L / strip.numPixels();
uint32_t color = strip.gamma32(strip.ColorHSV(hue)); // hue -> RGB
strip.setPixelColor(c, color); // Set pixel 'c' to value 'color'
}
strip.show(); // Update strip with new contents
delay(wait); // Pause for a moment
firstPixelHue += 65536 / 90; // One cycle of color wheel over 90 frames
}
}
}
程序流程图:
驱动ws2812模块效果:
必做任务二:学习IMU基础知识,调试IMU传感器,通过串口打印六轴原始数据;
下载库LSM6DSOX
程序代码:
#include <Arduino_LSM6DSOX.h>
void setup() {
Serial.begin(115200); // 初始化串口
while (!Serial); // 等待串口连接
if (!IMU.begin()) {
Serial.println("无法初始化 LSM6DSOX IMU 传感器!");
while (1);
}
Serial.println("LSM6DSOX IMU 传感器已初始化");
}
void loop() {
float ax, ay, az; // 加速度
float gx, gy, gz; // 角速度
// 读取加速度值
if (IMU.accelerationAvailable()) {
IMU.readAcceleration(ax, ay, az);
Serial.print("加速度 (m/s^2): X=");
Serial.print(ax);
Serial.print(" Y=");
Serial.print(ay);
Serial.print(" Z=");
Serial.println(az);
}
// 读取角速度值
if (IMU.gyroscopeAvailable()) {
IMU.readGyroscope(gx, gy, gz);
Serial.print("陀螺仪 (rad/s): X=");
Serial.print(gx);
Serial.print(" Y=");
Serial.print(gy);
Serial.print(" Z=");
Serial.println(gz);
}
delay(100); // 延迟 500 毫秒
}
程序流程图:
编译下载程序:
必做任务三:学习PDM麦克风技术知识,调试PDM麦克风,通过串口打印收音数据和音频波形。
打开案例库:
编译程序:
程序流程图:
程序代码:
#include <PDM.h>
// default number of output channels
static const char channels = 1;
// default PCM output frequency
static const int frequency = 16000;
// Buffer to read samples into, each sample is 16-bits
short sampleBuffer[512];
// Number of audio samples read
volatile int samplesRead;
void setup() {
Serial.begin(9600);
while (!Serial);
// Configure the data receive callback
PDM.onReceive(onPDMdata);
// Optionally set the gain
// Defaults to 20 on the BLE Sense and 24 on the Portenta Vision Shield
// PDM.setGain(30);
// Initialize PDM with:
// - one channel (mono mode)
// - a 16 kHz sample rate for the Arduino Nano 33 BLE Sense
// - a 32 kHz or 64 kHz sample rate for the Arduino Portenta Vision Shield
if (!PDM.begin(channels, frequency)) {
Serial.println("Failed to start PDM!");
while (1);
}
}
void loop() {
// Wait for samples to be read
if (samplesRead) {
// Print samples to the serial monitor or plotter
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]);
}
// Clear the read count
samplesRead = 0;
}
}
/**
* Callback function to process the data from the PDM microphone.
* NOTE: This callback is executed as part of an ISR.
* Therefore using `Serial` to print messages inside this function isn't supported.
* */
void onPDMdata() {
// Query the number of available bytes
int bytesAvailable = PDM.available();
// Read into the sample buffer
PDM.read(sampleBuffer, bytesAvailable);
// 16-bit, 2 bytes per sample
samplesRead = bytesAvailable / 2;
}
串口打印数据:
选做任务一(非必做):通过RGB LED不同颜色、亮度显示PDM麦克风收到的声音大小;
参考内容:https://docs.arduino.cc/tutorials/nano-rp2040-connect/rp2040-microphone-basics/
演示效果:不同敲击显示不同颜色
程序代码:
#include <WiFiNINA.h>
#include <PDM.h>
bool LED_SWITCH = false;
// default number of output channels
static const char channels = 1;
// default PCM output frequency
static const int frequency = 20000;
// Buffer to read samples into, each sample is 16-bits
short sampleBuffer[512];
// Number of audio samples read
volatile int samplesRead;
void setup() {
Serial.begin(9600);
pinMode(LEDB, OUTPUT);
while (!Serial);
// Configure the data receive callback
PDM.onReceive(onPDMdata);
// Optionally set the gain
// Defaults to 20 on the BLE Sense and -10 on the Portenta Vision Shields
// PDM.setGain(30);
// Initialize PDM with:
// - one channel (mono mode)
// - a 16 kHz sample rate for the Arduino Nano 33 BLE Sense
// - a 32 kHz or 64 kHz sample rate for the Arduino Portenta Vision Shields
if (!PDM.begin(channels, frequency)) {
Serial.println("Failed to start PDM!");
while (1);
}
}
void loop() {
// Wait for samples to be read
if (samplesRead) {
// Print samples to the serial monitor or plotter
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]);
if (sampleBuffer[i] > 10000 || sampleBuffer[i] <= -10000) {
LED_SWITCH = !LED_SWITCH;
if (LED_SWITCH) {
Serial.println();
digitalWrite(LEDR, HIGH);
Serial.println("ON!");
Serial.println();
delay(100);
}
else {
Serial.println();
digitalWrite(LEDR, LOW);
Serial.println("OFF!");
Serial.println();
delay(100);
}
}
if (sampleBuffer[i] > 8000 || sampleBuffer[i] <= -8000) {
LED_SWITCH = !LED_SWITCH;
if (LED_SWITCH) {
Serial.println();
digitalWrite(LEDG, HIGH);
Serial.println("ON!");
Serial.println();
delay(100);
}
else {
Serial.println();
digitalWrite(LEDG, LOW);
Serial.println("OFF!");
Serial.println();
delay(100);
}
}
if (sampleBuffer[i] > 5000 || sampleBuffer[i] <= -5000) {
LED_SWITCH = !LED_SWITCH;
if (LED_SWITCH) {
Serial.println();
digitalWrite(LEDB, HIGH);
Serial.println("ON!");
Serial.println();
delay(100);
}
else {
Serial.println();
digitalWrite(LEDB, LOW);
Serial.println("OFF!");
Serial.println();
delay(100);
}
}
}
// Clear the read count
samplesRead = 0;
}
}
/**
Callback function to process the data from the PDM microphone.
NOTE: This callback is executed as part of an ISR.
Therefore using `Serial` to print messages inside this function isn't supported.
* */
void onPDMdata() {
// Query the number of available bytes
int bytesAvailable = PDM.available();
// Read into the sample buffer
PDM.read(sampleBuffer, bytesAvailable);
// 16-bit, 2 bytes per sample
samplesRead = bytesAvailable / 2;
}
程序流程图:
一 、3-5分钟短视频
视频链接:https://training.eeworld.com.cn/course/68912/learn?preview=1#lesson/42241
Follow me第二季第4期
二、任务实现详情
本帖内容
项目总结:通过这次Follow me第二季第4期活动,熟悉Arduino编程环境搭建及开发板的使用,通过移植FFT音频LED加深对Arduino Nano RP2040了解。
三、可编译下载的代码
地址:https://download.eeworld.com.cn/detail/eew_cT3H5d/635478
|