5x5 Led Matrix - Microphone Input PROBLEMS

Hi,

As part of my masters I am trying to create a prototype of a led matrix that responds to sounds that are picked up by a microphone. I have only been introduced to an arduino less then a month ago so bear with my lack of knowledge.

So far I have managed to build a working 5x5 led matrix, which works with other codes that do not rely on a mic input. However once I try to control it with sound I cant seem to get the code to work.

I have adapted a code supplied by gallactronics for a 8x8 matrix as follows:

const int rownum[5] = {
  12,11,10,9,8}; 
// here you are naming the rows const 

int colnum[5] = { 
7,6,5,4,3};
//here you are naming the columns 

int audioIn = A0; 
int Vin = 0; 

float audioVin = 0; 

//now you are saying which LEDs to light at what amplitude 

int blank[5][5] = { 
{0,0,0,0,0}, 
{0,0,0,0,0}, 
{0,0,0,0,0}, 
{0,0,0,0,0}, 
{0,0,0,0,0}}; 

int minimum[5][5] = { 
{0,0,0,0,0}, 
{0,0,0,0,0}, 
{0,0,1,0,0}, 
{0,0,0,0,0}, 
{0,0,0,0,0}}; 
  
  
int drum[5][5] = { 
  
{0,0,0,0,0}, 
{0,1,1,1,0}, 
{0,1,0,1,0}, 
{0,1,1,1,0}, 
{0,0,0,0,0}};   
  

int mediocre[5][5] = { 
  
{1,1,1,1,1}, 
{1,0,0,0,1}, 
{1,0,0,0,1}, 
{1,0,0,0,1}, 
{1,1,1,1,1}};   
  
  
 
void setup() { 
 analogReference(EXTERNAL);
Serial.begin(19200);
// initialize the I/O pins as outputs: 

// iterate over the pins: 
for (int thisPin = 0; thisPin < 5; thisPin++) { 
// initialize the output pins: 
pinMode(colnum[thisPin], OUTPUT);
pinMode(rownum[thisPin], OUTPUT); 
// take the col pins (i.e. the cathodes) high to ensure that 
// the LEDS are off: 
digitalWrite(colnum[thisPin], HIGH); 
digitalWrite(rownum[thisPin], LOW); } } 

void loop() { 
  // This could be rewritten to not use a delay, which would make it appear brighter 
  int audioVin = analogRead(A0);
Serial.println(audioVin, DEC); 

//now you are specifying the ranges for the mp3 jack audio input voltage (audioVin) 
if (audioVin < 6) { drawScreen(blank); 
} else if(audioVin < 14) { drawScreen(minimum); 
} else if (audioVin < 35) { drawScreen(drum); 
} else if (audioVin < 45) { drawScreen(mediocre); 
} 
} 

int row(int i) { 
if(i == 1) 
{ return A5; 
} else if (i == 2) 
{ return A4; 
} else if (i == 3) 
{ return A3; 
} else if (i == 4)
{ return A2;
} else if (i == 5) 
{ return 3; 
} 
} 

int col(int i) { 
if(i == 1) 
{ return 7; 
} else if (i == 2)
{ return 8; 
} else if (i == 3) 
{ return 9; 
} else if (i == 4)
{ return 10; 
} else if (i == 5) 
{return 11; 
} 
} 

void drawScreen(int character[5][5]) { 
for(int j = 0; j < 5; j++) { 
// Turn the row on 
int rowNumber = j + 1; 
digitalWrite(row(rowNumber), LOW); 
for (int k = 0; k < 5; k++) { 
// draw some letter bits 
int columnNumber = k + 1; 
if(character[j][k] == 1) { 
digitalWrite(col(columnNumber), HIGH); 
} 

digitalWrite(col(columnNumber), LOW); 
} 

digitalWrite(row(rowNumber), HIGH); 
} 
}

When uploaded the LED Matrix does not respond at all! Using adafruits Electrect mic as shown here:

any clue where I am going wrong?

Thanks!

Hi, what is your masters in?

