Introduction: Arduino 10 Bit Analog Output

Standard pwm output from the Arduino has an 8 bit resolution. This project improves the resolution for an analog output to around 10 bits, plus has a much faster settling time and allows up to six analog outputs. The project uses only one resistor and one capacitor and one arduino pin, and uses a software trick where an analog input pin can be turned into an output, then used to charge or discharge a capacitor, and then turned back into an input to read back the value.

If you add a standard RC low pass filter to the pwmout signal on an arduino the output looks noisy on a CRO, and fluctuates considerably if another arduino samples the voltage. Fancy multipole filters use lots of components. Adding a very large RC filter (eg 100k and 100uF) means it can be ten seconds for the output to stabilise, plus you have to be careful about internal leakage within the capacitor, using tantalum capacitors instead of electrolytics.

This circuit does all the clever work in software and uses a 10k resistor and a 1uF greencap capacitor. Sample the voltage on the capacitor, rapidly charge or discharge to near the correct value, eg 50 millivolts, then apply brief charge or discharge pulses of around 1 microsecond to keep the value correct. Settling time is around 1 millisecond which is 100,000 times faster than using a large RC on pwmout. The self discharge of a greencap polyester capacitor or a tantalum means that 1 microsecond adjustments are only needed every five or ten seconds.

Stray RF can be an issue so it helps to keep the leads short. Even so, there can be some errors with the ADC on an arduino so to improve this, take twenty samples and take the average.

Perhaps this has already been done before? Anyway, it is a nifty little circuit and code that I am using in a couple of practical circuits, mainly as a simple way of sending information between Arduino's as an analog voltage.

Step 1:


acheide (author)2017-01-22

Nice technique. Do you have a schematic to attach? Thanks.

James Moxham (author)acheide2017-01-22

Good idea. I'll try doing this in text, hopefully this makes sense:

Connect pin A0 to one end of the 10K resistor. Connect the other end of the resistor to the +ve of the capacitor (either end, if non polarised). Then the other end of the capacitor to Gnd.

Omnivent (author)James Moxham2017-01-22


If you want to use the output for anything but feeding a high impedance meter, you should consider adding a rail-rail (in as well as out) op-amp to buffer the signal.

Have a nice day :)

James Moxham (author)Omnivent2017-01-23

Good point. I've used old-skool CA3140 op amps as they can swing rail to rail. And yes, you have to be very careful with loading the output - all of my multimeters load it too much. Another Arduino is ok though, but there one little catch there - with thin hookup wire powering boards, there is a little bit of voltage drop in the gnd wire as that second arduino is using ?30mA to power itself, so the readings become slightly higher than they should be. Thick ground wires will minimise this.

I need to do more experiments, but I think it might be something like a voltage follower, then a twisted pair of wires with the Vout and Gnd, then at the other end a unity gain differential amplifier.

Omnivent (author)James Moxham2017-01-30

Hi again,

CA3140 (and the dual version CA3240) is still a great op-amps within their capabilities, but unfortunately, the price has sky-rocketed, at least in DK, which is pretty odd, when you can get good (/better) replacements much cheaper.

I assume the loading that you mention, is without the buffer(?) as even the worst present day DMMs has an input impedance of 1M (10M on most).

The output impedance of the CA3140 is around 60 Ohms, very high in this day and age, but even that shouldn't matter, as the feedback includes this in the loop.

If the error is a steady measure over the entire range (like e.g. 5mV too little) the problem is likely offset, which can be trimmed out (10k trimmer from pin 1 to pin 5 with the wiper to pin 4).

If you feed both boards directly from your power source (i.e. supply terminals of each goes all the way to the supply, rather than being fed of one another) and make it with proper filtering, then one board can sag its supply without much influence on the other - just keep a good low impedance ground (with each terminated at the supply as well).

While twisting the wire can reduce radiated noise effects (if using long wires), there's no need for a differential amplifier/buffer. The effective output impedance will be very low (your 60 Ohm is before 100% negative feedback, so the real Zout will be much less than 1 Ohm [in theory under 1mOhm])

First thing is to make sure you have a proper power supply and when that's done, I think the rest will follow by itself.

Have a nice day :)

James Moxham (author)acheide2017-01-23

I've added a schematic just now. Cheers :)

About This Instructable




Bio: Dr James Moxham is a general medical practitioner in Blackwood, Australia. His interests include general family medicine, medical politics, microcontrollers and tending a rose garden ... More »
More by James Moxham:Arduino String Manipulation Using Minimal RamCharlieplex 30 Led BargraphArduino Dual 20x4 Display
Add instructable to: