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)