DEV Community

Hedy
Hedy

Posted on

How to meaure resistance on a microcontroller?

Measuring resistance with a microcontroller is a fundamental task, but microcontrollers can't directly measure resistance - they can only measure voltage. Therefore, we need to use the microcontroller's ADC (Analog-to-Digital Converter) in clever circuit configurations to determine resistance.

Here are the most common and practical methods, from simplest to most advanced.

Method 1: Voltage Divider (Most Common & Practical)
This is by far the most widely used method for measuring resistance in the range of ~100Ω to ~1MΩ.

Circuit Diagram

text

     Vcc (e.g., 3.3V)
      |
     +-+
     | | R_ref (Known reference resistor)
     +-+
      |---→ To ADC Pin & AIN
      |
     +-+
     | | R_unknown (Resistor to measure)
     +-+
      |
     GND
Enter fullscreen mode Exit fullscreen mode

How It Works

  • The voltage at the ADC pin (V_adc) depends on the ratio of R_unknown to R_ref
  • Using the voltage divider formula: V_adc = Vcc × (R_unknown / (R_ref + R_unknown))
  • Solve for R_unknown: R_unknown = R_ref × (Vcc / V_adc - 1)

Arduino Code Example

cpp

const int ADC_PIN = A0;
const float VCC = 3.3;        // Microcontroller voltage
const float R_REF = 10000.0;  // 10kΩ reference resistor

void setup() {
  Serial.begin(9600);
  analogReference(EXTERNAL);  // Use external reference if available
}

void loop() {
  int adcValue = analogRead(ADC_PIN);
  float voltage = (adcValue / 1023.0) * VCC;

  // Calculate unknown resistance
  float R_unknown = R_REF * (VCC / voltage - 1.0);

  Serial.print("ADC Value: "); Serial.print(adcValue);
  Serial.print(" | Voltage: "); Serial.print(voltage, 3);
  Serial.print("V | Resistance: "); Serial.print(R_unknown);
  Serial.println("Ω");

  delay(1000);
}
Enter fullscreen mode Exit fullscreen mode

Choosing R_ref

  • For similar resistance ranges: Choose R_ref ≈ expected R_unknown
  • For wide range: Use multiple R_ref values with analog multiplexer
  • Typical values: 1kΩ, 10kΩ, 100kΩ, 1MΩ

Method 2: Constant Current Source (More Accurate)
This method uses a constant current source and measures the voltage drop across the unknown resistor.

Circuit Diagram

text

     Vcc
      |
     Constant Current Source
      |
     +-+
     | | R_unknown
     +-+
      |---→ To ADC Pin
      |
     GND
Enter fullscreen mode Exit fullscreen mode

How It Works

  • A constant current I flows through R_unknown
  • Measure voltage: V_adc = I × R_unknown
  • Calculate: R_unknown = V_adc / I

Simple Constant Current Source using LM317

text

LM317 Configuration:
V_in → LM317 → R_set → R_unknown → GND
          |           |
        Adj Pin     To ADC
Enter fullscreen mode Exit fullscreen mode

With: I = 1.25V / R_set

Arduino Code

cpp

const float CURRENT = 0.001;  // 1mA constant current

void loop() {
  int adcValue = analogRead(ADC_PIN);
  float voltage = (adcValue / 1023.0) * VCC;

  float R_unknown = voltage / CURRENT;

  Serial.print("Resistance: "); Serial.print(R_unknown); 
  Serial.println("Ω");
}
Enter fullscreen mode Exit fullscreen mode

Advantages: Linear relationship, good accuracy
Disadvantages: More complex circuit, limited current range

Method 3: Capacitive Timing (For Very High Resistances)
This method is excellent for measuring very high resistances (>1MΩ) where ADC resolution is insufficient.

Circuit Diagram

text

     Vcc
      |
     +-+
     | | R_unknown
     +-+
      |
     === C (Known capacitor, e.g., 0.1µF)
      |
     GND
     |
Digital Pin ---→ To same junction
Enter fullscreen mode Exit fullscreen mode

How It Works

  1. Charge the capacitor through R_unknown
  2. Measure time to reach a specific voltage threshold
  3. Time constant τ = R × C

Arduino Code

cpp

const int CHARGE_PIN = 7;
const int MEASURE_PIN = A0;
const float CAPACITANCE = 0.1e-6;  // 0.1µF

void setup() {
  pinMode(CHARGE_PIN, OUTPUT);
  Serial.begin(9600);
}

void loop() {
  // Discharge capacitor
  digitalWrite(CHARGE_PIN, LOW);
  pinMode(MEASURE_PIN, INPUT);
  delay(1000);

  // Start charging and timing
  unsigned long startTime = micros();
  digitalWrite(CHARGE_PIN, HIGH);

  // Wait for capacitor to charge to ~63.2% (1 time constant)
  int threshold = (int)(1023 * 0.632);
  while(analogRead(MEASURE_PIN) < threshold) {
    // Wait...
  }

  unsigned long chargeTime = micros() - startTime;

  // Calculate resistance: τ = R × C
  float R_unknown = (chargeTime / 1000000.0) / CAPACITANCE;

  Serial.print("Charge Time: "); Serial.print(chargeTime);
  Serial.print("µs | Resistance: "); Serial.print(R_unknown);
  Serial.println("Ω");

  delay(1000);
}
Enter fullscreen mode Exit fullscreen mode

Method 4: Wheatstone Bridge (High Precision)
For applications requiring high precision and sensitivity.

Circuit Diagram

text

     Vcc
      |
     +-+     +-+
     | | R1  | | R3 (Reference)
     +-+     +-+
      |       |
      |---→ ADC Pin
      |       |
     +-+     +-+
     | | R2  | | R_unknown
     +-+     +-+
      |       |
     GND     GND
Enter fullscreen mode Exit fullscreen mode

Arduino Code

cpp

// When bridge is balanced: R_unknown = (R2 × R3) / R1
// For unbalanced bridge, use differential measurement
Enter fullscreen mode Exit fullscreen mode

Practical Considerations & Tips
1. ADC Resolution Matters

  • 10-bit ADC (Arduino): 0-1023 values → Limited precision
  • 12-bit ADC: 0-4095 values → Better precision
  • 16-bit ADC (ADS1115): 0-65535 values → High precision

2. Reference Voltage Stability

  • Use a stable voltage reference (not the power supply)
  • Consider external reference chips (e.g., REF3030)

3. Noise Reduction

cpp

// Software averaging
float readAveragedADC(int pin, int samples) {
  long sum = 0;
  for(int i = 0; i < samples; i++) {
    sum += analogRead(pin);
    delay(1);
  }
  return (float)sum / samples;
}
Enter fullscreen mode Exit fullscreen mode

4. Auto-Ranging Circuit
For measuring a wide resistance range (1Ω to 10MΩ):

cpp

// Use multiple reference resistors with analog multiplexer
const int R_REF_LOW = 100;     // 100Ω
const int R_REF_MED = 10000;   // 10kΩ  
const int R_REF_HIGH = 1000000;// 1MΩ

int selectReferenceResistor(int range) {
  // Control multiplexer to select appropriate R_ref
  digitalWrite(RANGE_LOW_PIN, range == 0);
  digitalWrite(RANGE_MED_PIN, range == 1);
  digitalWrite(RANGE_HIGH_PIN, range == 2);
}
Enter fullscreen mode Exit fullscreen mode

5. 4-Wire Measurement (For Low Resistances)
Eliminates wire resistance by using separate force and sense lines.

Quick Comparison Table

Summary
For most applications, start with Method 1 (Voltage Divider) - it's simple, requires minimal components, and works well for a wide range of resistances. Choose your reference resistor to be in the same order of magnitude as the resistance you expect to measure for best accuracy.

The voltage divider approach gives you the best balance of simplicity and performance for most microcontroller-based resistance measurement applications.

Top comments (0)