Using Digital I/O as analog input (working!)

Here's a program that will measure an analog value (currently set up as measuring resistance) that can measure an extremely wide range of resistances from around 300ohms to 2.2meg ohms tested so far. Expect about +-4% accuracy (usually 4% too high on resistance). With my setup the measurements were very stable. This is great for getting analog input that will blow the 10bit onboard ADC away.

Here's a picture of circuit and equation. the unlabeled resistor is the one you want to measure

Anyway you can remove all the analog pin usage ( they're just there to measure voltage before and after the pin goes high). Call measureOhms(digitalPin) with digitalPin as the pin that the circuit is on, so you can easily use this for multiple pins. As for timings the larger the capacitor, the longer it will take to measure resistance. You can fix this by using a smaller capacitor, and if your resistance is too low then use larger capacitors for the timing to be large enough for the arduino to measure

Here's how it works

The capacitor gets discharged by the arduino, then the blue line's rising edge means that the digital pin has been set to input. The falling edge on the blue line is when the digital input triggers as HIGH. the arduino then compares the uptime before and after the capacitor started to charge. Resistor calculations can be done knowing initial volts (0v), final volts (2.55v), and the difference in time.

double arduinoVoltage = 4.94; 
 int Vpin = A0;
 
 int digitalPin = 12;

 int analogValuePrior = 0;
 int analogValueAfter = 0;


void setup() {                
  
  Serial.begin(9600);
  delay(100); 
  Serial.print("on");
  
}

void loop() {
  

  
  Serial.print("resistance: ");
  Serial.println(measureOhms(digitalPin));
  Serial.print("ohms");
  
  Serial.print("voltage prior: ");
  Serial.println(analogValuePrior/1023.*arduinoVoltage);
  Serial.print("voltage after: ");
  Serial.println(analogValueAfter/1023.*arduinoVoltage);
  Serial.print("\n\n");
  delay(500);
  
}

double measureOhms(int pinNum){ //pinNum is the digital i/o pin

 double timeStart = 0;
 double timeEnd = 0;
 double timeMicroSec = 0;


  timeMicroSec = 0; 
  pinMode(digitalPin, OUTPUT);
  digitalWrite(digitalPin,LOW);
  delay(2); //discharge the cap
  
  pinMode(digitalPin,INPUT);
  //timeMicroSec = pulseIn(digitalPin, LOW);
                                                      analogValuePrior = analogRead(Vpin);
  timeStart = micros();
  
   while(digitalRead(digitalPin) == LOW){}//wait for the pin to go HIGH
  
  timeEnd = micros();
                                                      analogValueAfter = analogRead(Vpin);
  timeMicroSec = timeEnd - timeStart;
  
  return convertToResist(timeMicroSec);
}


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)    );

}

A good example of lateral thinking. :slight_smile:

Could come in handy some day.

Good work!
I was always told that a voltage between digital HIGH and LOW will be giving indeterminate digital levels. So does your digital pin always turns LOW/HIGH at the same voltage and won't flip in the undefined voltage range? I'm curious.

So does your digital pin always turns LOW/HIGH at the same voltage and won't flip in the undefined voltage range? I'm curious.

It will vary a little with the specific Vcc voltage on the chip and with temperature changes. It's normally not a recommended method to read a digital input, but working 'outside' the box sometimes gives decent results even if not the established method.

Lefty

This is kind of like an integrating ADC, which can be very accurate but slow.

The ATMEGA chips have built-in voltage comparators that can be used for things like this more precisely, but I don't know how to access them using strictly arduino code.

This is great for getting analog input that will blow the 10bit onboard ADC away.

Hard to see how that is justified. The resolution is poorer, it takes longer to read a sample and it ties up the CPU while you are doing it. But well done anyway.