Electronic – arduino – Reading very low capacitances with Arduino


I'm trying to measure the capacitance of a very low capacitance sensor (two parallel plates across a block of foam). This is a self-produced force sensor; I'm trying to eventually use some of the work presented here. I'm estimating that the capacitance should be in the neighborhood of 90 pF.

I started with the CapacitanceMeter tutorial from the Arduino web site. I modified it to use micros() instead of millis() and output pF instead of nF. I also swapped in a 10 megohm resistor in place of the 10K ohm one, and updated the code. However, I'm getting readings that swing by over 50 pF.

How can I improve the accuracy of the setup?


Best Answer

You can get an approximate measure of the capacitance with just 2 microcontroller pins, 1 resistor and 1 known capacitor. The circuit looks something like this:

cap sensing circuit

C2 is the unknown capacitance you're trying to measure. C1 is a reference capacitor of known value, and about 50-1000 times the value of C2. R1 isn't too critical, 1k Ohm or so.

The idea is to charge C2 with a known voltage (5 or 3.3 V, whatever V+ is), and then transfer its charge (q = C*V) into C1. Each time we transfer the charge from C2 to C1, C1's voltage increases by a tiny amount proportional to C2. The number of times we have to transfer charge to make C1's voltage exceed some threshold (for us, the logical "1" threshold of pin A) is then inversely proportional to the value of C2.

The trick is to take advantage of the high-impedance state of the microcontroller pins. If we kept the bottom side of C1 grounded while charging C2, then we would also end up fully charging C1. Instead, we let the bottom side of C1 float by configuring pin B as high-impedance. Now, whatever the top side of C1 does, the bottom side does too, always keeping the same voltage across C1.

The measurement algorithm goes like this (in pseudo-C):

// Step 0: discharge C1 to prepare for a new measurement
PIN_A = 0;
PIN_B = 0;
delay(some_time); // long enough to discharge C1

bool under_threshold = true; // has the voltage across C1 exceeded the threshold?
int count = 0;
while (under_threshold)
    // Step 1: Charge C2
    PIN_B = Z; // Z means high-impedance
    PIN_A = 1;
    delay(some_time); // long enough to charge C2

    // Step 2: Transfer charge from C2 to C1
    PIN_A = Z;
    PIN_B = 0;
    delay(some_time); // long enough for C2 to discharge into C1

    // Step 3: Check if the threshold is exceeded
    if (PIN_A || (count > COUNT_MAX))
        under_threshold = false;
return count;

You can see a demonstration of the circuit at https://www.circuitlab.com/circuit/uq2zs6/cap-sensing/