Arduino Capacitance Meter
In this tutorial we will use the Arduino Uno along with an RC circuit to create a capacitance meter!
Throughout, we will learn about the principles of a capacitor and how we can leverage that to make a meter that can measure as low as 4pF! This meter has an uncertainty of ~+/-800pF due to interesting constraints of the Arduino that we will soon go through!
This tutorial is meant as a resource to learn important tips and tricks about the Arduino along with a fun and interesting application.
I hope you enjoy!
Supplies
- Arduino (ie. Uno)
- Resistors 10Ω, 3x100Ω, 1MΩ
- 2x NPN Transistors
- Comparator IC or Op Amp (ie. LM741)
- Atleast 5 control capacitors (ie. 10pF, 100pF, 1nF, 100nF, 1uF)
- Assorted capacitors to test
Understanding Principles
The charge on a capacitor is proportional to its capacitance C via the following relation: q=CV
When placed in series with a resistor and connected to a power supply it will charge to the source voltage.
When the potential is removed and the capacitor has a path connecting its electrodes to discharge, it will do so according to the relationship Vc = V0e^-t/RC. Rearranging, we can see that for the voltage on a capacitor to fall from V0 to Vc, the time taken for a capacitor to discharge is given by t=aRC where a = ln(V0/Vc).
Using this relationship, we should be able to use an arduino to measure how long it takes for a capacitor to discharge and knowing the resistance of the circuit, calculate its capacitance.
In practice, circuits have parasitic impedance. Our circuit contains wires, an arduino and transistors which possess internal resistance, capacitance and inductance. This makes it hard for us to calculate R exactly.
To get around this, we can model our capacitor discharge time as t=kC+b where k is a proportionality constant characteristic of our circuit. Along with the offset b, these can be calibrated using capacitors of known capacitance.
Constructing the Circuit
The above circuit can be broken up into distinct parts.
- The resistor and capacitor in series form the RC charging circuit that we wish to measure
- The rightmost transistor acts as a switch allowing the arduino to enable (when on) or disable (when off) the discharging of the capacitor. The resistor acts as a current limiter.
- The leftmost transistor acts as a switch allowing the arduino to enable (when on) or disable (when off) the charging of the capacitor. The resistor acts as a current limiter.
- The comparator/op amp allows the arduino to rapidly poll when the capacitor passes a particular voltage threshold that we set using the 2 resistor voltage divider. The voltage divider is set to provide the inverting input of the comparator a voltage as low as possible to maximise the amount of time a capacitor can take to discharge. This allows us to further support measurements of lower capacitances
It's important to note the location of where the capacitor's voltage is sampled - in between the capacitor and resistor. As the arduino is always using ground as a reference, this location is crucial for getting accurate readings of the voltage profile. To see this better, play around with the circuit simulation in the next step.
Note
- A comparator would be ideal as unlike an op amp, it has a much wider output headroom which allows us to measure lower voltages and thus (given our time measuring restraints mentioned later) smaller capacitances.
- A comparator also has a much faster slew rate, unlike the LM741 op amp which means it can react to changes in voltage sooner. This is not so much of a problem as our calibration will take this into account.
Simulating Circuit Behaviour
Before going on to program the arduino, it's important to check that the circuit connections have all been made correctly. To get a sense of correct behaviour, it is extremely useful to simulate this circuit in a free, open source program such as LTSpice. The following .asc file can be downloaded for you to open and play with. It may be useful to view some tutorials on youtube for the program's basic use.
If you are comfortable with using LTSpice, you can test two scenarios of the circuit, charging and discharging. You can then see a graph (like the one attached) of how the voltage across the capacitor, opamp input and op amp output changes. Aside from being super cool, it helps to see what the arduino is measuring.
Scenario 1 - Charging:
- Set IC(Capacitor)=0 so there is no preexisting charge on the capacitor.
- Turn the charging transistor on (connect base to 5V)
- Turn the discharge transistor off (connect base to ground
Scenario 2 - Discharging:
- Set IC(Capacitor)=5 so the capacitor is initially charged.
- Turn the charging transistor off (connect base to ground)
- Turn the discharge transistor off (connect base to 5V)
Downloads
Programming the Arduino
The code here makes use of a few extremely useful, albeit a little advanced topics.
Firstly, we make use of interrupts to conveniently detect when someone inserts a capacitor they want to measure. As the capacitor is inserted, it completes a circuit path and causes a voltage to be dropped over the 1M ohm resistor as the capacitor charges up. Note that on the Uno, only digital pins 2 and 3 can be used to attach interrupts.
attachInterrupt(digitalPinToInterrupt(insertPin), onCapCharging, FALLING);
When a capacitor is detected, the arduino will make sure its charged up by waiting a second or two before it toggles both transistors into opposite states instantaneously and starts checking if the capacitor has fallen to the voltage set by the comparators inverting input.
To achieve this, we have to read and write to the GPIO pins directly as Arduino's digitalRead function takes almost 100us to execute! Which is an order of magnitude larger than some of the capacitor charge times we wish to measure. We also need to disconnect the charge circuit and connect the discharge circuit as close in time as possible to ensure correct discharge behaviour.
The way we read and write to GPIO pins directly is through using Arduino Port Manipulation. As this requires an understanding of bitwise operations, it may be useful to brush up using Arduino's resource.
PORTD is a byte in which each bit represents the outputs of the digital pins 0-7.
As such we create a mask for chargePin and dischargePin (which control respective transistors)
(1 << chargePin) | (1 << dischargePin)
We then use this mask to toggle those particular bits with a XOR bitwise operation (^)
PORTD ^=((1 << chargePin) | (1 << dischargePin));
To read the state of measurePin which is connected to the output of the comparator, checking if it's high, we simply execute:
bitRead(PIND, measurePin) == HIGH
Running simple tests, we can see this is faster than digitalRead by a factor of 25!
Lastly, the arduino code allows you to calibrate the device using linear regression upon giving it a few capacitors to measure. To initiate this process make sure the following lines are equal to 0
double capacitancePerTime = 0; // proportionality constant for t=kC [pF/us] double capacitanceOffset = 0; // offset for model
With that out of the way, test it out and see how you go! The next step will be evaluating the performance of this device.
Downloads
Evaluating Performance
Let's evaluate how accurate and precise this device is!
To begin, let's lay out the constraints of the circuit posed by the elements we've chosen and the Arduino Uno as a time keeping device.
In terms of accuracy, the following factors affect our ability to correctly calculate capacitance using this method.
- The major limitation in this design is that Arduino can only measure time intervals as short as 4µs as evidenced by the micros() function. This creates a lower bound for the set of capacitances that can be measured.
- When calibrating, manufacturers state rough capacitances that have uncertainty thus introducing error to our (k,b) model parameters.
- Capacitors have differing levels of effective series resistance which will change the series resistance and thus the calibrated model parameters.
- Commercially available resistors only go upto a certain order ~1M ohms. As a result there is a lower bound of capacitance below which the arduino does not cycle fast enough to measure.
- Temperature will affect resistor values and capacitance values of certain elements in the circuit thus skewing the charge time and consequent measured capacitance
Using the lower bound for time intervals and upper bound for resistance in the RC circuit, we can use the theoretical relationship of t=aRC (where a = 1 to be conservative) to estimate a lower bound of 4pF. Given no upper bound this encompasses most commercial capacitance values. Awesome!
In previous calibrations, I obtained a k value of about 200. Given the time step of 4µs, this leads to an uncertainty of about +/-800pF.
More investigation should be done for uncertainty factors 2,3,5 however based on experimentation it seems as though +/-1nF is a reasonable uncertainty.
The last thing to consider is precision, or how reproducible the measurement is for a given input capacitor.
The one factor that comes to mind here is that due to the nature of interrupts present through the arduino's kernel, execution times can vary slightly. As a result, it may take slightly longer for the timer we have implemented to stop. However, this can be mitigated by taking a few measurements and then isolating any outliers before displaying the results.
Thanks for reading and I hope you've learned some cool tricks!