loading

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!
<p>&quot;Test any capacitor with this circuit - even down to 1 pico Farad.&quot; Mmmmm... have you actually tested for such low values? Reason for asking: you see... <a href="http://forum.arduino.cc/index.php?topic=392847.0..." rel="nofollow"> http://forum.arduino.cc/index.php?topic=392847.0....</a> ATMEGA's ADC works on a &quot;sample-and-hold&quot; approach and uses (internally) a 14pF sampling capacitor. Now, imagine you connect a 1pF capacitor to a 14pF &quot;sampling&quot; one... it would be like hearing a hospital nurse telling you &quot;Now, hold still... I'll take a blood sample from you using this 50 litres syringe... hey, why so pale already, I haven't even started yet?!... Now-now, if you faint from such a trifle, what will you do when I'll tell you I'm going to do this repeatedly until I'm satisfied you got at least 63% of your blood capacity?&quot;<br><br>Letting (poor taste) analogies aside, the process of measuring goes well when the effect of the measurement on the measured value is negligible in magnitude when compared to the actual value. For up to hundred of picos, Charlie or not, certainly this is *not* the case - you will have a systematic error due to the measuring system, and it will be a systematic one only for each specific capacitor you'll test (in the pico range, each unknown capacitor will drain a different amount of charge into the sampling capacitor).</p><p>I tried this method myself on the moisture capacitive probe (if you remember it) - sorta works for determining a <em>significant change</em> in the capacitance, but fails with horrendous errors for absolute values. Even the parasitic capacitances will have values in this range - e.g. the position of your serial USB cable relative to the other components on your breadboard is able to influence the results you'll be reading.</p><p>* Another sources of errors are inside the ADC itself and will be acting no matter the value of your capacitor-under-test. I found this interesting - calibration of ADC on an AVR: <a href="http://www.atmel.com/Images/Atmel-2559-Characterization-and-Calibration-of-the-ADC-on-an-AVR_ApplicationNote_AVR120.pdf" rel="nofollow"> http://www.atmel.com/Images/Atmel-2559-Characteri...</a></p><p><br>* Some extra: instead of relying on repeated calls to analogRead , you may want to have a look over Arduino hardware interrupts: </p><p><a href="http://playground.arduino.cc/Code/Interrupts" rel="nofollow">http://playground.arduino.cc/Code/Interrupts</a></p><p>As you accept external components on your board, arrange a trimpot to represent your 63.2% Vcc value as an external reference and you move your code into an interrupt handler which captures only the time required to reach this point (then reset your capacitor and relaunch the process until having sufficient values to have your average). </p><p>* And finally - when done correctly, averaging will get you rid of random noise and afford you the equivalent of extra precision bits - here are some good read for oversampling and increased ADC resolution: <a href="http://www.atmel.com/Images/doc8003.pdf" rel="nofollow">http://www.atmel.com/Images/doc8003.pdf <br></a></p><p>Hope you'll enjoy the reading as the nights get longer.. ahem... by the day. What else is for druids to do in winter?</p>
<p>Well, although 10 pF is measurable on this system, 5 pF is not:(. Hopefully my homemade 'parallel bar' type capacitor will be greater than 10 pF or it will fail before it has started!)</p>
<p>Plastics have a dielectric constant above 2. One inch of 3/4 plate will get you an area of 483 sq-mm. Some online parallel plate capacitance calculator shows about 6pF for that inch of length at a plate separation of 1mm (which is huge).<br>The cling-wrap nowadays is PVC (dielectric constant of 4) and 0.5mils (0.012mm) or less thick, which will bring your capacitance/inch (at 3/4&quot; width) in the order of 1nF. But:<br>- a risky proposition to use a single layer of cling-wrap - easy to puncture during manipulation and hard to maintain the mechanical integrity in exploitation - squeeze the capacitor a bit and you may finish cutting through the film.<br>- <em>more important</em> - you aren't interested in increasing the capacitance of the capacitor itself - let it be zero for all you care. Rather you are interested in the &quot;stray capacitance&quot; resulted from the electrostatic field closing through the surrounding medium. So, instead of mounting the plates face-2-face, a better approach would be to align them side by side - just glue them on a strip of plastic as close as you can and then apply an <em>as thin water-proof insulator as you can</em>. Strip of plastic - mmm - a plastic ruler the kids use for school (may dissolve when insulating or gluing the bars)? For longer lengths or a bit higher resistance to solvents in the insulation coating - a segment from a PVC rainwater pipe that you cut at length, put an Al-foil on top and flatten you with the clothing iron set just a tad above the nylon/polyester setting?</p>
<p>I've got my 3/4&quot; brass bars coated in resin and ..... Yes they work better side by side as you suggested. They do take too long to 'settle down' to a consistent reading so I think I need to keep swapping the polarity of the plates, which is what I'll do next. I think something weird is happening in the water!</p>
<p>I reckon you will discover that the &quot;long settling&quot; phenomenon has little to do with the polarity (why should it?) and more to do with the adsorption/reorientation reorientation of water molecules in the micro-dips of the coating and/or degassing of the same surface. That <em>may</em> be a problem on a scenario in which you empty/replenish your shower tank frequently (who doesn't). </p><p>However, see first what's the percentage of change between no-settled/settled - if the error is acceptable (e.g. 5-10%) you may not need special solutions to tackle the problem; just make sure you have another small probe just below overflow level to stop the pump and accept a situation in which you know the water level to a +/-5% accuracy using your assumed-linear-but-with-hysteresis bar-crafted probe.</p>
<p>Thank you very much for your comment - much appreciated. I was aware of the capacitor in the ADC and yes this would make reading very low values more prone to error but I tried the circuit with a 10 pico Farad and it seemed to work ok and with minimal errors. I also tried reading your soil probe and it did a grand job except I found that the probe seemed to slowly change it's capacitance until it reached a steady state - should I dunk the whole probe in epoxy resin to waterproof the sides of the circuit board where it was cut?</p>
<p>&quot;should I dunk the whole probe in epoxy resin to waterproof the sides of the circuit board where it was cut?&quot; Definitely not, you'll kill the sensitivity by increasing the thickness of the dielectric. If you want to try insulating the sides, try applying the insulation on a narrow strip along the edges. What I can tell, I had the same experience with the DIY probes I insulated by repeated dip-coating in polystyrene solution - the sides where insulated and yet the steady state was attained only after 4-6 hours (the fabbed probes stabilized a bit sooner, but not much sooner). I suspect some sort of phenomenon in which the air trapped in micropores dissolves in water or actually reorientation of the water dipoles inside those micropores may play a rle. With a thin coating, you have higher sensitivity and, of course, no free lunch (or drinks) - the price to pay is sensitivity to trapped air too.</p>
<p>Aha ....... Thought as such ......... I will do some more head scratching and invoke the Druidic Gods of Capacitance (or Google) to help me get a more responsive probe.</p>
See the adventures of diy_bloke in the capacitive probes land - depending on the application, it may be the quality of the coating that matters more than the geometry of the electrodes - <p><a href="https://www.instructables.com/id/Comparison-of-Capacitive-Soil-Probes/" rel="nofollow">https://www.instructables.com/id/Comparison-of-Capa...</a></p><p>&gt; invoke the Druidic Gods of Capacitance (or Google) to help me get a more responsive probe.</p><p>My assessment <br>based on my prev conjuring of the same (a bit over a year ago) didn't <br>show anything in this regard - perhaps the Aboriginal totem animals deal in some other ways with the presence of water. By all means, all the best luck to you (and please keep me posted if you run into anything interesting) - but... be prepared to switch the approaches if you run out of time without getting to the bottom of it.</p><p>If you are still toying around the &quot;water level sensor&quot;, a suggestion: </p><p>1. use an as-long-as-your-depth cap (something like two parallel strips of Al-foil pasted on a piece of plastic and water-proofed after). You will have, say, +/-10% error on the level, but it should be a linear dependency between the submerged part of the probe vs reported capacitance. That will be &quot;informational purposes only&quot;.</p><p>2. use one small probe to detect the max level and prevent overflow (shut down the inlet pump or something) and another one for the &quot;low level&quot; (start the pump) - you may use something like the one I sent you or the simpler ones diy_bloke is using. Since they'll be used as &quot;threshold detector&quot;, the absolute value won't matter too much, as long as the &quot;submerged/above water&quot; signals are distinct enough (at they are distinct enough for the ones diy_bloke and me are using)</p><p>Actually, the minimum necessary would be point 2. <br>Point 1 may even be implemented as some other threshold-type of probes spread along the monitoring depth (instead of a continuous one) - a smaller size will make the task of waterproofing them easier.</p>
<p>I think I might try using some 'off the shelf' brass bar approx. profile 3/4&quot; x 1/8&quot; (http://www.ebay.co.uk/itm/222140384721?var=520985376268) and glue and clamp some plastic in between, then coat with resin as thin as possible.</p>
<p>I have a drawer full of unknown salvaged components, this will definitely come in handy</p>
<p>I spotted a fault in the schematics which has now been fixed ;)</p>
Yes and it could save you some cash on future purchases!
<p>ı did vote</p>
oy verdiğiniz i&ccedil;in teşekk&uuml;rler
<p>rica ederim</p>

About This Instructable

2,609views

65favorites

License:

Bio: Ugly pirate roaming the seas in search of Treasure.
More by Tecwyn Twmffat:Arduino Cell Phone 4G Signal Booster / Repeater Simple Manual Arduino 4 Axis Stepper Motor / 16 Channel LED Power Controller Full English Breakfast 
Add instructable to: