Sunday, June 26, 2016

Sound Controlled LED Matrix

Goal: To control a matrix of LEDs with a microphone input.
Equipment: LED matrix(2088RGB-5), shift registers (74HC595), Micro-controller (arduino), Analog Amplifier (LM386), Resistors(varies), Capacitors (varies), wire, breadboard.

Quick Explanation
A matrix of LEDs works by applying a voltage over each individual LED, one at a time. To do this effectively (ie. not use up the Digital pins on a micro-controller) shift registers are used. Two shift registers to be precise, one for the anodes and one for the cathodes of the LEDs in the matrix. If you are unsure of what an anode or a cathode is, hopefully this diagram will help you out:
Draw A Wire Diagram
The first step is to find the datasheets of the specific components you are going to use. The reason for finding the data sheets is so that the pin-outs of the components can be identified. Which will allow them to be wired up properly. Below is the initial diagram created for this project. It is used to test out how the matrix and shift registers work together. If you have identical components, feel free to copy. If your part numbers do not match, you better hunt for the correct data sheets. Your pin one might not be the same as the pin one below!


Calculate Current Limiting
Hopefully you noticed that 180 ohm resistors are used. This value was chosen based off of information from the matrix manufacturer. What that means is that the manufacturer filled in most of the variables in the equations used (forward current and voltage). The math for finding what resistance value to use is detailed below. The calculation did not need to be as long as it is, it was done that way to help out anyone that may need it.
  
Include the Micro-Controller
If all of the above was completed and the circuit was powered on, random LEDs should have lit up within the matrix. This is because the control pins for the shift registers are not connected to anything! That is alright, the goal was to test the circuit, take it as a good sign if lights are on. The next step is to introduce the micro controller and have it control the shift registers. Since this project uses an arduino board, a good place to help figure this out would be the arduino website. With help from that resource, the circuit diagram turns into something like this:
Don't Forget About the Mic!
You may notice the LM386 is included in the second diagram. This is what the microphone will plug into. It is a fairly well-known and reliable circuit. All it does is take in an analog signal and "boost" it. The output of the LM386 is what should connect to the analog input of the micro-controller. The 10K potentiometer is there to allow the tweaking of the circuit's amplification.

Finish The Code
After the micro-controller is thrown into the mix, start telling it how to talk to the shift registers. A good way is to first use the example code on the arduino website and add to it until you understand what is going on. The ultimate goal for this project was to get the board to take in a mic signal and light up the matrix based upon how "loud" that sound was. The louder the signal, the more of the LEDs would be illuminated. The final code it pasted below:

//**************************************************************//
//  Name    : Matrix with mic                                      //
//  Author  : IllInformed Human                                    //
//  Version : 1.3                                               //                                                        
//  Notes   : Code for controlling a 74HC595 Shift Register    //
//          : With an analog (mic) input                      //
//************************************************************//
//
//Matrix Setup
int latchPin = 8;//Pin connected to ST_CP of 74HC595
int clockPin = 12;//Pin connected to SH_CP of 74HC595
int dataPin = 11;//Pin connected to DS of 74HC595
byte NullDataArray[2];
byte dataArray1[6];
byte dataArray2[8];
byte dataArray3[10];
byte dataArray4[12];
byte dataArray5[14];
byte dataArray6[16];
//
//Microphone Setup
int microphonePin= 0; //the microphone positive terminal will connect to analog pin A0 to be read
int MicSample; // variable that will hold the mic value each cycle
//All other variables
char smalltime= 5; // Variable used within the case stucture
//
void setup() {
  Serial.begin(9600);
  pinMode(latchPin, OUTPUT); //set pins to output because they are addressed in the main loop
  //Use Decimal values to define each row then column of the array.
 //
//This first array will be used to send 0's to both shift registers when called. (To clear matrix)
  NullDataArray[0]=0;
  NullDataArray[1]=0;
//
//Value for:
// 2nd shift Reg              1st shift Reg
  dataArray1[0] = 4; dataArray1[3] = 63;
  dataArray1[1] = 2; dataArray1[4] = 15;
  dataArray1[2] = 1; dataArray1[5] = 1;          
//
  dataArray2[0] = 8; dataArray2[4] = 63;
  dataArray2[1] = 4; dataArray2[5] = 15;
  dataArray2[2] = 2; dataArray2[6] = 3;
  dataArray2[3] = 1; dataArray2[7] = 0; 
//
  dataArray3[0] = 16; dataArray3[5] = 63;
  dataArray3[1] = 8; dataArray3[6] = 31;
  dataArray3[2] = 4; dataArray3[7] = 15;
  dataArray3[3] = 2; dataArray3[8] = 1;
  dataArray3[4] = 1; dataArray3[9] = 0;
//
  dataArray4[0] = 32; dataArray4[6] = 127;
  dataArray4[1] = 16; dataArray4[7] = 31;
  dataArray4[2] = 8; dataArray4[8] = 15;
  dataArray4[3] = 4; dataArray4[9] = 7;
  dataArray4[4] = 2; dataArray4[10] = 0;
  dataArray4[5] = 1; dataArray4[11] = 0;
//
  dataArray5[0] = 64; dataArray5[7] = 63;
  dataArray5[1] = 32; dataArray5[8] = 63;
  dataArray5[2] = 16; dataArray5[9] = 31;
  dataArray5[3] = 8; dataArray5[10] = 15;
  dataArray5[4] = 4; dataArray5[11] = 3;
  dataArray5[5] = 2; dataArray5[12] = 0;
  dataArray5[6] = 1; dataArray5[13] = 0;
//
  dataArray6[0] = 128; dataArray6[8] = 127;
  dataArray6[1] = 64; dataArray6[9] = 63;
  dataArray6[2] = 32; dataArray6[10] = 63;
  dataArray6[3] = 16; dataArray6[11] = 15;
  dataArray6[4] = 8; dataArray6[12] = 7;
  dataArray6[5] = 4; dataArray6[13] = 1;
  dataArray6[6] = 2; dataArray6[14] = 0;
  dataArray6[7] = 1; dataArray6[15] = 0;
}

