Note: Before i explain my issue i would like to note that I am a beginner in electronics. Please pay attention to that when providing solutions and explanations. Thank you.

I have succeeded at making an auto ranging Ohmmeter it is still ofcours experimental there for I would like to get some opinions and perhaps solutions to some of the issues I’m facing How it works:

It is based on a simple voltage divider. After experimenting it seems that a voltage drop across the unknown resistor in a certain range (this case [3.135V, 0.99V] with a voltage source equal to 3.3V) gives the most precise results compared to other values.

This Ohmmeter has a very useful feature and that is auto ranging, it changes the range automatically when the voltage drop values are not in the previously mentioned interval ([3.135V, 0.99V]). The accompanied image shows how the device works.

If the value of Rx is too small compared to (R1+R2+R3) the Arduino switches the analog reading from A0 to A1 if the problem still accurse the Arduino will change again to A2 meaning it is now measuring not the value of Rx but (Rx+R1+R2) in series after that the Arduino is programmed to do the subtraction accordingly.

This device presents some noticeable inconvenients that need to be eliminated:

  1. It depends on experimental values, so it is not certain if it’ll function properly in different conditions.

  2. For accurate (still not exact) measurements the value of Rx has to be greater than R1

  3. It provides acceptable measurements compared to the actual value with an error that is not too big (less than 1% relative error) the precision was obtained by the use of some of the arduino functions (such as voltage reference) also I have chosen the voltage source to be 3.3V instead of 5V to reduce noise, now if one wishes to use a different microcontroller other than arduino will it still be possible to obtain the same precision.

I would like to know your professional opinion regarding these inconvenients and if you may solutions for them, I have accompanied the code for better understanding.

Thank you

#include <ResponsiveAnalogRead.h>
ResponsiveAnalogRead analogPin0(A0, true);
ResponsiveAnalogRead analogPin1(A1, true);
ResponsiveAnalogRead analogPin2(A2, true);

int raw1= 0,raw2=0,raw3=0;
int Vin= 3.3;
float Vout1= 0,Vout2=0,Vout3=0;

float R1= 10000,R2=100000,R3=1000000;
float Rx= 0;
float buffer= 0;

void setup()


void loop()
buffer= raw1 * Vin;
Vout1= (buffer)/1024.0;
if(Vout1<=3.135&&Vout1>=0.99) //firstif

buffer= (Vin/Vout1) -1;
Rx= (R1+R2+R3) * buffer;
Serial.print("Vout1: ");
Serial.print("Rx: ");
   else //else1 of first if

   buffer= raw2 * Vin;
   Vout2= (buffer)/1024.0;
      if(Vout2<=3.135&&Vout2>=0.99) //second if of first else
      buffer= (Vin/Vout2) -1;
      Rx= (R2+R3) * buffer;
      Serial.print("Vout2: ");
      Serial.print("Rx: ");
      buffer= raw3 * Vin;
      Vout3= (buffer)/1024.0;
          buffer= (Vin/Vout3) -1;
          Rx= R3 * buffer;
          Serial.print("Vout3: ");
          Serial.print("Rx: ");

====================================================== Circuit

New contributor
Rekaia Draoui is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
  • 1
    Make the variable Vin a float. The range is limited by the number of analog inputs and the resistors are in series. It will be hard to adapt the circuit to measure a resistor of 10 ohm. It is possible to use digital pins to power resistors or not and use a single analog input. – Jot Sep 13 at 23:37
up vote 4 down vote accepted

As you probably already know, the standard setup for measuring a resistance with an Arduino is to put the unknown resistor in series with a known one between 5V and GND, and measure the voltage at the point in-between them:

 A0 ─┤

where R is the unknown resistor and R1 is the known reference. The resistance is then computed as:

const float R1 = ...;  // reference resistance

int reading = analogRead(A0);
float R = (float) reading / (1024 - reading) * R1;

