In this tutorial we look at a digital voltmeter project and how it used the Arduino analog input. This involves understanding ADC or analog to digital converters and how they work. We also troubleshoot why the output reading on the LCD display is noisy.We also gave a quick peek at the Arduino DUE: http://arduino.cc/en/Main/arduinoBoardDue

The Arduino Due is a microcontroller board based on the Atmel SAM3X8E ARM Cortex-M3 CPU (datasheet). It is the first Arduino board based on a 32-bit ARM core microcontroller. It has 54 digital input/output pins (of which 12 can be used as PWM outputs), 12 analog inputs, 4 UARTs (hardware serial ports), a 84 MHz clock, an USB OTG capable connection, 2 DAC (digital to analog), 2 TWI, a power jack, an SPI header, a JTAG header, a reset button and an erase button.

Buy the Arduino DUE here:http://astore.amazon.com/m0711-20/detail/B00A6C3JN2

I just wanted to share my last experience with arduino analog inputs. I have also had this issue with the noise when Arduino is powered by USB, but I found another solution that allows you to user an external voltage reference using AREF pin, it is actually very handy sometimes. You can read more about it here: http://arduino.cc/en/Reference/AnalogReference?from=Reference.AREF

Also do you have a GitHub account? Or maybe you consider creating one? It might get you some improvements to your code by the members of this community.

You can try a shunt voltage reference to drive AREF. This should give a pretty stable reference even with noise on the powersupply. Just hook it up to the 5v rail with a series current limiting resistor the same way you would hook up an LED (check the datasheet, 1-2mA is the norm), then connect the anode to AREF. The ATMega processor will get upset if you use a reference higher than VCC and you will need a supply higher than 5v to power a 5v reference, so it's probably best to stick with a 4.096V/4.1V reference rather than 5V.Just make sure you set the reference to external in your code (link in above post)

Another thing you can do is dither the ADC. You can do this on Arduino by setting the ADC prescaler to increase the ADC clock. This will make the ADC noisy, but if you take a large number of samples and average them the noise will average out and you can achieve resolution beyond the quantisation levels. On an Arduino Mega powered by USB and using the internal reference i could achieve around 12bit accuracy from the Arduino's 10bit ADC.

float analogReadDither(int pin){ float result; //to store the final value int num = 500; //the number of readings to take float fnum = float(num); //cast number of readings to floating point

//get [num] readings and obtain the mean value for(int i=0; i<num; i++) { result += float(analogRead(pin))/fnum; } return result;}Then use analogReadDither(pin) instead of analogRead(pin). Just make sure your code won't cast the returned floating point number back to integer. You can reduce the number of acquisitions from 500 to make it run faster, or increase it for better accuracy.

The above won't work for the ARM based Arduino Due. Only for ATMega based boards (Uno, Duemilanove, Mega, Nano, etc).

ADC inputs are anything but resistive, they are in most cases a switched capacitor sample and hold. Especially on a MCU with multiple inputs and a single ADC with a mux for them. This leads to the inputs being a high impedance most of the time but drawing a small pulse of current to charge ( or source a small current if the input is dropping) an internal sample and hold cap in the ADC. This can lead to both scale errors and to noise on the converted value, as well as the values becoming dependant on the other ADC inputs if you are using multiple inputs. There are 2 methods to mitigate this, you can use a unity gain opamp buffer on the pin to give a low impedance drive or you can use a RC filter to the pin. This was always used on the 7106/7 with a 1M and 47n to 100n film capacitor across the input, the 1M resistor gave less then 1 LSB of error on the device due to the 100M plus input impedance ( aside from those current spikes as the internal switches operated of course, which is why the capacitor was there to provide a current buffer that swamped the charge).

To not use the RC you must have a higher current through any voltage divider, generally 1mA or thereabouts at full scale will work as a ballpark figure. Will be increased dissipation in the resistors and cause some thermal drift, but will give a slightly lower input noise than high value resistors.

As seen the reference needs to be stable, using a 4.096V LDO reference and driving the internal reference input with this gives about the best full scale range, but you need to have the LDO well decoupled and the output needs a filter as well to reduce the noise that the MCU will place on it. There have been many applications that run the whole MCU on a precision 5V reference ( providing the current drawn is low and essentially constant, and you use bus buffers on the input and output digital pins supplied from a separate logic 5V supply) to get a stable internal operating environment.

Another noise reduction technique is to initiate the ADC conversion and then stop the MCU and wake it when the conversion is complete. This reduces internal noise from changing data buses and voltage noise across the power and ground bonds and the substrate from influencing the result. With this the only thing running is a clock oscillator driving the ADC.

Another method after all the above is to use oversampling to average out the noise, and this does work well, though you do have the drawback of long sampling times and long update rates.

oversampling works pretty good! I am able to get a stable reading down to .001 and I am impressed by this capabilty!

However the internal reference on the arduino drifts by millivolts so it is kind of useless. An external reference is a must if you need better accuracy.

Here is a link to the best oversampling code that I have found thus far. It includes a library. I am using it for measuring temperature accurately down to 0.1c resolution. My arduino clone can't run it higher than 17 bit. It runs best for me at 16 bit with 5 samples. It runs a little slow and works hard to calculate everything but it is perfect for my little hotbox project.

oversampling works pretty good! I am able to get a stable reading down to .001 and I am impressed by this capabilty!

However the internal reference on the arduino drifts by millivolts so it is kind of useless. An external reference is a must if you need better accuracy.

Here is a link to the best oversampling code that I have found thus far. It includes a library. I am using it for measuring temperature accurately down to 0.1c resolution. My arduino clone can't run it higher than 17 bit. It runs best for me at 16 bit with 5 samples. It runs a little slow and works hard to calculate everything but it is perfect for my little hotbox project.