Introduction: Capacitor Tester / Capacitance Meter

If, like myself, you've got an enormous stash of unlabelled electronic components that seem to look like capacitors, it's probably a good idea to either throw them away or test them with a capacitance tester. Furthermore, there's no need to go out and buy an expensive proprietary meter as the lowly Arduino will do a very good job just by adding a few resistors and using some clever coding.

I'm not saying it was me who did the clever stuff and most of this project was borrowed from the interweb from the following people:

Maximous at: https://www.instructables.com/id/Measure-Capacitanc...

Gabriel Staples at: http://electricrcaircraftguy.blogspot.com/

Actually this is a really easy project and you may even learn something about capacitors and microcontrollers. Just for my own curiosity, I had a go at using the Autodesk Circuits Lab to create the schematics and even design a PCB, which, sadly will probably never actually be manufactured, but whatever!

Test any capacitor with this circuit - even down to 1 pico Farad. The secret behind this gadget is to swap out the 'charging resistor' into the realm of the mega Ohms to slow down the charging speed of small capacitors. I got so fond of this resistor that I even gave it a name - 'Charlie'.

Step 1: How It Works

Most things in life require energy and charging a capacitor is no exception. We need to shove a load of electrons into this gadget with a certain amount of voltage in a similar way to a battery except that no chemical reaction occurs. In the capacitor, electrons, or charge, is stored in a material called a dielectric sandwiched between two electrodes. As with charging a battery, if we put a resistor in the charging circuit the charging can be slowed down and if the resistor is absolutely enormous ie mega ohms, we can slow the charging to such a speed that even an Arduino can measure.

The Arduino has analogue circuitry that can read the value of any voltage between 0 and 5v so if the capacitor itself is slowly charging from 0 to 5v through an enormous resistor this voltage change can be watched and the time taken to charge up measured, as long as it is not too fast. A very small capacitor such as one having a value of 10 pico Farads will normally charge extremely quickly as it has almost nothing inside it - too quick for an Arduino - which is where our friendly resistor comes into play.

However, one thing that we may well forget is that the capacitor does not charge at the same rate all the time. It starts off charging pretty quickly and then gradually falls off exponentially as it becomes more and more saturated. What this means in reality is that we should not wait until the capacitor becomes fully charged, but pick an arbitrary cut off point where we say 'OK, it's charged enough now'. When we code the Arduino we don't want to time the charging to a full 5v, but around about 3 volts instead. Doing this will result in a lot less error.

Step 2: Breadboard and Schematic

Parts:
  • C1 Ceramic Capacitor voltage 6.3V; package 0603 [SMD, multilayer]; capacitance 100nF; part # TEST
  • LCD1 LCD screen pins 16; type Character Part1 Arduino Nano (Rev3.0) type
  • Arduino Nano (3.0)
  • R1 Rotary Potentiometer (Small) maximum resistance 100kΩ; size Rotary - 9mm; track Linear; package THT; type Rotary Shaft Potentiometer
  • R2 10MΩ Resistor pin spacing 400 mil; tolerance ±5%; package THT; resistance 10MΩ; bands 4
  • R5 200Ω Resistor pin spacing 400 mil; tolerance ±5%; package THT; resistance 200Ω; bands 4
  • VCC1 4 x AAA Battery Mount voltage 4.8V

The capacitor, in this case a 1uF electrolytic, is charged from pin 13 through Charlie, the resistor. The voltage across the capacitor is detected by analogue pin A0 which wont let the charging stop until it has reached a certain level. In terms of the code, this is made possible by sticking the analogue read in a 'while' loop:

while(analogRead(analogPin) < 648)<br>  
  {       
    // Does nothing until capacitor reaches 63.2% of total voltage
  }

It is then discharged through a resistance of 200 ohms to pin 11.

In my version the process is repeated 10 times (i) to get more accuracy and I've used a library built by Gabriel Staples to get better timer functionality out of the Arduino.

To test large capacitors resistor Charlie would have to be swapped out for a smaller one eg 10,000 ohms or the testing will take too long.

In my set up I used an Arduino nano and a standard 4 x 20 LCD display.

Step 3: Code

#include <LiquidCrystal.h>

LiquidCrystal lcd(2, 3, 4, 5, 6, 7);


