驴友花雕 发表于 3 天前

【Arduino 动手做】ESP32 带有 INMP441 的 WS2812B 矩阵

ESP32-INMP441-Matrix-VU
重要提示:目前,该代码仅适用于 ESP32 核心 1.0.6,在 2.0.0 上不可靠。我认为这是一个 FastLED 问题,但我可能错了!使用 Boards Manager 恢复到 1.0.6 以便编译和上传。

这是 3D 打印的(可选)电池供电的 WS2812B LED 矩阵的存储库,它使用来自 INMP441 数字麦克风的音频输入产生漂亮的图案,并在 ESP32 上运行。在下面的 YouTube 链接中观看解释视频:

硬件
您至少需要:
可以使用用于生产外壳的 3D 打印机,STL。
ESP32 开发板,确切的类型并不重要。
一个 8x8 (80x80 mm) 或 16x16 (160x160 mm) WS2812B LED 矩阵。
我的代码应该适用于宽度为 8 或 16 的倍数的任何矩阵。高度并不重要。如果您使用的是 WLED,您可以拥有任何您喜欢的尺寸!
我的矩阵的数据输入位于左下角,并以水平之字形模式连接。
INMP441 I2S 麦克风。
电源开关
DC 输入插座和 5V 电源(如果您不是由电池供电)。
建造它的常用电子设备和设备。
无电池原理图

如果您想为您的创作提供电池,您还需要:
LiPo / LiIon 电池 - 确切规格取决于您需要的运行时间以及您用于充电/升压电路的解决方案。
一个充电/升压板,用于连接您的电池并为 LED 输出 5V。
或者,您可以为这些函数使用单独的模块,这对于更高功率的 16x16 矩阵来说可能是一个好主意。
电池原理图

软件
关于软件,您有两个主要选择,此存储库中给出的软件或 WLED Sound Reactive fork。任一选项的硬件连接都是相同的。与该软件相比,使用 WLED 有很多优点,它是一个更完整的解决方案,可以更好地支持同步多个控制器、设置模式播放列表和自定义现有的模式。我的软件唯一真正的优势是我想编写自己的模式,并且能够完全自定义事情的运作方式。您可以自由选择。如果您想使用我的软件,请继续阅读...

软件设置
下载代码,并确保已安装所有必需的库。它们列在 .ino 文件的顶部。
确保在软件中正确设置了矩阵的输入位置和接线样式。有关更多详细信息,请参阅 .ino 文件顶部的注释。
将 和 更改为矩阵的正确 LED 数量。M_WIDTHM_HEIGHT
进入 web_server.h 并将 、 、 和 更改为您的主网络凭证和备用网络凭证。ssidpasswordssid2password2
将代码上传到您的 ESP32 并希望一切顺利!

使用矩阵
每次您为矩阵供电时,它都会尝试连接到主 WiFi 网络 5 秒钟。如果失败,它将尝试辅助凭证 5 秒钟。如果此作也失败,它将回退到之前的设置,但您将无法进行任何更改。我已将辅助凭证设置为手机上的热点,因此我可以在家庭网络之外使用该设备。 如果成功连接到网络,ESP 的本地 IP 将在屏幕上滚动。在任何浏览器中转到此地址以更改设置。可以更改的设置包括:

下一个模式 - 不言自明。
Auto-change pattern (自动更改模式) - 将每隔几秒循环一次模式,定义如下...
在 auto 上显示每个模式的秒数 - 接受 1 到 65535 秒之间的值
亮度 - 在这里要小心,在最大亮度下,较大的面板可能会消耗许多安培。确保您的电源能够胜任工作!
增益 - 提高麦克风的灵敏度,以适应更响亮或更安静的环境。
静噪 - 增加此值会限制将拾取的最安静的声音。如果您有一些背景噪音要消除,则很有用。 这些设置保存在 EEPROM 中,因此它们在重启后应保持不变。












驴友花雕 发表于 3 天前

【Arduino 动手做】ESP32 带有 INMP441 的 WS2812B 矩阵

项目代码

