Black Lives Matter - Action and Equality. ... Adafruit joins the Stop Hate for Profit campaign.

measuring resistance with only digital I/O, no ADC (working!)

Here is some code to get a pretty good estimation of a resistor from about 10k to 2.4M ohms. This method measures the resistance digitally without an ADC. Using this method someone can also get above 10bit analog in with only a capacitor and resistor. I was getting results of around +-3% accuracy (33k to 400k tested). 2.2M measured as 2.16M. 10k came out to be about .7k. It will be less accurate at lower resistance values. Equation is shown below, tune it to suite your needs

EDIT: sorry the unlabeled resistor is the one you want to measure. Also if you notice a mistake in the formula, think of it as delta voltage
circuit and formulas you can remove all the analog reads and resistance measurement will continue to work. The previous analog should be very close to zero (.01v) and the post analog should be around 2.55v.

disreguarding calculation times the whole thing will time out after 176mili seconds
(with r = 2.46M ohms and .1uF it will be near the limit). Time will be much shorter with lower resistance (expect 10ish mili sec)

Code: Select all | TOGGLE FULL SIZE
`  double arduinoVoltage = 4.94;  int Vpin = A0; int digitalPin = 12; int timeMicroSec = 0; int analogValuePrior = 0; int analogValueAfter = 0; void setup() {                    Serial.begin(9600);  delay(100);   Serial.print("on");  }void loop() {  timeMicroSec = 0;   pinMode(digitalPin, OUTPUT);  digitalWrite(digitalPin,LOW);  delay(2); //discharge the cap    pinMode(digitalPin,INPUT);  //timeMicroSec = pulseIn(digitalPin, LOW);    analogValuePrior = analogRead(Vpin);    while(digitalRead(digitalPin) == LOW){//wait for the pin to go HIGH    delayMicroseconds(1);    timeMicroSec++;        if(timeMicroSec > 32700){ //max is +-32767          Serial.println("timeout..........");      goto error;    }          }    error:      analogValueAfter = analogRead(Vpin);    Serial.print("voltage prior: ");  Serial.println(analogValuePrior/1023.*arduinoVoltage);  Serial.print("voltage after: ");  Serial.println(analogValueAfter/1023.*arduinoVoltage);  Serial.print("time MicroSec:");  Serial.println(timeMicroSec*5.37);//the 5.37 is a correction due to the fact that the counter has loop time, so the counter is off.   //should be linear though, which only needs a linear correction (checked with +-3% accuracy from 33k - 500k)    Serial.print("resistance: ");  Serial.println(convertToResist(timeMicroSec*5.37));  Serial.print("ohms");    delay(500);  }double convertToResist(double timeMicroSec){  double voltageTrigger = 2.55;  //double Vin = 4.94;  double capacitorUF = .1; // value of capacitor in micro farads (larger cap means you can measure lower resistance resistors)  return (  pow( -log(-voltageTrigger/arduinoVoltage + 1)*capacitorUF/(timeMicroSec),-1)    );}`

You should be able to get this working with pulseIn, but i couldn't and this isn't terribly bad. Anyway this is mainly for a propeller microcontroller (it doesnt have on board ADC....wtf?). Thought i'd try it with arduino too.
Last edited by thefatmoop on Mon Jan 31, 2011 1:29 am, edited 2 times in total.
thefatmoop

Posts: 352
Joined: Tue Aug 19, 2008 4:36 pm

Re: measuring resistance with only digital I/O, no ADC (working!)

This would be a good start out program if you wanted to measure resistance, capacitance, voltage, or current using just a digital i/o

A good edit someone may want to make is to store the uptime before the test and after the pin goes high. then subtract the two to find the total time it took. Here's why:

Code: Select all | TOGGLE FULL SIZE
`  while(digitalRead(digitalPin) == LOW){//wait for the pin to go HIGH    delayMicroseconds(1);    timeMicroSec++;    if(timeMicroSec > 32700){ //max is +-32767      Serial.println("timeout..........");      goto error;    }    }`

this block of code adds 1us every round, but on this small of a time scale the microcontroller's computation times will start adding in significant error, hence the
Code: Select all | TOGGLE FULL SIZE
`Serial.println(timeMicroSec*5.37);`
correction