/*
Timer2_Counter_measure_time_interval.ino
Timer2 Counter Basic Example - Demonstrates use of my Timer2_Counter, which is a timer function with 0.5us precision, 
                               rather than 4us precision like the built-in Arduino micros() function has.
By Gabriel Staples
Visit my blog at http://electricrcaircraftguy.blogspot.com/
-My contact info is available by clicking the "Contact Me" tab at the top of my blog.
-Please support my work & contributions by buying something here: https://sites.google.com/site/ercaguystore1/
My original post containing this code can be found here: http://electricrcaircraftguy.blogspot.com/2014/02/Timer2Counter-more-precise-Arduino-micros-function.html
Written: 8 Feb. 2014
Updated: 30 May. 2014

History (newest on top):
20140517 - Timer2_Counter is now a true library!  This is the first example utilizing Timer2_Counter as an actual, installed library. This was a huge challenge for me,
           as this is only my 2nd library I have ever written, and it is the first library I have written with an ISR() in it, which was a special challenge.
20140208 - initial example; required a special "Timer2_Counter.ino" file, with all of the setup & functions, that had to be in the same directory as this example file.
*/

//CODE DESCRIPTION:
//This code demonstrates the use of my Timer2, which provides a more precise timer than micros().  
//micros() has a precision of only 4us.  However, Timer2 keeps track of time to a precision of 0.5us.
//This is especially important in my code which reads an RC receiver PWM signal, which varies from 900~2100us. 
//Though this code demonstrates the use of the Timer_2 functions I have written, it does not adequately demonstrate the 
//real utility of the code, so I will state the following:
//By using my Timer2 timer to measure the PWM high time interval on an RC receiver, in place of using micros(), I can get repeatable 
//pulse width reads with a fluctuation of ~1us, rather than having a read-in range fluctuating by as much as +/- 4~8 us when I use micros().
//This is an increase in precision of ~8x.

//include the library
#include <eRCaGuy_Timer2_Counter.h>

//Note: an object of this class was already pre-instantiated in the .cpp file of this library, so you can simply access its methods (functions)
//      directly now through the object name "timer2"
//eRCaGuy_Timer2_Counter timer2;  //this is what the pre-instantiation line from the .cpp file looks like

  // Initialize Pins
int analogPin = 0;
int chargePin = 13;
int dischargePin = 11; //speeds up discharging process, not necessary though

// Initialize Resistor
int resistorValue = 10000;

// Initialize Timer
unsigned long startTime;
unsigned long elapsedTime;
int i=0;
int j=0;
// Initialize Capacitance Variables
float microFarads;                
float nanoFarads;



  unsigned long t_elapsed1 =0;
  unsigned long t_elapsed2_ul =0;
  float t_elapsed2_fl =0;
  float t_elapsed3 =0;
  float result =0;

void setup() 
{
  lcd.begin(20, 4);
  pinMode(chargePin, OUTPUT);     
  digitalWrite(chargePin, LOW);  
  //configure Timer2
  timer2.setup(); //this MUST be done before the other Timer2_Counter functions work; Note: since this messes up PWM outputs on pins 3 & 11, as well as 
                  //interferes with the tone() library (http://arduino.cc/en/reference/tone), you can always revert Timer2 back to normal by calling 
                  //timer2.unsetup()
  
  //prepare serial
  Serial.begin(115200);  
  
  //Output a header of info:
  Serial.println(F("Notes:"));
  Serial.println(F("micros() has a precision of 4us"));
  Serial.println(F("get_count() with unsigned long final data type has a final precision of 1us, and is fast"));
  Serial.println(F("get_count() with float final data type has a final precision of 0.5us, and is not quite as fast"));
  Serial.println(F("get_micros() has a precision of 0.5us, and is slower than the above 2 methods, so one of the above 2 methods is preferred"));
  Serial.println(F("=============================================="));
}


