Arduino ohm meter again

Hi,

I’m trying to use a nano as an ohm meter to help me identify quickly the resistors I have in my workbench, being somewhat colorblind learning the band code is not an option, colors like red and brown, specially with a blue background are just the same to me.

I made the classic circuit, 6 ‘reference’ resistors connected to digital pins and to A0, the other side of the resistors goes to GND. I’m afraid they are not exactly precision resistors, but I measured the values with a DMM and I’m using those values instead of 10, 100, 1000, etc…
So far it’s being powered from USB but I’d like to power it from 4xAA rechargeable batteries (not LIPOs).
It kind of works, but the auto range code that selects the best reference by looking at Vout (read via A0) and choosing the one that’s closest to Vin/2 sometimes is not correct, sometimes the closest value is in the next reference.
What I’d like to ask is if there is an alternative way do measure this, I’m thinking in a constant current source made with a LM 317 (how much current do I need ? 10 or 20 mA ?), and measuring the voltage with A0 before the unknown resistor and with A1 after the unknown resistor this should give me the voltage drop, right ? Maybe I need to use an opamp to amplify this values, I have no idea if the ADC is good enough to differentiate between a few mV.
Am I thinking right ?

Using a current source is going to screw up the ratiometric behaviour of Arduino's A/D.

Post a link to that "clasic circuit", and code.
Leo..

What’s wrong with using a DMM? If you want to leave one permanently set-up to measure resistors it’s probably worthwhile buying another one.

how much current do I need ? ?10 or 20 mA ?),

I have two DMMs at work, and connecting them “back-to-back”, I get 1mA (the lowest resolution I can read) on the lowest resistance reading and it’s too low to measure on the other settings. (And it looks like the other meter has blown current fuse because I’m reading megohms with and no current when I switch them around.)

If you want to use a constant-current source you can make your own Ohm’s Law calculations, but you have about 5mV resolution with the default 5V reference and about 1mV resolution with the optional 1.1V reference. And of course, you only have 5V available so that’s the maximum you’ll get with a constant-current source and high resistance (or an open circuit).

[qutoe]So far it’s being powered from USB but I’d like to power it from 4xAA rechargeable batteries (not LIPOs).[/quote]There’s a way (which you’d have to research) to measure Vcc using the internal 1.1V reference so you could know when the batteries are getting weak, or you could “get fancy” and compensate for any drop in voltage.

It kind of works, but the auto range code that selects the best reference by looking at Vout (read via A0) and choosing the one that’s closest to Vin/2 sometimes is not correct, sometimes the closest value is in the next reference.

I’m not sure what you’re doing but I assume you know that a voltage divider with one variable/unknown resistance isn’t linear…

But typically, any meter needs to be calibrated (using a known-good, calibrated meter). It’s usually a “straight line” calibration with an offset (addition/subtraction) calibrated at zero and a slope (multiplication) calibrated at (or near) the maximum. And, you’d want to calibrate each range separately.

Using a current source is going to screw up the ratiometric behaviour of Arduino’s A/D.

It will work fine as long as you realize you are reading voltage across a resistor and as long as you’re reading the voltage relative to ground (one end of the resistor grounded).

When measuring an unknown resistor with a voltage divider with Arduino's A/D,
then you should NOT measure/calculate with voltage.
Arduino's A/D works with ratios.
When you work with ratios, supply/Aref voltage becomes irrelevant.
If you use a constant current source to measure that unknown resistor,
then you must change default Aref to a fixed Aref voltage.
Now you have TWO variables to calibrate, instead of one.
The current source AND the voltage source, instead of just the fixed resistor value.
Leo..

/* Arduino Nano autorange Ohm meter
    v1.0, 2018.08.17, by Ocsav
*/

#define APIN A0
const float Vin = 4.5;
const int samples = 20;

int p[] = { 3, 4, 5, 6, 7, 8 }; // sense pins
float v[] = {10.1, 100.2, 1000.0, 10000.0, 100000.0, 999999.8}; // measure the sample resistors that you're using

// used to store each reading
typedef struct {
  float Vout;
  float R2;
} rec;

rec vv[6];

// in order to 'read' using each resistor, each pin connected to each resistor is made OFF by
// doing to each one pinMode(X, OUTPUT); digitalWrite(X, LOW); pinMode(X, INPUT).
// to 'activate' one of the resistors you just have to pinMode(X, OUTPUT); digitalWrite(X, HIGH);
void setup() {
  int f;

  //analogReference(INTERNAL1V1);
  pinMode(APIN, INPUT);

  for (f = 0; f < 6; f++)
  {
    pinMode(p[f], OUTPUT);
    digitalWrite(p[f], LOW);
    pinMode(p[f], INPUT);
  }
  Serial.begin(9600);
}

void loop() {

  int x, xtot, xmed;
  int f;
  int g;
  float Vhalf = Vin / 2;
  float Vout = 0.0;
  float R1 = 0.0;
  float R2 = 0.0;
  float buf = 0.0;
  char *Unit = " ohm";
  boolean EMPTY = false;

  for (f = 0; f < 6; f++)
  {
    pinMode(p[f], OUTPUT);
    digitalWrite(p[f], HIGH);
    delay(10);
    xtot = 0;
    xmed = 0;
    // I'm not sure if this is really needed, and how many times I should do it
    // and what delay to use. If I only do it 2 times the values returned are not
    // constant, it is ok with 10x, 20x or even 30x, however 100x produce totally
    // wrong values.
    for (g = 0; g < samples; g++)
    {
      x = analogRead(APIN);
      xtot += x;
      delay(2);
    }
    //    xtot=xtot*(1.1/5);
    xmed = xtot / samples;

    Vout = (xmed * Vin) / 1024.0;
    R1 = v[f];
    R2 = Vout * R1 / (Vin - Vout);

    // store the reading done with each sample resistor for
    // later to choose the best one
    vv[f].Vout = Vout;
    vv[f].R2 = R2;

    // turn the pin OFF
    pinMode(p[f], INPUT);
    digitalWrite(p[f], LOW);

    Serial.print("Pin ");
    Serial.print(p[f]);
    Serial.print(" - Vin = " + String(Vin));
    Serial.print(" - Vout = ");
    Serial.print(Vout);
    Serial.print(" [diff to Vin/2: " + String(abs(Vout - Vhalf)) + "] ");
    Serial.print(" - R1 = ");
    Serial.print(R1);
    Serial.print(" R2 = ");
    Serial.println(R2);

    delay(10);
  }

  // Choose the best value.
  // After searching high and low I found a page that told me that the best value
  // would be the one with Vin closest to 2.5 wich is Vin/2.
  // After some testing I noticed that it is not always true, sometimes it is the NEXT after the
  // closest to Vin/2... I really don't know

  float diff = 0;
  float diffMin = 999;
  int place = 0;
  for (f = 0; f < 6; f++)
  {
    diff = abs(vv[f].Vout - Vhalf);
    if (diff < diffMin)
    {
      diffMin = diff;
      place = f;
    }
  }

  /*
    place<4?place++:place; // use the one closest to Vin/2 or the next one, I don't know how to choose
  */

  R2 = vv[place].R2;

  // set units
  if (R2 >= 1000000)
  {
    R2 = R2 / 1000000;
    Unit = " M";
    if (R2 > 2) EMPTY = true; // detect that there is no resistor to be measured, 2M should be ok
  } else if (R2 >= 1000)
  {
    R2 = R2 / 1000;
    Unit = " K";
  } else Unit = " ohm";
  if (! EMPTY)
  {
    Serial.print(R2);
    Serial.println(Unit);
  } else Serial.println("EMPTY");

  delay(3000);
}

ohm_1.png

DMM=555 ohm :slight_smile:

Pin 3 - Vin = 4.50 - Vout = 4.22 [diff to Vin/2: 1.97] - R1 = 10.10 R2 = 154.07
Pin 4 - Vin = 4.50 - Vout = 3.67 [diff to Vin/2: 1.42] - R1 = 100.20 R2 = 445.57
Pin 5 - Vin = 4.50 - Vout = 1.57 [diff to Vin/2: 0.68] - R1 = 1000.00 R2 = 535.23
Pin 6 - Vin = 4.50 - Vout = 0.22 [diff to Vin/2: 2.03] - R1 = 10000.00 R2 = 524.15
Pin 7 - Vin = 4.50 - Vout = 0.01 [diff to Vin/2: 2.24] - R1 = 100000.00 R2 = 293.83
Pin 8 - Vin = 4.50 - Vout = 0.00 [diff to Vin/2: 2.25] - R1 = 999999.81 R2 = 0.00
535.23 ohm

DMM=4.7K

Pin 3 - Vin = 4.50 - Vout = 4.46 [diff to Vin/2: 2.21] - R1 = 10.10 R2 = 1282.70
Pin 4 - Vin = 4.50 - Vout = 4.35 [diff to Vin/2: 2.10] - R1 = 100.20 R2 = 2917.59
Pin 5 - Vin = 4.50 - Vout = 3.69 [diff to Vin/2: 1.44] - R1 = 1000.00 R2 = 4535.14
Pin 6 - Vin = 4.50 - Vout = 1.42 [diff to Vin/2: 0.83] - R1 = 10000.00 R2 = 4628.57
Pin 7 - Vin = 4.50 - Vout = 0.19 [diff to Vin/2: 2.06] - R1 = 100000.00 R2 = 4489.80
Pin 8 - Vin = 4.50 - Vout = 0.01 [diff to Vin/2: 2.24] - R1 = 999999.81 R2 = 2938.30
4.63 K

DMM=150 ohm

Pin 3 - Vin = 4.50 - Vout = 3.60 [diff to Vin/2: 1.35] - R1 = 10.10 R2 = 40.60
Pin 4 - Vin = 4.50 - Vout = 2.31 [diff to Vin/2: 0.06] - R1 = 100.20 R2 = 105.42
Pin 5 - Vin = 4.50 - Vout = 0.57 [diff to Vin/2: 1.68] - R1 = 1000.00 R2 = 144.13 ← should have been this one
Pin 6 - Vin = 4.50 - Vout = 0.06 [diff to Vin/2: 2.19] - R1 = 10000.00 R2 = 128.59
Pin 7 - Vin = 4.50 - Vout = 0.00 [diff to Vin/2: 2.25] - R1 = 100000.00 R2 = 0.00
Pin 8 - Vin = 4.50 - Vout = 0.00 [diff to Vin/2: 2.25] - R1 = 999999.81 R2 = 0.00
105.42 ohm

DMM=10K

Pin 3 - Vin = 4.50 - Vout = 4.48 [diff to Vin/2: 2.23] - R1 = 10.10 R2 = 2575.50
Pin 4 - Vin = 4.50 - Vout = 4.44 [diff to Vin/2: 2.19] - R1 = 100.20 R2 = 7792.48
Pin 5 - Vin = 4.50 - Vout = 4.07 [diff to Vin/2: 1.82] - R1 = 1000.00 R2 = 9448.98
Pin 6 - Vin = 4.50 - Vout = 2.23 [diff to Vin/2: 0.02] - R1 = 10000.00 R2 = 9806.58
Pin 7 - Vin = 4.50 - Vout = 0.40 [diff to Vin/2: 1.85] - R1 = 100000.00 R2 = 9753.48
Pin 8 - Vin = 4.50 - Vout = 0.04 [diff to Vin/2: 2.21] - R1 = 999999.81 R2 = 7874.01
9.81 K

First thing I noticed is R1 (10ohm) and R2 (100ohm).
Both can get the digital pin in the >40mA danger zone.
Those low values (if needed) should be switched with external mosfets.

Also, A0 should have a 100n cap to ground, because of the possible >10k impedance on the pin.

The code is done in volts.
Weird, because it's not a voltmeter.

1.1volt Aref is used. Totally wrong here.
Read up about ratiometric A/D's.
The A/D returns a value (not a voltage) of the ratio of the fixed resistor and the unknown resistor.
Not a maths nerd, but I think this is the basic formula without the use of 'voltage'.

R_unknown = R_fixed * (( 1024 / analogRead(A0)) - 1); // for a fixed pull down resistor.

I probably would have designed to display in 1-10 values (an average value of 5.5).
That would have needed 55, 550, 5500 etc pull up resistors (56ohm, 560ohm, etc),
therefore 10, 100, 1000 pull up does not make sense to me.
Leo..

Test code, without 'voltage', and without the needed boundaries etc.,
for resistor values from 100 to 1000 ohm.
Leo..

float R_fixed = 560.0; // pull up (or down) resistor value for testing
float R_x; // for unknown resistor value

void setup() {
  Serial.begin (9600);
}

void loop() {
  R_x = R_fixed * (( 1024. / (1024. - analogRead(A0))) - 1.); // this line for fixed pull up resistor
  //Rx = R_fixed * (( 1024. / analogRead(A0)) - 1.); // or this line for fixed pull down resisor

  Serial.println(R_x, 1); // one decimal place
  delay(1000);
}

DVDdoug:
What's wrong with using a DMM? If you want to leave one permanently set-up to measure resistors it's probably worthwhile buying another one.

I have two cheap autorange DMM, that normally are hidden bellow something on my workbench, never with the probes I need... :frowning: I need something more permanent and with fixed contacts that can be used easily.

If you want to use a constant-current source you can make your own Ohm's Law calculations, but you have about 5mV resolution with the default 5V reference and about 1mV resolution with the optional 1.1V reference. And of course, you only have 5V available so that's the maximum you'll get with a constant-current source and high resistance (or an open circuit).

I'm still trying to understand why a 1.1V voltage reference is better than the normal 5V. Ok, I understand that it's easier to maintain a stable 1.1V reference, even when the Vcc is bellow 5V, but why do you get a better resolution ?
Is it because you have 10 bits to measure between 0V and 1.1V (1.1/1024=0,00107421875) instead of 10 bits between 0V and 5V (5/1024=0,0048828125) ?
But I don't understand what a reference voltage is, I'm going to try to measure some know values, I have no idea of what to expect. If it is what I'm thinking than how is it possibly to measure a value that it's above the voltage reference ?

There's a way (which you'd have to research) to measure Vcc using the internal 1.1V reference so you could know when the batteries are getting weak, or you could "get fancy" and compensate for any drop in voltage.

You might be talking about that scary readVcc() function, I tryed it when on USB power and I always got 4000 mV... Does it makes sense ?

I'm not sure what you're doing but I assume you know that a voltage divider with one variable/unknown resistance isn't linear...

Hmmm, I might be wrong here, I was thinking that if R1 = R2 then Vout=Vin/2, so, the closest value of R1 (in order to select the sense resistor) should be the one where Vout was closer to Vin/2. So I just do an abs(Vin-Vout) and choose the reading where this value is smaller. I know it does not work for every case but I don't know why. [/quote]

Wawa:
First thing I noticed is R1 (10ohm) and R2 (100ohm).
Both can get the digital pin in the >40mA danger zone.
Those low values (if needed) should be switched with external mosfets.

You are right, I haven't noticed that.
I don't think I have any mosfet small enough for that job, all I have are for 30A and over... Not sure if they'll work here.

Also, A0 should have a 100n cap to ground, because of the possible >10k impedance on the pin.

Done, but I see no difference in the readings.

The code is done in volts.
Weird, because it's not a voltmeter.

I don't follow you here,
I have Vin and R1, then use pin A0 to read a value, that, as you say, is a ratio and not a voltage, it's being calculated as

Vout=(Vinx)/1024.0;
R2=Vout
R1/(Vin-Vout);

Is that wrong ?
I got a set of values (Vout and R2) for each sense resistor, and then choose the one where Vout is closest to Vin/2.

1.1volt Aref is used. Totally wrong here.
Read up about ratiometric A/D's.
The A/D returns a value (not a voltage) of the ratio of the fixed resistor and the unknown resistor.

The 1.1 ref is commented out, I just used it to see what values I got.

Not a maths nerd, but I think this is the basic formula without the use of 'voltage'.

R_unknown = R_fixed * (( 1024 / analogRead(A0)) - 1); // for a fixed pull down resistor.

I probably would have designed to display in 1-10 values (an average value of 5.5).

I'll try that, but I do not understand (happens a lot I'm afraid) :slight_smile:

That would have needed 55, 550, 5500 etc pull up resistors (56ohm, 560ohm, etc),
therefore 10, 100, 1000 pull up does not make sense to me.

My resistor collection is not very rich, I just used values that I saw used in other projects that I happened to have.
Maybe this values made more sense 10 100 470 1K 5K 10K 51K 100K 330K 680K 750K 1M ?

Thank you for your help.[/quote]

Say you connect a voltage divider with two equal value resistors to the 5volt pin and an analogue pin.
What do you get.

An A/D value of 512, or a voltage of 2.5volt.

Half of the A/D range of 1024 is always 512.
Half of the voltage on the 5volt pin is NOT always 2.5volt.
It depends on what the actual voltage on the 5volt pin is.
And it can change over time.
That's why it makes more sense (to me) to use ratio instead of voltage in calculations.
Note that both ways will lead to the same result, because if you multiply and divide by someRandomValue, the outcome is the same.

To measure a resistor with the highest possible resolution, the fixed resistor must be about the same value.
If you use a fixed value of 10k, then you can measure resistors between ~5k and ~15k accurate.
If you use a fixed resistor of 5k6, then the accurate range is ~1-10k.
More suited to human brains that think in 1-10.
Leo..

The resulting value of an A/D converter depends on two things.

  1. the voltage you connect to it.
  2. the reference voltage (that the A/D compares it to)

If you want to measure a voltage (e.g battery), then you want the A/D outcome to only depend on battery voltage, not on reference voltage.
In this case you need a stable reference voltage, like the internal 1.1volt Aref or 2.56volt Aref (Mega).

If you measure a voltage divider, connected to the 5volt pin, than divider output depends on the voltage on the 5volt pin.
If that happens to be 5volt, then a 1:1 divider will produce 2.5volt.
But if the 5volt pin is instable, or drops to e.g. 4volt, then divider voltage drops to 2volt.

Fortunately the default reference of most Arduinos is linked to the 5volt supply.
The 1024 A/D values are spread out over that voltage.
You could say that when output voltage of the divider drops, the A/D sensitivity (mV per A/D step) goes up with the same amount,
thus keeping resulting A/D value the same. RATIOmetric.
Hope this help you to understand it a bit better.
Leo..

Wawa:
Test code, without 'voltage', and without the needed boundaries etc.,
for resistor values from 100 to 1000 ohm.
Leo..

float R_fixed = 560.0; // pull up (or down) resistor value for testing

float R_x; // for unknown resistor value

void setup() {
 Serial.begin (9600);
}

void loop() {
 R_x = R_fixed * (( 1024. / (1024. - analogRead(A0))) - 1.); // this line for fixed pull up resistor
 //Rx = R_fixed * (( 1024. / analogRead(A0)) - 1.); // or this line for fixed pull down resisor

Serial.println(R_x, 1); // one decimal place
 delay(1000);
}

Ok, your formula works. R2 is the unknown resistor, R1 is the sense resistor and Vin is being read by the readVcc() functio, it returns 4V with the Nano powered from USB, weird...
xmed is the arithmetical medium of 30 analogRead().

R2 = R1 * (( 1024.0 / (1024.0 - xmed)) - 1.0);

I then calculate Vout using the traditional resistor divider formula in order to auto range.

Vout=Vin*(R2/(R1+R2));

10K -> 9.84 K
555 ohm -> 535.23 ohm
46K -> 46.29 K
4.7K -> 4.63 K
5K -> 5.01 K
2K -> 1.92 K

Not very good in high values, probably a 500K sense resistor is needed.

472K
Pin 3 - Vin = 5.00 - Vout = 5.00 [diff to Vin/2: 2.50] - R1 = 10.10 R2 = 10332.30
Pin 4 - Vin = 5.00 - Vout = 4.99 [diff to Vin/2: 2.49] - R1 = 100.20 R2 = 51202.20
Pin 5 - Vin = 5.00 - Vout = 4.98 [diff to Vin/2: 2.48] - R1 = 1000.00 R2 = 255000.00
Pin 6 - Vin = 5.00 - Vout = 4.89 [diff to Vin/2: 2.39] - R1 = 10000.00 R2 = 455454.56
Pin 7 - Vin = 5.00 - Vout = 3.99 [diff to Vin/2: 1.49] - R1 = 100000.00 R2 = 397087.37
Pin 8 - Vin = 5.00 - Vout = 1.69 [diff to Vin/2: 0.81] - R1 = 999999.81 R2 = 510324.37
510.32 K

1M
Pin 3 - Vin = 5.00 - Vout = 5.00 [diff to Vin/2: 2.50] - R1 = 10.10 R2 = 10332.30
Pin 4 - Vin = 5.00 - Vout = 4.99 [diff to Vin/2: 2.49] - R1 = 100.20 R2 = 51202.20
Pin 5 - Vin = 5.00 - Vout = 4.99 [diff to Vin/2: 2.49] - R1 = 1000.00 R2 = 511000.00
Pin 6 - Vin = 5.00 - Vout = 4.94 [diff to Vin/2: 2.44] - R1 = 10000.00 R2 = 843333.37
Pin 7 - Vin = 5.00 - Vout = 4.44 [diff to Vin/2: 1.94] - R1 = 100000.00 R2 = 790434.75
Pin 8 - Vin = 5.00 - Vout = 2.80 [diff to Vin/2: 0.30] - R1 = 999999.81 R2 = 1275555.37
1.28 M

760K
Pin 3 - Vin = 5.00 - Vout = 5.00 [diff to Vin/2: 2.50] - R1 = 10.10 R2 = 10332.30
Pin 4 - Vin = 5.00 - Vout = 4.99 [diff to Vin/2: 2.49] - R1 = 100.20 R2 = 51202.20
Pin 5 - Vin = 5.00 - Vout = 4.99 [diff to Vin/2: 2.49] - R1 = 1000.00 R2 = 340333.34
Pin 6 - Vin = 5.00 - Vout = 4.93 [diff to Vin/2: 2.43] - R1 = 10000.00 R2 = 672666.68
Pin 7 - Vin = 5.00 - Vout = 4.30 [diff to Vin/2: 1.80] - R1 = 100000.00 R2 = 616083.93
Pin 8 - Vin = 5.00 - Vout = 2.41 [diff to Vin/2: 0.09] - R1 = 999999.81 R2 = 928436.68
928.44 K

680K
Pin 3 - Vin = 5.00 - Vout = 5.00 [diff to Vin/2: 2.50] - R1 = 10.10 R2 = 10332.30
Pin 4 - Vin = 5.00 - Vout = 4.99 [diff to Vin/2: 2.49] - R1 = 100.20 R2 = 51202.20
Pin 5 - Vin = 5.00 - Vout = 4.99 [diff to Vin/2: 2.49] - R1 = 1000.00 R2 = 340333.34
Pin 6 - Vin = 5.00 - Vout = 4.92 [diff to Vin/2: 2.42] - R1 = 10000.00 R2 = 630000.00
Pin 7 - Vin = 5.00 - Vout = 4.24 [diff to Vin/2: 1.74] - R1 = 100000.00 R2 = 560645.12
Pin 8 - Vin = 5.00 - Vout = 2.25 [diff to Vin/2: 0.25] - R1 = 999999.81 R2 = 815602.62
815.60 K

And not very good for low values either

270 ohm
Pin 3 - Vin = 4.00 - Vout = 3.53 [diff to Vin/2: 1.53] - R1 = 10.10 R2 = 75.37
Pin 4 - Vin = 4.00 - Vout = 2.68 [diff to Vin/2: 0.68] - R1 = 100.20 R2 = 202.47
Pin 5 - Vin = 4.00 - Vout = 0.83 [diff to Vin/2: 1.17] - R1 = 1000.00 R2 = 261.08
Pin 6 - Vin = 4.00 - Vout = 0.10 [diff to Vin/2: 1.90] - R1 = 10000.00 R2 = 250.25
Pin 7 - Vin = 4.00 - Vout = 0.00 [diff to Vin/2: 2.00] - R1 = 100000.00 R2 = 0.00
Pin 8 - Vin = 4.00 - Vout = 0.00 [diff to Vin/2: 2.00] - R1 = 999999.81 R2 = 0.00
202.47 ohm

150 ohm
Pin 3 - Vin = 4.00 - Vout = 3.22 [diff to Vin/2: 1.22] - R1 = 10.10 R2 = 41.61
Pin 4 - Vin = 4.00 - Vout = 2.11 [diff to Vin/2: 0.11] - R1 = 100.20 R2 = 112.23
Pin 5 - Vin = 4.00 - Vout = 0.51 [diff to Vin/2: 1.49] - R1 = 1000.00 R2 = 146.70
Pin 6 - Vin = 4.00 - Vout = 0.05 [diff to Vin/2: 1.95] - R1 = 10000.00 R2 = 128.59
Pin 7 - Vin = 4.00 - Vout = 0.00 [diff to Vin/2: 2.00] - R1 = 100000.00 R2 = 0.00
Pin 8 - Vin = 4.00 - Vout = 0.00 [diff to Vin/2: 2.00] - R1 = 999999.81 R2 = 0.00
112.23 ohm

215 ohm
Pin 3 - Vin = 4.00 - Vout = 3.42 [diff to Vin/2: 1.42] - R1 = 10.10 R2 = 59.31
Pin 4 - Vin = 4.00 - Vout = 2.40 [diff to Vin/2: 0.40] - R1 = 100.20 R2 = 150.06
Pin 5 - Vin = 4.00 - Vout = 0.69 [diff to Vin/2: 1.31] - R1 = 1000.00 R2 = 207.55
Pin 6 - Vin = 4.00 - Vout = 0.07 [diff to Vin/2: 1.93] - R1 = 10000.00 R2 = 189.06
Pin 7 - Vin = 4.00 - Vout = 0.00 [diff to Vin/2: 2.00] - R1 = 100000.00 R2 = 0.00
Pin 8 - Vin = 4.00 - Vout = 0.00 [diff to Vin/2: 2.00] - R1 = 999999.81 R2 = 0.00
150.06 ohm

Here it is off by 2 resistors, again the best value was from the 1K resistor.
12 ohm
Pin 3 - Vin = 4.00 - Vout = 0.90 [diff to Vin/2: 1.10] - R1 = 10.10 R2 = 2.93
Pin 4 - Vin = 4.00 - Vout = 0.35 [diff to Vin/2: 1.65] - R1 = 100.20 R2 = 9.54
Pin 5 - Vin = 4.00 - Vout = 0.05 [diff to Vin/2: 1.95] - R1 = 1000.00 R2 = 11.86
Pin 6 - Vin = 4.00 - Vout = 0.00 [diff to Vin/2: 2.00] - R1 = 10000.00 R2 = 0.00
Pin 7 - Vin = 4.00 - Vout = 0.00 [diff to Vin/2: 2.00] - R1 = 100000.00 R2 = 0.00
Pin 8 - Vin = 4.00 - Vout = 0.00 [diff to Vin/2: 2.00] - R1 = 999999.81 R2 = 0.00
2.93 ohm

With a 560ohm resistor you should only measure resistors in the 100-1000ohm range.
The A/D value per ohm gets too small outside that range.

Also don't forget you're using a 10-bit A/D with 1024 values,
and are only using a part of that range.

Returned/calculated values of 535.23 ohm are just not possible.
53524 values would require a 16-bit A/D.

With a 560ohm fixed resistor, you shouldn't expect more than a one ohm resolution in the middle of that range.
Less at the 100ohm/1kohm edges.
Leo..

Hi,

I know that you are trying to help me but I don't understand, why is a 560 ohm resistor important ?
And why is a calculated value of 535.23 ohm impossible ? I'll change the code to display the value read by analogRead along with the calculated values.

thanks.

The 560 ohm resistor is not important.
As explained, if you want to display resistance in 1-10, 10-100, 100-1000 etc. blocks,
then use a pull up resistor in the middle of that range.
560ohm for 100-1000 ohm, 5k6 for 1k-10kohm etc.

Don't expect to measure significantly less than 100 ohm or more than 1000 ohm with a 560 ohm pull up.
You quickly loose resolution if you deviate too much from that 560 ohm pull up value.

535.23ohm is impossible with a 10-bit A/D.
Because it requires more than 50 thousand A/D values (53523).
The Arduino A/D only has 1024.
535 might be true, but the .23 is largely made up by the code.
Leo..

Wawa:
The 560 ohm resistor is not important.
As explained, if you want to display resistance in 1-10, 10-100, 100-1000 etc. blocks,
then use a pull up resistor in the middle of that range.
560ohm for 100-1000 ohm, 5k6 for 1k-10kohm etc.

Ok, now I got it.

535.23ohm is impossible with a 10-bit A/D.
Because it requires more than 50 thousand A/D values (53523).
The Arduino A/D only has 1024.
535 might be true, but the .23 is largely made up by the code.

Your formula is generating it, I’m only helping :slight_smile:
The values for that reading are these
The DMM say it’s a 555 ohm resistor

Pin 3 - Vin = 4.00 - Vout = 3.76 [diff to Vin/2: 1.76] - xmed = 962.00 - R1 = 10.10 - R2 = 156.71
Pin 4 - Vin = 4.00 - Vout = 3.17 [diff to Vin/2: 1.17] - xmed = 812.00 - R1 = 100.20 - R2 = 383.78
Pin 5 - Vin = 4.00 - Vout = 1.39 [diff to Vin/2: 0.61] - xmed = 357.00 - R1 = 1000.00 - R2 = 535.23
Pin 6 - Vin = 4.00 - Vout = 0.20 [diff to Vin/2: 1.80] - xmed = 51.00 - R1 = 10000.00 - R2 = 524.15
Pin 7 - Vin = 4.00 - Vout = 0.01 [diff to Vin/2: 1.99] - xmed = 3.00 - R1 = 100000.00 - R2 = 293.83
Pin 8 - Vin = 4.00 - Vout = 0.00 [diff to Vin/2: 2.00] - xmed = 0.00 - R1 = 999999.81 - R2 = 0.00
535.23 ohm

Xmed is the value read from the ADC, when reading with the 1K sense resistor we have 357, by the formula

R2 = R1 * (( 1024.0 / (1024.0 - xmed)) - 1.0);

calculating that in ‘bc’
scale=10
1000 * (( 1024.0 / (1024.0 - 357)) - 1.0)
535.2323838000

This is the current code

/* Arduino Nano autorange Ohm meter
    v1.0, 2018.08.17, by Ocsav
*/

#define APIN A0
float Vin = 5.3;
const int samples = 20;

int p[] = { 3, 4, 5, 6, 7, 8 }; // sense pins
float v[] = {10.1, 100.2, 1000.0, 10000.0, 100000.0, 999999.8}; // measure the sample resistors that you're using

// used to store each reading
typedef struct {
  float Vin;
  float Vout;
  float R2;
} rec;

rec vv[6];

// in order to 'read' using each resistor, each pin connected to each resistor is made OFF by
// doing to each one pinMode(X, OUTPUT); digitalWrite(X, LOW); pinMode(X, INPUT).
// to 'activate' one of the resistors you just have to pinMode(X, OUTPUT); digitalWrite(X, HIGH);
void setup() {
  int f;

  pinMode(APIN, INPUT);

  for (f = 0; f < 6; f++)
  {
    pinMode(p[f], OUTPUT);
    digitalWrite(p[f], LOW);
    pinMode(p[f], INPUT);
  }
  Serial.begin(9600);
}

void loop() {
  int x, xtot;
  int f;
  int g;
  float xmed, Vhalf = Vin / 2;
  float Vout = 0.0;
  float R1 = 0.0;
  float R2 = 0.0;
  float buf = 0.0;
  char *Unit = " ohm";
  boolean EMPTY = false;

  for (f = 0; f < 6; f++)
  {
    pinMode(p[f], OUTPUT);
    digitalWrite(p[f], HIGH);
    delay(10);
    xtot = 0;
    xmed = 0.0;
    Vin = readVcc(); // read current Vcc instead of using 5.0, for a Nano on USB this is returning 4
    //    Vin=5.0;
    // I'm not sure if this is really needed, and how many times I should do it
    // and what delay to use. If I only do it 2 times the values returned are not
    // constant, it is ok with 10x, 20x or even 30x, however 100x produce totally
    // wrong values.
    for (g = 0; g < samples; g++)
    {
      x = analogRead(APIN);
      xtot += x;
      delay(2);
    }
    xmed = xtot / samples;
    R1 = v[f];
    /*
        Vout = (xmed * Vin) / 1024.0;
        R2 = Vout * R1 / (Vin - Vout);
    */
    R2 = R1 * (( 1024.0 / (1024.0 - xmed)) - 1.0);
    Vout = Vin * (R2 / (R1 + R2));

    // store the reading done with each sample resistor for
    // later to choose the best one

    vv[f].Vout = Vout;
    vv[f].R2 = R2;
    vv[f].Vin = Vin;

    // turn the pin OFF
    pinMode(p[f], INPUT);
    digitalWrite(p[f], LOW);

    Serial.print("Pin ");
    Serial.print(p[f]);
    Serial.print(" - Vin = " + String(Vin));
    Serial.print(" - Vout = ");
    Serial.print(Vout);
    Serial.print(" [diff to Vin/2: " + String(abs(Vout - Vhalf)) + "] ");
    Serial.print("- xmed = " + String(xmed));
    Serial.print(" - R1 = ");
    Serial.print(R1);
    Serial.print(" - R2 = ");
    Serial.println(R2);

    delay(10);
  }

  // autorange code

  float diff = 0;
  float diffMin = 999;
  int place = 0;
  for (f = 0; f < 6; f++)
  {
    diff = abs(vv[f].Vout - Vhalf);
    if (diff < diffMin)
    {
      diffMin = diff;
      place = f;
    }
  }

  R2 = vv[place].R2;

  // set units
  if (R2 >= 1000000)
  {
    R2 = R2 / 1000000.0;
    Unit = " M";
    if (R2 > 2) EMPTY = true; // detect that there is no resistor to be measured, 2M should be ok
  } else if (R2 >= 1000)
  {
    R2 = R2 / 1000.0;
    Unit = " K";
  } else Unit = " ohm";
  if (! EMPTY)
  {
    Serial.print(R2);
    Serial.println(Unit);
  } else Serial.println("EMPTY");

  delay(3000);
}

long readVcc() {
  // Read 1.1V reference against AVcc
  // set the reference to Vcc and the measurement to the internal 1.1V reference
#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
  ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
#elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
  ADMUX = _BV(MUX5) | _BV(MUX0);
#elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
  ADMUX = _BV(MUX3) | _BV(MUX2);
#else
  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
#endif

  delay(2); // Wait for Vref to settle
  ADCSRA |= _BV(ADSC); // Start conversion
  while (bit_is_set(ADCSRA, ADSC)); // measuring

  uint8_t low  = ADCL; // must read ADCL first - it then locks ADCH
  uint8_t high = ADCH; // unlocks both

  long result = (high << 8) | low;

  result = (1125300L / result) / 1000.0; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000
  return result; // Vcc in volts
}

Serial.print(R2); // prints to default two decimal places
Serial.print(R2, 1); // one decimal place

Digital output ports have some internal resistance (~20-40ohm).
So if you're going to switch pull up resistors with a port, then that 560ohm resistor could be 580ohm.
Leo..