This is a basic capacitance meter for use with the Arduino.
This capacitance meter is designed to be extremely cheap and quick to set up. As such, it's not very accurate or stable, but it works. It has also been designed to be battery-friendly, taking advantage of several power-saving options in the AVR hardware. It does not use an integrated display; it uses your laptop to show output. It could be adapted to use a battery pack and an integrated display, or could be used as-is with a small tablet or cell phone capable of hosting USB serial TTY devices.
Setups such as that of Jonathan Nethercott have both advantages and disadvantages compared to this one. The main advantage with his is that fewer external parts are required. Disadvantages include poorer resolution.
Nick Gammon and Circuit Basics have yet more variants.
The design presented below pays a little more attention to hardware specific to the AT2560, and uses fairly little Arduino helper library code.
- Connect the three resistors between pins 5/A0/A1/A2 as shown below. If you don't have exact values, you can substitute, but you need to modify the range struct as necessary.
- Install the latest version of the Arduino IDE.
- Copy and paste the code into it.
- Connect your Arduino over USB.
- Select the appropriate port and board.
- Upload the code.
For all connections try to use relatively short jumpers. A breadboard will work, but a project board with soldered connections (especially a proper "shield"-style board) will introduce less parasitic capacitance. Parasitic or stray elements are not fatal, but will inflate measurements in the pF range. The board partially accommodates for this with the zeroing feature.
This has been written for the Arduino Mega 2560, the only Arduino sitting in my toolbox. This is definitely overkill. It should be possible to port to other AVR-based Arduino systems, such as the Arduino Uno based on the ATmega328P, because it shares all of the same comparator and capture functionality. The following registers are used in the Mega code but missing in the Uno, and would require removal or replacement:
COM1C0 COM3A0 COM3B0 COM3C0 CS30 DDRA DDRE DDRF DDRG DDRH DDRJ DDRK DDRL
ICES3 ICNC3 MUX5 OCIE1C OCIE3A OCR3A PORTA PORTE PORTF PORTG PORTH PORTJ
PORTK PORTL PRR0 PRR1 PRTIM3 TCCR3A TCCR3B TIMSK3 WGM30 WGM32
I'd be happy to write a port for anyone who sends me the hardware. I also take pull requests for ports.
- Remove any existing capacitors from the measurement pins before boot (or reboot), while leaving attached any leads you anticipate using to connect to capacitors.
- Connect your Arduino over USB.
- Select the appropriate port and board.
- Start the Arduino IDE's Serial Monitor. Set the monitor to 115200 baud.
- Observe as the meter zeroes itself. My unloaded capacitance is usually about 50pF.
- Connect the capacitor to be measured as shown below.
- Observe as the meter converges on a capacitance value. Switching between large and small capacitors will take a few iterations for the auto-range to kick in completely.
| Arduino Mega
| 2560 Rev2
|
| Arduino AVR
| Pin Pin Function I/O
|
---------| 5V VCC drive out
| |
== C |
| |
|--------| 5 PE3/AIN1 -comptor in
| |
|-270R---| A0 PF0 (dis)charge out or Z
|--15k---| A1 PF1 (dis)charge out or Z
|---1M---| A2 PF2 (dis)charge out or Z
|
| 0 PE0/RXD0 UART rx in
| 1 PE1/TXD0 UART tx out
|
| 13 PB7 LED out
Digital I/O pins are 5V. Using an internal reference voltage of 1.1V for the comparator, the capture time to charge in tau-units is:
Higher R slows down charge for small capacitance. Lower R is necessary to speed up charge for high capacitance. Too fast, and max capacitance will suffer. Too slow, and update speed will suffer. Minimum R is based on the max pin "test" current of 20mA (absolute max 40mA).
Choose maximum R based on the impedance of the pins and susceptibility to noise. The ATMega specsheet lists a leakage current of up to 1μA at 5.5V, equivalent to a minimum input impedance of 5.5MΩ - so a drive resistor anywhere above 1MΩ doesn't work well.
For good range coverage, having an intermediate resistor is useful. This resistor should be close to the geometric mean of the other two:
Board has a 16MHz xtal connected to XTAL1/2. Timer 1 is 16-bit. We can switch between prescalers of 1, 8, 64, 256 and 1024 based on capacitance.
The maximum capacitance measured is when R is minimal, the prescaler is maximal, and the timer value is maximal:
We don't want to go too much higher, because that will affect the refresh rate of the result. We can improve discharge speed by decreasing R, but it cannot go so low that the current exceeds the pin max.
Ideally, we would allow the capacitor to fully discharge between each measurement. Currently, the refresh time is hard-coded at 500ms, so for discharge to 1% or better, the measured capacitor would be at most:
The theoretical minimum capacitance is when R is maximal, the prescaler is minimal, and the timer value is minimal:
but practical limitations of this hardware will not do anything useful for such a small capacitance. Parasitics alone are much higher than that. Just plugging a wire into my breadboard introduced 10pF, and my typical unloaded capacitance is 50pF.
To determine when to switch ranges, aim for a charge timer that runs up to somewhere near the 16-bit capacity to get decent resolution, choosing a good combination of R and prescaler.
For more justification of the range choices, run range-analysis.r and check out the graphs it produces.
Store - This sells the rev3, but I have a rev2.
Board - This is the R1 schematic. My R2 is closer to the R1 than the R3. The R3 was released in Nov 2011.
The actual entry point is main() in here (ignoring the bootloader):
hardware/arduino/avr/cores/arduino/main.cpp
The include chain is:
- Arduino.h
- avr/io.h
- avr/sfr_defs.h ; based on -mmcu=atmega2560, __AVR_ATmega2560__ is defined
- avr/iom2560.h
- avr/iomxx0_1.h - this has most of the interesting SFR defs
- avr/io.h
We need to use a lot of the SFRs directly.
When using tools such as avr-objdump, the architecture should be avr:6, and since link-time optimization is enabled, don't dump the .o; dump the .elf. Something like:
avr-objdump -D -S capmeter.ino.elf > capmeter.asm
- Maybe disable the comparator via ACSR.ACD between measurements to save power - currently won't work
- Maybe tweak the autorange algo or enable "fast" - currently barfs sometimes
- Dynamic refresh rate using OC3 based on capacitance and discharge minima