专栏名称: 嵌入式微处理器
关注这个时代最火的嵌入式微处理器,你想知道的都在这里。
目录
相关文章推荐
佛山电视台  ·  明天出分!复试攻略都在这儿了→ ·  昨天  
广东公共DV现场  ·  女子报警:我举报我自己!网友直呼太可怕,“吓 ... ·  2 天前  
佛山电视台  ·  注意!本周末,佛山多路段有交通管制→ ·  3 天前  
广东公共DV现场  ·  员工连续工作29小时被通报表扬?多方回应 ·  4 天前  
广东台今日关注  ·  局长酒后驾车砸店伤人,官方通报→ ·  4 天前  
51好读  ›  专栏  ›  嵌入式微处理器

Arduino声控RGB矩阵音乐节奏灯DIY指南

嵌入式微处理器  · 公众号  ·  · 2024-07-05 18:21

正文

今天将为大家展示如何巧用Arduino、RGB LED矩阵扩展板和音频频谱分析扩展板,亲手打造一个RGB LED矩阵音频可视化器,并配上透明的亚克力外壳,为你的音乐带来一场美妙的灯光秀,增添一抹绚烂的光影!


项目来 源:hackster

驱动代码: https://www.eetree.cn/project/3045



一、项目介绍


对于音频频谱分析部分,本项目中使用的是SparkFun的频谱扩展板,它使用两个MSGEQ7图形均衡器显示滤波器,将立体声音频输入分割成7个频段(每个通道),并使用Arduino上的ADC读取每个频段的幅度。它附带了Arduino示例草图,以便开始使用。


对于RGB LED矩阵,本项目中使用的是Adafruit为Arduino设计的NeoPixel扩展板,它由40个RGB NeoPixels组成(Adafruit对他们的WS2812光源的术语)。红色、绿色和蓝色LED与驱动芯片集成在一起,通过单根导线进行控制。它们可以单独使用,串联成更长的灯串,或者组装成更有趣的形态。在扩展板上,它们是串联在一起的。扩展板还附带了Adafruit_NeoMatrix库,该库简化了对RGB LED矩阵的访问和LED的控制。


最后是外壳部分,本项目创建了一种新的可堆叠、模块化的外壳系统,叫做ProtoStax。它支持不同阶段的原型设计,提供保护和开放访问,以便在开始时使用,并有能力稍后添加侧壁和顶部,但也有能力水平堆叠或垂直堆叠多个单元,从而能够根据原型设计需求和其他板卡及组件的增加进行扩展。


本项目中使用ProtoStax for Arduino,一个为Arduino设计的透明亚克力外壳——它适合Uno/Leonardo尺寸以及更大的Mega/Due尺寸——这也是可堆叠和模块化的,并且有足够的空间容纳两个扩展板。采用了透明且坚固的亚克力材料,方便展示你的音频可视化器以及你的音乐系统!


步骤1 - 将Arduino安装到外壳基座板上


首先将Arduino(以示例中的Uno为例)安装到外壳的基座板上。这样做可以在配置和设置Arduino时提供保护,同时提供完全开放的访问权限,以便进行操作和调整。当你准备将其封闭起来时,可以轻松地添加侧壁和顶板,并用螺丝将所有部件固定。


将Arduino安装到基座板上,并添加脚垫和其他硬件,以准备外壳的平板配置。请参阅下图所有步骤的动态演示图:



步骤2 - 为Arduino准备SparkFun频谱扩展板


SparkFun频谱扩展板没有附带插座。幸运的是,Adafruit为Arduino设计的NeoPixel扩展板既附带堆叠插座也附带普通插座。由于想要NeoPixel扩展板位于顶部,本项目中使用普通插座,这样它就能平齐,这样就留下了堆叠插座供频谱扩展板使用。


但带有堆叠接头的 Spectrum Shield 并不紧密地适合,Arduino Uno 上的 USB 和电源端口会妨碍,如下图所示:



在此做了以下两项修改:
  • 切断覆盖在USB和电源端口上的频谱扩展板的末端(有原型区域,但未使用)这使得频谱扩展板能够紧密地安装在Arduino上。
  • 即使如此,堆叠插座的腿可能仍然太长,导致频谱扩展板无法紧密贴合。稍微修剪堆叠插座的腿,以使频谱扩展板能够使用堆叠插座紧密地安装在Arduino上。




现在它很贴合!



步骤3 - 将Adafruit NeoPixel扩展板插入频谱扩展板的堆叠插座中


Adafruit NeoPixel Shield 位于 Spectrum Shield 之上。首先需要焊接常规接头,在本项目中还焊接了它附带的终端连接器,尽管在这个例子中,使用 Arduino 为其供电,因为所有 LED 不会同时亮起,所以功耗在Arduino能够提供的范围内。


来自Adafruit的NeoPixel扩展板页面的消息: 为了便于启动,LED 默认由 5V 板载 Arduino 电源供电。 只要你不是让所有像素都以全功率白色点亮,那应该没问题。 如果要使用外部电源为扩展板供电,请焊接随板附带的接线端子(专业提示: 将其放在电路板底部,以免粘住)以连接到外部 4-6VDC 电源 - 该电源也将为 Arduino 和扩展板供电。 如果您想使用接线端子为屏蔽层供电,但保持Arduino本身仅使用DC或USB电源,请将焊接跳线的中心切到接线端子的右侧。 外部输入端有一个极性保护 FET,以防您将电源向后接线。



步骤4 - 演示代码


代码分为两个主要部分:
  • 频谱分析和保存结果
  • 将其转换为 8x5 NeoPixel Matrix 的显示/配色方案。

演示代码链接:

https://github.com/protostax/ProtoStax_Audio_Visualizer_Demo/blob/master/ProtoStax_Audio_Visualizer_Demo.ino


二、频谱分析


参考 Spectrum Shield 连接指南,了解有关 Spectrum Shield 的更多信息。


通过将数字序列写入 Spectrum Shield 的 STROBE 和 RESET 引脚,可以初始化 Shield 使用的 MSGEQ7 芯片。然后,继续读取频谱被分成的 7 个不同频段中每个频段的幅度。每个频段被读取后,通过脉冲STROBE引脚来启动下一个频段的读取。这些值被存储在Frequencies_One[7]和Frequencies_Two[7]中,分别对应立体声输入的两个通道。使用Arduino的10位ADC读取这些值,因此输出值可以是0 - 1023之间,它们提供了每个频段的振幅的表示。


