Arduino Powered LED Equalizer
Construction of LED Matrix
Construction:
The first thing I decided to make was the LED matrix. I was originally going to make an 8 by 10 matrix but I later trimmed it down to 8 by 8 for reasons I will explain later.
LED matrix:
I made the LED matrix with 64 green LED’s and a prototyping board. The LED matrix needs to be carefully planned out and constructed. You can’t wire up each LED because you would have 128 wires coming from your board and you don’t have 64 I/O pins. There Is a way to take the amount of I/O pins required from the arduino down to 3 and I will explain that later. To make the Array, I placed the LEDs in the Prototyping board in a rectangle and trimmed down the wires so that only about two millimeters were showing. Then I bent down the positive wires of all the LEDs vertically and left the negative wires standing. I first soldered a line to connect all the bent down wires to make vertical lines which would be all the positive wires for each column. To make the row wires which are the negative wires for each row, I took the clipped wires from the LEDs, and soldered them to the top of the standing wires in a horizontal line. The reason I needed to wire the anodes and cathodes in this way is because of the fact that in a matrix, you cannot light multiple columns or rows without two rows interfering. For example, if you tried to light the top-leftmost led and the bottom-rightmost led, you would need to set the leftmost and rightmost column high and the upper and bottom row low. But if you did this you would light up the bottom-leftmost and top-rightmost which is not what you originally intended (diagram above).
The first thing I decided to make was the LED matrix. I was originally going to make an 8 by 10 matrix but I later trimmed it down to 8 by 8 for reasons I will explain later.
LED matrix:
I made the LED matrix with 64 green LED’s and a prototyping board. The LED matrix needs to be carefully planned out and constructed. You can’t wire up each LED because you would have 128 wires coming from your board and you don’t have 64 I/O pins. There Is a way to take the amount of I/O pins required from the arduino down to 3 and I will explain that later. To make the Array, I placed the LEDs in the Prototyping board in a rectangle and trimmed down the wires so that only about two millimeters were showing. Then I bent down the positive wires of all the LEDs vertically and left the negative wires standing. I first soldered a line to connect all the bent down wires to make vertical lines which would be all the positive wires for each column. To make the row wires which are the negative wires for each row, I took the clipped wires from the LEDs, and soldered them to the top of the standing wires in a horizontal line. The reason I needed to wire the anodes and cathodes in this way is because of the fact that in a matrix, you cannot light multiple columns or rows without two rows interfering. For example, if you tried to light the top-leftmost led and the bottom-rightmost led, you would need to set the leftmost and rightmost column high and the upper and bottom row low. But if you did this you would light up the bottom-leftmost and top-rightmost which is not what you originally intended (diagram above).
Shift Registers
Now that I had the LED matrix built, I had to figure out how I would light it. I did some quick research and found that shift registers would be my best solution. I chose shift registers because they can direct current to specific pins that are set through a digital signal sent to them. The shift registers I used have 8 parallel output pins which is why I only used an 8 by 8 matrix. The 8 parallel pins (Qa-h) are set by a digital signal which makes it an 8-bit shift register. The shift register requires 3 pins (SRCLK,SER,OE) from the arduino along with a 5v source(Vcc) and ground(GND). You can chain these shift registers together to sort of make a 16 bit register but not really. Each shift register needs its own ground and 5v but it can share 2 of the same pins(SRCLK,OE) and the other one needs to be wired from the last shift register. The third pin (Qh’) is like an overflow from the last shift register that passes on the 8 bit number that it has in it.
Binary
One thing I didn’t realize with the shift registers at first was that if a pin is off, it acts like a ground wire and if it is on, it acts like a +5v wire. So if I wanted to turn a row(cathode) off, I would have to set that pin on. That would insure that none of the LEDs in that row will turn on. The way I approached lighting the led matrix was to cycle through it from left to right. So that meant I would need to set the columns on one by one from left to right. If you look at the pins in order from left to right this is what they would look like represented in binary when cycling from left to right 10000000 -> 01000000 -> 00100000 -> 00010000 -> etc… and for my project the only thing I will be sending the cathode shift register would be these 8 values which is 128, 64, 32, 16 etc. respectively. The same thing applies with the anode shift register except it is opposite. If I want to light an led up I need to set it low as I explained earlier. Since I am only doing an equalizer, there will only be 9 options for this shift register, none to all the pins low. I had to calculate the binary values for this as well.
Design Method
The Code/Arduino:
Overall, I have 6 pins plugged in to the Arduino; 5v, ground, the 3 pins for the shift registers, and an analog input for the audio input. The goal of the code in this project is to take in audio signal, process it and output the correct numbers to the shift registers. Reading the audio is as simple as making an array with a certain number of 8-bit values. This will be stored and used to find the frequency. I used 128 for the size of my array because it is a balance between accuracy of the actual analysis of the audio and speed of the program.
Fast Fourier Transform:
I used a fast Fourier transform to analyze the frequencies of the audio. I had to look for a library on the internet. I asked my EE285 teacher Dr. Daniels and he led me to one called fix_fft.h it had everything I needed but I kept getting an error. It turned out you have to change an #include in the header and .cpp file from <WProgram.h> to <Arduino.h>. This function takes in the array of values, an array of zeros, and 7 which comes from log2(128).
For some reason fft only takes chars so I had to convert the value read from the analog pin to a char data type by using the function char(). I guessed it is because chars are only 8 bit but I don’t know why it couldn’t have used byte data type.
Getting Shift Registers to Work:
Thankfully, Arduino has a function that does the work for me in sending the bytes to the shift registers. It is called shiftOut() and it takes 4 parameters the first being the number of the data pin, second being the number of the clock pin, third being LSBFIRST or FSBFIRST meaning last significant bit first or first significant bit. This means that the byte passed through can be reversed so that the ones and zeros are flipped. And the last parameter for this function is the 8-bit number to be sent to the shift register. This is basically the binary number I explained earlier converted to decimal.
Overall, I have 6 pins plugged in to the Arduino; 5v, ground, the 3 pins for the shift registers, and an analog input for the audio input. The goal of the code in this project is to take in audio signal, process it and output the correct numbers to the shift registers. Reading the audio is as simple as making an array with a certain number of 8-bit values. This will be stored and used to find the frequency. I used 128 for the size of my array because it is a balance between accuracy of the actual analysis of the audio and speed of the program.
Fast Fourier Transform:
I used a fast Fourier transform to analyze the frequencies of the audio. I had to look for a library on the internet. I asked my EE285 teacher Dr. Daniels and he led me to one called fix_fft.h it had everything I needed but I kept getting an error. It turned out you have to change an #include in the header and .cpp file from <WProgram.h> to <Arduino.h>. This function takes in the array of values, an array of zeros, and 7 which comes from log2(128).
For some reason fft only takes chars so I had to convert the value read from the analog pin to a char data type by using the function char(). I guessed it is because chars are only 8 bit but I don’t know why it couldn’t have used byte data type.
Getting Shift Registers to Work:
Thankfully, Arduino has a function that does the work for me in sending the bytes to the shift registers. It is called shiftOut() and it takes 4 parameters the first being the number of the data pin, second being the number of the clock pin, third being LSBFIRST or FSBFIRST meaning last significant bit first or first significant bit. This means that the byte passed through can be reversed so that the ones and zeros are flipped. And the last parameter for this function is the 8-bit number to be sent to the shift register. This is basically the binary number I explained earlier converted to decimal.
The Code
#include <fix_fft.h>
#include <math.h>
//Pin connected to latch pin (ST_CP) of 74HC595
const int latchPin = 10;
//Pin connected to clock pin (SH_CP) of 74HC595
const int clockPin = 9;
////Pin connected to Data in (DS) of 74HC595
const int dataPin = 11;
const int colset[9] = {255,127,63,31,15,7,3,1,0};
const int rowset[8] = {128,64,32,16,8,4,2,1};
int currentCols[8] = {0,0,0,0,0,0,0,0};
int a = 0;
int b = 0;
//Audio part ---
const int samp = 128;
const int apin = 14;
char data[samp];
char im[samp];
int temp;
int cal;
//---
void setup() {
//set pins to output because they are addressed in the main loop
pinMode(latchPin, OUTPUT);
pinMode(dataPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(apin, INPUT);
Serial.begin(9600);
cal = analogRead(apin);
}
void loop() {
data[b] = analogRead(apin) - cal;
im[b] = 0;
digitalWrite(latchPin,LOW);
shiftOut(dataPin, clockPin, LSBFIRST, colset[currentCols[a]]);
shiftOut(dataPin, clockPin, LSBFIRST, rowset[a]);
digitalWrite(latchPin,HIGH);
a ++;
if(a == 8){
a = 0;
}
b ++;
if(b == samp){
myfft();
setCols();
b = 0;
}
}
void myfft(){
fix_fftr(data,7,0);
for(int i = 0; i<samp/2;i++){
data[i] = sqrt(data[i] * data[i] + im[i] * im[i]);
//Serial.println(int(data[i]));
}
//delay(2000);
}
void setCols(){
int j = 0;
for(int i = 0; i<64; i = i+8){
currentCols[j] = (sqrt(pow(int(data[i]),2) + pow(int(data[i+1]),2) + pow(int(data[i+2]),2) + pow(int(data[i+3]),2)
+ pow(int(data[i+4]),2) + pow(int(data[i+5]),2) + pow(int(data[i+6]),2) + pow(int(data[i+7]),2) /*+ pow(int(data[i+8]),2)*/ ));
if(currentCols[j] > 10){
currentCols[j] = 9;
}
//Serial.println((currentCols[j]));
j++;
}
//delay(2000);
}
In the end, it came together and it looked like an equalizer so i was happy. As music played, the Led's lit up in synchrony with the music.