65浏览
查看: 65|回复: 2

[项目] 【Arduino 动手做】双显示像素矩阵分析仪

[复制链接]
这个频谱分析仪项目简直令人惊叹。它包括一个 Teensy 微控制器板,可以同时以非常高的速度驱动 2 个显示器。凭借其板载音频芯片,它能够实时对音频进行频率分析,以创建 69 个通道的立体声频谱分析仪。

是的,你没看错我的意思!69 个立体声通道...所以这实际上是 138 个频率箱。最重要的是,我们将在第二个显示器上显示立体声 VU 表。所以或多或少我们实际上正在处理 140 个频道。

但还有更多:它可以同时驱动多达 3 个像素 LED 矩阵。因此,又增加了 768 个 LED

最重要的是:它是开源的!

你会需要:

带有所有组件的 PCB(购买预组装或仅购买 PCB 并添加您自己的组件)
但是在我的 tindy 商店里,您需要添加的只是显示器、保险丝和一个小控制器 4.1 : 在这里购买 PCB
使用 gerbers 来制造您自己的 PCB。我需要使用 PCBWAY.COM 您可以在此处下载所需的 gerber 文件: 下载 GERBER 文件
两个显示器类型:ILI9341这是 2.8 英寸版本。您也可以使用 3.2 英寸版本
Teensy 4.1 微控制器板
Teensy 的外部 Ram(您需要将其焊接到 teensy 板上)
如果您使用板载 PSU,请熔断 2AT TR5(您可以在 teensy 上使用 USB)
一些接头或连接器用于连接电线,或直接焊接到电路板上。

插座
如果您使用麦克风输入,则为一个驻极体麦克风
三个按钮进行作(如果您不使用像素化矩阵,则为两个)
三个 Potmeters,我使用 10K 版本(仅在添加像素化矩阵时才需要)

我们将使用两个显示器,每个显示器将使用一些屏幕缓冲区。由于缓冲区的大小相当大,由于我们需要的缓冲区数量众多,因此内部存储器是不够的。我们需要添加额外的内存。对我们来说,Teensy 4.1 有可能添加一个额外的内存芯片。

我在这里买了 Teensy 4.1:https://opencircuit.nl/product/teensy-4-1

您需要在预期的插座上添加 PSRAM,如图所示。

我用过这个芯片:8MB PSRAM64我在这里买的:https://opencircuit.nl/product/8-MB-PSRAM-chip-voor-Teensy-4.1

由于大多数组件直接连接到 PCB,因此所需电线的数量保持在最低限度

您可以查看原理图了解详细信息,但简而言之,归结为:

电波计(亮度、峰值延迟、输入增益)仅当您使用 LED 矩阵时才会转到连接器 CN5、CN6 和 CN10。将每个电位计的中心连接到连接器的中心引脚。将电位计的另外 2 个引脚连接到每个连接器的其余引脚。如果您的电位计反应是逆时针而不是 CW,反之亦然,只需转动该电位计的外侧两个引脚即可。

开关:

开关 1:CN2

开关 2:CN4

开关 3:标有 CN12 引脚(- 和 s)

麦克风连接到连接器 CN11

线路输入到连接器 CN3;两个外引脚接地,两个内引脚为通道 L 和 R

电源转到U1,注意板上的标记:+和-使用8-12VDC

Ledmatrix(我串联使用了 3 个矩阵,每个矩阵有 16 x 16 个 LED)连接器 CN10,查看 PCB 上的标记以查看 +、- 和 L(L = 数据线)

您不需要手册即可作本机。

这很简单。

使用麦克风或连接音频源。有一个按钮可以选择您正在使用的输入

另一个按钮选择右侧显示屏上显示的屏幕

最后一个开关是选择像素化矩阵上显示的图案

还有 3 个锅计。( 10....50K 就可以完成这项工作 )

电波计1:LED显示强度

Potmeter 2:LED 显示增益

电波计 3:峰值延迟时间。(峰值下降到堆叠之前多长时间)

【Arduino 动手做】双显示像素矩阵分析仪图3

【Arduino 动手做】双显示像素矩阵分析仪图1

【Arduino 动手做】双显示像素矩阵分析仪图2

【Arduino 动手做】双显示像素矩阵分析仪图4

【Arduino 动手做】双显示像素矩阵分析仪图5

【Arduino 动手做】双显示像素矩阵分析仪图6

【Arduino 动手做】双显示像素矩阵分析仪图7

【Arduino 动手做】双显示像素矩阵分析仪图8

【Arduino 动手做】双显示像素矩阵分析仪图9

【Arduino 动手做】双显示像素矩阵分析仪图10

【Arduino 动手做】双显示像素矩阵分析仪图11

【Arduino 动手做】双显示像素矩阵分析仪图12

【Arduino 动手做】双显示像素矩阵分析仪图13

【Arduino 动手做】双显示像素矩阵分析仪图14

【Arduino 动手做】双显示像素矩阵分析仪图15

驴友花雕  中级技神
 楼主|

发表于 昨天 12:16

【Arduino 动手做】双显示像素矩阵分析仪

