Components and supplies
Capacitor 1000 µF
WS2812B 8x32 RGB LED MATRIX
Resistor 100k ohm
Resistor 10k ohm
Capacitor 100 nF
Resistor 4.75k ohm
Pushbutton switch 12mm
4x6 cm multihole protototype board
Arduino Nano R3
Through Hole Resistor, 390 ohm
Tools and machines
3,5 mm Jack splitter cable
Soldering iron (generic)
Project description
Code
Spectrum_Analyzer_WS2812B.ino
arduino
1/* 2 Copyright (c) 2019 Shajeeb TM 3 4 Permission is hereby granted, free of charge, to any person obtaining a copy 5 of this software and associated documentation files (the "Software"), to deal 6 in the Software without restriction, including without limitation the rights 7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 copies of the Software, and to permit persons to whom the Software is 9 furnished to do so, subject to the following conditions: 10 The above copyright notice and this permission notice shall be included in all 11 copies or substantial portions of the Software. 12 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 15 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 18 SOFTWARE. 19 20 WS2812B Led Matrix vesion by Janux 21*/ 22 23#include <arduinoFFT.h> 24#include <SPI.h> 25#include <Adafruit_NeoPixel.h> 26 27#define SAMPLES 64 //Must be a power of 2 28#define xres 32 // Total number of columns in the display, must be <= SAMPLES/2 29#define yres 8 // Total number of rows in the display 30#define ledPIN 6 // pint to control Led Matrix 31#define NUM_LEDS (xres * yres) 32#define BRIGHTNESS 32 33#define buttonPin 5 // the number of the pushbutton pin to change displaycolor 34 35byte yvalue; 36byte displaycolumn, displayvalue; 37int peaks[xres]; 38byte state = HIGH; // the current reading from the input pin 39byte previousState = LOW; // the previous reading from the input pin 40byte displaycolor = 0; 41 42//Arrays for samplig 43double vReal[SAMPLES]; 44double vImag[SAMPLES]; 45byte data_avgs[xres]; 46arduinoFFT FFT = arduinoFFT(); // FFT object 47 48unsigned long lastDebounceTime = 0; // the last time the output pin was toggled 49unsigned long debounceDelay = 100; // the debounce time; increase if the output flickers 50 51// Parameter 1 = number of leds in matrix 52// Parameter 2 = pin number (most are valid) 53// Parameter 3 = pixel type flags, add together as needed: 54// NEO_KHZ800 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs) 55// NEO_KHZ400 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers) 56// NEO_GRB Pixels are wired for GRB bitstream (most NeoPixel products) 57// NEO_RGB Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2) 58Adafruit_NeoPixel pixel = Adafruit_NeoPixel(NUM_LEDS, ledPIN, NEO_GRB + NEO_KHZ800); 59 60// EQ filter to attenuates bass and improves treble 61// Useful on PC sound card which usually has many bass and poor high frequency 62bool EQ_ON = true; // set to false to disable eq 63byte eq[32] = {50, 55, 60, 70, 75, 80, 85, 95, 64 100, 100, 100, 100, 100, 100, 100, 100, 65 100, 100, 100, 100, 100, 100, 100, 100, 66 115, 125, 140, 160, 185, 200, 225, 255 67 }; 68 69//Define color for single led, used in setColumn function, 0 for custom color 70//Color are calculated by Wheel function, see below 71byte colors[][8] = { 72 {170, 160, 150, 140, 130, 120, 1, 1}, 73 {1, 5, 10, 15, 20, 25, 90, 90}, 74 {90, 85, 80, 75, 70, 65, 1, 1}, 75 {90, 90, 90, 30, 30, 30, 1, 1}, 76 {170, 160, 150, 140, 130, 120, 0, 0}, 77 {170, 160, 150, 140, 130, 120, 1, 1}, 78 {170, 160, 150, 140, 130, 120, 1, 1} 79}; 80 81void setup() { 82 83 pixel.begin(); 84 pixel.setBrightness(BRIGHTNESS); 85 86 // Begin FFT operations 87 ADCSRA = 0b11100101; // set ADC to free running mode and set pre-scalar to 32 (0xe5) 88 ADMUX = 0b00000000; // use pin A0 and external voltage reference 89} 90 91void loop() { 92 93 // ++ Sampling 94 for (int i = 0; i < SAMPLES; i++) { 95 while (!(ADCSRA & 0x10)); // wait for ADC to complete current conversion ie ADIF bit set 96 ADCSRA = 0b11110101 ; // clear ADIF bit so that ADC can do next operation (0xf5) 97 int value = ADC - 512 ; // Read from ADC and subtract DC offset caused value 98 vReal[i] = value / 8; // Copy to bins after compressing 99 vImag[i] = 0; 100 } 101 102 FFT.Windowing(vReal, SAMPLES, FFT_WIN_TYP_HAMMING, FFT_FORWARD); 103 FFT.Compute(vReal, vImag, SAMPLES, FFT_FORWARD); 104 FFT.ComplexToMagnitude(vReal, vImag, SAMPLES); 105 106 // -- FFT 107 // ++ re-arrange FFT result to match with no. of columns on display (xres) 108 int step = (SAMPLES / 2) / xres; 109 int c = 0; 110 for (int i = 0; i < (SAMPLES / 2); i += step) { 111 data_avgs[c] = 0; 112 for (int k = 0 ; k < step ; k++) { 113 data_avgs[c] = data_avgs[c] + vReal[i + k]; 114 } 115 data_avgs[c] = data_avgs[c] / step; 116 c++; 117 } 118 119 // ++ send to display according measured value 120 for (int i = 0; i <xres; i++) { 121 if (EQ_ON) 122 data_avgs[i] = data_avgs[i] * (float)(eq[i]) / 100; //apply eq filter 123 data_avgs[i] = constrain(data_avgs[i], 0, 80); // set max & min values for buckets to 0-80 124 data_avgs[i] = map(data_avgs[i], 0, 80, 0, yres); // remap averaged values to yres 0-8 125 yvalue = data_avgs[i]; 126 peaks[i] = peaks[i] - 1; // decay by one light 127 if (yvalue > peaks[i]) peaks[i] = yvalue; //save peak if > previuos peak 128 yvalue = peaks[i]; 129 displaycolumn = i; 130 displayvalue = yvalue; 131 setColumn(displaycolumn, displayvalue); // draw buckets 132 } 133 pixel.show(); // show buckets 134 displaycolorChange(); // check if button pressed to change color mode 135} 136 137//----------------------------------------------------------------- 138// Light leds of x column according to y value 139void setColumn(byte x, byte y) { 140 byte led, i; 141 142 for (i = 0; i < yres; i++) { 143 led = GetLedFromMatrix(x, i); //retrieve current led by x,y coordinates 144 if (peaks[x] > i) { 145 switch (displaycolor) { 146 case 4: 147 //put zero 0 on array value to customize peaks color 148 if (colors[displaycolor][i] > 0) { 149 //normal color defined on color array 150 pixel.setPixelColor(led, Wheel(colors[displaycolor][i])); 151 } 152 else { 153 //custom color for peaks only with 0 on array value 154 pixel.setPixelColor(led, 255, 255, 255); //Led number, R, G, B values 155 } 156 break; 157 158 case 5: 159 //change color by column 160 pixel.setPixelColor(led, Wheel(x * 16)); 161 break; 162 163 case 6: 164 //change color by row 165 pixel.setPixelColor(led, Wheel(i * 36)); 166 break; 167 168 default: 169 //display color set -> displaycolor from 0 to 3 170 //color are defined on color array 171 pixel.setPixelColor(led, Wheel(colors[displaycolor][i])); 172 }//END SWITCH 173 } 174 else { 175 pixel.setPixelColor(led, 0); 176 } 177 } 178} 179 180//====================================================================== 181// Calculate a led number by x,y coordinates 182// valid for WS2812B with serpentine layout placed in horizzontal 183// and zero led at bottom right (input connector on the right side) 184// input value: x=0-31, y=0-7, return a led number from 0 to 255 185//======================================================================== 186byte GetLedFromMatrix(byte x, byte y) { 187 x = xres - x - 1; 188 if (x & 0x01) { 189 //Odd columns increase backwards 190 return ((x + 1) * yres - y - 1); 191 } 192 else { 193 //Even columns increase normally 194 return ((x + 1) * yres - yres + y); 195 } 196} 197//======================================================================== 198 199void displaycolorChange() { 200 int reading = digitalRead(buttonPin); 201 if (reading == HIGH && previousState == LOW && millis() - lastDebounceTime > debounceDelay) // works only when pressed 202 { 203 displaycolor++; 204 if (displaycolor > 6) displaycolor = 0; 205 lastDebounceTime = millis(); 206 } 207 previousState = reading; 208} 209 210/* Utility from Adafruit Neopixel demo sketch 211 Input a value 0 to 255 to get a color value. 212 The colours are a transition R - G - B - back to R.*/ 213unsigned long Wheel(byte WheelPos) { 214 WheelPos = 255 - WheelPos; 215 if (WheelPos < 85) { 216 return pixel.Color(255 - WheelPos * 3, 0, WheelPos * 3); 217 } 218 if (WheelPos < 170) { 219 WheelPos -= 85; 220 return pixel.Color(0, WheelPos * 3, 255 - WheelPos * 3); 221 } 222 WheelPos -= 170; 223 return pixel.Color(WheelPos * 3, 255 - WheelPos * 3, 0); 224} 225
Spectrum_Analyzer_WS2812B.ino
arduino
1/* 2 Copyright (c) 2019 Shajeeb TM 3 4 Permission is hereby granted, free of charge, to any person obtaining a copy 5 of this software and associated documentation files (the "Software"), to deal 6 in the Software without restriction, including without limitation the rights 7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 copies of the Software, and to permit persons to whom the Software is 9 furnished to do so, subject to the following conditions: 10 The above copyright notice and this permission notice shall be included in all 11 copies or substantial portions of the Software. 12 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 15 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 18 SOFTWARE. 19 20 WS2812B Led Matrix vesion by Janux 21*/ 22 23#include <arduinoFFT.h> 24#include <SPI.h> 25#include <Adafruit_NeoPixel.h> 26 27#define SAMPLES 64 //Must be a power of 2 28#define xres 32 // Total number of columns in the display, must be <= SAMPLES/2 29#define yres 8 // Total number of rows in the display 30#define ledPIN 6 // pint to control Led Matrix 31#define NUM_LEDS (xres * yres) 32#define BRIGHTNESS 32 33#define buttonPin 5 // the number of the pushbutton pin to change displaycolor 34 35byte yvalue; 36byte displaycolumn, displayvalue; 37int peaks[xres]; 38byte state = HIGH; // the current reading from the input pin 39byte previousState = LOW; // the previous reading from the input pin 40byte displaycolor = 0; 41 42//Arrays for samplig 43double vReal[SAMPLES]; 44double vImag[SAMPLES]; 45byte data_avgs[xres]; 46arduinoFFT FFT = arduinoFFT(); // FFT object 47 48unsigned long lastDebounceTime = 0; // the last time the output pin was toggled 49unsigned long debounceDelay = 100; // the debounce time; increase if the output flickers 50 51// Parameter 1 = number of leds in matrix 52// Parameter 2 = pin number (most are valid) 53// Parameter 3 = pixel type flags, add together as needed: 54// NEO_KHZ800 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs) 55// NEO_KHZ400 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers) 56// NEO_GRB Pixels are wired for GRB bitstream (most NeoPixel products) 57// NEO_RGB Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2) 58Adafruit_NeoPixel pixel = Adafruit_NeoPixel(NUM_LEDS, ledPIN, NEO_GRB + NEO_KHZ800); 59 60// EQ filter to attenuates bass and improves treble 61// Useful on PC sound card which usually has many bass and poor high frequency 62bool EQ_ON = true; // set to false to disable eq 63byte eq[32] = {50, 55, 60, 70, 75, 80, 85, 95, 64 100, 100, 100, 100, 100, 100, 100, 100, 65 100, 100, 100, 100, 100, 100, 100, 100, 66 115, 125, 140, 160, 185, 200, 225, 255 67 }; 68 69//Define color for single led, used in setColumn function, 0 for custom color 70//Color are calculated by Wheel function, see below 71byte colors[][8] = { 72 {170, 160, 150, 140, 130, 120, 1, 1}, 73 {1, 5, 10, 15, 20, 25, 90, 90}, 74 {90, 85, 80, 75, 70, 65, 1, 1}, 75 {90, 90, 90, 30, 30, 30, 1, 1}, 76 {170, 160, 150, 140, 130, 120, 0, 0}, 77 {170, 160, 150, 140, 130, 120, 1, 1}, 78 {170, 160, 150, 140, 130, 120, 1, 1} 79}; 80 81void setup() { 82 83 pixel.begin(); 84 pixel.setBrightness(BRIGHTNESS); 85 86 // Begin FFT operations 87 ADCSRA = 0b11100101; // set ADC to free running mode and set pre-scalar to 32 (0xe5) 88 ADMUX = 0b00000000; // use pin A0 and external voltage reference 89} 90 91void loop() { 92 93 // ++ Sampling 94 for (int i = 0; i < SAMPLES; i++) { 95 while (!(ADCSRA & 0x10)); // wait for ADC to complete current conversion ie ADIF bit set 96 ADCSRA = 0b11110101 ; // clear ADIF bit so that ADC can do next operation (0xf5) 97 int value = ADC - 512 ; // Read from ADC and subtract DC offset caused value 98 vReal[i] = value / 8; // Copy to bins after compressing 99 vImag[i] = 0; 100 } 101 102 FFT.Windowing(vReal, SAMPLES, FFT_WIN_TYP_HAMMING, FFT_FORWARD); 103 FFT.Compute(vReal, vImag, SAMPLES, FFT_FORWARD); 104 FFT.ComplexToMagnitude(vReal, vImag, SAMPLES); 105 106 // -- FFT 107 // ++ re-arrange FFT result to match with no. of columns on display (xres) 108 int step = (SAMPLES / 2) / xres; 109 int c = 0; 110 for (int i = 0; i < (SAMPLES / 2); i += step) { 111 data_avgs[c] = 0; 112 for (int k = 0 ; k < step ; k++) { 113 data_avgs[c] = data_avgs[c] + vReal[i + k]; 114 } 115 data_avgs[c] = data_avgs[c] / step; 116 c++; 117 } 118 119 // ++ send to display according measured value 120 for (int i = 0; i <xres; i++) { 121 if (EQ_ON) 122 data_avgs[i] = data_avgs[i] * (float)(eq[i]) / 100; //apply eq filter 123 data_avgs[i] = constrain(data_avgs[i], 0, 80); // set max & min values for buckets to 0-80 124 data_avgs[i] = map(data_avgs[i], 0, 80, 0, yres); // remap averaged values to yres 0-8 125 yvalue = data_avgs[i]; 126 peaks[i] = peaks[i] - 1; // decay by one light 127 if (yvalue > peaks[i]) peaks[i] = yvalue; //save peak if > previuos peak 128 yvalue = peaks[i]; 129 displaycolumn = i; 130 displayvalue = yvalue; 131 setColumn(displaycolumn, displayvalue); // draw buckets 132 } 133 pixel.show(); // show buckets 134 displaycolorChange(); // check if button pressed to change color mode 135} 136 137//----------------------------------------------------------------- 138// Light leds of x column according to y value 139void setColumn(byte x, byte y) { 140 byte led, i; 141 142 for (i = 0; i < yres; i++) { 143 led = GetLedFromMatrix(x, i); //retrieve current led by x,y coordinates 144 if (peaks[x] > i) { 145 switch (displaycolor) { 146 case 4: 147 //put zero 0 on array value to customize peaks color 148 if (colors[displaycolor][i] > 0) { 149 //normal color defined on color array 150 pixel.setPixelColor(led, Wheel(colors[displaycolor][i])); 151 } 152 else { 153 //custom color for peaks only with 0 on array value 154 pixel.setPixelColor(led, 255, 255, 255); //Led number, R, G, B values 155 } 156 break; 157 158 case 5: 159 //change color by column 160 pixel.setPixelColor(led, Wheel(x * 16)); 161 break; 162 163 case 6: 164 //change color by row 165 pixel.setPixelColor(led, Wheel(i * 36)); 166 break; 167 168 default: 169 //display color set -> displaycolor from 0 to 3 170 //color are defined on color array 171 pixel.setPixelColor(led, Wheel(colors[displaycolor][i])); 172 }//END SWITCH 173 } 174 else { 175 pixel.setPixelColor(led, 0); 176 } 177 } 178} 179 180//====================================================================== 181// Calculate a led number by x,y coordinates 182// valid for WS2812B with serpentine layout placed in horizzontal 183// and zero led at bottom right (input connector on the right side) 184// input value: x=0-31, y=0-7, return a led number from 0 to 255 185//======================================================================== 186byte GetLedFromMatrix(byte x, byte y) { 187 x = xres - x - 1; 188 if (x & 0x01) { 189 //Odd columns increase backwards 190 return ((x + 1) * yres - y - 1); 191 } 192 else { 193 //Even columns increase normally 194 return ((x + 1) * yres - yres + y); 195 } 196} 197//======================================================================== 198 199void displaycolorChange() { 200 int reading = digitalRead(buttonPin); 201 if (reading == HIGH && previousState == LOW && millis() - lastDebounceTime > debounceDelay) // works only when pressed 202 { 203 displaycolor++; 204 if (displaycolor > 6) displaycolor = 0; 205 lastDebounceTime = millis(); 206 } 207 previousState = reading; 208} 209 210/* Utility from Adafruit Neopixel demo sketch 211 Input a value 0 to 255 to get a color value. 212 The colours are a transition R - G - B - back to R.*/ 213unsigned long Wheel(byte WheelPos) { 214 WheelPos = 255 - WheelPos; 215 if (WheelPos < 85) { 216 return pixel.Color(255 - WheelPos * 3, 0, WheelPos * 3); 217 } 218 if (WheelPos < 170) { 219 WheelPos -= 85; 220 return pixel.Color(0, WheelPos * 3, 255 - WheelPos * 3); 221 } 222 WheelPos -= 170; 223 return pixel.Color(WheelPos * 3, 255 - WheelPos * 3, 0); 224} 225
Downloadable files
Wiring
Wiring
Wiring
Wiring
Documentation
Eagle Project
Eagle Project
Circuit board sample
Circuit board sample
Circuit board sample
Circuit board sample
Eagle Schematic sample picture
Eagle Schematic sample picture
Eagle Project
Eagle Project
Comments
Only logged in users can leave comments
janux
0 Followers
•0 Projects
Table of contents
Intro
11
0