First, it is worth noting that the reference voltage does not appear in this calculation. You could, of course, do the calculation in terms of voltage, but you should then notice that the reference voltage can be simplified away. This is not surprising if you realize than the ADC of the Arduino does not actually measure a voltage: it rather measures a voltage ratio: the ratio of the input voltage to the reference voltage. This ratio can then be easily related to the resistance ratio R/R1. What all this implies is that you should not expect to get better accuracy by using a 3.3 V reference rather than 5 V. Any inaccuracy in the voltage reference is irrelevant to the measurement of the resistance.

Next, when measuring a physical quantity, you are almost always interested in the relative rather than the absolute accuracy. From the equation above, it can be easily shown that you get the best relative resolution when the reading is near the middle of the ADC range:

raw reading    │   64 │  128 │  256 │  512 │  768 │  896 │  960
resolution (%) │ 1.67 │ 0.89 │ 0.52 │ 0.39 │ 0.52 │ 0.89 │ 1.67

This is consistent with your observations, and it means that the reference resistor should ideally have a value that is of the same order as the unknown resistor.

Now, for the autoranging, I would advise you against putting all your reference resistors in series. With this setup, you always have the same voltage across the unknown resistor, irrespective of what range you choose. Reading a different input does not help. You may find out that the voltage between R1 and R2 gives a better reading (closer to mid-range), and you get a better accuracy on the measurement of R+R1. However, when you subtract R1 you are immediately degrade the relative accuracy of the result. In the end you cannot really improve the accuracy this way.

What I suggest is to put the reference resistors in parallel instead of in series, and power each one from an analog pin:

     A1  A2  A3
     │   │   │
     R₁  R₂  R₃
 A0 ─┼───┴───┴── ...

You then use these analog pins in digital mode: all of then in INPUT mode, except one which is set to OUTPUT HIGH. You can try all of them in turn and select whichever gives a result closer to mid-range. Or you can implement a smarter algorithm that finds the optimal one without trying them all.

There is something to be aware of with this setup: the pins have an output resistance that is about 25 Ω, which ends up being in series with the corresponding reference resistors. You can account for that by adjusting, in your code, the values of those references. But then that output resistance is not very well known, and can vary with temperature. This should only be an issue when you are in the low ranges though. You can mitigate this problem by measuring the voltage at the pin that is currently pulling up, and replacing 1024 in the equation for R by that reading. That's why I suggest to use analog instead of digital pins.

Finally, there are a couple of limitations that you should be aware of when measuring resistances with the Arduino ADC. At the low end of the resistance range, you cannot use a reference resistor with a very low value, because you have to make sure you do not pull more than about 20 mA from the pin that pulls up. Your smallest reference may then end up being somewhere around 220 Ω, and you will loose significant accuracy when you try to measure anything below 50 Ω. At the upper end of the range, you should be aware that the ADC is meant to measure voltage sources with an output resistance no larger than 10 kΩ, otherwise you risk cross-talk between the ADC channels. Then your higher reference should probably be 10 kΩ, and any measurement above 50 kΩ will give poor accuracy. Going past these limitations would require extra electronics, like a good-quality op-amp to “condition” the signal into something that the ADC can reliably measure.

  • The 50kΩ upper limit is on the safe side. I have no problem with 1M. That requires the average of a number of samples and sometimes an extra delay or a capacitor to gnd (to keep the voltage the same when the adc eats some charge). When for example only 5% accuracy is required for the very low and very high resistor values, then a lot is possible. – Jot Sep 14 at 20:59
  • thank you for your answer it has served me alot, as a last question i have felt after reading your answer that my project doesn't seem to be well made and that is of course due to my lack of knowledge in this field now, do you think it is worth fixing or should i jump to another way? it doesn't metter how it works as long as it is eventually an autoranging ohmmeter, thank you @EdgarBonet – Rekaia Draoui Sep 14 at 23:29
  • @RekaiaDraoui Your circuit has too many limitations. Use this circuit with turning on a resistor one at a time. Find in the sketch which value is the most in the middle and use that to calculate the unknown resistor. – Jot Sep 15 at 7:10
  • I don't quite get your last question. Can you easily change the circuit, or is it something you have soldered? – Edgar Bonet Sep 15 at 12:48
  • @EdgarBonet yes i can easily change the circuit – Rekaia Draoui 2 days ago

