本文继承自之前的👉彩灯驱动章节
本文完成的效果:

1. 硬件准备#
1.1. WS2812矩阵彩灯#

购买地址:WS2812B全彩软像素屏8X8 8X32 16X16幻彩5V显示可编程像素软屏
1.2. 麦克风模块#

购买地址:GY-MAX4466 声音传感器模块 MAX4466麦克风前置放大器 提供程序
1.3. ESP32S3开发板#

购买地址:立创·ESP32S3R8N8 开发板
2. 工程创建#
在VSCode中打开PlatformIO扩展创建名为OscillatingLED
的 Espressif ESP32-S3-DevKitM-1
工程。
关于详细图文创建工程的过程请参考👉RTC时钟驱动章节的工程创建小节。
3. 安装驱动库#
创建完成之后,打开驱动库下载界面。实现功能的最底层的驱动,需要分别安装三个库:
搜索Adafruit NeoMatrix
,安装来自Adafruit
的Adafruit NeoMatrix
库。
搜索Adafruit GFX Library
,安装来自Adafruit
的Adafruit GFX Library
库。
搜索arduinoFFT
,安装来自Enrique Condes
的arduinoFFT
库。
将它们都安装到我们的工程当中。
关于详细图文安装驱动库的过程请参考👉RTC时钟驱动章节的安装驱动库小节。
都安装完成之后,打开platformio.ini
文件,应该可以看到已经安装上了三个驱动库。

4. 编辑代码#
在工程下的include
文件夹下新建一个 musicfft.h
文件。
接下来往 musicfft.h
文件写入代码:
#include <Adafruit_NeoMatrix.h>
#include <arduinoFFT.h>
#define CHANNEL 1
#define xres 32
#define yres 8
const uint16_t samples = 64;
const double samplingFrequency = 4000;
unsigned int sampling_period_us;
unsigned long microseconds;
unsigned long lastTime = 0;
unsigned long fallingTime = 0;
double vReal[samples];
double vImag[samples];
int freq_gain2[xres] = {30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30};
int Intensity[xres] = {};
int FallingPoint[xres] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
int Displacement = 1;
ArduinoFFT<double> FFT = ArduinoFFT<double>(vReal, vImag, samples, samplingFrequency);
void getSamples(){
microseconds = micros();
for(int i = 0; i < samples; i++){
vReal[i] = analogRead(CHANNEL);
vImag[i] = 0;
microseconds += sampling_period_us;
}
bool reduce = false;
if ((millis() - lastTime) > 16) {
lastTime = millis();
reduce = true;
}
FFT.windowing(vReal, 1, FFT_WIN_TYP_HAMMING, FFT_FORWARD);
FFT.compute(vReal, vImag, samples, FFT_FORWARD);
FFT.complexToMagnitude(vReal, vImag, samples);
int t = 16;
for(int i = t; i < (xres*Displacement)+t; i+=Displacement){
vReal[i] = constrain(vReal[i], 0 ,3596);
vReal[i] = map(vReal[i], freq_gain2[(i-t)/Displacement], 1548, 0, yres);
if(reduce){
Intensity[(i-t)/Displacement] --;
}
if (vReal[i] > Intensity[(i-t)/Displacement])
Intensity[(i-t)/Displacement] = vReal[i];
}
}
void drawYLine(Adafruit_NeoMatrix *matrix, int16_t x, int16_t y, int16_t h, int16_t c){
for(int i=y;i<y+h;i++){
matrix->drawPixel(x,7 - i,c);
}
}
uint16_t hsv2rgb2(Adafruit_NeoMatrix *matrix, uint16_t hue, uint8_t saturation, uint8_t value)
{
uint8_t red = 0;
uint8_t green = 0;
uint8_t blue = 0;
uint16_t hi = (hue / 60) % 6;
uint16_t F = 100 * hue / 60 - 100 * hi;
uint16_t P = value * (100 - saturation) / 100;
uint16_t Q = value * (10000 - F * saturation) / 10000;
uint16_t T = value * (10000 - saturation * (100 - F)) / 10000;
switch (hi)
{
case 0:
red = value;
green = T;
blue = P;
break;
case 1:
red = Q;
green = value;
blue = P;
break;
case 2:
red = P;
green = value;
blue = T;
break;
case 3:
red = P;
green = Q;
blue = value;
break;
case 4:
red = T;
green = P;
blue = value;
break;
case 5:
red = value;
green = P;
blue = Q;
break;
default:
return matrix->Color(255, 0, 0);
}
red = red * 255 / 100;
green = green * 255 / 100;
blue = blue * 255 / 100;
return matrix->Color(red, green, blue);
}
void displayUpdate(Adafruit_NeoMatrix *matrix, int displayPattern){
int color = 0;
switch(displayPattern){
case 0:
for(int i = 0; i < xres; i++){
drawYLine(matrix,i,yres-Intensity[i],Intensity[i],hsv2rgb2(matrix, color, 80, 80 ));
drawYLine(matrix,i,0,yres-1-Intensity[i],hsv2rgb2(matrix, color, 80, 80 ));
color += 360/xres;
}
break;
case 1:
if ((millis() - fallingTime) > 130) {
for(int i = 0; i < xres; i++){
if(FallingPoint[i]>0){
FallingPoint[i]--;
}
}
fallingTime = millis();
}
for(int i = 0; i < xres; i++){
drawYLine(matrix,i,0,yres-1,matrix->Color(0,0,0));
if(FallingPoint[i]<Intensity[i]){
FallingPoint[i] = Intensity[i];
}
drawYLine(matrix,i,yres-Intensity[i]+1,Intensity[i]-1,hsv2rgb2(matrix, color, 80, 80 ));
if(FallingPoint[i]>0){
matrix->drawPixel(i,yres-FallingPoint[i],matrix->Color(255,255,255));
}
color += 360/xres;
}
break;
case 2:
for(int i = 0; i < xres; i++){
drawYLine(matrix,i,0,yres,matrix->Color(0,0,0));
drawYLine(matrix,i,0,Intensity[i]+1,hsv2rgb2(matrix, color, 80, 80 ));
color += 360/xres;
}
break;
}
}
接下来在 main.cpp
中编写以下代码:
5. 硬件连接#

6. 代码验证
代码编写完成之后,将ESP32S3开发板接入电脑下载代码。然后观察彩灯矩阵的现象。
实物显示如下:
使用黑色亚克力面板+白纸格挡光线显示
叠层从上到下是这样的:黑色亚克力面板 -> 白纸 -> LED矩阵

说明:如果你根据代码操作运行不起来,可以下载👉例程看看
Gitalking ...