I'm trying to measure a material which might fluctuate between 500-100k Ohms with an ADC (e.g. an Arduino or Raspberry Pi with something like the MCP3008). I'm a novice with electronics, and my go to strategy was simply what I knew already: voltage dividers. The problem I'm running into is the wide range. My setup is like so, where I want to know R1:

3.3V -- R1 -|- R2 -- GND

I conduct the following simple calculations to get it:

v_out = ADC * 3.3/1024
R1 = R2*(3.3-v_out)/v_out

The problem as many of you likely know, is that highly mismatched values for R1 and R2 make for poor resolution, so the output looks very "steppy." Here's a simulated plot of a range of R1 values (what we're measuring), and the value calculated using the formula above using some common resistor values for R2:

enter image description here

The 1k and 4.7k are great for the low end, but they really flatten out at the high end where a 10k would be much better.

Is there a reasonably simple and low cost circuit/method to read a dynamic resistance that might swing several orders of magnitude?

Dreams/wish list:

  • lost cost (say, $25)
  • works with hobby-level hardware (Arduino or RPi)
  • measurement error of <= 1%

Ideas considered

Given the above, the dream seemed to have a variable resistor! I learned that digital pots exist and thought I could idea to use one. With some great answers there, it turns out I can, but the accuracy is poor (~5% vs. <1% with fixed resistors) and somewhat unrepeatable.

I also thought of having several R2 resistors connected to separate pins on the ADC. As the value of R1 changes I could switch which pin I read from. With this circuit, all candidate R2's will be connected to the output of R1 and analog inputs... I don't know what that will create with respect to a circuit. Are they floating? Can I sort of disconnect the unused pins so I don't get a weird multi-voltage-divider? That might be what this question gets at, just for the purpose of stopping power drain.

Sorry if this is a dumb question. I can find plenty of confirmation that this problem is real, such as from this article on making an Arduino Ohmmeter:

The accuracy of the Ohm meter will be poor if the value of the known resistor is much smaller or larger than the resistance of the unknown resistor.

I just don't find much on what people actually do in this situation in the real world. Many thanks.

  • \$\begingroup\$ You only have a 10 bit ADC, so other than manual scaling the resolution will not be that good. I ran into the same issue with the PIC MPU's. \$\endgroup\$
    – user105652
    Jan 8 '18 at 5:04
  • \$\begingroup\$ If you have extra IO's, you can certainly switch in and out additional resistors to get a few different values of R2. There are a couple different ways to do it. \$\endgroup\$
    – mkeith
    Jan 8 '18 at 6:42
  • \$\begingroup\$ @Sparky256 for my purposes, resolution of 10 bits is fine; it's just what if I stick a 1k in for R2 to capture the low end, higher resistances look like stairs. A huge range of voltages end up captured by only a few ADC values. \$\endgroup\$
    – Hendy
    Jan 8 '18 at 13:40
  • \$\begingroup\$ @Sparky256 I retract! I hadn't thought this would matter, but it's the number of steps. I looked at Spehro's answer below and now get what you meant. \$\endgroup\$
    – Hendy
    Jan 8 '18 at 13:50
  • \$\begingroup\$ What is the material dielectric made of and what is the capacitance and does it change with resistance. This may introduce gross AC impedance measurement errors. \$\endgroup\$ Jan 8 '18 at 15:48

In an Arduino, pins are high impedance when set to 'Input', and a good low output impedance when set to 'Output', capable of sinking >20mA. This enables you to split up the range, and measure each optimally. This applies to both digital AND analog pins.

For instance, let's the split the 500ohm to 100k range, which is a resistance ratio of 200 end to end, into 3 sub-ranges, by taking the cube root of the ratio. Then we can handle it in 500-3k, 3k to 17k, 17k to 100k ranges, each with a ratio of 6 end to end. We get the best centring of the range when we measure it against the geometric mean of its end points, so use 1200ohms, 7k and 41k as the 'other leg'.

Connect up the Arduino as follows. I've rounded the resistors to preferred values, as the actual values are not important, just that they're known.

Measure the voltage on pin A0, using the ADC with VCC as the reference.


simulate this circuit – Schematic created using CircuitLab

With all pins set to Input, the effective resistor to ground is about 40k, for the range 7k to 100k.

Setting pin A2 to output low, and making sure A1 is high impedance, by

pinMode(A1, INPUT);
pinMode(A2, OUTPUT);
digitalWrite(A2, LOW);

pulls R3 down to ground. Now the resistance to ground is about 7k, for the range 3k to 17k.

Set it back to high impedance like this

pinMode(A2, INPUT);

When you set A1 low in the same way, the resistance to ground is 1200, for the lowest range. Note the maximum current that A1 has to sink is about 2mA in this case, well within the capability of those pins.

You can of course split the range into more and finer ranges, by doing the appropriate sums and using more pins and resistors.

You may be able to substitute digital pins for A1 and A2. While they too are high impedance on input, I've not yet waded through the documentation to check whether intermediate voltages are OK on a digital input. They aren't on usual CMOS logic families, the inputs can oscillate and draw excess power, but Arduino may be different. Analog inputs are (of course) happy with any intermediate voltage on the pin.

  • \$\begingroup\$ Oh wow, I hadn't realized that setting a downstream pin to ground negates the resistors sitting after it. Very cool. In my head I was assuming all reference resistors would be in parallel. I'll soak this in and try it, hopefully adjusting it for the RPi and MCP3008, as it has features that are easier for my use-case. Thanks! \$\endgroup\$
    – Hendy
    Jan 8 '18 at 13:47
  • \$\begingroup\$ Yes, a series string of resistors, and taking each junction to ground, is a very common pattern in electrical engineering. But you can do them is parallel as well if you like. You just need to make sure that the things you use for switching don't draw a high leakage current when they're supposed to be off, and ASAICS, arduino inputs don't. So which answer are you going to accept, Sphero's expensive ADC, or my dirt cheap pair of resistors? \$\endgroup\$
    – Neil_UK
    Jan 8 '18 at 14:05

One simple way is to just use a better external ADC. For example, an ADS1115 gets you 16-bit conversion with an on-chip PGA and reference, for around five dollars in singles. I2C interface.

Pretty decent for non-critical applications.

  • \$\begingroup\$ I hadn't expected that higher resolution would matter as I thought it was a limitation of the circuit (just needing to maintain certain ratios between R1 and R2). I just replaced 1024 with 65535 in the plot in my question and get this. It really raises the curves and now the 4.7k would likely cover this whole range really nicely. Great insight! \$\endgroup\$
    – Hendy
    Jan 8 '18 at 13:52

I would look into two ways of doing this:

Voltage dividers where the known resistances are multiplexed.
(This idea is already hinted at in the O.P.)

If you want to try this on the cheap, connect the resistors to digital pins on the microcontroller. When the digital pin is low, the resistor is connected to ground. When the digital pin is floating, the resistor is disconnected.

Otherwise, an analog mux like a CD4051 or ADG728 should do the job.

OpAmp current source

The current through the unknown resistance is supplied by an OpAmp current source, and this current source is adjustable.
(Look up voltage controlled current sources. My favorite is modified Howland current source, very versatile.)


One could convert R to frequency then convert f to some other parameter like force or displacement. There will likely be hysteresis or backlash effects.

I would use the resistance as a negative feedback value to shunt cap in an inverting Schmitt Trigger inverter. Then use a reference Xtal clock to measure the frequency over a time interval.


I have yet to find such a material that has 1% accuracy and doubt such a material repeatability exists with such a wide dynamic range.

Material capacitance is also of great importance when the resistance changes this much since AC impedance measurements will measure both at one frequency and one value, but introduce great errors when any variable changes.

The accuracy of the frequency measurement can be made to better than 1% but I suspect the material measurement after repeated motions to the original position will most likely change > 50% in the relaxed position which may require a minimum tension to reduce dynamic range but improve repeatability/accuracy.

Thus the question needs to be re-written to include all the properties (specs) of the material and not just a simple how to measure R?


The best test method is not to try to design an ADC on an unknown material but rather use a calibrated RLC meter with at least 3 frequency values and characterize the material properties properly for Rs, Rp, C values @f and repeatability and perhaps variance with temperature, Vdc bias etc.

You are a novice and you have much to learn.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.