measuring resistance with arduino

Hi.
As part of an arduino multimeter project , I had this issue where I had to measure resistance with arduino. I did it a couple of times with a voltage divider and different reference resistors , but it did not cover a satisfactory range (unless I used 100k Ohms which meant a lack of precision in small and large values alike )
So I decided to make multiple ranges . I searched google and found 2 websites and one forum topic , but the websites did not fix the issue about range - one of them had 220~22k resistors which would still mean issues in the million range , the other did not look like anything I was looking for.

But the forum post was interesting. someone suggested current mirrors

And I understand the concept of having similar currents and varying resistance and measuring voltage , but I do not understand which parts of the circuit need to be measured in order to do this.

Furthermore , I used the websites' schematics and changed them a bit to make this (the attached image) (sorry btw I did not have any proper schematic applications on my PC at this time)

and this is the code for the attached image:

float buf;
float buf2;

int ref;
float R2;
int analogPin = 0;










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

void loop() {
 //call functions highend and lowend
 lowend();
 Serial.print("lowend: ");
 Serial.println(R2);
 
 if (R2 > 100000) {
  highend();
  Serial.print("highend: ");
 Serial.println(R2);
 }
 
 Serial.println("   ");
 Serial.println("   ");
 delay(1000);

}

void lowend () {
  digitalWrite(6 , HIGH);
  digitalWrite(5, LOW);
  buf = analogRead(analogPin);
  buf = buf / 903;
  ref = 10000;

  
  buf2 = 1-buf;
  buf=buf*ref;
  R2=buf/buf2;
  
}

void highend () {
  digitalWrite(6, LOW);
  digitalWrite(5, HIGH);
  buf = analogRead(analogPin);
  buf = buf / 903;
  ref = 1000000;

  
  buf2 = 1-buf;
  buf=buf*ref;
  R2=buf/buf2;
}

I also tried using transistors instead of diodes but I could not calculate the error caused by the transistors in order to remove it , so I had to use this method , but for some unknown reason this does not work either.

I do not understand why my code/circuit fails , and I dont understand how to use the current mirror method , and I have been searching but I cant figure out a way to measure resistance with the arduino reliably that can measure 100~10M Ohms.

Another thing I thought of was to use the Voltage/Current sensor I am using in the project to calculate resistance as well , but that somehow seems like a bad idea to me because of the method current sensors are placed in circuits and because yet again I cant figure out how to use it.

any help is more than appreciated
thanks in advance

You can't measure 10M with the Arduino and get 10 bits accuracy. Perhaps 5% accurate is possible.
The current mirror is to create a small current. The transistors must have the same temperature. A small current through 10M can result into a voltage that can perhaps be read by the Arduino.

It is easer if you have a few pins with different resistors. Turn one output on, and the others off. An output is turned off when it is set as INPUT with pinMode().

Do not use diodes. That reduces the accuracy a lot.

Perhaps four pins with 1kΩ, 10kΩ, 100kΩ and 1MΩ resistors.
The 1MΩ will introduce noise and the ADC will not be accurate. You could add a capacitor of 1nF to 10nF to the analog input and GND to help the ADC a little. Also use the average of many samples.

Do not use a 100Ω resistor. The Arduino Uno can not supply enough current for a 100Ω resistor. A 220Ω will not damage the Arduino Uno, but the output voltage will be lowered, and that lowers the accuracy. I suggest to use at least 470Ω but 1kΩ is better for the lowest resistor value.

Once you get this working, then you can try a current mirror to test if that has any advantage over a simple resistor.

Arman5592:
Hi.
As part of an arduino multimeter project , I had this issue where I had to measure resistance with arduino. I did it a couple of times with a voltage divider and different reference resistors , but it did not cover a satisfactory range

Are you saying you have actually had code working which gave reasonable resistance measurement values ? Or has nothing really worked for you yet ?

I did notice the magic number '903', I can guess where this comes from and why it is not very accurate.
Did you dream this up ?

Yours,
TonyWilk

Koepel:
You can't measure 10M with the Arduino and get 10 bits accuracy. Perhaps 5% accurate is possible.
The current mirror is to create a small current. The transistors must have the same temperature. A small current through 10M can result into a voltage that can perhaps be read by the Arduino.

It is easer if you have a few pins with different resistors. Turn one output on, and the others off. An output is turned off when it is set as INPUT with pinMode().

Do not use diodes. That reduces the accuracy a lot.

Perhaps four pins with 1kΩ, 10kΩ, 100kΩ and 1MΩ resistors.
The 1MΩ will introduce noise and the ADC will not be accurate. You could add a capacitor of 1nF to 10nF to the analog input and GND to help the ADC a little. Also use the average of many samples.

Do not use a 100Ω resistor. The Arduino Uno can not supply enough current for a 100Ω resistor. A 220Ω will not damage the Arduino Uno, but the output voltage will be lowered, and that lowers the accuracy. I suggest to use at least 470Ω but 1kΩ is better for the lowest resistor value.

Once you get this working, then you can try a current mirror to test if that has any advantage over a simple resistor.

Thanks
My original intention was only ever 2 ranges - a 10k and a 1M would be sufficiently accurate since the goal is to have an operational ohmmeter (but not being able to measure some common values was an issue with a single range , hence the 2 ranges)
my problem is , I want only one analog pin to be used , to make it like a normal multimeter where 2 wires measure everything , which caused all the diodes and transistors issue.

So this means instead of using diodes for the digital pins , I can change their pinMode so no current moves there and they do not affect the other pin that is measuring ? and keep using 1 analog pin?

TonyWilk:
Are you saying you have actually had code working which gave reasonable resistance measurement values ? Or has nothing really worked for you yet ?

I did notice the magic number '903', I can guess where this comes from and why it is not very accurate.
Did you dream this up ?