I can think of several reasons why it is not working!

What do you see on the serial monitor when the sketch is running?

What is connected to the Arduino's Vref pin? Can you post a schematic please?

Paul

Hi Paul

I'm doing a masters in architecture, currently trying to create a LED facade that would respond to sound.

I have attached the wiring diagram, I hope it helps you find you what I am doing wrong! Ha

Thanks for your help!

Thanks for that. I'm glad you said Architecture! I would have been very disappointed if you had said Maths, Physics, Electronics or Engineering. If you were studding for a masters in those, I would expect you to know what your problem is here.

Your diagram: On the microphone side, looks OK. On the matrix side, which you already said is working, my only concern is you may be overloading the Arduino pins connected to the common cathodes of the matrix rows. What value resistors are you using?

Anyway, I believe the real problem here is the sketch. In the item description on the link you posted, it says

The output will have a DC bias of VCC/2 so when its perfectly quiet, the voltage will be a steady VCC/2 volts (it is DC coupled).

In your case, you have sensibly used the 3.3V Arduino output to power the mic module. So your "VCC" is 3.3V. When it is quiet, the Arduino analog input should be receiving a voltage of VCC/2 = 3.3/2 = 1.65V.

Your sketch is using "analogReference(EXTERNAL)" and you are feeding the 3.3V to the Aref pin. This sets the allowable input range between 0 and 3.3V When it is quiet, the mic module's output voltage will be around half way up the allowed range.

