ADC Nonlinear Output

Hello Everyone,

I am having a problem with a nonlinear output on my Arduino Mega2560. See the attached picture for a graph of the output vs. input. At around 3.3V, the output of the ADC plateaus to about 687. Here are a few things that I have checked:

  • The AREF is set to 5V using the:
    analogReference(DEFAULT)
    command, and probing the AREF pin confirms this (it's at 5V).
  • I've tried using different analog inputs with varying results - one of them plateaus at a higher voltage.
  • I've tried using a new Arduino Mega board.

Has anyone else had similar issues with the ADC? If you have a suggestion for me, that would be great.

Thanks!

defrost

Strange...

What does it do when you uncomment the line

// analogReference(DEFAULT);

Do you have a multimeter?
Does it read the same?

Without knowing the circuit you're using to drive the pin nor the way you are measuring the voltage it's impossible to say anything useful. Do you use 3.3V for any part of the circuit, it looks suspiciously like something is limiting the voltage to the pins. Full code is useful too.

Hi Guys,

Thanks for your responses. Here's some more info:

robtillart: uncommenting that line yields the same results. The voltage on the AREF pin also remains the same.

MarkT: The input to the analog reference comes from an op amp, in voltage follower mode. (I'm just using it as a buffer). I've checked the voltage into the analog input while varying in the input voltage, and everything is linear there. The original graph I posted actually has the voltage into the analog input in the x-axis. All of my logic is 5V, however I would have to agree with you that something is suspicious with the 3.3V - nothing is ringing a bell for me.

Below is the code. I'm going to break it into two sections to make it easier to understand. This first part contains all of the configuration of the Arduino. Note there are a few lines "pinMode(AXX, INPUT);" which are commented out. I've tried with and without them with no success.

void setup(){
  
  // === PIN CONFIGURATION ===
  
  // PWM setup (leaving CS bits at zero means timer is off)
  pinMode(13, OUTPUT);
  pinMode(13, OUTPUT);
  TCCR0A = (1 << COM0A1) | (1 << WGM01) | (1 << WGM00);
  TCCR0B = (1 << CS00);
  OCR0A = 50;
  digitalWrite(13,LOW);
  
  pinMode(12, OUTPUT);
  pinMode(12, OUTPUT);
  TCCR1A = (1 << COM1B1) | (1 << WGM10);
  TCCR1B = (1 << WGM12) | (1 << CS10);
  OCR1B = 50;
  digitalWrite(12,LOW);
  
  // Shutdown signal for charging chip (low = off)
  pinMode(42, OUTPUT);
  
  // Charging indicator
  pinMode(46, INPUT);
  
  // LEDs
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  pinMode(led3, OUTPUT);
  
  // Fault indicator
  pinMode(54, INPUT);
  
  // Current sensors
  //pinMode(A15, INPUT);
  //pinMode(A14, INPUT);
  //pinMode(A12, INPUT);
  
  // Auxiliary analog sensors
  //pinMode(A11, INPUT);
  //pinMode(A13, INPUT);
  
  // Voltage sensors
  //pinMode(A10, INPUT); // Output: 1/3 of actual
  //pinMode(A9, INPUT); // 7.2 V on battery: 1/2 of actual
  //pinMode(A8, INPUT); // 3.6 V on battery: 1/2 of actual
  
  // Initial pin settings
  //digitalWrite(42,LOW);
  digitalWrite(42,HIGH);
  
  Serial.begin(9600);
  
  analogReference(DEFAULT);
  
  // Determine current sensor zero values
  i1Offset = 0;
  i2Offset = 0;
  i3Offset = 0;
  for (int i = 0; i < 10; i++){
    i1Offset += (1/0.185)*5.0*(float)analogRead(A12)/1023.0;
    i2Offset += (1/0.185)*5.0*(float)analogRead(A15)/1023.0;
    i3Offset += (1/0.185)*5.0*(float)analogRead(A14)/1023.0;
  }
  i1Offset = i1Offset/10;
  i2Offset = i2Offset/10;
  i3Offset = i3Offset/10;
}

This next part actually reads the sensors. I removed the code which outputs the data to the serial terminal.

void loop(){
  
  // === CHECK FOR A FAULT ===
  
  /*if (!faultOccurred && digitalRead(54) == LOW){
    digitalWrite(42,LOW); // Turn off charging chip
    faultOccurred = true;
  }*/
  
  // === READ CELL VOLTAGES ===
  
  float vCellBoth = 2.0843*5.0*(float)analogRead(A9)/1023.0 + offsetVCellBoth; // 7.2 V sensor (both cells of the battery)
  float vCellMid = 2.0843*5.0*(float)analogRead(A8)/1023.0 + offsetVCellMid; // 3.6 V sensor (between the cells)
  float vOutput = 3.0*5.0*(float)analogRead(A10)/1023.0; // Output voltage sensor
}

I'm going to try the Arduino itself WITHOUT the op-amp circuit this weekend. I'll let you know how I get on. Perhaps my op-amp circuit is doing something strange - although I have no idea what....

Thanks,

defrost

When delaing with A/D measurements a DVM is a good way to test code, from Experience.

Doc.

Sounds like we need to know a lot more about the circuit - several opamps, not clear what values are getting to AREF, we don't really know what you were plotting against what and you haven't posted the code that prints out the analogRead() values - you have several unexplained constants in the code that might mean you are not printing out the straight output from analogRead() ??

In general it pays to post the whole code and the circuit, rather than describe them in words, saves a lot of guesswork and questioning. The problem may not be where you think it is, thats often the nature of problems...

Hi Everyone,

I apologize for not posting sooner. Last week I discovered the mistake lies on my end - I was getting a nonlinear output from the Arduino when I had my op-amp plugged into it because the op-amp was not powered :~. I was tricked into thinking it was working since it would provide a nice linear output for the low end of the scale. The op amp is part of a larger power management board that I am working on, and I just forgot that I did not populate the jumper which would connect the 5V Arduino supply to the 5V rail of my power management board.

Thanks for replying to my post! It helps a lot just to say some things out loud to figure out a problem.

defrost

I used to use my wife for that before she passed on... frequently if you can hear your words you can find the error. BTW Cancer got her. not terminal boredom from my infrequent... Monologs.

Doc