Question about imprecision of Analog Input

Hi!

I tried to search a little on the forum but didn't really find a question to my answer.
The following situation: I own an Arduino Duemilanove since yesterday, I "come" from building analog electronic devices and want to get into digital stuff now.

I tried the very easy "Control the speed of a LED through a resistor" example and I'm really curious about the accurateness of the analog input. When I leave the pot to a steady setting and print the incoming values a get (for example) values between 330 to 350. Where does that come from?
In addition I have the feeling it keeps decreasing over time... Like some minutes ago (and I didn't touch anything) I think it was about up to 370.

I know analog circuitry well and I know it's not the most precise stuff on earth but these conversion mistakes (is is that?) seem really HUGE to me.

Please tell me what I'm getting wrong or which information I did miss. Thank you so much, every thought is appreciated.

PS: I use the following code:

 int sensorPin = 3;
 int ledPin = 13;
 int sensorValue = 0;

 void setup() {
   pinMode(ledPin, OUTPUT);
 Serial.begin(9600);  
 }

 void loop() {
   sensorValue = analogRead(sensorPin);    
   digitalWrite(ledPin, HIGH);  
   delay(sensorValue);          
   digitalWrite(ledPin, LOW);   
   delay(sensorValue);
  Serial.println(sensorValue);   
 }

"Control the speed of a LED through a resistor

LEDs have speeds? ;D

Well, like you said, it's not the most precise stuff in the world, but I think those fluctuations are a bit much for the ATmega chip.

I have a hunch that's it's your potentiometer. Try doing the same thing but with a "traditional" voltage divider (with regular resistors).

If you still get that much variation, then I would be very surprised.

As an afterthought, you should probably have a "delay(50)" in there to avoid flooding the Serial buffer.

This could also be a power elated issue. If you don't have a good steady power source then the reading will change. This is especially true on a battery. over time the battery becomes weaker and the value will drop. USB power will also fluctuate a bit. As your PC performed different functions it draws more or less power from the PSU. The PSU is constantly fluctuating to help maintain a steady power source regardless of the load, but within its specs. Even power from a wall-wart will change a bit as the plug gets warmer.

Then if you factor in any margin of error with the ATmega chip, timing crystal, and power converter built into the board and the total margin of error grows pretty fast.

This could also be a power elated issue. If you don't have a good steady power source then the reading will change. This is especially true on a battery. over time the battery becomes weaker and the value will drop. USB power will also fluctuate a bit. As your PC performed different functions it draws more or less power from the PSU. The PSU is constantly fluctuating to help maintain a steady power source regardless of the load, but within its specs. Even power from a wall-wart will change a bit as the plug gets warmer.

Then if you factor in any margin of error with the ATmega chip, timing crystal, and power converter built into the board and the total margin of error grows pretty fast.

That's another good point I hadn't considered. Unless the Analog reference voltage is dead on 5V, your readings will change some.

Ok, thanks for your answers. The argument about the fluctuating power supply (even though I would have considered the USB through Arduino board voltage quite steady) seems pretty reasonable to me.

So actually it's not the imprecision of the Atmega, it's the PRECISION, isn't it?

With different pots I get readings of interestingnumber (= difference between greatest and smallest number) from 9 - 12 and with resistors 11 with the following code (about which you please could tell me if it's clever or not :)):

int sensorPin = 3;
int ledPin = 13;
int sensorValue = 0;
int sensorValueGreat = 0;
int sensorValueLow = 1023;
int interestingnumber = 0;

void setup() {
  pinMode(ledPin, OUTPUT);
  Serial.begin(9600);  
}

void loop() {
  sensorValue = analogRead(sensorPin);    
  digitalWrite(ledPin, HIGH);  
  delay(sensorValue);               
  digitalWrite(ledPin, LOW);
  delay(sensorValue);
  if (sensorValue > sensorValueGreat) sensorValueGreat = sensorValue;
  if (sensorValue < sensorValueLow) sensorValueLow = sensorValue;
  interestingnumber = sensorValueGreat - sensorValueLow;
  Serial.println(interestingnumber);
  delay(50);
}

Hui, now if I wait long enough even with resistors I have a difference of 14...

Hui, now if I wait long enough even with resistors I have a difference of 14...

I think that'll fall back to the fact that you can never get perfect voltage reference, etc. Are these 1% resistors?

I think that'll fall back to the fact that you can never get perfect voltage reference, etc. Are these 1% resistors?

Yup they are. As I let the program running I know have 21...
Maybe if I'm funny tomorrow I'll try with a battery...

//edit
Even though, now I realize that it shouldn't matter in this case what kind of tolerance the resistors have...

No where does any one mention the value of the pot. The A/D input is designed to work best with a 10K or lower input impedance therefore a 10K pot should be used. If you are using a bigger pot then you might be getting noise pickup.
The 10 bit A/D is not the best in the world and I would expect noise of around +/- 4 readings at best. Remember even the best A/D in the world can only be +/- the lease significant bit.

You could input the Aref to another analogin, and compensate for the changes.

A breadboard test with loose wires flying evevrywhere is probably not the best recipe for accurate ADC readings. My experience is that you will get approximately 8 bits of reliable/repeatable precision from the builtin ADC with a proper setup.

It is always preferred to use the same reference as your sensor so that readings are derived from the same reference and subject to the same fluctuations over time/temperature and what not (this is the case for your examples, but not equally obvious for external sensors that use internal on-chip references.)

The first ADC reading after change of reference is ureliable. So discard the first reading (e.g. do a dummy reading in setup) and also if and whenever reference (AREF) is changed.

Mutliple samples and averaging can improve precision. 4 averaged readings will roughly give you an extra bit, 16 readings two bits (now you're back up to 10 bits), 64 readings 3 bits and so forth. The Arduino setup configures ADC for roughly 8k samples per second by default so for many applications oversampling/averaging is an acceptable tradeoff.

From the 328p datasheet, ADC accuracy: "± 2 LSB Absolute Accuracy"

That should tell you something in the way of expectation. The data sheet explains a lot of things that can help accuracy like board layout, reference choices, etc. The AVR on chip ADC function is very useful, but it is not instrumentation grade measurements. Learning to work within its limitiations or research external ADC devices.

Lefty

Another thing you could try is connecting a bandgap refence to the pin and see what the range of values is - maybe supply it from a battery.

As you have an analogue background, you'll understand the importance of good earth routes and separating the "power" grounds from the lower signal grounds.

I looked into this a while back and, from memory, the Atmel chip has separate analog and digital supply and ground, but the Arduino guys tied these together on the board. This won't help keep the converter noise down.

If you have an Arduino with a DIL processor, you could pull the analogue section legs out and see if you can make improvements like that.

Other than that you're down to implementing some filters in firmware.

Regards,

Mike

Arduino schematic:

By far the best thing I have done to get better ADC with the Arduino is to take an average of readings. My usual is total 20 reads, then divide by 20 to get an average.

Also the datasheet mentions taking power to the AVcc (pin 20) via a 10uH inductor wtih bypass cap connected right at the pin.

Ken