analogRead() gives a value between 0 and 1023. So when its quiet, you should be getting a value of 512, but in practice around 500~520. (That's why I asked the question earlier.) Your code compares this value with figures in the range below 6 to below 45. There is no code that deals with values above 45, and I suspect the values are in fact nearer 500. I think this is why your matrix is blank.

So have a look at the serial monitor and confirm what values you are seeing printed there.

Even once you have adjusted your ranges for the values you are seeing on the serial monitor, it still won't do what you want. You will just get flashing/flickering combinations of your matrix patterns.

This is because sound is a wave, as I'm sure you know, with peaks and troughs. For the human audible range, there will be between around 20 and 20,000 of these peaks per second. When you use analogRead(), you are picking up the voltage at a random point on the soundwave, maybe near a peak, or a trough, or somewhere in between.

What you want to do is measure the measure the sound's apparent "loudness". To do this, you need to take many readings over a longer period, for example a hundred milliseconds. Then you can average them. Unfortunately, this average will always come out to be around 500~520, because it will be over that for the peaks and under for the troughs. So you need to take the difference of each individual reading from a typical "quiet" reading, and then average the absolute differences.

Hope this makes sense. If you need help coding that, come back. Also note that if you write each reading to the serial monitor, the process of writing takes many times longer than the process of taking a reading, so you will not get many readings in 100ms! Only print the result/average to serial monitor after you have completed your 100ms of samples.

Paul

Hi Paul

Right now I wish I know more about arduinos, but I'm glad I have been given some exposure to it! something I will certainly carry forward.

I understood, the theory of everything you said in your last post. However I have no clue how to produce a code to read the 'loudness' you mentioned in the latter part of your post and would greatly appreciate some help with that!

I ran the code provided above only to find the first a series of gibberish as shown in image 1.

I then ran this code:

int analogPin = 0;     // potentiometer wiper (middle terminal) connected to analog pin 3
                       // outside leads to ground and +5V
int val = 0;           // variable to store the value read

void setup()
{
  Serial.begin(9600);          //  setup serial
}

void loop()
{
  val = analogRead(analogPin);    // read the input pin
  Serial.println(val);             // debug value
}

To which i got the serial monitor to print values that you hd mentioned averaging at around 500-520 as shown in image 2.

Any idea why this is not happening when using the original code?

image 1.png

Image 2.png

ABCreates:
I ran the code provided above only to find the first a series of gibberish as shown in image 1. Any idea why this is not happening when using the original code?

This is simply because your earlier code says "Serial.begin(19200);" and you haven't set the Serial Monitor to match that same speed. Set Serial Monitor to 19200 and the gibberish will suddenly make sense.

ABCreates:
I understood, the theory of everything you said in your last post. However I have no clue how to produce a code to read the 'loudness' you mentioned in the latter part of your post and would greatly appreciate some help with that!

Give this a try:

int analogPin = 0;     // potentiometer wiper (middle terminal) connected to analog pin 3
                       // outside leads to ground and +5V
long val = 0;           // variable to store the value read

void setup()
{
  Serial.begin(9600);          //  setup serial
}

void loop()
{
  val = 0;
  for (int i=0; i<1000; i++) {
    val += abs(analogRead(analogPin) - 512);    // read the input pin
  }
  val /= 1000;
  Serial.println(val);             // debug value
}

What do you see on Serial Monitor with this? (don't forget to select the correct speed on Serial Monitor)

Running the code you just gave me i printed image 1. - the 40-70s range indicates when i tapped the microphone.

From what I understand the numbers printed = average peaks of multiple readings (within a certain time frame) - 512 (being the average 'quiet' reading?

Please correct as I am most likely wrong.

Thanks for your help

Image1.png

The code I gave you corrects for the 512 average level and takes an average over 1000 readings. It would give zero for prefect quiet in theory, but in practice there will always be some circuit noise. So do you think it will be suitable? It needs to be integrated with your multiplexing sketch. I was thinking it could be sampling the input instead of the delay() periods you have in there now.

Makes much more sense!

Yeah from what I can tell it would be fine, however i didn't quite understand this bit...

I was thinking it could be sampling the input instead of the delay() periods you have in there now.

He means do not use delay it is literally a waste of time. Do something useful with the time by taking more samples.

ABCreates:
i didn't quite understand this bit...

I was thinking it could be sampling the input instead of the delay() periods you have in there now.

My bad, there are no delay() commands in your multiplexing sketch. I assumed there were because... well, normally there are! We will have to have another look at your multiplexing sketch and figure out where and for how long we can sample the mic input.

EDIT: since you only "adapted" the multiplexing sketch, I hope I can comment on it without upsetting you... its a dog's breakfast.

PaulRB:
my only concern is you may be overloading the Arduino pins connected to the common cathodes of the matrix rows. What value resistors are you using?

Reading the sketch again, I can see now why there is no danger of overloading the Arduino pins. Only 1 LED is ever lit at any instant. You have a 1:25 multiplexing ratio, i.e. an led that appears "on" is actually only on for one twenty-fifth of the time. The display must be pretty dim I would think. Could do with an answer on those resistor values!

But I have had a though about how we can combine this with sampling the mic input. Will explain more later.

Hey Paul,

Sorry for the late reply on those resistor values, I calculated 160 ohms, however opted for 180 ohms (maplin stock issues).

Oh and yes, please use the code as you choose - i think it would have taken weeks and a lot of luck to end up at this point! I greatly appreciate you help!

With no matrix and no mic module, I'm working more than half blind, but see what this does:

const int rownum[5] = {
  12,11,10,9,8}; 
// here you are naming the rows const 

int colnum[5] = { 
  7,6,5,4,3};
//here you are naming the columns 

int audioIn = A0; 
int Vin = 0; 

int audioVin = 0; 

long vinTotal = 0;
int vinCount = 0;

//now you are saying which LEDs to light at what amplitude 

int blank[5][5] = { 
  {    0,0,0,0,0  }, 
  {    0,0,0,0,0  }, 
  {    0,0,0,0,0  }, 
  {    0,0,0,0,0  }, 
  {    0,0,0,0,0  }
}; 

int minimum[5][5] = { 
  {    0,0,0,0,0  }, 
  {    0,0,0,0,0  }, 
  {    0,0,1,0,0  }, 
  {    0,0,0,0,0  }, 
  {    0,0,0,0,0  }
}; 

int drum[5][5] = { 

  {    0,0,0,0,0  }, 
  {    0,1,1,1,0  }, 
  {    0,1,0,1,0  }, 
  {    0,1,1,1,0  }, 
  {    0,0,0,0,0  }
};   


int mediocre[5][5] = { 

  {    1,1,1,1,1  }, 
  {    1,0,0,0,1  }, 
  {    1,0,0,0,1  }, 
  {    1,0,0,0,1  }, 
  {    1,1,1,1,1  }
};   



void setup() { 
  analogReference(EXTERNAL);
  Serial.begin(19200);
  // initialize the I/O pins as outputs: 

  // iterate over the pins: 
  for (int thisPin = 0; thisPin < 5; thisPin++) { 
    // initialize the output pins: 
    pinMode(colnum[thisPin], OUTPUT);
    pinMode(rownum[thisPin], OUTPUT); 
    // take the col pins (i.e. the cathodes) high to ensure that 
    // the LEDS are off: 
    digitalWrite(colnum[thisPin], HIGH); 
    digitalWrite(rownum[thisPin], LOW); 
  } 
} 

void loop() { 
  
  // This could be rewritten to not use a delay, which would make it appear brighter 
  
  if (vinCount >= 1000) {
    audioVin = vinTotal / vinCount;
    Serial.println(audioVin, DEC); 
    vinTotal = vinCount = 0;
  }

  //now you are specifying the ranges for the mp3 jack audio input voltage (audioVin) 
  if (audioVin < 40) { 
    drawScreen(blank); 
  } 
  else if(audioVin < 50) { 
    drawScreen(minimum); 
  } 
  else if (audioVin < 60) { 
    drawScreen(drum); 
  } 
  else { 
    drawScreen(mediocre); 
  } 
} 

int row(int i) { 
  if(i == 1) 
  { 
    return A5; 
  } 
  else if (i == 2) 
  { 
    return A4; 
  } 
  else if (i == 3) 
  { 
    return A3; 
  } 
  else if (i == 4)
  { 
    return A2;
  } 
  else if (i == 5) 
  { 
    return 3; 
  } 
} 

int col(int i) { 
  if(i == 1) 
  { 
    return 7; 
  } 
  else if (i == 2)
  { 
    return 8; 
  } 
  else if (i == 3) 
  { 
    return 9; 
  } 
  else if (i == 4)
  { 
    return 10; 
  } 
  else if (i == 5) 
  {
    return 11; 
  } 
} 

void drawScreen(int character[5][5]) { 
  for(int j = 0; j < 5; j++) { 
    // Turn the row on 
    int rowNumber = j + 1; 
    digitalWrite(row(rowNumber), LOW); 
    for (int k = 0; k < 5; k++) { 
      // draw some letter bits 
      int columnNumber = k + 1; 
      if(character[j][k] == 1) { 
        digitalWrite(col(columnNumber), HIGH); 
      }
      for (byte i=0; i<3; i++) {
        vinTotal += abs(analogRead(A0) - 512);
        vinCount++;
      }
      digitalWrite(col(columnNumber), LOW); 
    } 

    digitalWrite(row(rowNumber), HIGH); 
  } 
}

Now I will explain what I have changed. Its important to me that you understand, and know that its not all black magic, even if you can't remember exactly how it was done later!

I've declared a couple more variables. These will keep the total of all analog readings taken from the mic module, and the count of the number of readings taken:

long vinTotal = 0;
int vinCount = 0;

When over a thousand readings have been taken, a new average is calculated, and the variables are zeroed for the next thousand readings:

  if (vinCount >= 1000) {
    audioVin = vinTotal / vinCount;
    Serial.println(audioVin, DEC); 
    vinTotal = vinCount = 0;
  }

The readings are taken while the matrix is being refreshed. Each time an individual LED is lit (or not, depending on the pattern being displayed), 3 readings are taken before the LED is switched off again. Why 3? I tried 5, then 4, but my single LED (representing one of your 25 LEDs) flickered too much. At 3, the flicker just about disappears.

      for (byte i=0; i<3; i++) {
        vinTotal += abs(analogRead(A0) - 512);
        vinCount++;
      }

Hey Paul

That makes perfect sense when you explain it like that!

The main issue that did arrive when using your code was that only a constant few leds would light up. - but they did respond to the sound (tap and a couple less would light up.) I checked my matrix with another code to test its the LEDS were fine - which they were. I then realised the issue and changed it accordingly as shown - just needed to change the 'return' pin to the ones states at the beginning. (My bad I should have changed it before I gave you the code)

int row(int i) { 
  if(i == 1) 
  { 
    return 12; 
  } 
  else if (i == 2) 
  { 
    return 11; 
  } 
  else if (i == 3) 
  { 
    return 10; 
  } 
  else if (i == 4)
  { 
    return 9;
  } 
  else if (i == 5) 
  { 
    return 8; 
  } 
} 

int col(int i) { 
  if(i == 1) 
  { 
    return 7; 
  } 
  else if (i == 2)
  { 
    return 6; 
  } 
  else if (i == 3) 
  { 
    return 5; 
  } 
  else if (i == 4)
  { 
    return 4; 
  } 
  else if (i == 5) 
  {
    return 3; 
  } 
}

However now once I made that change al that would happen is all the LEDs are on, constantly with no response to sound at all. The serial monitor is producing single digits now as shown in image_1.

Not quite sure whats going wrong...!

Cheers for your help!

Image_1.png

This code:-

int col(int i) { 
  if(i == 1) 
  { 
    return 7; 
  } 
  else if (i == 2)
  { 
    return 6; 
  } 
  else if (i == 3) 
  { 
    return 5; 
  } 
  else if (i == 4)
  { 
    return 4; 
  } 
  else if (i == 5) 
  {
    return 3; 
  } 
}

is the same as

int col(int i) {
return 8-i;
}

See if you can work out what the first function reduces to.

ABCreates:
The serial monitor is producing single digits now as shown in image_1.

That's not right, we should still be seeing numbers in the range seen in this post. We are doing the same calculations, in theory.

Re-load the sketch from that post - if you don't see similar figures, better check your wiring! If you do see those same figures, post your latest sketch in full.

Hey Paul,

I ran the first code from 5x5 Led Matrix - Microphone Input PROBLEMS - #7 by PaulRB - LEDs and Multiplexing - Arduino Forum and received image A - Exactly the same as before.

Ran the last code you posted, all with the same results, all the LEDs on and single digit numbers printed. However when i gave the mic a tap the readings began to hit the 50+ as with the previous code as shown in image B... but went back to single digits...

So far the code i'm using right now is as follows...

const int rownum[5] = {
  12,11,10,9,8}; 
// here you are naming the rows const 

int colnum[5] = { 
  7,6,5,4,3};
//here you are naming the columns 

int audioIn = A0; 
int Vin = 0; 

int audioVin = 0; 

long vinTotal = 0;
int vinCount = 0;

//now you are saying which LEDs to light at what amplitude 

int blank[5][5] = { 
  {    0,0,0,0,0  }, 
  {    0,0,0,0,0  }, 
  {    0,0,0,0,0  }, 
  {    0,0,0,0,0  }, 
  {    0,0,0,0,0  }
}; 

int minimum[5][5] = { 
  {    0,0,0,0,0  }, 
  {    0,0,0,0,0  }, 
  {    0,0,1,0,0  }, 
  {    0,0,0,0,0  }, 
  {    0,0,0,0,0  }
}; 

int drum[5][5] = { 

  {    0,0,0,0,0  }, 
  {    0,1,1,1,0  }, 
  {    0,1,0,1,0  }, 
  {    0,1,1,1,0  }, 
  {    0,0,0,0,0  }
};   


int mediocre[5][5] = { 

  {    1,1,1,1,1  }, 
  {    1,0,0,0,1  }, 
  {    1,0,0,0,1  }, 
  {    1,0,0,0,1  }, 
  {    1,1,1,1,1  }
};   



void setup() { 
  analogReference(EXTERNAL);
  Serial.begin(19200);
  // initialize the I/O pins as outputs: 

  // iterate over the pins: 
  for (int thisPin = 0; thisPin < 5; thisPin++) { 
    // initialize the output pins: 
    pinMode(colnum[thisPin], OUTPUT);
    pinMode(rownum[thisPin], OUTPUT); 
    // take the col pins (i.e. the cathodes) high to ensure that 
    // the LEDS are off: 
    digitalWrite(colnum[thisPin], HIGH); 
    digitalWrite(rownum[thisPin], LOW); 
  } 
} 

void loop() { 
  
  // This could be rewritten to not use a delay, which would make it appear brighter 
  
  if (vinCount >= 1000) {
    audioVin = vinTotal / vinCount;
    Serial.println(audioVin, DEC); 
    vinTotal = vinCount = 0;
  }

  //now you are specifying the ranges for the mp3 jack audio input voltage (audioVin) 
  if (audioVin < 60) { 
    drawScreen(blank); 
  } 
  else if(audioVin < 70) { 
    drawScreen(minimum); 
  } 
  else if (audioVin < 80) { 
    drawScreen(drum); 
  } 
  else { 
    drawScreen(mediocre); 
  } 
} 

int row(int i) { 
  if(i == 1) 
  { 
    return 12; 
  } 
  else if (i == 2) 
  { 
    return 11; 
  } 
  else if (i == 3) 
  { 
    return 10; 
  } 
  else if (i == 4)
  { 
    return 9;
  } 
  else if (i == 5) 
  { 
    return 8; 
  } 
} 

int col(int i) { 
  if(i == 1) 
  { 
    return 7; 
  } 
  else if (i == 2)
  { 
    return 6; 
  } 
  else if (i == 3) 
  { 
    return 5; 
  } 
  else if (i == 4)
  { 
    return 4; 
  } 
  else if (i == 5) 
  {
    return 3; 
  } 
} 

void drawScreen(int character[5][5]) { 
  for(int j = 0; j < 5; j++) { 
    // Turn the row on 
    int rowNumber = j + 1; 
    digitalWrite(row(rowNumber), LOW); 
    for (int k = 0; k < 5; k++) { 
      // draw some letter bits 
      int columnNumber = k + 1; 
      if(character[j][k] == 1) { 
        digitalWrite(col(columnNumber), HIGH); 
      }
      for (byte i=0; i<3; i++) {
        vinTotal += abs(analogRead(A0) - 512);
        vinCount++;
      }
      digitalWrite(col(columnNumber), LOW); 
    } 

    digitalWrite(row(rowNumber), HIGH); 
  } 
}

Im not to sure what the problem is, hopefully to humour you I have a few ideas/questions

in this extract of the code as follows:

//now you are specifying the ranges for the mp3 jack audio input voltage (audioVin) 
  if (audioVin < 60) { 
    drawScreen(blank); 
  } 
  else if(audioVin < 70) { 
    drawScreen(minimum); 
  } 
  else if (audioVin < 80) { 
    drawScreen(drum); 
  } 
  else { 
    drawScreen(mediocre); 
  } 
}

say audioVin= 5 which s <60, 70 and 80 how does the code know to associate the auidoVin under the <60 pattern and not the <70 pattern, as it suffices both?

secondly, more of a request.

what exactly is going on in this part of the following code extract?

void drawScreen(int character[5][5]) { 
  for(int j = 0; j < 5; j++) { 
    // Turn the row on 
    int rowNumber = j + 1; 
    digitalWrite(row(rowNumber), LOW); 
    for (int k = 0; k < 5; k++) { 
      // draw some letter bits 
      int columnNumber = k + 1; 
      if(character[j][k] == 1) { 
        digitalWrite(col(columnNumber), HIGH); 
      }
      for (byte i=0; i<3; i++) {
        vinTotal += abs(analogRead(A0) - 512);
        vinCount++;
      }
      digitalWrite(col(columnNumber), LOW); 
    } 

    digitalWrite(row(rowNumber), HIGH); 
  } 
}

Cheers!

A.png

B.png