bad programming that i'll fix later
thefatmoop

Posts: 352
Joined: Tue Aug 19, 2008 4:36 pm

Re: measuring resistance with only digital I/O, no ADC (working!)

@fatmoop - Cool little circuit! Slightly off topic, but for the Propeller, a better way to read analog voltages is using a Delta Sigma circuit. Just requires 2 resistors + 2 caps and you can get 11-bit resolution @ 40kHz or 14-bit @ 5kHz. I did a tutorial on it right here. nmcclana

Posts: 5
Joined: Wed Jul 30, 2008 11:15 pm

Re: measuring resistance with only digital I/O, no ADC (working!)

very cool i'll have to try that. The other main member of the microcontroller team is using the smd prop board you make.

Here's an updated program and some great pictures of the circuit on an oscilloscope

http://arduino.cc/forum/index.php/topic,50642.0.html
thefatmoop

Posts: 352
Joined: Tue Aug 19, 2008 4:36 pm

Re: measuring resistance with only digital I/O, no ADC (working!)

Great shot of the O'scope! nmcclana

Posts: 5
Joined: Wed Jul 30, 2008 11:15 pm

Re: measuring resistance with only digital I/O, no ADC (working!)

Hey guys,

This might be my first post ever to a forum and also a couple of years late. I used this for a project I was working on. Here is my updated code. I have a project with up to 6 'sensor boards' and to report those numbers back to my web server output I have either a 100,200,300,400,500 or 600K resistor as resistor X (or the unlabeled) resistor in the above schematic. For some reason I had to divide by 14 to get the resistance right, but I am using an Arduino Mega 2560, maybe it has to do with the clock timing on that chip. Works great though and reports back to me which board number, 1-6, my sensor's are on. This is just a snip of code, look for more when I am not swamped. Wanted to return the updated code if anyone finds it useful. GREAT INITIAL POST! thefatmoop, you are a life saver! :) Also, I DID use the optional A0 debug 10K resistor. That circuit is on each sensor board. Each sensor board then uses a digital pin, starting at 19 and going down that row, 6 in total. Those each have the 100, 200, 300, 400, 500, or 600K resistor attached. My sensor circuit is separate, using digital or analog pins, whichever is required by that particular sensor, for example sensor board 1 has a Modern Devices Humidity/Temp (SDA/SCL) and an Ambient light (analog). Sensor board 2 has a parallax motion sensor (digital). Sensor board 3, etc.

double arduinoVoltage = 4.94;
int Vpin = A0;
int digitalPin = 21;
int timeMicroSec = 0;
int analogValuePrior = 0;
int analogValueAfter = 0;
float roundedvalue = 0;
int finalboardnum = 0;

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

void loop() {
timeMicroSec = 0;
pinMode(digitalPin, OUTPUT);
digitalWrite(digitalPin,LOW);
delay(2); //discharge the cap
pinMode(digitalPin,INPUT);

while(digitalRead(digitalPin) == LOW){//wait for the pin to go HIGH
delayMicroseconds(1);
timeMicroSec++;

if(timeMicroSec > 32700){ //max is +-32767

Serial.println("timeout..........");
goto error;
}

}
error:
roundedvalue = (convertToResist(timeMicroSec*5.37)/14)/100;
roundedvalue = round(roundedvalue);
finalboardnum = (roundedvalue/10)*10;
Serial.println(finalboardnum);
delay(500);
}
double convertToResist(double timeMicroSec){
double voltageTrigger = 2.55;
//double Vin = 4.94;
double capacitorUF = .1; // value of capacitor in micro farads (larger cap means you can measure lower resistance resistors)
return ( pow( -log(-voltageTrigger/arduinoVoltage + 1)*capacitorUF/(timeMicroSec),-1) );
}
mainphrame

Posts: 1
Joined: Wed Mar 16, 2011 7:18 pm

Re: measuring resistance with only digital I/O, no ADC (working!)

Wrote about this on my site. Can also be used to measure voltage using 1 digital i/o.

http://reibot.org/2011/05/23/measuring- ... igital-io/
thefatmoop

Posts: 352
Joined: Tue Aug 19, 2008 4:36 pm