Yours,
TonyWilk

well the single range - which I copied from somewhere and was my inspiration for the other versions of the code - did work , and so did my other single ranges , but I could not add a second range.

I wanted "buf" to be the value of Vout/Vin but instead of using 1023 for Vin I used 903 which is 1023 minus the diodes voltage drop :smiley: I know it is a bad method but at that point I had tried everything to find the issue , so I thought maybe that would help

Arman5592:
I wanted "buf" to be the value of Vout/Vin but instead of using 1023 for Vin I used 903 which is 1023 minus the diodes voltage drop :smiley:

Yeh, but that assumes a diode drops exactly 0.6v - if you have a meter, measure it.

Although your circuit is not ideal, you can try and make it a bit better by calibrating it...
Add 0.1uf from A0 to GND, this will make the readings a bit more stable (as Koepel says)

With D6 = HIGH and D5=LOW (just deal with the 10k for now), put in a 10k resistor to 'measure'
Add a delay(50) after setting the pins, before your analogRead. Use Serial.print to show you the value.

The value should be around 450 or so.
What you have there is the source voltage (after the diode) divided across two 10k resistors, your analog value is the reading across the bottom 10k... twice this value is the 'analogRead voltage' across both 10k resistors.
The value should be somewhere around 850 to 950. This is your 'calibrated' voltage value.

Then putting in a resistor to measure (e.g. 1k) you should be able to calculate:

float cal10k= 900;   // whatever value you got after measuring 10k *2
buf = analogRead(analogPin);
ohms= (buf * 10000.0 ) / ( cal10k - buf );

It won't be brilliant (the voltage across the diode will change with different resistors), but it should be close.

You can then try Koepel's suggestion... take out the diodes and set D6 as output HIGH and set D5 as INPUT. Do the calibrate thing again and try a measurement again.

Then try D6= INPUT, D5= OUTPUT HIGH, calibrate with a 1M ohm resistor, try measuring a 100k resistor.

I expect this last step using 1Mohm to not be very accurate because the Arduino pins set as INPUT still 'leak' a bit which will affect the reading.

Yours,
TonyWilk

Forget the diodes. That won't work.

The analog input requires stability and a lower impediance of the input signal (maximum 10k impedance for good accuracy of the ADC). That's what the capacitor is for, to compensate for high impedance when the 1M resistor is used.

The 10k impedance for an analog input is adviced in the datasheet. However, 100k is often no problem, and 1M is not really a problem either. You might get a lot of noise though.

@TonyWilk suggests 100nF from A0 to GND, and I suggest 1nF to 10nF.
Doing a rough math with 1M and 100nF will delay the input signal by a few seconds (until it is stable). Therefor a lower value is better for a multimeter. When constantly measuring a battery voltage, the 100nF is okay. For a quick test, you don't even need the capacitor.

A digital pin as input does not really leak, and what it leaks is not to GND or VCC. You can consider it as fully turned off when set as input. An open input is so high impedance, it can smell the charged ions in the air.

TonyWilk:
Yeh, but that assumes a diode drops exactly 0.6v - if you have a meter, measure it.

Although your circuit is not ideal, you can try and make it a bit better by calibrating it...
Add 0.1uf from A0 to GND, this will make the readings a bit more stable (as Koepel says)

With D6 = HIGH and D5=LOW (just deal with the 10k for now), put in a 10k resistor to 'measure'
Add a delay(50) after setting the pins, before your analogRead. Use Serial.print to show you the value.

The value should be around 450 or so.
What you have there is the source voltage (after the diode) divided across two 10k resistors, your analog value is the reading across the bottom 10k... twice this value is the 'analogRead voltage' across both 10k resistors.
The value should be somewhere around 850 to 950. This is your 'calibrated' voltage value.

Then putting in a resistor to measure (e.g. 1k) you should be able to calculate:

float cal10k= 900;   // whatever value you got after measuring 10k *2

buf = analogRead(analogPin);
ohms= (buf * 10000.0 ) / ( cal10k - buf );



It won't be brilliant (the voltage across the diode will change with different resistors), but it should be close.

You can then try **Koepel**'s suggestion... take out the diodes and set D6 as output HIGH and set D5 as INPUT. Do the calibrate thing again and try a measurement again.

Then try D6= INPUT, D5= OUTPUT HIGH, calibrate with a 1M ohm resistor, try measuring a 100k resistor.

I expect this last step using 1Mohm to not be very accurate because the Arduino pins set as INPUT still 'leak' a bit which will affect the reading.

Yours,
TonyWilk

Koepel:
Forget the diodes. That won't work.

The analog input requires stability and a lower impediance of the input signal (maximum 10k impedance for good accuracy of the ADC). That's what the capacitor is for, to compensate for high impedance when the 1M resistor is used.

The 10k impedance for an analog input is adviced in the datasheet. However, 100k is often no problem, and 1M is not really a problem either. You might get a lot of noise though.

@TonyWilk suggests 100nF from A0 to GND, and I suggest 1nF to 10nF.
Doing a rough math with 1M and 100nF will delay the input signal by a few seconds (until it is stable). Therefor a lower value is better for a multimeter. When constantly measuring a battery voltage, the 100nF is okay. For a quick test, you don't even need the capacitor.

A digital pin as input does not really leak, and what it leaks is not to GND or VCC. You can consider it as fully turned off when set as input. An open input is so high impedance, it can smell the charged ions in the air.

Thanks everyone . I did it with the input method , but noticed all the numbers were weird , so I did the calibration and added some lines which changed the weird numbers into real results , but I had trouble with the 1M resistor connected to the arduino no matter what capacitor value so I just used 1k and 100k instead of 10k and 1M , and redid the calibration and used 10nF and it works great !
thanks

1 Like