/*
* Web enabled FFT VU meter for a matrix, ESP32 and INMP441 digital mic.
* The matrix width MUST be either 8 or a multiple of 16 but the height can
* be any value. E.g. 8x8, 16x16, 8x10, 32x9 etc.
*
* We are using the LEDMatrx library for easy setup of a matrix with various
* wiring options. Options are:
*HORIZONTAL_ZIGZAG_MATRIX
*HORIZONTAL_MATRIX
*VERTICAL_ZIGZAG_MATRIX
*VERTICAL_MATRIX
* If your matrix has the first pixel somewhere other than the bottom left
* (default) then you can reverse the X or Y axis by writing -M_WIDTH and /
* or -M_HEIGHT in the cLEDMatrix initialisation.
*
* REQUIRED LIBRARIES
* FastLED            Arduino libraries manager
* ArduinoFFT         Arduino libraries manager
* EEPROM             Built in
* WiFi               Built in
* AsyncTCP         https://github.com/me-no-dev/ESPAsyncWebServer
* ESPAsyncWebServerhttps://github.com/me-no-dev/AsyncTCP
* LEDMatrix          https://github.com/AaronLiddiment/LEDMatrix
* LEDText            https://github.com/AaronLiddiment/LEDText
*
* WIRING
* LED data   D2 via 470R resistor
* GND          GND
* Vin          5V
*
* INMP441
* VDD          3V3
* GND          GND
* L/R          GND
* WS         D15
* SCK          D14   
* SD         D32
*
* REFERENCES
* Main code      Scott Marley            https://www.youtube.com/c/ScottMarley
* Web server   Random Nerd Tutorials   https://randomnerdtutorials.com/esp32-web-server-slider-pwm/
*                                  and   https://randomnerdtutorials.com/esp32-websocket-server-arduino/
* Audio and micAndrew Tuline et al   https://github.com/atuline/WLED
*/

#include "audio_reactive.h"
#include <FastLED.h>
#include <LEDMatrix.h>
#include <LEDText.h>
#include <FontMatrise.h>
#include <EEPROM.h>

#define EEPROM_SIZE 5
#define LED_PIN   2
#define M_WIDTH   16
#define M_HEIGHT    16
#define NUM_LEDS    (M_WIDTH * M_HEIGHT)

#define EEPROM_BRIGHTNESS   0
#define EEPROM_GAIN         1
#define EEPROM_SQUELCH      2
#define EEPROM_PATTERN      3
#define EEPROM_DISPLAY_TIME 4

uint8_t numBands;
uint8_t barWidth;
uint8_t pattern;
uint8_t brightness;
uint16_t displayTime;
bool autoChangePatterns = false;

#include "web_server.h"

cLEDMatrix<M_WIDTH, M_HEIGHT, HORIZONTAL_ZIGZAG_MATRIX> leds;
cLEDText ScrollingMsg;

