To measure capacitance with an Arduino, you charge an unknown capacitor through a known precision resistor and use the micros() function to time how long it takes the voltage to reach 63.2% of Vcc. Using the RC time constant formula ($C = \tau / R$), the microcontroller calculates the capacitance. While dedicated LCR meters use AC impedance, this DC charge-timing method is highly effective for the 1nF to 1000µF range, provided you calibrate out the microcontroller's internal parasitic capacitance.
Hardware BOM & Pin Mapping
Accuracy in RC timing is entirely dependent on the tolerance of your charge resistor and the stability of your logic voltage. Do not use a standard 5% carbon film resistor for this build; the error will compound directly into your capacitance reading.
| Component | Specification / Part Number | Notes |
|---|---|---|
| Microcontroller | Arduino Uno R3 (ATmega328P) | 5V logic and predictable ADC clock prescaler required. |
| Charge Resistor | 10kΩ 1% Metal Film (e.g., Vishay MRS25) | 1% tolerance minimum. 10kΩ covers 1nF to 1000µF. |
| Test Capacitor | Unknown (Target: 1nF - 1000µF) | Discharge electrolytics before inserting. |
| Prototyping | 400-point breadboard & 22 AWG jumpers | Keep leads short to minimize stray inductance. |
Pin Mapping Table
| Arduino Pin | Function | Connection |
|---|---|---|
| Digital 8 | Charge / Discharge Control | Connects to one leg of the 10kΩ resistor. |
| Analog A0 | Voltage Sense (ADC) | Connects to the junction of the resistor and capacitor. |
| GND | Circuit Common | Connects to the negative leg of the capacitor. |
The Physics: RC Timing and Parasitic Ghosts
When a DC voltage is applied to an RC circuit, the voltage across the capacitor rises exponentially. The time it takes to reach exactly 63.2% of the supply voltage is defined as one time constant ($\tau$). The governing equation is:
τ = R × C therefore C = τ / R
On a 5V Arduino Uno, 63.2% of Vcc is 3.16V. The 10-bit ADC maps 0-5V to 0-1023. Therefore, 3.16V corresponds to an ADC reading of 647. The firmware simply starts a timer, sets the charge pin HIGH, and waits for analogRead(A0) >= 647.
The Parasitic Capacitance Problem
Most basic tutorials ignore the microcontroller's own hardware. According to the Microchip ATmega328P datasheet, the I/O pin parasitic capacitance is roughly 10pF, and the internal ADC sample-and-hold capacitor adds another ~14pF. This creates a baseline offset of ~24pF.
If you are measuring a 10,000µF electrolytic, 24pF is irrelevant. But if you are measuring a 100pF ceramic disc, that 24pF ghost will cause a massive 24% measurement error. Furthermore, with a 10kΩ resistor and the 4µs resolution of the micros() function on a 16MHz AVR, your practical lower measurement limit is around 1nF. To measure picofarads accurately, you must step up to a 1MΩ charge resistor or bypass the ADC entirely in favor of the internal analog comparator.
Firmware: Compilable RC Measurement Code
The following C++ code targets the Arduino Uno R3 (ATmega328P). It includes a discharge cycle to ensure the capacitor starts at 0V, a timeout safeguard to prevent infinite loops, and a software offset to nullify the ~24pF parasitic ghost.
/*
* Arduino RC Capacitance Meter
* Target: Arduino Uno R3 (ATmega328P)
* Method: RC Time Constant (63.2% Vcc threshold)
*/
#define CHARGE_PIN 8
#define ANALOG_PIN A0
#define RESISTOR_OHMS 10000.0
#define PARASITIC_PF 24.0 // Estimated pin + ADC capacitance in pF
#define THRESHOLD 647 // 63.2% of 1023 (5V logic)
#define TIMEOUT_US 5000000 // 5 second timeout
void setup() {
Serial.begin(115200);
pinMode(CHARGE_PIN, OUTPUT);
digitalWrite(CHARGE_PIN, LOW); // Ensure safe start state
Serial.println("Capacitance Meter Ready. Insert capacitor.");
}
void loop() {
// 1. Discharge the capacitor completely
pinMode(CHARGE_PIN, OUTPUT);
digitalWrite(CHARGE_PIN, LOW);
delay(500); // Allow time for large caps to drain
// 2. Begin charge cycle and timing
unsigned long startMicros = micros();
digitalWrite(CHARGE_PIN, HIGH);
unsigned long elapsedMicros = 0;
bool timeout = false;
// 3. Poll ADC until threshold or timeout
while (analogRead(ANALOG_PIN) < THRESHOLD) {
elapsedMicros = micros() - startMicros;
if (elapsedMicros > TIMEOUT_US) {
timeout = true;
break;
}
}
// 4. Stop charging
digitalWrite(CHARGE_PIN, LOW);
// 5. Calculate and output results
if (timeout) {
Serial.println("Error: Charge timeout - check capacitor range or wiring");
} else {
// C = t / R. Result in Farads if t is seconds and R is Ohms.
// We have t in microseconds, so result is in microfarads (uF).
double capacitance_uF = (elapsedMicros / RESISTOR_OHMS);
double capacitance_nF = capacitance_uF * 1000.0;
double capacitance_pF = capacitance_nF * 1000.0;
// Apply parasitic offset correction
capacitance_pF -= PARASITIC_PF;
if (capacitance_pF < 0) capacitance_pF = 0;
Serial.print("Time: "); Serial.print(elapsedMicros); Serial.println(" us");
if (capacitance_pF < 1000.0) {
Serial.print("Capacitance: "); Serial.print(capacitance_pF, 2); Serial.println(" pF");
} else if (capacitance_nF < 1000.0) {
Serial.print("Capacitance: "); Serial.print(capacitance_nF, 2); Serial.println(" nF");
} else {
Serial.print("Capacitance: "); Serial.print(capacitance_uF, 3); Serial.println(" uF");
}
}
delay(2000); // Pause before next reading
}
Debugging: First Three Checks & Timeout Errors
When working with analog timing circuits, the physical layer is usually the culprit. If your serial monitor outputs the exact string: "Error: Charge timeout - check capacitor range or wiring", the microcontroller waited 5 seconds without the ADC reaching the 647 threshold.
- Polarity & Shorts: If testing an electrolytic capacitor, ensure it is not inserted backwards. A reverse-biased electrolytic will act as a partial short, clamping the voltage well below the 3.16V threshold.
- Resistor Verification: Do not trust the color bands. Measure your 10kΩ resistor with a multimeter. If you accidentally grabbed a 1MΩ resistor, the charge time for a 10µF capacitor jumps from 0.1 seconds to 10 seconds, triggering the timeout.
- Capacitor Range Limit: The 5-second timeout caps the maximum measurable capacitance at roughly 500µF with a 10kΩ resistor. If you are testing a 2200µF or 4700µF capacitor, increase the
TIMEOUT_USconstant in the code to 20000000 (20 seconds).
Scaling the Design: Auto-Range vs. 555 Timer Simplification
The single-resistor RC method is an excellent bench prototype, but it lacks the dynamic range of a commercial LCR meter. Depending on your end goal, you should either extend the hardware or simplify the topology.
How to Extend: Auto-Ranging via Multiplexer
To measure from 10pF up to 10,000µF without swapping resistors manually, integrate a CD4051 analog multiplexer. Wire four different precision resistors (e.g., 1kΩ, 10kΩ, 100kΩ, 1MΩ) to the multiplexer channels. Use three Arduino digital pins to select the channel. The firmware should start with the 1kΩ resistor; if a timeout occurs, it switches to the 10kΩ, and so on, effectively creating an auto-ranging capacitance meter.
How to Simplify: The 555 Timer Astable Method
If you find polling the ADC and managing microsecond timing too resource-intensive (or if you are using a board with a noisy ADC), offload the timing to hardware. Wire a NE555 timer in an astable configuration where the unknown capacitor dictates the oscillation frequency. Feed the 555 output into an Arduino digital pin and use the pulseIn() function to read the period. As detailed in All About Circuits' RC timing resources, frequency is inversely proportional to capacitance in this topology, completely bypassing the need for analog voltage threshold tracking.
Frequently Asked Questions
Can I measure very small capacitance (pF) with an Arduino?
Yes, but not reliably with the standard analogRead() and 10kΩ resistor method. The 4µs resolution of micros() on a 16MHz ATmega328P means a 10pF capacitor charging through 10kΩ (which takes 0.1µs) will register as 0µs. To measure picofarads, you must use a much larger charge resistor (e.g., 1MΩ to 10MΩ) to stretch the time constant into the measurable microsecond range, or utilize the Arduino's internal analog comparator which responds in nanoseconds.
Why does my Arduino capacitance reading drift over time?
Drift is almost always caused by dielectric absorption (also known as battery action) in electrolytic and some film capacitors. When you discharge the capacitor via the digital pin, the dielectric material doesn't release all its stored energy instantly. It slowly bleeds charge back into the circuit, artificially raising the baseline voltage before the next charge cycle begins. To fix this, increase the discharge delay in the code from 500ms to 2000ms, or add a physical bleed resistor (e.g., 100kΩ) in parallel with the test capacitor.
Is the Arduino capacitance meter method accurate enough for matching audio capacitors?
For rough binning (e.g., separating 10µF caps into 9µF and 11µF piles), yes. However, for precision audio crossover networks where 1% tolerance matters, no. The DC charge method measures the bulk capacitance but ignores the Equivalent Series Resistance (ESR) and the capacitance drop-off at high AC frequencies. For audio matching, you need an AC-bridge LCR meter that tests the component at 1kHz or 10kHz, as detailed in the Arduino hardware documentation community forums where users frequently hit the limits of DC timing for AC signal-path components.