void loop() 
{
  
  i=10;
  j=i;
  while (i>0)
  {
  //Grab Start Times
  unsigned long t_start1 = micros(); //us; get the current time using the built-in Arduino function micros(), to a precision of 4us
  unsigned long t_start2 = timer2.get_count(); //count units of 0.5us each; get my Timer2 count, where each count represents 0.5us; PREFERRED METHOD
  float t_start3 = timer2.get_micros(); //us; get the current time using my Timer2; Note: THE METHOD ONE LINE ABOVE IS PREFERRED OVER THIS METHOD
                                        //since using floats is a tiny bit slower than using unsigned longs
  digitalWrite(chargePin, HIGH); // Begins charging the capacitor
  startTime = millis(); /////////////////////////////////////////////////////////////////////////////////////////////////
  //Wait a bit                       
  while(analogRead(analogPin) < 648)
  {       
    // Does nothing until capacitor reaches 63.2% of total voltage
  }
  //  delayMicroseconds(10);
  //Grab End Times
  unsigned long t_end1 = micros(); //us; using built-in Arduino function that has a precision of 4us
  unsigned long t_end2 = timer2.get_count(); //count units of 0.5us each; using my Timer2 count, where each count represents 0.5us
  float t_end3 = timer2.get_micros(); //us; using my Timer2 micros, which has a precision of 0.5us
  
  //Calculate elapsed times
  t_elapsed1 = t_end1 - t_start1 + t_elapsed1; //us; using micros()
  t_elapsed2_ul = (t_end2 - t_start2)/2 + t_elapsed2_ul; //us; to a precision of 1us, due to using unsigned long data type truncation, using Timer2 count
  t_elapsed2_fl = (t_end2 - t_start2)/2.00 + t_elapsed2_fl; //us; to a precision of 0.5us, due to using float data type for final time difference calc; note that I divide by 2.0, NOT 2
  t_elapsed3 = t_end3 - t_start3 +t_elapsed3; //us; to a precision of 0.5us
  
  elapsedTime= millis() - startTime; // Determines how much time it took to charge capacitor
  microFarads = ((float)elapsedTime / resistorValue) * 1000;

  digitalWrite(chargePin, LOW); // Stops charging capacitor
  pinMode(dischargePin, OUTPUT); 
  digitalWrite(dischargePin, LOW); // Allows capacitor to discharge    
  while(analogRead(analogPin) > 0)
  {
    // Do nothing until capacitor is discharged      
  }

  pinMode(dischargePin, INPUT); // Prevents capacitor from discharging  
  
  lcd.setCursor(0,3);
  lcd.print("i:");
  lcd.setCursor(2,3);  
  lcd.print("   ");  
  lcd.setCursor(2,3);  
  lcd.print(i);
  
  i--;
  delay(100);
  } // while i<10 
  
  t_elapsed1 =   t_elapsed1/j;
  t_elapsed2_ul = t_elapsed2_ul/j;
  t_elapsed2_fl = t_elapsed2_fl/j;
  t_elapsed3 = t_elapsed3/j;
  
  results();
  //Wait a second before repeating
 
}

void results()
 {
      //Display the results
//  Serial.println(""); //insert a space
//  Serial.print(F("elapsed time using micros() = "));
//  Serial.print(t_elapsed1);
//  Serial.println(F("us"));
  Serial.print(F("elapsed time using get_count() with unsigned long final data type = "));
  Serial.print(t_elapsed2_ul);
  Serial.println(F("us"));
  result= t_elapsed2_ul/100000.000; 
  
  lcd.setCursor(0,0);    
  lcd.print("Time to charge cap:"); 
  lcd.setCursor(0,1);   
  lcd.print("         ");    
  lcd.setCursor(0,1);   
  lcd.print(t_elapsed2_ul);  
  lcd.setCursor(10,1);    
  lcd.print("us");  
  lcd.setCursor(0,2);    
  lcd.print("Cap. value:");
  lcd.setCursor(12,2); 
  lcd.print("        ");
  lcd.setCursor(12,2);
  lcd.print(result,4);
  lcd.setCursor(18,2);
  lcd.print("uF");

//  Serial.print(F("elapsed time using get_count() with float final data type = "));
//  Serial.print(t_elapsed2_fl);
//  Serial.println(F("us"));
//  Serial.print(F("elapsed time using get_micros() = "));
//  Serial.print(t_elapsed3);
//  Serial.println(F("us"));
 
//  Serial.print("elapseTime millis:  "); 
//  Serial.print(elapsedTime);       
//  Serial.print(" mS    ");  
//  Serial.println(" ");  
 }  



Step 4: PCB

Just for fun, I designed a PCB with the Autodesk circuits software. In the second picture, the PCB appears to be covered with a blue haze, but this is the copper pour and is created by clicking on any of the copper traces connected to Ground and drawing a box around the circuit.

I'm not going to build this PCB but am looking forward to the day when we can create our own components which would then raise the usefulness of this software above all the others.

Sorry, but no Gerber files are available yet as the software wont allow them to be exported at this stage.

Step 5: Final

As I said before, this project is incredibly easy - so why wouldn't we want to make our own capacitor tester?

Maybe also build your own capacitor or a capacitance probe?

The photo above shows Charlie, my faithful 1 Mega Ohm resistor and a 1uF capacitor being tested.

Please in the competitions - top right - Thanks!
Circuits Contest 2016

Participated in the
Circuits Contest 2016