High input impedance with analog read

I'm using a resistor divider to get a rough voltage reading on a higher voltage circuit. Works great with my multimeter, never goes above 5V. But I am using a few megaohms of resistor there to keep the current loss on the circuit low.

If I understand correctly, this means that it will take a long time for the sampling capacitor to charge up and my analogRead might not return the right value.

Is this something that would stabilize with time, like over many successive reads? Is there any good solution to this problem? Can I run the conversion slower? Is it as simple as just waiting a little longer between reads?

Use high impedance MOS Op-Amp or JFET Op-Amp to isolate input.

High Impedance DC Voltmeter using MOS Op-Amp

One solution is to buffer the signal with an opamp and feed that to the analog pin. Or wait a long time between samples. I don't know how long.

Yes use an opamp in non inverting mode with a gain of 1 (connect the output to the inverting input directly). another "trick" you can employ is to put a decent value capacitor on the input that will charge up and hold a charge and effectively reduce the input impedance for the read. This comes with a couple of caveats, you need to allow time between reads to let the capacitor recuperate and your reserve capacitor voltage will slowly follow the voltage applied to the divider so no good following a changing voltage, if you just want to check that say the power is on then this will work fine (with a delay)

Delta_G: If I understand correctly, this means that it will take a long time for the sampling capacitor to charge up and my analogRead might not return the right value.

A "long time" is very relative. If the input signal isn't high frequency then there's usually no problem.

Delta_G: Is this something that would stabilize with time, like over many successive reads? Is there any good solution to this problem? Can I run the conversion slower? Is it as simple as just waiting a little longer between reads?

If the signal is noisy you can average the result over time. You could also add a small ceramic capacitor between GND and the analog input to filter out the noise.

sonnyyu: Use high impedance MOS Op-Amp or JFET Op-Amp to isolate input.

Completely pointless for a slowly changing signal.

(And by "slowly changing" I mean in the tens of Hz).

fungus:

sonnyyu: Use high impedance MOS Op-Amp or JFET Op-Amp to isolate input.

Completely pointless for a slowly changing signal.

(And by "slowly changing" I mean in the tens of Hz).

Thanks you for the comment, I do not see anywhere in the thread has "tens of Hz". OP want measure DC for my understanding.

sonnyyu: I do see anywhere in the thread has "tens of Hz". OP want measure DC for my understanding.

He doesn't say...but if he can measure it with a digital multimeter then it's DC (or very close to it) so at most he'll need a capacitor (maybe not even that if he averages in software).

I think we need more information on the purpose of the measurement or at the very least the measuring frequency

But I am using a few megaohms of resistor there to keep the current loss on the circuit low.

Then don't, there seems to be a bit of an obsession with saving the odd milli amp in the mistaken impression that it represents good design. It rarely does.

Is this something that would stabilize with time, like over many successive reads? Is there any good solution to this problem? Can I run the conversion slower? Is it as simple as just waiting a little longer between reads?

As you may know the arduino analogRead() function is designed and assumes the source impedance of voltage to be read is 10K ohms of lower. The fact that the AVR adc has but a single sample and hold capacitor but multiple multiplexed analog input pins means that you have to deal with the problem that trying to read a high impedance signal. As already posted you can lower the impedance by buffering the signal with a op-amp voltage follower. Or if you are only using a single analog input pin in your project you could just do multiple readings and only use the last reading. Hanging a cap on the analog input pin in question to ground can be effective in many cases. The best solution is only apparent in the context and requirements of the complete project, the purpose of the measurement, costs, power source used, and on and on. If this a personal 'hobby project' you are free to try and use simple or low cost solutions (that may not be optimum but still effective) that one may not be allowed or wish to use in a commercial professional setting.

So try stuff and see what works for you.

Lefty

retrolefty: As you may know the arduino analogRead() function is designed and assumes the source impedance of voltage to be read is 10K ohms of lower. The fact that the AVR adc has but a single sample and hold capacitor but multiple multiplexed analog input pins means that you have to deal with the problem that trying to read a high impedance signal.

Good point. If you're switching between different analog inputs with impedence higher than 10K then you have to give the capacitor time to charge. For slow moving signals this can be mitigated by adding a capacitor on the analog input pin.

Hi Delta_g,

There are two separate issues with using a high impedance source with the atmega328 ADC:

  1. Sampling capacitor charge time. The default implementation of analogRead starts the conversion in the very next instruction after setting the multiplexer to the required input. This allows only a very short time for the sample capacitor to charge. For source resistances above 10K, I usually patch the analogRead function to add a delayMicroseconds call between these instructions. The minimum delay required is about 1us per additional 10K of source resistance. As an alternative to patching the Arduino runtime, write your own code to set the multiplexer to the desired channel, then call delayMicroseconds, then call analogRead.

The common solution of calling analogRead twice and discarding the first reading is less effective, because the sampling capacitor is not connected to the input during most of the first analogRead call. Two analogRead calls with a delay between them would work, if you don't mind the 110us or so wasted by the first analogRead call.

If you are reading a DC or slowly-varying signal, then a hardware solution is to connect a 0.01uF or greater capacitor between the analog input and ground, if whatever is driving the analog input can tolerate that. The capacitor also provides immunity to noise pickup, which may otherwise be a problem when using high source resistances.

  1. Finite input resistance of the ADC. The datasheet specifies 100M typical. Therefore, with 100K source resistance, you can expect an error of about 1 part in 1000, i.e. 1 bit. With 1M source resistance, you can expect an error around 1%.

In one design that was powered from a 9V battery, to measure the battery voltage I used a voltage divider made from two 4.7M resistors, giving an effective source resistance of 2.35M. The reason for such high resistors was that the design didn't have an on/off switch, it just put everything to sleep when inactive; so I needed to minimize the current consumption of the voltage divider.

dc42: Hi Delta_g,

There are two separate issues with using a high impedance source with the atmega328 ADC:

...but they're only issues if you're trying to read more than one analog pin. If you're only using one analog input then they don't affect you.

fungus:

dc42: Hi Delta_g,

There are two separate issues with using a high impedance source with the atmega328 ADC:

...but they're only issues if you're trying to read more than one analog pin. If you're only using one analog input then they don't affect you.

If you are using only one analog input, then the first one doesn't affect you after the first few readings, but I believe that the second one does still affect you.

An simulation example based on dc42 post (in reality you switch on/off the S/H instead of the input 9V; that is a worst case scenario to see how long it takes to charge the internal S/H capacitor fully, when input changes from 0 to 9V and vice versa):

pito: An simulation example based on dc42 post (in reality you switch on/off the S/H instead of the input 9V; that is a worst case scenario to see how long it takes to charge the internal S/H capacitor fully, when input changes from 0 to 9V and vice versa):

A quarter of a millisecond? You could still sample a 2KHz signal...

More precise simulation:
So with applying 9V via such dividers it will take ~300usecs worst case in order to charge/discharge the internal S/H capacitor fully…
For example when you have got 2 analog input channels with such dividers, one with near 9V, the second with near 0V - you need to wait at least 300usecs when switching between channels to charge/discharge the S/H capacitor fully.

And with 10k input impedance:
So with applying 9V via such dividers it will take ~8usecs worst case in order to charge/discharge the internal S/H capacitor fully…
Mind the limiting resistor in the RC dis/charging is the R3 (atmega’s internal S/H resistor, according to the datasheet up to 100k).

fungus:

pito: An simulation example based on dc42 post (in reality you switch on/off the S/H instead of the input 9V; that is a worst case scenario to see how long it takes to charge the internal S/H capacitor fully, when input changes from 0 to 9V and vice versa):

A quarter of a millisecond? You could still sample a 2KHz signal...

The issue is the S/H period is fixed to 1.5 ADC clock period. So it cannot be "prolonged" from outside by a delay(). With 16MHz/128 = 125kHz ADC clock that means S/H period is 12usecs. That is "a little bit more" than worst case scenario for 10k input impedance..