//Declare Spectrum Shield pin connections #define STROBE 4#define RESET 5#define DC_One A0#define DC_Two A1 //Define spectrum variablesint freq_amp;int Frequencies_One[7];int Frequencies_Two[7]; int i;
void setup() { ...//Initialize Spectrum Analyzers digitalWrite(STROBE, LOW); delay(1); digitalWrite(RESET, HIGH); delay(1); digitalWrite(STROBE, HIGH); delay(1); digitalWrite(STROBE, LOW); delay(1); digitalWrite(RESET, LOW);...}
void loop() {... Read_Frequencies();...}
/*******************Pull frquencies from Spectrum Shield********************/void Read_Frequencies(){...//Read frequencies for each bandfor (freq_amp = 0; freq_amp<7; freq_amp++) { Frequencies_One[freq_amp] = (analogRead(DC_One) + analogRead(DC_One) ) >> 1 ; Frequencies_Two[freq_amp] = (analogRead(DC_Two) + analogRead(DC_Two) ) >> 1; ... digitalWrite(STROBE, HIGH); digitalWrite(STROBE, LOW); }}


频谱的 7 个频段是:

  • 63赫兹

  • 160赫兹

  • 400赫兹

  • 1kHz

  • 2.5k赫兹

  • 6.25k赫兹

  • 16k赫兹


将这些频段分为三个范围 - 低音(BASS)、中音(MID_RANGE)和高音(TREBLE)。典型的低音范围是 60 到 250 Hz,因此前两个频段在低音范围内。中频频率通常为 500 Hz 至 2 kHz,因此将接下来的 3 个频段归入中音范围,剩余的两个频段归入高音范围。


注意:每个波段的最大读数到一个单独的变量中。这可能被用来自动将读数缩放到RGB矩阵列所代表的级别 - 这在输入信号较弱的情况下很有用,否则在这种情况下只有极少数 RGB 矩阵会亮起。


三、RGB矩阵


可以参考 Adafruit NeoPixel Überguide 了解有关 NeoPixel Shield 和 NeoPixel 的更多信息。


首先要注意的是,在坐标系中,[0, 0] 总是指左上角,无论方向如何。


其次是记下您感兴趣的任何方向的宽度,然后是高度。


第三是注意物理 LED #0 的位置(以 Adafruit 标志为标志)。右上角、左上角、左下角和右下角,视情况而定。还要注意物理 LED 的进展方向。在本项目的电路板中,布局是渐进式的(一行结束后的下一个物理 LED 从下一行的开头开始,如黄线所示)。进展的方向在宽度更宽(水平方向)时是沿着行的(由短的绿色箭头指示),在宽度更窄(垂直方向)时是沿着列的(同样由短的绿色箭头指示)。


以下图片说明了这些:



在示例中,有 7 个频段和一个 8 x 5(或 5 x 8,取决于您查看它的方式!本项目中选择沿着8的维度展示这7个频率带(留下一个未使用)。然后沿着5的维度展示每个频率带的幅度表示。


原点从左下角开始(代表最低频段的最低电平),然后向上移动。但由于在坐标系统中首先要记住的是[0, 0]总是指左上角,因此您应该将头向左倾斜并查看下图,以了解初始化 NeoMatrix 的值选择!(宽度 = 5,高度 = 8,右上角,逐行列)



现在来深入研究一下与 NeoMatrix 相关的演示代码并绘制频率图。首先,确定 NeoPixel 的宽度=5,高度=8,我们选择的朝向是右上角(TOP-RIGHT),并且列是递增的(COLUMNS PROGRESSIVE)。按照setup()函数中所需的矩阵设置进行操作。


在 loop()中,读取任何串行输入以选择配色方案 ,本项目中定义了 3 种不同的配色方案。


enum SCHEME {MAGNITUDE_HUE = 0,MAGNITUDE_HUE_2 = 1, HSV_COLOR_WHEEL = 2};


接着,根据选定的颜色方案调用Graph_Frequencies函数。同时请注意,该函数的第一个参数可以选择要展示的频率范围(低音、中音或高音)。


enum RANGE {BASS = 0,MID_RANGE = 1,TREBLE = 2,ALL = 3};


现在,选择所有要显示的范围,通过串行输入或包括一个瞬时按钮在 BASS、MID_RANGE、TREBLE 或 ALL 之间切换显示。RANGE的选择决定了要显示的行的起始和结束范围。


对于每一行(频段),选取立体声输入的左右两个声道中较大的频率幅度。该值介于 0 和 1023 之间,需要将其映射到显示器的 5 个不同的列中,因此将频率除以FREQ_DIV_FACTOR(1023/204 = 5,它将输出 1023 映射到 5)。为了安全起见,确保要显示的 numCol 不大于 5,这决定了要为每个频段显示的列数。


然后使用matrix.drawPixel()函数来以正确的颜色显示正确的像素。


在图形显示中使用 HSV 色轮,通常,通常情况下,使用方法是matrix.drawPixel(column, row, Color(r, g, b)),这里Color(r, g, b)代表由红色、绿色和蓝色值定义的颜色。然而,使用HSV可以带来一些平滑的颜色渐变效果。


NeoMatrix提供了matrix.ColorHSV(uint16_t hue)方法,它接受一个uint16_t的色调值并返回一个uint32_t的HSV颜色。


但是,matrix.Color(r, g, b)返回的是uint16_t颜色。matrix.drawPixel()也期望一个16位的颜色值。


解决此问题的方法是,使用 matrix.setPassThruColor(32 位颜色值)。这将在矩阵中设置一个标志,使 drawPixel 忽略其颜色参数,使用上述方法已设置的 32 位颜色。只需记住调用 matrix.setPassThruColor() 来重置该标志。


static uint16_t hue = 0; //21845 22250 to -250 uint16_t hueDelta = 200; hue += hueDelta;... rgbcolor = matrix.ColorHSV(hue);... matrix.setPassThruColor(rgbcolor); matrix.drawPixel(col, row, (uint16_t)0); // color does not matter here matrix.setPassThruColor();...matrix.show();


使用 HSV,可以递增16位的色调值并生成HSV颜色码,这样就可以实现颜色的平滑过渡。


以下是供参考的不同代码片段:


#define NEO_MATRIX_WIDTH 5#define NEO_MATRIX_HEIGHT 8#define NEOPIXEL_PIN 6 // Shield maps it to pin 6Adafruit_NeoMatrix matrix = Adafruit_NeoMatrix(NEO_MATRIX_WIDTH, NEO_MATRIX_HEIGHT, NEOPIXEL_PIN, NEO_MATRIX_TOP + NEO_MATRIX_RIGHT + NEO_MATRIX_COLUMNS + NEO_MATRIX_PROGRESSIVE, NEO_GRB + NEO_KHZ800);
....
void setup() {... matrix.begin(); matrix.setTextWrap(false); matrix.setBrightness(40); matrix.fillScreen(0); matrix.show();...}
void loop() {static int scheme = 0;while (Serial.available() > 0) { scheme = Serial.parseInt(); }... Graph_Frequencies(ALL, scheme);... delay(50);}
void Graph_Frequencies(CHANNEL c, SCHEME s){...for( row= from; row {int freq = (Frequencies_Two[row] > Frequencies_One[row])?Frequencies_Two[row]:Frequencies_One[row]; int numCol = (freq/FREQ_DIV_FACTOR);if (numCol > 5) numCol = 5;for (int col = 0 ; col < numCol ; col++) {... // pick color scheme to display matrix.setPassThruColor(rgbcolor); matrix.drawPixel(col, row, (uint16_t)0); // color does not matter here matrix.setPassThruColor();//matrix.show(); } matrix.show(); }}


接下来是配色方案的选择。请注意,我已经预留了根据不同频率范围选择颜色的选项(低音色调、中音色调、高音色调)。我创建了 3 种不同的配色方案 - 一种方案是从最低幅度到最高幅度使用绿色至红色/粉色的渐变,另一种方案使用更多偏向粉色/蓝色的范围。第三种方案则是所有像素使用单一颜色,但在运行时会循环遍历整个色轮。


switch(s) {case MAGNITUDE_HUE: bassHue = 22250; midHue = 22250; //54613 trebleHue = 22250; //43690







请到「今天看啥」查看全文