The answer by @EdgarBonet seems to be a very nice solution for the lowered output voltage of a pin, when a low resistor value is used.

A arduino uno pin can output 20mA without problem, even up to 40mA if needed. So a safe value to measure low resistor values is 220 ohm, which could result in a maximum of 23mA.

Analog input A1 is used both as digital output to power the circuit and also as a analog input to measure how much the voltage has dropped.

This is a quick test:

// Using the idea in the answer by Edgar Bonet
// Allow that the voltage of a digital output is
// lowered by the low resistor value,
// to calculate the unknown resistor.
// With two resistors in series.
// A1 - 220 ohm - A0 - 10 ohm - GND
// The circuit is a voltage divider.
// A1 powers the voltage divider.
// A0 measures the output.

#define R1 220
#define N_SAMPLES 10

void setup() {
  digitalWrite(A1, HIGH);

void loop() {

  // Pin A1 is already set as a digital output and set HIGH.
  // Using analogRead(A1) is to measure the real output
  // voltage. There is a voltage drop, because of the current.
  float Vin = averageRead(A1);

  float Vout = averageRead(A0);
  Serial.print(" Vout=");

  if(Vin > 0.0 && Vout < Vin) {
    float Vt = Vout / Vin;
    float Rx = (Vt * R1) / (1 - Vt);
    Serial.print(" Rx=");


float averageRead(int analogPin) {
  int total = 0;
  for(int i=0; i<N_SAMPLES; i++) {
    total += analogRead(analogPin);
  return float(total) / N_SAMPLES;

That is very nice. It is no problem when the unknown resistor is 10 ohm.

Because of the low resistor values, I did not add delays. With high resistor values, some delay is needed before measuring the analog values.

  • Wow this is pretty impressive i see what you did right there one small issue that still worries me, EdgarBonet previously mentioned "the pins have an output resistance that is about 25 Ω, which ends up being in series with the corresponding reference resistors. You can account for that by adjusting, in your code, the values of those references." i wonder why you didn't take this detail in consideration when you wrote this code?, thank you – Rekaia Draoui 2 days ago
  • I did! Not the 25 ohm, but I measure the actual voltage drop. Edgar Bonet wrote "That's why I suggest to use analog instead of digital pins" (to be able to measure the voltage drop of a pin). I measure the voltage of the pin that powers the circuit and the voltage over the unknown resistor. The analogRead of pin a1 could be 840 (instead of 1023) and the a0 could be 37. The actual voltage does not matter. With the two resistors, everything is relative. Because it is a voltage divider, the unknown resistor is measured relative to the 220 ohm resistor. The calculation is just two lines. – Jot 2 days ago
  • OH! true i missread both of your answers well thank you big time! i will improve it and post it here as an answer once im done if anybody was interested, thank you again – Rekaia Draoui 2 days ago
  • i have another question, i've tried ur circuit in a simulator bcz my pc decided to stop all of a sudden, anyway when i chose a high value reference resistor(say 100k) vin was equal to 1024 so 5v unlike a low value reference resistor(say 220)where vin was about 824 can you please explain to me why is that ? – Rekaia Draoui yesterday
  • Because of the output resistance of 25 ohm, that Edgar Bonet was talking about. The atmega328 can output 20mA (even up to 40mA), but with such high currents the pin is no longer Vcc (5.0v), but lower. With very small current, it has no problem to set a pin to Vcc (5.0v). That is what my sketch is for. To test the accuracy by actually measuring the output pin with a analog pin. Since the arduino uno has a digital pin and a analog pin combined for all analog inputs, it is possible to use that single pin. Did you choose reference resistors? You can set them apart by 15 times: 220, 3k3, 47k, 750k. – Jot yesterday

Your Answer

Rekaia Draoui is a new contributor. Be nice, and check out our Code of Conduct.

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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