Odd behavior on ADC, please help!

I'm getting somewhat strange behavior from the ADC on my arduino, I will try my best to explain. I made a microphone amplifier circuit that gives a peak-to-peak of 0 to 5 V with a DC offset of 2.5 V. This signal is fed into the Arduino ADC. I'm building a VU meter, so based on the ADC reading, some number of lights is turned on.

The circuit in the following condition with the LED ground connections open, as seen here, works fine. The Arduino reads in values like its supposed to picking up any sound into the mic. I verified this by doing a serial print of the values to my computer and also probing the output of the the opamp into an oscilloscope.


Simplified circuit.

The problem arises when I close the LED ground connections as seen in the following picture. Oddly enough, the ADC seems to be giving a square pulse at the instant it samples the signal. I verified this by probing the output of the opamp into an oscilloscope: the graph below the circuit shows what I saw on the oscilloscope. The ADC is reading a value of 1016 (almost 5 V) which turns on all the lights perpetually.


Simplified circuit.

To further complicate things, when I reduce the voltage supply to the entire circuit (including the microcontroller) down to about 3 V, the odd behavior described above does not happen and the VU meter functions perfectly! But at this voltage the lights are too dim and barely visible :frowning:

I have been stuck at this for a long time and have no idea why this is happening.
Any insight or help is appreciated!

P.S. Here is the schematic of the amp circuit: https://lh4.googleusercontent.com/-NoR336KuNxI/T4fCuknClLI/AAAAAAAAAZE/QNEQJGeatxM/s640/vu.png

When you connect the LED ground and see the ADC sampling problem, what sketch is running on the Arduino? It could be that turning on the LED is affecting the power supply and hence disturbing the ADC. Try connecting your scope to Vcc. Also check Aref (the ADC's full-scale reference voltage) and AVcc (connected to Vcc on Unos, but may be different on other boards).

Another possibility is a software bug: is there any chance that you write to the ADC pin by accident? Try replacing the preamp with a simple voltage divider (providing 2.5V). Then modify your code to generate a stream of LED pulses and look for glitches on the ADC input.

BTW, when using a transistor as a switch the "common-emitter" arrangement often works better. The "on" voltage across the load is higher and depends less on the load resistance. Eg.

The is a pro mini (5V, 16Mhz). It's running the following sketch:

void setup() 
{
  Serial.begin(9600); 

  pinMode(A1, INPUT);
  
  pinMode(2, OUTPUT); pinMode(3, OUTPUT); pinMode(4, OUTPUT); pinMode(5, OUTPUT); 
  pinMode(6, OUTPUT); pinMode(7, OUTPUT); pinMode(8, OUTPUT); pinMode(9, OUTPUT); 
  pinMode(10, OUTPUT); pinMode(11, OUTPUT); pinMode(12, OUTPUT); pinMode(13, OUTPUT); 
  
}

void loop() 
{  
  int sensorValue = analogRead(A1);   
  
  if(sensorValue > 520)
    digitalWrite(2, 1);
  if(sensorValue > 540)
    digitalWrite(3, 1);
  if(sensorValue > 560)
    digitalWrite(4, 1);
  if(sensorValue > 580)
    digitalWrite(5, 1);
  if(sensorValue > 600)
    digitalWrite(6, 1);
  if(sensorValue > 620)
    digitalWrite(7, 1);    
  if(sensorValue > 640)
    digitalWrite(8, 1);
  if(sensorValue > 660)
    digitalWrite(9, 1);
  if(sensorValue > 680)
    digitalWrite(13, 1);
  if(sensorValue > 700)
    digitalWrite(12, 1);
  if(sensorValue > 720)
    digitalWrite(11, 1);
  if(sensorValue > 740)
    digitalWrite(10, 1);   
  delay(1);
  
  //Serial.println(sensorValue);
  allOff();

}

void allOff()
{
  digitalWrite(2,0); digitalWrite(3,0); digitalWrite(4,0); digitalWrite(5,0);
  digitalWrite(6,0); digitalWrite(7,0); digitalWrite(8,0); digitalWrite(9,0);
  digitalWrite(10,0); digitalWrite(11,0); digitalWrite(12,0); digitalWrite(13,0);
  
  //delay(10);
}

Unfortunately, I have all the negative leads of the LED's connected together with the intention of grounding them which is why I cannot put them individually at the collector. Can I do the following to the same effect as the common-emitter arrangement?

Also, I'm running everything through USB so I can only supply up to 5V to anything. If I have 5V going to the collector and base, it shouldn't be a problem, right?

Thank you for you help!

That arrangement with the moved resistor is better. Another way of driving common-cathode LEDs is with PNP transitors (emitter to Vcc, collector to load, pull base low to switch transistor on).

The code looks ok, although you're drawing ~200mA from the USB port. If your computer is a laptop it might not like that. In any case check Vcc for glitches.

Is the preamp signal always disturbed when the LEDs are connected, or only when the signal amplitude is large?

I suspect that noise caused by the LED current switching on and off is getting fed back into the amplifier, either through the ground line or the Vcc line. But you haven't shown the schematic of the amplifier, so it's difficult to make recommendations for how to fix it.

Code look OK ... Hmm...Not so..so..

 pinMode(A1, INPUT); // A bug here

//should be :
Nothing - A1 is analog pin 
 ------

 int sensorValue = analogRead(A1);  // A bug here

should be :

int sensorValue;

sensorValue = analogRead(A1);  // That is better

@Techone, I'm afraid I'm going to have to disagree.

 pinMode(A1, INPUT); // A bug here

//should be :
Nothing - A1 is analog pin

Pin A1 must be set as an input in order to allow the voltage on that pin to float. Actually after reset all pins are inputs, so the statement is not required - but it doesn't cause any harm either.

 int sensorValue = analogRead(A1);  // A bug here

should be :

int sensorValue;

sensorValue = analogRead(A1);  // That is better

It's quite ok to initialise a variable at the same time as it is declared.

In any case it don't see how either of these lines could cause the symptoms reported by shubhamgandhi.

@dc42, check the link at the bottom of shubhamgandhi's first post. The schematic at least seems ok to me.

@tim7

I am just trying to help.

In his code, I see to many ----> if () statements.... I am not comfy with that... just pointing this out.

I wonder if the OP connect some voltage into the V ref pin ? Without a analogReference(); in the setup, that may cause some problems. Using A1, well I am not to comfy on that one. I simply use myvalue = analogRead(1); in my opinion. Heh, some may disagree with me, but that is my standard.

Another way of driving common-cathode LEDs is with PNP transitors (emitter to Vcc, collector to load, pull base low to switch transistor on).

That, I agree.

If I was the OP, I will test the code using a pot. I will vary the pot, the leds will light up according to the value at the input of the analog pin. If that work, the amp test will be next. If not, I will fix the code so my leds lights up. To test the amp, I will use a scope <-- if the OP has one. To test the leds, I will do a test code. In the OP case, a simple blink, one led at a time. And also a test code to see the analog pins are working.

When I build my circuit, I always test one section at a time. If any problems, it is easier to isolated the problem.

Here some test code :

Digital pins test

// check all digital pins except pin 1 and 0
// Those a reserved pins for Com link

const byte the_pins[12] = {13,12,11,10,9,8,7,6,5,4,3,2};
int number_of_output = 12;

void setup() 
{                
  for (int i=0;i<number_of_output;i++)
  {
    pinMode(the_pins[i], OUTPUT);
    digitalWrite(the_pins[i], LOW);
  }    
}

void loop() 
{
  for (int i=0;i<number_of_output;i++)
  {
    digitalWrite(the_pins[i], HIGH);
    delay(1000);
    digitalWrite(the_pins[i], LOW);
    delay(500);
  }  
}

Here the analog pins test code :

const byte anapin[6] = {0,1,2,3,4,5};

int my_value[6];

void setup()
{
  analogReference(INTERNAL); // If a voltage at Vref pin, use EXTERNAL
  Serial.begin(9600);
}

void loop()
{
  for (int i=0;i<6;i++)
  {
    my_value[i] = analogRead(anapin[i]);
      
    Serial.print("Analog pin ");
    Serial.print(i, DEC);
    Serial.print(" value : ");
    Serial.println(my_value[i], DEC);
    delay(1000);
  }  
}

If you're interested, look at the diagram in the "Alternate port functions" section of the ATmega328 datasheet (section 14.3 in my copy). The digital and analogue circuitry is simply connected together at the pin, so the A0, A1 etc pins are permanently digital I/Os at the same time as being analogue inputs.

There's nothing to stop you making the pin a digital-output, and then doing an analogue read (although the result won't be very interesting). Try it. In order to allow the ADC input to float the digital circuitry must be set as an input so that it doesn't "pull" on the pin voltage. Setting pins A0-A5 as digital inputs doesn't stop them being analogue inputs, because they are always analogue inputs.