项目代码

  1. #include <Adafruit_GFX.h>
  2. #include <Adafruit_GrayOLED.h>
  3. #include <Adafruit_SPITFT.h>
  4. #include <Adafruit_SPITFT_Macros.h>
  5. #include <gfxfont.h>
  6. /**
  7.        _    _____ ___   ___          _             _ _    __     ___                 _ _
  8.       / \  |___  / _ \ / _ \        / \  _   _  __| (_) __\ \   / (_)___ _   _  __ _| (_)_______ _ __
  9.      / _ \    / / | | | | | |_____ / _ \| | | |/ _` | |/ _ \ \ / /| / __| | | |/ _` | | |_  / _ \ '__|
  10.     / ___ \  / /| |_| | |_| |_____/ ___ \ |_| | (_| | | (_) \ V / | \__ \ |_| | (_| | | |/ /  __/ |Twin
  11.    /_/   \_\/_/  \___/ \___/     /_/   \_\__,_|\__,_|_|\___/ \_/  |_|___/\__,_|\__,_|_|_/___\___|_|Display
  12.    with optional added Neopixel matrix
  13.    ReVox A700 AudioVisualizer
  14.    Copyright (C) 2021 by DIYLAB <https://www.diylab.de> GitHub: <https://github.com/DIYLAB-DE/AudioVisualizer>
  15.    Modification for Dual Display and pixelleds done by Mark Donners, TheElectronicEngineer.nl
  16.    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  17.    This Software is free software: you can redistribute it and/or modify it under the terms of the
  18.    GNU General Public License as published by the Free Software Foundation, either version 3 of the
  19.    License, or (at your option) any later version.
  20.    This Software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
  21.    without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  22.    See the GNU General Public License for more details: <http://www.gnu.org/licenses/>
  23.    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  24.    !!! IMPORTANT !!!
  25.    The GNU General Public License (GNU GPL) obligates the user to also place the software under the
  26.    conditions of the GPL (copyleft) when redistributing the software in its original or modified form
  27.    (so-called derivative works). If the licensee does not comply with the conditions, the right to free use expires retroactively!
  28.    Therefore, the user is also required to make the source code available and to subject the derived software to the GPL.
  29.    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  30.    !!! WICHTIG !!!
  31.    Die GNU General Public License (GNU GPL) verpflichtet den Nutzer dazu, bei Weiterverbreitung der Software
  32.    in ihrer ursprünglichen oder veränderten Form (sog. abgeleitete Werke), diese ebenfalls unter die Bedingungen der GPL zu stellen (Copyleft).
  33.    Hält sich der Lizenznehmer nicht an die Bedingungen, erlischt die Befugnis zur freien Benutzung rückwirkend!
  34.    Daher ist der Verwender gehalten, ebenfalls den Quellcode zugänglich zu machen und die abgeleitete Software wiederum der GPL zu unterwerfen.
  35.    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  36.    Special thanks to Bodmer <https://github.com/Bodmer> for the AA drawing routines and the rainbow colors!
  37.    Used libraries
  38.    ---------------
  39.    Optimized ILI9341 screen driver library for Teensy 4/4.1, with vsync and differential updates: <https://github.com/vindar/ILI9341_T4>
  40.    TGX - a tiny/teensy graphics library: <https://github.com/vindar/tgx>
  41.    Arduino OneButton Library: <https://github.com/mathertel/OneButton> (install via the Arduino library manager)
  42.    IRremote Arduino Library: <https://github.com/Arduino-IRremote/Arduino-IRremote>
  43.    TeensyID: https://github.com/sstaub/TeensyID
  44.    Used development software
  45.    -------------------------
  46.    Arduino IDE 1.8.19
  47.    Teensyduino, Version 1.56
  48.    
  49. /**************************************************************************************************
  50.    Updated to version for 2 displays. The function of the first display is unchanged, compared to
  51.    the orignal firmware. the second display will always show Stereo Analog VU meter
  52.    Also implemented extra button to switch between line and mic input
  53.    Take Note: For this sketch to work, you will need Arduino 4.1 with added EXTERNAL PSRAM
  54.    This update will include Pixelled matrix and potmeters to adjust sensitivity
  55.    Compared to the original version 2.0.1, the folowing files where changed:
  56.    AudioVisualizer, Analog, Gfx
  57.    Logo.h, was added
  58.    I did a succesful compilation using the following library versions:
  59.    Using library Wire at version 1.0
  60.    Using library Audio at version 1.3
  61.    Using library SPI at version 1.0
  62.    Using library SD at version 2.0.0
  63.    Using library SdFat at version 2.1.0
  64.    Using library SerialFlash at version 0.5
  65.    Using library ILI9341_T4-main at version 0.1
  66.    Using library tgx-main at version 0.5
  67.    Using library EEPROM at version 2.0
  68.    Using library OneButton at version 2.0.4  
  69.    Using library IRremote at version 3.6.1  
  70.    Using library TeensyID-main at version 1.3.3
  71.    Using library ILI9488_t3 at version 1.0
  72. *************************************************************************************************/
  73. //////////////////////////////////////////////////////////////////////////////////////////////////
  74. // USER CONFIG SECTION (please only edit here!)                                                 //
  75. //////////////////////////////////////////////////////////////////////////////////////////////////
  76. #define VERSION "v4.0, 25.10.2023"
  77. #define SHOWLOGO                true  // show logo
  78. #define BUTTON                     2  // PIN0
  79. #define BUTTON2                    3  // ADDED By MARK DONNERS
  80. //#define IR                         4  // PIN4
  81. #define BUTTON3                    4  // Pin xx Added By Mark Donners
  82. // set the pins: here for SPI0 on Teensy 4.x
  83. // ***  Recall that DC must be on a valid cs pin !!! ***
  84. // FIRST SCREEN IS WIRED TO SPI0
  85. #define PIN_SCK0        13  // mandatory
  86. #define PIN_MISO0       12  // mandatory
  87. #define PIN_MOSI0       11  // mandatory
  88. #define PIN_DC0         10  // mandatory
  89. #define PIN_CS0          9  // mandatory (but can be any digital pin)
  90. #define PIN_RESET0       6  // could be omitted (set to 255) yet it is better to use (any) digital pin whenever possible.
  91. #define PIN_BACKLIGHT0 5  // optional. Set this only if the screen LED pin is connected directly to the Teensy
  92. #define PIN_TOUCH_IRQ0 255  // optional. Set this only if touch is connected on the same spi bus (otherwise, set it to 255)
  93. #define PIN_TOUCH_CS0  255  // optional. Set this only if touch is connected on the same spi bus (otherwise, set it to 255)
  94. // ADDED By MARK DONNERS
  95. // SECOND SCREEN IS WIRED TO SPI1
  96. #define PIN_SCK1        27  // mandatory
  97. #define PIN_MISO1        1  // mandatory
  98. #define PIN_MOSI1       26  // mandatory
  99. #define PIN_DC1          0  // mandatory
  100. #define PIN_CS1         30  // mandatory (but can be any digital pin)
  101. #define PIN_RESET1      29  // could be omitted (set to 255) yet it is better to use (any) digital pin whenever possible.
  102. #define PIN_BACKLIGHT1 28  // optional. Set this only if the screen LED pin is connected directly to the Teensy
  103. #define PIN_TOUCH_IRQ1 255  // optional. Set this only if touch is connected on the same spi bus (otherwise, set it to 255)
  104. #define PIN_TOUCH_CS1  255  // optional. Set this only if touch is connected on the same spi bus (otherwise, set it to 255)
  105. // Changed the default SPI speed
  106. #define SPI_SPEED          50000000  // SPI speed
  107. #define SPI_SPEED2         50000000  // SPI speed
  108. //////////////////////////////////////////////////////////////////////////////////////////////////
  109. /**/
  110. #include <Wire.h>
  111. #include <Audio.h>
  112. #include "SPI.h"
  113. #include "ILI9341Driver.h"
  114. #include <ILI9341_T4.h>
  115. #include <tgx.h>
  116. #include <EEPROM.h>
  117. #include <OneButton.h>
  118. //IR#include <IRremote.h>
  119. #include <TeensyID.h>
  120. #include <Adafruit_NeoMatrix.h>                    // Fastled Neomatrix driver.
  121. #include <Adafruit_NeoPixel.h>
  122. #include "_timers.h"
  123. #include "globals.h"
  124. #include "Pixel_Spec.h"
  125. #include "helpers.h"
  126. #include "graphics.h"
  127. #include "_ili9341_t3n_font_Arial.h"
  128. #include "_ili9341_t3n_font_ArialBold.h"
  129. //////////////////////////////////////////////////////////////////////////////////////////////////
  130. /// <summary>
  131. /// inherit from the 'AudioControlSGTL5000' class to modify the CHIP_ANA_ADC_CTRL register
  132. /// </summary>
  133. #include "control_sgtl5000.h"
  134. class mSGTL5000 : public AudioControlSGTL5000 {
  135.   public:
  136.     void attGAIN(uint8_t att) {
  137.       modify(0x0020, (att & 1) << 8, 1 << 8);
  138.     }
  139. };
  140. // namespace for draw graphics primitives
  141. using namespace tgx;
  142. // Framebuffers and some variables below have moved to External memory, compared to orginal firmware
  143. // all related to the use of two displays
  144. // framebuffers
  145. DMAMEM uint16_t internalBuffer[240 * 320] = { 0 }; // used for internal buffering
  146. DMAMEM  uint16_t internalBuffer1[240 * 320] = { 0 }; // used for internal buffering
  147. EXTMEM  uint16_t frontBuffer[240 * 320] = { 0 };    // paint in this buffer
  148. EXTMEM  uint16_t frontBuffer1[240 * 320] = { 0 };     // background buffer
  149. EXTMEM uint16_t backBuffer[240 * 320] = { 0 };     // background buffer
  150. EXTMEM uint16_t backBuffer1[240 * 320] = { 0 };     // background buffer
  151. /********************************************************************************************************************************
  152.   * ** // Adafruit_NeoMaxtrix                                                                         **
  153.   ********************************************************************************************************************************/
  154. Adafruit_NeoMatrix matrix = Adafruit_NeoMatrix(kMatrixWidth, kMatrixHeight, LED_PIN,
  155.   NEO_MATRIX_BOTTOM     + NEO_MATRIX_RIGHT +
  156.   NEO_MATRIX_COLUMNS + NEO_MATRIX_ZIGZAG,
  157.   NEO_GRB            + NEO_KHZ800);
  158. const uint16_t colors[] = {
  159.   matrix.Color(255, 0, 0), matrix.Color(0, 255, 0), matrix.Color(0, 0, 255) };
  160. // samplebuffers
  161. int16_t samplesLeft[2048] = { 0 };
  162. int16_t samplesRight[2048] = { 0 };
  163. // screen driver objects
  164. ILI9341_T4::ILI9341Driver tft(PIN_CS0, PIN_DC0, PIN_SCK0, PIN_MOSI0, PIN_MISO0, PIN_RESET0, PIN_TOUCH_CS0, PIN_TOUCH_IRQ0); // for screen on SPI0
  165. ILI9341_T4::ILI9341Driver tft1(PIN_CS1, PIN_DC1, PIN_SCK1, PIN_MOSI1, PIN_MISO1, PIN_RESET1, PIN_TOUCH_CS1, PIN_TOUCH_IRQ1); // for screen on SPI1
  166. // two diff buffers
  167. ILI9341_T4::DiffBuffStatic<8000> diff1;
  168. ILI9341_T4::DiffBuffStatic<8000> diff2;
  169. // two diff buffers for second display
  170. ILI9341_T4::DiffBuffStatic<8000> diff3;
  171. ILI9341_T4::DiffBuffStatic<8000> diff4;
  172. // images that encapsulates framebuffers
  173. Image<RGB565> im(frontBuffer, 240, 320);
  174. Image<RGB565> im1(frontBuffer1, 240, 320);
  175. EXTMEM Image<RGB565> bg(backBuffer, 240, 320);
  176. EXTMEM Image<RGB565> bg1(backBuffer1, 240, 320);
  177. // instantiate button object
  178. OneButton btn(BUTTON, true, true);
  179. OneButton btn2(BUTTON2, true, true);
  180. OneButton btn3(BUTTON3, true, true);
  181. // GUItool: begin automatically generated code
  182. AudioInputI2S            i2s1;           //xy=205,270
  183. AudioOutputI2S           i2s2;           //xy=233.00000381469727,400.0000057220459
  184. AudioAnalyzeFFT1024      fft1024_1;      //xy=425.00000762939453,132.00000190734863
  185. AudioAnalyzeFFT1024      fft1024_2;      //xy=426.00000381469727,320.0000047683716
  186. AudioAnalyzeRMS          rms1;           //xy=431.00000381469727,93.00000190734863
  187. AudioRecordQueue         queue2;         //xy=431.00000381469727,280.00000381469727
  188. AudioAnalyzePeak         peak1;          //xy=432.00000762939453,54.000003814697266
  189. AudioRecordQueue         queue1;         //xy=432.00000381469727,171.00000381469727
  190. AudioMixer4              mixer1;         //xy=432.00000381469727,225.00000381469727
  191. AudioAnalyzeRMS          rms2;           //xy=433.00000762939453,359.0000047683716
  192. AudioAnalyzePeak         peak2;          //xy=435.00000762939453,399.0000057220459
  193. AudioAnalyzeFFT1024      fft1024_3;      //xy=566.0000076293945,225.00000286102295
  194. AudioConnection          patchCord1(i2s1, 0, queue1, 0);
  195. AudioConnection          patchCord2(i2s1, 0, peak1, 0);
  196. AudioConnection          patchCord3(i2s1, 0, rms1, 0);
  197. AudioConnection          patchCord4(i2s1, 0, fft1024_1, 0);
  198. AudioConnection          patchCord5(i2s1, 0, mixer1, 0);
  199. AudioConnection          patchCord6(i2s1, 0, i2s2, 0);
  200. AudioConnection          patchCord7(i2s1, 1, queue2, 0);
  201. AudioConnection          patchCord8(i2s1, 1, fft1024_2, 0);
  202. AudioConnection          patchCord9(i2s1, 1, rms2, 0);
  203. AudioConnection          patchCord10(i2s1, 1, peak2, 0);
  204. AudioConnection          patchCord11(i2s1, 1, mixer1, 1);
  205. AudioConnection          patchCord12(i2s1, 1, i2s2, 1);
  206. AudioConnection          patchCord13(mixer1, fft1024_3);
  207. mSGTL5000                sgtl5000_1;
  208. // GUItool: end automatically generated code
  209. /// <summary>
  210. /// setup
  211. /// </summary>
  212. void setup() {
  213.   Serial.println("enter setup");
  214.   //  The following code was added by Mark Donners to change the internal busspeed for the external Memory
  215.   // turn on clock  (TODO: increase clock speed later, slow & cautious for first release)
  216.   CCM_CCGR7 |= CCM_CCGR7_FLEXSPI2(CCM_CCGR_OFF);
  217.   CCM_CBCMR = (CCM_CBCMR & ~(CCM_CBCMR_FLEXSPI2_PODF_MASK | CCM_CBCMR_FLEXSPI2_CLK_SEL_MASK))
  218.               | CCM_CBCMR_FLEXSPI2_PODF(4) | CCM_CBCMR_FLEXSPI2_CLK_SEL(2);
  219.   CCM_CCGR7 |= CCM_CCGR7_FLEXSPI2(CCM_CCGR_ON);
  220.   // link the button events
  221.   btn.attachClick(buttonClick);
  222.   btn.attachDoubleClick(buttonDoubleClick);
  223.   btn.attachLongPressStart(buttonLongPressStart);
  224.   btn.attachLongPressStop(buttonLongPressStop);
  225.   btn.attachDuringLongPress(buttonLongPress);
  226.   
  227.   // Added functions for button2 by Mark Donners
  228.   btn2.attachClick(button2Click);
  229.   // added function for button 3 ( mode );
  230.   btn3.attachClick(button3Click);
  231.   // set bin ranges
  232.   setBins();
  233.   // Audio
  234.   AudioMemory(128);//64
  235.   sgtl5000_1.enable();
  236.   InputSelect=!InputSelect; // we need to invert it once because it will change back in the button2Click function
  237.   button2Click(); //this will call the subroutine where I change the input selector.
  238.   // some default settings for the sgtl5000_1 where moved to the button2Click function
  239.   // dsp
  240.   sgtl5000_1.autoVolumeDisable();
  241.   sgtl5000_1.surroundSoundDisable();
  242.   sgtl5000_1.enhanceBassDisable();
  243.   // fft
  244.   fft1024_1.windowFunction(AudioWindowHanning1024);
  245.   fft1024_2.windowFunction(AudioWindowHanning1024);
  246.   fft1024_3.windowFunction(AudioWindowHanning1024);
  247.   // display
  248.   while (!tft.begin(SPI_SPEED)) delay(1000);
  249.   tft.setScroll(0);
  250.   tft.setFramebuffers(internalBuffer); // set 1 internal framebuffer -> activate float buffering
  251.   tft.setDiffBuffers(&diff1, &diff2);  // set the 2 diff buffers => activate differential updates
  252.   tft.setDiffGap(16);                   // use a small gap for the diff buffers
  253.   tft.setRefreshRate(120);             // around 120hz for the display refresh rate
  254.   tft.setVSyncSpacing(2);              // set framerate = refreshrate/2 (and enable vsync at the same time)
  255.   // ADDED by Mark Donners for Second Display
  256.   while (!tft1.begin(SPI_SPEED2)) delay(1000);
  257.   tft1.setScroll(0);
  258.   tft1.setFramebuffers(internalBuffer1); // set 1 internal framebuffer -> activate float buffering
  259.   tft1.setDiffBuffers(&diff3, &diff4);  // set the 2 diff buffers => activate differential updates
  260.   tft1.setDiffGap(16);                   // use a small gap for the diff buffers
  261.   tft1.setRefreshRate(120);             // around 120hz for the display refresh rate
  262.   tft1.setVSyncSpacing(2);              // set framerate = refreshrate/2 (and enable vsync at the same time)
  263.   // make sure backlight is on
  264.   if (PIN_BACKLIGHT0 != 255) {
  265.     pinMode(PIN_BACKLIGHT0, OUTPUT);
  266.     digitalWrite(PIN_BACKLIGHT0, HIGH);
  267.   }
  268.   // ADDED by Mark Donners for Second Display
  269.   // make sure backlight is on
  270.   if (PIN_BACKLIGHT1 != 255) {
  271.     pinMode(PIN_BACKLIGHT1, OUTPUT);
  272.     digitalWrite(PIN_BACKLIGHT1, HIGH);
  273.   }
  274.   // force reset to factory defaults
  275.   if (digitalRead(BUTTON) == LOW) {
  276.     clearEEPROM();
  277.     // waiting for release the button
  278.     while (digitalRead(BUTTON) == LOW) {}
  279.   }
  280.   // get config from EEPROM or initialize EEPROM
  281.   if (isFirstStart()) {
  282.     clearEEPROM();
  283.     delay(3000);
  284.   } else {
  285.     readGLOBALConfig();
  286.     readDBCorrection();
  287.     readDIGITALConfig();
  288.     readANALOGConfig();
  289.     readFFTConfig();
  290.     readGONIOConfig();
  291.     readREMOTECONTROLConfig();
  292.   }
  293.   // show logo
  294. #if SHOWLOGO
  295.   showLogo();
  296. #endif
  297.   // initialize display from ModuleType
  298.   initalizeDisplayFromModuleType(moduleType);
  299. matrix.begin();
  300. matrix.setTextColor(colors[0]);
  301.   
  302. }
  303. int x    = matrix.width();
  304. int pass = 0;
  305. /// <summary>
  306. /// mainloop
  307. /// </summary>
  308. void loop() {
  309.   static elapsedMillis fps = 0;
  310.   //oddeven=!oddeven;
  311.   // watching the button
  312.   btn.tick();
  313.   // watching the button2
  314.   btn2.tick();
  315.   btn3.tick();
  316.   // watching the serialport
  317.   // draw modules
  318.   if (!lockScreenUpdate && !DIGITAL_MenuActive && !ANALOG_MenuActive && !FFT_MenuActive && !GONIO_MenuActive) {
  319.     drawAnalog2(false);
  320.     if (moduleType == 0) drawDigital(false);
  321.     else if (moduleType == 1) drawAnalog(false);
  322.     else if (moduleType == 2) drawFFT(false);
  323.     else if (moduleType == 3) drawGonio(false);
  324.     // send global RMS & PPM data
  325.     if (calibrate && fps > 16) {
  326.       fps = 0;
  327.       sendRMSPPM();
  328.     }
  329.   }
  330. ////*******************++
  331. //matrix.clear();
  332. int SENSE = analogRead(SENSEPOT)/2;
  333. Peakdelay= map(analogRead(PEAKDELAYPOT),0,1024,0,100); // this is the peak delay pot
  334. for(int i=0; i<numBands; i++) {
  335. FreqBinsNew[i]=(fft1024_3.read(Startbin,Stopbin) * SENSE);
  336.   }
  337. // Process the  data from bandValues and transform them into bar heights
  338.   for (byte band = 0; band < numBands; band++)
  339.   { // Scale the bars for the display
  340.     int barHeight = FreqBinsNew[band];
  341.     if (barHeight > TOP) barHeight = TOP;
  342.     // Small amount of averaging between frames
  343.     barHeight = ((FreqBinsOld[band] * 1) + barHeight) / 2; // Fast Filter, more rapid movement
  344.     // barHeight = ((oldBarHeights[band] * 2) + barHeight) / 3; // minimum filter makes changes more smooth
  345.     // Move peak up
  346.   
  347.     if (barHeight > peak[band])
  348.     {
  349.       peak[band] = min(TOP, barHeight);
  350.       PeakFlag[band] = 1;
  351.     }
  352.   
  353.     /*
  354.        Mode 0: All leds OFF
  355.        Mode 1: TriBar each Column is devided into 3 sections, Bottom,Middle and Top, Each section has different color
  356.        Mode 2: Tribar without peaks
  357.        Mode 3: No bars, only peaks in try color
  358.        Mode 4: yellow bars white peaks
  359.        Mode 5: yellow bars no peaks
  360.        Mode 6: Center Bars yellow with red outerline
  361.        Mode 7: Center Bars green with purple outerline
  362.     */
  363.      
  364.     // Now visualize those bar heights
  365.     switch (LedMode) {
  366.       case 0:
  367.       NoBars(band, barHeight);
  368.       break;
  369.       
  370.       case 1:
  371.       TriBar(band, barHeight);
  372.       TriPeak(band);
  373.       break;
  374.       
  375.       
  376.       case 2:
  377.       TriBar(band, barHeight);
  378.       break;
  379.       case 3:
  380.       NoBars(band, barHeight);
  381.       TriPeak(band);
  382.       break;
  383.       case 4:
  384.       YellowBars(band, barHeight);
  385.       NormalPeak(band,50,78,90);
  386.       break;
  387.       
  388.       case 5:
  389.       YellowBars(band, barHeight);
  390.       break;
  391.       case 6:
  392.       centerBars(band, barHeight);
  393.       break;
  394.       case 7:
  395.       centerBars2(band, barHeight);
  396.       break;
  397.       
  398.     }
  399.     FreqBinsOld[band] = barHeight;  // Save oldBarHeights for averaging later
  400.   }
  401.   
  402.   
  403. BRIGHTNEW=map(analogRead(BRIGHTPOT),0,1023,10,200);
  404. matrix.setBrightness(BRIGHTNEW);
  405.   matrix.show();
  406. EVERY_N_MILLISECONDS(Fallingspeed) {
  407.     for (byte band = 0; band < numBands; band++) {
  408.       if (PeakFlag[band] == 1) {
  409.         PeakTimer[band]++;
  410.         if (PeakTimer[band] > Peakdelay) {
  411.           PeakTimer[band] = 0;
  412.           PeakFlag[band] = 0;
  413.         }
  414.       } else if (peak[band] > 0) {
  415.         peak[band] -= 1;
  416.       }
  417.     }
  418.   }
  419.   
  420. }
  421. /// <summary>
  422. /// samples = sampleblocks * 128
  423. /// </summary>
  424. void setSampleBlocks() {
  425.   lockScreenUpdate = true;
  426.   queue1.freeBuffer();
  427.   queue2.freeBuffer();
  428.   memset(samplesLeft, 0, sizeof(samplesLeft));
  429.   memset(samplesRight, 0, sizeof(samplesRight));
  430.   GONIO_SampleBlocks = 8;
  431.   if (GONIO_Samples == 1) GONIO_SampleBlocks = 16;
  432.   lockScreenUpdate = false;
  433. }
  434. /// <summary>
  435. /// get samples for left and right channel
  436. /// </summary>
  437. /// <param name="blocks"></param>
  438. void getSamples(uint16_t blocks) {
  439.   if (blocks == 0) {
  440.     queue1.readBuffer();
  441.     queue1.freeBuffer();
  442.     queue2.readBuffer();
  443.     queue2.freeBuffer();
  444.   } else {
  445.     if (queue1.available() >= blocks && queue2.available() >= blocks) {
  446.       for (byte i = 0; i < blocks; i++) {
  447.         memcpy(&samplesLeft[i * 128], queue1.readBuffer(), 256);
  448.         memcpy(&samplesRight[i * 128], queue2.readBuffer(), 256);
  449.         queue1.freeBuffer();
  450.         queue2.freeBuffer();
  451.       }
  452.     }
  453.   }
  454. }
  455. /// <summary>
  456. /// this function will be called when the button was pressed 1 time
  457. /// </summary>
  458. void buttonClick() {
  459.   if (++moduleType > 3) moduleType = 0;
  460.   modeSwitch();
  461. }
  462. /// this function will be called when the button2 was pressed 1 time
  463. /// ADDED By Mark Donners
  464. /// </summary>
  465. void button2Click() {
  466.   if (InputSelect == AUDIO_INPUT_LINEIN) {
  467.     // change parameters for optimal use with your mic
  468.     InputSelect = AUDIO_INPUT_MIC;
  469.     sgtl5000_1.inputSelect(InputSelect);
  470.     sgtl5000_1.lineOutLevel(13); // 3.16 Volts p-p
  471.     sgtl5000_1.volume(0.7f);     // 0.8 corresponds to the maximum undistorted output for a full scale signal
  472.     sgtl5000_1.lineInLevel(0);   // 3.12 Volts p-p
  473.     sgtl5000_1.attGAIN(0);       // ADC volume range reduction down by 6.0 dB
  474.     Serial.println("Input change to Microphone");
  475.   }
  476.   else {
  477.     // change parameters for optimal use with your line in
  478.     InputSelect = AUDIO_INPUT_LINEIN;
  479.     sgtl5000_1.inputSelect(InputSelect);
  480.     sgtl5000_1.lineOutLevel(13); // 3.16 Volts p-p
  481.     sgtl5000_1.volume(0.7f);     // 0.8 corresponds to the maximum undistorted output for a full scale signal
  482.     sgtl5000_1.lineInLevel(0);   // 3.12 Volts p-p
  483.     sgtl5000_1.attGAIN(0);       // ADC volume range reduction down by 6.0 dB
  484.     Serial.println("Input change to Line-IN");
  485.   }
  486. }
  487. void button3Click() {
  488.   Serial.println("Mode button was pressed");
  489.   LedMode++;
  490.   if (LedMode>LedModeMax)LedMode=0;
  491.   Serial.println(LedMode);
  492. }
  493. /// <summary>
  494. /// this function will be called when the button was pressed 2 times in a int16_t timeframe
  495. /// </summary>
  496. void buttonDoubleClick() {
  497.   setSubMode(moduleType);
  498. }
  499. /// <summary>
  500. /// this function will be called often, while the button is pressed for a long time
  501. /// </summary>
  502. void buttonLongPress() {
  503. }
  504. /// <summary>
  505. /// this function will be called once, when the button is pressed for a long time
  506. /// </summary>
  507. void buttonLongPressStart() {
  508.   calibrate = !calibrate;
  509.   initalizeDisplayFromModuleType(moduleType);
  510. }
  511. /// <summary>
  512. /// this function will be called once, when the button is released after beeing pressed for a long time
  513. /// </summary>
  514. void buttonLongPressStop() {
  515. }
  516. /// <summary>
  517. /// switch module
  518. /// </summary>
  519. void modeSwitch() {
  520.   lockScreenUpdate = true;
  521.   EEPROM.put(20, moduleType);
  522.   initalizeDisplayFromModuleType(moduleType);
  523.   Serial.printf("{ModuleType=%i}", moduleType);
  524.   lockScreenUpdate = false;
  525. }
  526. /// <summary>
  527. /// initialize display from ModuleType
  528. /// </summary>
  529. /// <param name="mType"></param>
  530. void initalizeDisplayFromModuleType(int16_t mType) {
  531.   if (mType < 0 || mType > 3) {
  532.     mType = 0;
  533.     moduleType = 0;
  534.   }
  535.   lockScreenUpdate = true;
  536.   if (mType == 0) displayInitDigital(true);
  537.   if (mType == 1) displayInitAnalog();
  538.   if (mType == 2) displayInitFFT(true);
  539.   if (mType == 3) displayInitGonio(true);
  540.   display2InitAnalog(); // second display always vu meter
  541.   lockScreenUpdate = false;
  542. }
  543. /// <summary>
  544. /// set subMode
  545. /// </summary>
  546. void setSubMode(int16_t mType) {
  547.   lockScreenUpdate = true;
  548.   switch (mType) {
  549.     case 0: // digitalmeter
  550.       if (++DIGITAL_WorkMode > 3)  DIGITAL_WorkMode = 0;
  551.       EEPROM.put(504, DIGITAL_WorkMode);
  552.       setMode(true);
  553.       break;
  554.     case 1:
  555.       break;
  556.     case 2: // spectrumanalyzer
  557.       if (++FFT_WorkMode > 11) FFT_WorkMode = 0;
  558.       EEPROM.put(706, FFT_WorkMode);
  559.       setMode(true);
  560.       break;
  561.     case 3: // goniometer
  562.       if (++GONIO_WorkMode > 7) GONIO_WorkMode = 0;
  563.       EEPROM.put(806, GONIO_WorkMode);
  564.       setMode(true);
  565.       break;
  566.   }
  567.   lockScreenUpdate = false;
  568. }
  569. /// <summary>
  570. /// set mode
  571. /// </summary>
  572. void setMode(bool showMessage) {
  573.   switch (moduleType) {
  574.     case 0: // digitalmeter
  575.       switch (DIGITAL_WorkMode) {
  576.         case 0:
  577.           DIGITAL_dBLow = -40;
  578.           DIGITAL_PeakHold = false;
  579.           if (showMessage) messageBox("-40dB");
  580.           break;
  581.         case 1:
  582.           DIGITAL_dBLow = -30;
  583.           DIGITAL_PeakHold = false;
  584.           if (showMessage) messageBox("-30dB");
  585.           break;
  586.         case 2:
  587.           DIGITAL_dBLow = -40;
  588.           DIGITAL_PeakHold = true;
  589.           if (showMessage) messageBox("-40dB HOLD");
  590.           break;
  591.         case 3:
  592.           DIGITAL_dBLow = -30;
  593.           DIGITAL_PeakHold = true;
  594.           if (showMessage) messageBox("-30dB HOLD");
  595.           break;
  596.       }
  597.       break;
  598.     case 1: // analogmeter
  599.       break;
  600.     case 2: // spectrumanalyzer
  601.       switch (FFT_WorkMode) {
  602.         case 0:
  603.           FFT_dBLow = -40;
  604.           FFT_LevelBarMode = 1 /*RMS*/;
  605.           FFT_PeakHold = false;
  606.           if (showMessage) messageBox("RMS -40dB");
  607.           break;
  608.         case 1:
  609.           FFT_dBLow = -40;
  610.           FFT_LevelBarMode = 0 /*PEAK*/;
  611.           FFT_PeakHold = false;
  612.           if (showMessage) messageBox("PPM -40dB");
  613.           break;
  614.         /*****************************************/
  615.         case 2:
  616.           FFT_dBLow = -30;
  617.           FFT_LevelBarMode = 1 /*RMS*/;
  618.           FFT_PeakHold = false;
  619.           if (showMessage) messageBox("RMS -30dB");
  620.           break;
  621.         case 3:
  622.           FFT_dBLow = -30;
  623.           FFT_LevelBarMode = 0 /*PEAK*/;
  624.           FFT_PeakHold = false;
  625.           if (showMessage) messageBox("PPM -30dB");
  626.           break;
  627.         /*****************************************/
  628.         case 4:
  629.           FFT_dBLow = -40;
  630.           FFT_LevelBarMode = 1 /*RMS*/;
  631.           FFT_PeakHold = true;
  632.           if (showMessage) messageBox("RMS.HOLD -40dB");
  633.           break;
  634.         case 5:
  635.           FFT_dBLow = -40;
  636.           FFT_LevelBarMode = 0 /*PEAK*/;
  637.           FFT_PeakHold = true;
  638.           if (showMessage) messageBox("P.HOLD -40dB");
  639.           break;
  640.         /*****************************************/
  641.         case 6:
  642.           FFT_dBLow = -30;
  643.           FFT_LevelBarMode = 1 /*RMS*/;
  644.           FFT_PeakHold = true;
  645.           if (showMessage) messageBox("RMS.HOLD -30dB");
  646.           break;
  647.         case 7:
  648.           FFT_dBLow = -30;
  649.           FFT_LevelBarMode = 0 /*PEAK*/;
  650.           FFT_PeakHold = true;
  651.           if (showMessage) messageBox("P.HOLD -30dB");
  652.           break;
  653.         /*****************************************/
  654.         case 8:
  655.           FFT_dBLow = -40;
  656.           FFT_LevelBarMode = 1 /*RMS*/;
  657.           FFT_PeakHold = true;
  658.           if (showMessage) messageBox("RMS.HOLD4 -40dB");
  659.           break;
  660.         case 9:
  661.           FFT_dBLow = -40;
  662.           FFT_LevelBarMode = 0 /*PEAK*/;
  663.           FFT_PeakHold = true;
  664.           if (showMessage) messageBox("P.HOLD4 -40dB");
  665.           break;
  666.         /*****************************************/
  667.         case 10:
  668.           FFT_dBLow = -30;
  669.           FFT_LevelBarMode = 1 /*RMS*/;
  670.           FFT_PeakHold = true;
  671.           if (showMessage) messageBox("RMS.HOLD4 -30dB");
  672.           break;
  673.         case 11:
  674.           FFT_dBLow = -30;
  675.           FFT_LevelBarMode = 0 /*PEAK*/;
  676.           FFT_PeakHold = true;
  677.           if (showMessage) messageBox("P.HOLD4 -30dB");
  678.           break;
  679.       }
  680.       break;
  681.     case 3: // goniometer
  682.       switch (GONIO_WorkMode) {
  683.         case 0:
  684.           GONIO_dBLow = -40;
  685.           GONIO_BarMode = 1 /*RMS*/;
  686.           GONIO_PeakHold = false;
  687.           if (showMessage) messageBox("RMS -40dB");
  688.           break;
  689.         case 1:
  690.           GONIO_dBLow = -40;
  691.           GONIO_BarMode = 0 /*PEAK*/;
  692.           GONIO_PeakHold = false;
  693.           if (showMessage) messageBox("PPM -40dB");
  694.           break;
  695.         case 2:
  696.           GONIO_dBLow = -30;
  697.           GONIO_BarMode = 1 /*RMS*/;
  698.           GONIO_PeakHold = false;
  699.           if (showMessage) messageBox("RMS -30dB");
  700.           break;
  701.         case 3:
  702.           GONIO_dBLow = -30;
  703.           GONIO_BarMode = 0 /*PEAK*/;
  704.           GONIO_PeakHold = false;
  705.           if (showMessage) messageBox("PPM -30dB");
  706.           break;
  707.         case 4:
  708.           GONIO_dBLow = -40;
  709.           GONIO_BarMode = 1 /*RMS*/;
  710.           GONIO_PeakHold = true;
  711.           if (showMessage) messageBox("RMS.HOLD -40dB");
  712.           break;
  713.         case 5:
  714.           GONIO_dBLow = -40;
  715.           GONIO_BarMode = 0 /*PEAK*/;
  716.           GONIO_PeakHold = true;
  717.           if (showMessage) messageBox("P.HOLD -40dB");
  718.           break;
  719.         case 6:
  720.           GONIO_dBLow = -30;
  721.           GONIO_BarMode = 1 /*RMS*/;
  722.           GONIO_PeakHold = true;
  723.           if (showMessage) messageBox("RMS.HOLD -30dB");
  724.           break;
  725.         case 7:
  726.           GONIO_dBLow = -30;
  727.           GONIO_BarMode = 0 /*PEAK*/;
  728.           GONIO_PeakHold = true;
  729.           if (showMessage) messageBox("P.HOLD -30dB");
  730.           break;
  731.       }
  732.       break;
  733.   }
  734. }
  735. /// <summary>
  736. /// start queue
  737. /// </summary>
  738. void queueStart() {
  739.   queue1.clear();
  740.   queue2.clear();
  741.   queue1.begin();
  742.   queue2.begin();
  743. }
  744. /// <summary>
  745. /// stop queue
  746. /// </summary>
  747. void queueStop() {
  748.   queue1.end();
  749.   queue2.end();
  750.   queue1.clear();
  751.   queue2.clear();
  752.   queue1.freeBuffer();
  753.   queue2.freeBuffer();
  754. }
  755. void TriBar(int band, int barHeight) {
  756.   int x =  band;
  757. // first draw active pixels
  758.     for (int y = TOP; y >= TOP - barHeight; y--) {
  759.       if (y < 4) matrix.drawPixel(x, y, matrix.Color(70,0,0));     //Top red
  760.       else if (y > 8) matrix.drawPixel(x, y, matrix.Color(0,70,0)); //red
  761.       else matrix.drawPixel(x, y, matrix.Color(0,0,70));      
  762.     }
  763. // now draw empty pixels
  764.    for ( int y2=TOP;y2>barHeight;y2--){
  765.      matrix.drawPixel(x, 16-y2, matrix.Color(0,0,0));
  766.    }
  767.   
  768. }
  769. void TriPeak(int band) {
  770.   int xStart = band;
  771.   int peakHeight = TOP - peak[band] - 1;
  772.   for (int x = xStart; x < xStart + 1; x++) {
  773.     if (peakHeight < 4) matrix.drawPixel(x, peakHeight, matrix.Color(70,0,0)); //Top red
  774.     else if (peakHeight > 8) matrix.drawPixel(x, peakHeight, matrix.Color(0,70,0)); //green
  775.     else matrix.drawPixel(x, peakHeight, matrix.Color(0,0,70));
  776.   }
  777. }
  778. void NormalPeak(int band, int R, int G, int B) {
  779.   int xStart = band;
  780.   int peakHeight = TOP - peak[band] - 1;
  781.   for (int x = xStart; x < xStart + 1; x++) {
  782.     matrix.drawPixel(x, peakHeight, matrix.Color(R,G,B));
  783.   }
  784. }
  785. void YellowBars(int band, int barHeight) {
  786.   int x =  band;
  787. // first draw active pixels
  788.     for (int y = TOP; y >= TOP - barHeight; y--) {
  789.       matrix.drawPixel(x, y, matrix.Color(70,70,0));      
  790.     }
  791. // now draw empty pixels
  792.    for ( int y2=TOP;y2>barHeight;y2--){
  793.      matrix.drawPixel(x, kMatrixHeight-y2, matrix.Color(0,0,0));
  794.    }
  795. }
  796. void NoBars(int band, int barHeight) {
  797.   int x =  band;
  798. // first draw active pixels
  799.     for (int y = TOP; y >= TOP - barHeight; y--) {
  800.       matrix.drawPixel(x, y, matrix.Color(0,0,0));      
  801.     }
  802. // now draw empty pixels
  803.    for ( int y2=TOP;y2>barHeight;y2--){
  804.      matrix.drawPixel(x, kMatrixHeight-y2, matrix.Color(0,0,0));
  805.    }
  806. }
  807. void centerBars(int band, int barHeight) {
  808.   int x =  band;
  809.   barHeight=(barHeight/2)+(kMatrixHeight/2);
  810.   for (int y=(kMatrixHeight/2);y<kMatrixHeight;y++){
  811.    if (y<=barHeight){
  812.     if(y==barHeight){
  813.       matrix.drawPixel(x, y, matrix.Color(70,0,0));
  814.       matrix.drawPixel(x, (15-y), matrix.Color(70,0,0));
  815.       }
  816.     else{
  817.      matrix.drawPixel(x, y, matrix.Color(70,30,10));
  818.      matrix.drawPixel(x, (15-y), matrix.Color(70,30,10));
  819.      }
  820.     }
  821.    if (y>barHeight){
  822.     matrix.drawPixel(x, y, matrix.Color(0,0,0));  
  823.     matrix.drawPixel(x, 15-y, matrix.Color(0,0,0));  
  824.    }
  825.    
  826.   }
  827.   
  828. }
  829. void centerBars2(int band, int barHeight) {
  830.   int x =  band;
  831.   barHeight=(barHeight/2)+(kMatrixHeight/2);
  832.   for (int y=(kMatrixHeight/2);y<kMatrixHeight;y++){
  833.    if (y<=barHeight){
  834.     if(y==barHeight){
  835.       matrix.drawPixel(x, y, matrix.Color(70,0,70));
  836.       matrix.drawPixel(x, (15-y), matrix.Color(70,0,70));
  837.       }
  838.     else{
  839.      matrix.drawPixel(x, y, matrix.Color(0,70,10));
  840.      matrix.drawPixel(x, (15-y), matrix.Color(0,70,10));
  841.      }
  842.     }
  843.    if (y>barHeight){
  844.     matrix.drawPixel(x, y, matrix.Color(0,0,0));  
  845.     matrix.drawPixel(x, 15-y, matrix.Color(0,0,0));  
  846.    }
  847.    
  848.   }
  849.   
  850. }
复制代码


回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 昨天 12:18

【Arduino 动手做】双显示像素矩阵分析仪

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4 备案 沪公网安备31011502402448

© 2013-2025 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail