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
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);
}
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
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
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("Ω");
}
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
How It Works
- Charge the capacitor through R_unknown
- Measure time to reach a specific voltage threshold
- 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);
}
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
Arduino Code
cpp
// When bridge is balanced: R_unknown = (R2 × R3) / R1
// For unbalanced bridge, use differential measurement
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;
}
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);
}
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)