shubhamgandhi:
P.S. Here is the schematic of the amp circuit: https://lh4.googleusercontent.com/-NoR336KuNxI/T4fCuknClLI/AAAAAAAAAZE/QNEQJGeatxM/s640/vu.png

There are several issues with that circuit - the basic problem is you have severe sensitivity to the supply voltage at the input to your audio amp circuit. Switching on the LED(s) (or perhaps some other fluctuation) causes the supply to change a few mV and this gets amplified by the opamps. Hence the behaviour fixing itself when the current through the LEDs is reduced substantially.

The first op-amp stage is fed from a voltage divider connected to the supply - so you are directly feeding in the supply noise at source - there is no decoupling to ground where it is needed. Secondly your voltage divider is a lot lower in impedance than your microphone source (so it's attenuating the input you want by 13dB or so). Thirdly all your R C values are heavily attenuating the higher audio frequencies, you are only sampling the bass.

The simplest fix is to replace R5 by 470k, replace R8 by two 220k resistors in series and place a decoupling capacitor at the midpoint of the 220k resistors to ground - 100uF would be a good starting value.

The other audio caps might have to be increased - C3 is important in reducing power supply noise pick-up, the others set the high-frequency roll-off.

That latter circuit may not work at lower voltages because you know have to add the voltage drop of the b-e junction(.7) to your led(~2.1-3.8v?), so the normal way as someone exampled give you. 7v more ability to lower the voltage
also 16Mhz is to fast too run reliably at 3v, maybe 8Mhz is a better way to go if you are going to be a lower power situation
it all wont matter if your not intending to lower the voltage in the project
and try a decent 5v supply instead of usb, I've had similiar problems with voltage drop from loads cauding problem

I'm starting to consider the possibility of a bug within the arduino hardware or IDE (compiler).
I ran tests similar to suggested ones on this thread, and it turns out I can turn on all 12 lights without affecting the ADC if I don't use if statements using the following code:

void loop() 
{  
  int sensorValue = analogRead(A1);  
    
  digitalWrite(2, HIGH); digitalWrite(3, HIGH); digitalWrite(4, HIGH);
  digitalWrite(5, HIGH); digitalWrite(6, HIGH); digitalWrite(7, HIGH);
  digitalWrite(8, HIGH); digitalWrite(9, HIGH); digitalWrite(10, HIGH);  
  digitalWrite(11, HIGH); digitalWrite(12, HIGH); digitalWrite(13, HIGH);  
  delay(1);
}

When I'm sampling the audio signal but ignoring it, I can do whatever I want with the lights and the ADC does not exhibit the odd going-high behavior described in the original post. Can it have something to do with the if statements?

Thank you all for your interest and suggestions.

Looking at the two lots of code its clear to me that the call to allOff() in the original code was most likely the culprit for causing the ADC "odd high-going behaviour" since that creates a +ve going edge on the supply. This new code doesn't have a call to allOff() and doesn't create high-going ADC pulses.

@MarkT
I'm not sure I understand why this is happening. Would you mind elaborating on what you mean by "creates a +ve going edge on the supply"?
As I understand, all the allOff() function does is turn off the transistors so why would it affect the supply?

Thanks

Because the regulator has a non-zero dynamic impedance - the more current you take from it the lower the voltage. The resistance of the supply wiring also causes IR drops. Its not a big effect, millivolts, but you are feeding it into the input of an amplifier with a 100x gain.