void loop() {
  MicSample= analogRead(microphonePin); //Read the microphone pin and store value.
  Serial.println(MicSample); // for tuning
  if((MicSample > 550) && (MicSample < 575)){
    //This FOR loop is what loads the second then the first shift register(In a Not-straightforward way...)
    for (int j = 0; j < 3; j++) {
        digitalWrite(latchPin, 0);//ground latchPin and hold low for as long as you are transmitting
        shiftOut(dataPin, clockPin, dataArray1[j]); //Load this array into SR1
        shiftOut(dataPin, clockPin, dataArray1[j+3]); //Move what is in SR1 into SR2 and replace SR1 with this array
        //Return the latch pin high to signal chip to stop listening and set the Shift Reg pins to stored values
        digitalWrite(latchPin, 1);
        delay(smalltime);
        }}
   else if ((MicSample > 575) && (MicSample < 600)){
      for (int j = 0; j < 4; j++) {
        digitalWrite(latchPin, 0);
        shiftOut(dataPin, clockPin, dataArray2[j]);
        shiftOut(dataPin, clockPin, dataArray2[j+4]);
        digitalWrite(latchPin, 1);
        delay(smalltime);
        }}
    else if (MicSample > 600 && MicSample < 625){     
      for (int j = 0; j < 5; j++) {
        digitalWrite(latchPin, 0);
        shiftOut(dataPin, clockPin, dataArray3[j]);
        shiftOut(dataPin, clockPin, dataArray3[j+5]);
        digitalWrite(latchPin, 1);
        delay(smalltime);
        }}
    else if (MicSample > 625 && MicSample < 650){
      for (int j = 0; j < 6; j++) {
        digitalWrite(latchPin, 0);
        shiftOut(dataPin, clockPin, dataArray4[j]);
        shiftOut(dataPin, clockPin, dataArray4[j+6]);
        digitalWrite(latchPin, 1);
        delay(smalltime);
        }}
    else if (MicSample > 650 && MicSample < 700){
      for (int j = 0; j < 7; j++) {
        digitalWrite(latchPin, 0);
        shiftOut(dataPin, clockPin, dataArray5[j]);
        shiftOut(dataPin, clockPin, dataArray5[j+7]);
        digitalWrite(latchPin, 1);
        delay(smalltime);
        }}
    else if (MicSample > 700){
      for (int j = 0; j < 8; j++) {
        digitalWrite(latchPin, 0);
        shiftOut(dataPin, clockPin, dataArray6[j]);
        shiftOut(dataPin, clockPin, dataArray6[j+8]);
        digitalWrite(latchPin, 1);
        delay(smalltime);
        }}
    else{
    //fill the registers with all "0s" keeping it dark when no statement is true.
      for (int j = 0; j < 1; j++) {
        digitalWrite(latchPin, 0);
        shiftOut(dataPin, clockPin, NullDataArray[j]);
        shiftOut(dataPin, clockPin, NullDataArray[j+1]);
        digitalWrite(latchPin, 1);
        delay(smalltime);
        }
    }
}
//////////////////////////////////////////////////////////////////////////////////////////////
// ShiftOut Subroutine
//////////////////////////////////////////////////////////////////////////////////////////////
void shiftOut(int myDataPin, int myClockPin, byte myDataOut) {
  // This shifts 8 bits out MSB first,
  //on the rising edge of the clock,
  //clock idles low

  //internal function setup
  int i=0;
  int pinState;
  pinMode(myClockPin, OUTPUT);
  pinMode(myDataPin, OUTPUT);

  //clear everything out just in case to
  //prepare shift register for bit shifting
  digitalWrite(myDataPin, 0);
  digitalWrite(myClockPin, 0);

  //for each bit in the byte myDataOut
  //NOTICE THAT WE ARE COUNTING DOWN in our for loop
  //This means that 000001 or "1" will go through such
  //that it will be pin Q0 that lights.
  for (i=7; i>=0; i--)  {
    digitalWrite(myClockPin, 0);

    //if the value passed to myDataOut and a bitmask result
    // true then... so if we are at i=6 and our value is
    // %11010100 it would the code compares it to %01000000
    // and proceeds to set pinState to 1.
    if ( myDataOut & (1<<i) ) {
      pinState= 1;
    }
    else { 
      pinState= 0;
    }

    //Sets the pin to HIGH or LOW depending on pinState
    digitalWrite(myDataPin, pinState);
    //register shifts bits on upstroke of clock pin 
    digitalWrite(myClockPin, 1);
    //zero the data pin after shift to prevent bleed through
    digitalWrite(myDataPin, 0);
  }

  //stop shifting
  digitalWrite(myClockPin, 0);
}