uint8_t peak[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
uint8_t prevFFTValue[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
uint8_t barHeights[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

// Colors and palettes
DEFINE_GRADIENT_PALETTE( purple_gp ) {
0,   0, 212, 255,   //blue
255, 179,   0, 255 }; //purple
DEFINE_GRADIENT_PALETTE( outrun_gp ) {
0, 141,   0, 100,   //purple
127, 255, 192,   0,   //yellow
255,   0,   5, 255 };//blue
DEFINE_GRADIENT_PALETTE( greenblue_gp ) {
0,   0, 255,60,   //green
64,   0, 236, 255,   //cyan
128,   0,   5, 255,   //blue
192,   0, 236, 255,   //cyan
255,   0, 255,60 }; //green
DEFINE_GRADIENT_PALETTE( redyellow_gp ) {
0,   200, 200,200,   //white
64,   255, 218,    0,   //yellow
128,   231,   0,    0,   //red
192,   255, 218,    0,   //yellow
255,   200, 200,200 }; //white
CRGBPalette16 purplePal = purple_gp;
CRGBPalette16 outrunPal = outrun_gp;
CRGBPalette16 greenbluePal = greenblue_gp;
CRGBPalette16 heatPal = redyellow_gp;
uint8_t colorTimer = 0;

void setup() {
FastLED.addLeds<WS2812B, LED_PIN, GRB>(leds, NUM_LEDS);
Serial.begin(57600);

setupWebServer();
setupAudio();

if (M_WIDTH == 8) numBands = 8;
else numBands = 16;
barWidth = M_WIDTH / numBands;

EEPROM.begin(EEPROM_SIZE);

// It should not normally be possible to set the gain to 255
// If this has happened, the EEPROM has probably never been written to
// (new board?) so reset the values to something sane.
if (EEPROM.read(EEPROM_GAIN) == 255) {
    EEPROM.write(EEPROM_BRIGHTNESS, 50);
    EEPROM.write(EEPROM_GAIN, 0);
    EEPROM.write(EEPROM_SQUELCH, 0);
    EEPROM.write(EEPROM_PATTERN, 0);
    EEPROM.write(EEPROM_DISPLAY_TIME, 10);
    EEPROM.commit();
}

// Read saved values from EEPROM
FastLED.setBrightness( EEPROM.read(EEPROM_BRIGHTNESS));
brightness = FastLED.getBrightness();
gain = EEPROM.read(EEPROM_GAIN);
squelch = EEPROM.read(EEPROM_SQUELCH);
pattern = EEPROM.read(EEPROM_PATTERN);
displayTime = EEPROM.read(EEPROM_DISPLAY_TIME);

if (WiFi.status() == WL_CONNECTED) showIP();
}

void loop() {
if (pattern != 5) FastLED.clear();

uint8_t divisor = 1;                                                    // If 8 bands, we need to divide things by 2
if (numBands == 8) divisor = 2;                                       // and average each pair of bands together

for (int i = 0; i < 16; i += divisor) {
    uint8_t fftValue;
   
    if (numBands == 8) fftValue = (fftResult + fftResult) / 2;    // Average every two bands if numBands = 8
    else fftValue = fftResult;

    fftValue = ((prevFFTValue * 3) + fftValue) / 4;            // Dirty rolling average between frames to reduce flicker
    barHeights = fftValue / (255 / M_HEIGHT);                  // Scale bar height
   
    if (barHeights > peak)                        // Move peak up
      peak = min(M_HEIGHT, (int)barHeights);
      
    prevFFTValue = fftValue;                                 // Save prevFFTValue for averaging later
   
}

// Draw the patterns
for (int band = 0; band < numBands; band++) {
    drawPatterns(band);
}

// Decay peak
EVERY_N_MILLISECONDS(60) {
    for (uint8_t band = 0; band < numBands; band++)
      if (peak > 0) peak -= 1;
}

EVERY_N_SECONDS(30) {
    // Save values in EEPROM. Will only be commited if values have changed.
    EEPROM.write(EEPROM_BRIGHTNESS, brightness);
    EEPROM.write(EEPROM_GAIN, gain);
    EEPROM.write(EEPROM_SQUELCH, squelch);
    EEPROM.write(EEPROM_PATTERN, pattern);
    EEPROM.write(EEPROM_DISPLAY_TIME, displayTime);
    EEPROM.commit();
}

EVERY_N_SECONDS_I(timingObj, displayTime) {
    timingObj.setPeriod(displayTime);
    if (autoChangePatterns) pattern = (pattern + 1) % 6;
}

FastLED.setBrightness(brightness);
FastLED.show();

ws.cleanupClients();
}

void drawPatterns(uint8_t band) {

uint8_t barHeight = barHeights;

// Draw bars
switch (pattern) {
    case 0:
      rainbowBars(band, barHeight);
      break;
    case 1:
      // No bars on this one
      break;
    case 2:
      purpleBars(band, barHeight);
      break;
    case 3:
      centerBars(band, barHeight);
      break;
    case 4:
      changingBars(band, barHeight);
      EVERY_N_MILLISECONDS(10) { colorTimer++; }
      break;
    case 5:
      createWaterfall(band);
      EVERY_N_MILLISECONDS(30) { moveWaterfall(); }
      break;
}

// Draw peaks
switch (pattern) {
    case 0:
      whitePeak(band);
      break;
    case 1:
      outrunPeak(band);
      break;
    case 2:
      whitePeak(band);
      break;
    case 3:
      // No peaks
      break;
    case 4:
      // No peaks
      break;
    case 5:
      // No peaks
      break;
}
}

void showIP(){
char strIP = "               ";
IPAddress ip = WiFi.localIP();
ip.toString().toCharArray(strIP, 16);
Serial.println(strIP);
ScrollingMsg.SetFont(MatriseFontData);
ScrollingMsg.Init(&leds, leds.Width(), ScrollingMsg.FontHeight() + 1, 0, 0);
ScrollingMsg.SetText((unsigned char *)strIP, sizeof(strIP) - 1);
ScrollingMsg.SetTextColrOptions(COLR_RGB | COLR_SINGLE, 0xff, 0xff, 0xff);
ScrollingMsg.SetScrollDirection(SCROLL_LEFT);
ScrollingMsg.SetFrameRate(160 / M_WIDTH);       // Faster for larger matrices

while(ScrollingMsg.UpdateText() == 0) {
    FastLED.show();
}
}

//////////// Patterns ////////////

void rainbowBars(uint8_t band, uint8_t barHeight) {
int xStart = barWidth * band;
for (int x = xStart; x < xStart + barWidth; x++) {
    for (int y = 0; y <= barHeight; y++) {
      leds(x,y) = CHSV((x / barWidth) * (255 / numBands), 255, 255);
    }
}
}

void purpleBars(int band, int barHeight) {
int xStart = barWidth * band;
for (int x = xStart; x < xStart + barWidth; x++) {
    for (int y = 0; y < barHeight; y++) {
      leds(x,y) = ColorFromPalette(purplePal, y * (255 / barHeight));
    }
}
}

void changingBars(int band, int barHeight) {
int xStart = barWidth * band;
for (int x = xStart; x < xStart + barWidth; x++) {
    for (int y = 0; y < barHeight; y++) {
      leds(x,y) = CHSV(y * (255 / M_HEIGHT) + colorTimer, 255, 255);
    }
}
}

void centerBars(int band, int barHeight) {
int xStart = barWidth * band;
for (int x = xStart; x < xStart + barWidth; x++) {
    if (barHeight % 2 == 0) barHeight--;
    int yStart = ((M_HEIGHT - barHeight) / 2 );
    for (int y = yStart; y <= (yStart + barHeight); y++) {
      int colorIndex = constrain((y - yStart) * (255 / barHeight), 0, 255);
      leds(x,y) = ColorFromPalette(heatPal, colorIndex);
    }
}
}

void whitePeak(int band) {
int xStart = barWidth * band;
int peakHeight = peak;
for (int x = xStart; x < xStart + barWidth; x++) {
    leds(x,peakHeight) = CRGB::White;
}
}

void outrunPeak(int band) {
int xStart = barWidth * band;
int peakHeight = peak;
for (int x = xStart; x < xStart + barWidth; x++) {
    leds(x,peakHeight) = ColorFromPalette(outrunPal, peakHeight * (255 / M_HEIGHT));
}
}

void createWaterfall(int band) {
int xStart = barWidth * band;
// Draw bottom line
for (int x = xStart; x < xStart + barWidth; x++) {
    leds(x,0) = CHSV(constrain(map(fftResult,0,254,160,0),0,160), 255, 255);
}
}

void moveWaterfall() {
// Move screen up starting at 2nd row from top
for (int y = M_HEIGHT - 2; y >= 0; y--) {
    for (int x = 0; x < M_WIDTH; x++) {
      leds(x,y+1) = leds(x,y);
    }
}
}

驴友花雕 发表于 3 天前

【Arduino 动手做】ESP32 带有 INMP441 的 WS2812B 矩阵

【Arduino 动手做】可 3D 打印的 ESP32 供电 VU 显示屏,带有 INMP441 数字麦克风和 WS2812B 矩阵
项目链接:https://github.com/s-marley/ESP32-INMP441-Matrix-VU
项目作者:S-马利

项目视频 :https://www.youtube.com/watch?v=9PEjvFkdpIE&t=14s
项目代码:https://github.com/s-marley/ESP32-INMP441-Matrix-VU/tree/main/INMP441Matrix
3D 文件:https://github.com/s-marley/ESP32-INMP441-Matrix-VU/tree/main/3D%20Models
WLED Sound Reactive:https://github.com/atuline


页: [1]
查看完整版本: 【Arduino 动手做】ESP32 带有 INMP441 的 WS2812B 矩阵