Resistor & Capacitor Tester
Summary
Here's another easy to build project similar to the LED tester, and using the same hardware. This project will try to work out whether it's connected to a resistor or capacitor and then show you the value (resistance or capacitance) of it. If it's a resistor, it'll also suggest the nearest resistor from the Jaycar range of ½W resistors. Of course, using off the shelf components, it's not a high accuracy device, but handy to have if you're sorting through your junk drawer and are having trouble with the colour codes. There's about ten solder joins that need to be made to complete this project.
Materials Required
1 | Duinotech UNO r3 Main Board | XC4410 |
1 | Duinotech Arduino Compatible Prototyping Shield | XC4482 |
1 | Duinotech Arduino Compatible 2 X 16 LCD Screen Display with Controller | XC4454 |
1 | 150 Ohm 0.5 Watt Metal Film Resistors - Pack of 8 | RR0552 |
1 | 1.2k Ohm 0.5 Watt Metal Film Resistors - Pack of 8 | RR0574 |
1 | 10k Ohm 0.5 Watt Metal Film Resistors - Pack of 8 | RR0596 |
1 | 150mm Plug to Plug Jumper Leads - 40 Piece | WC6024 |
The resistor values aren't critical, but the smallest one can't be smaller than 125R as this will overload the Uno's outputs. If you use different values, check the notes in the code about the changes that need to be made.
I used two plug-plug jumper cables as my probes, but you could just use any small wire (eg speaker cable) that is lying around. You'll also need a small piece of wire to make a connection on the Protoshield.
Apart from plugging the shields into the Uno, the hard part is soldering the three resistors and probe leads onto the proto shield. See the diagram and photo below.
Once the resistors and wire have been soldered together, plug the Protoshield into the Uno, then plug the LCD Shield into the Protoshield (they should only go one way).
There aren't any extra libraries that are needed for this project as the 'LCD' and 'math' libraries are both included with the IDE. The code should work fine without changes on a Leonardo or Mega board if you have one of these instead. If you're using different resistors, you'll need to change the definitions of the R1VALUE, R2VALUE or R3VALUE constants. You can also change the pins here too. The code uses some of the functions from the LED tester sketch (such as the key handling), but is mostly completely different.
The component detector works by putting 5V onto the 10k resistor, and if A4 is anything but very close to 5V, then something is connected and pulling the analog reading closer to GND.
The routine for working out if the component is a capacitor or resistor works by assuming it is a capacitor, and discharging it (via 150R resistor to GND), then measuring the voltage on it, then charging it up again and measuring the voltage. If the voltage has changed, then it is a capacitor, if it hasn't changed, then it's a resistor.
To measure a resistor, the three test resistors are each set up as a voltage divider with the test resistor, and the voltage at the junction measured. The resistor which gives a reading nearest 2.5V is chosen (as this will give the best precision), and the resistor value is calculated using the voltage divider formula: R2 = (R1 x V2)/V1. This routine exits when it detects a very high resistance, assuming this means the test resistor has been disconnected.
The capacitor tester starts by trying to discharge the capacitor for half a second (the results are more accurate the less the capacitor is charged). The voltage on it is measured, then it is charged from 5V via the 150R resistor for 0.1s, then the voltage on it is measured again. The ratio between the two voltages gives the proportion of charge (towards fully charged) it has received. When this is combined with the 0.1s time, the time constant for the resistor-capacitor combination can be worked out, and this is simply divided by the resistor value to give the capacitance value. If the capacitor ends up nearly fully charge, then the measurement is not completely accurate, and the test is redone with the 1k2 resistor. The results are then converted to easy to read units, rounded and displayed. Similarly, if this routine detects a very low capacitance, it assumes the test component has been removed and returns to the main detect routine.
The two leads are simply connected to the leads of the component you wish to test. If the component is polarised (eg. electrolytic capacitor), then the lead attached to A4 should go to the positive side and the GND lead to the negative side. I've made the leads different colours to remind me of this. The tester should only be used on circuits that aren't connected to power, especially as the UNO's chip can easily be damaged by voltages more than 6V. Components in circuit may not read correctly, as they will be influenced by other components they may be connected to.
One day, I hope to combine all the functions of the two testers to run off the same sketch (and maybe the same leads). As built, the tester will measure resistance from 0R up to the Megohms, and capacitance from nanofarads up to near a Farad. With some changes to the resistor and timing values, this range could be expanded slightly, but this is mostly limited by the accuracy and internal resistance of the ADC on the UNO. When we get a colour LCD screen, perhaps the resistor colour codes can be added as well. I haven't added a component part number recommendation for the capacitor test routine, because there are so many different voltage rating and capacitor types, that a given capacitor value would probably match up with several part numbers. There's no reason this couldn't be added if you knew (for example) that you were always using 16V electrolytic capacitors.
12/* Arduino Resistor and Capacitor Tester
34D13--10k---+---------------> Positive probe
5D12--1k2---+
6D11--150R--+ +-----------> Negative probe
7| |
8A4 GND
910Resistor test by voltage divider- uses 3 different resistors to give auto-ranging.
11Capacitor tester- Capacitance by time constant calculation, ESR by discharge and resistance test. (ESR not accurate so not displayed)
123 modes: Auto (on startup, or by pressing select)- tries to autodetect component and then measures
13Resistor (press left)- assumes resistor and tries to measure resistance
14Capacitor (press right)- assumes capacitor and tries to measure capacitance
15*/
1617//ranging resistor pins and values: R1 should be lowest (use a decimal point to make sure they're floats)
18//values aren't critical, but should be span a good range
19//lowest value possible is 125R- lower would overload the pin. Max is probably 100K due to leakage etc.
20//if you have a good multimeter, you can tweak these values as calibration
2122#define R1VALUE 150.0
23#define R2VALUE 1200.0
24#define R3VALUE 10000.0
25#define R1PIN 11
26#define R2PIN 12
27#define R3PIN 13
28#define AIN A4
29#define MIDRANGE 512
30#define CAPTIME 0.1
3132#include <LiquidCrystal.h>
33#include <Math.h>
3435//pin defs to suit LCD Shield
36LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
3738//pin for buttons
39#define KEYPIN A0
4041//button constants
42#define btnRIGHT 6
43#define btnUP 5
44#define btnDOWN 4
45#define btnLEFT 3
46#define btnSELECT 2
47#define btnNONE (-1)
4849//Globals for display
50//resistors in Jaycar 1/2 W range, part nos start at RR0524 for 10R
51#define RCOUNT 121
52long rvals[]={10,11,12,13,15,16,18,20,22,24,27,30,33,36,39,43,47,51,56,62,68,
5375,82,91,100,110,120,130,150,160,180,200,220,240,270,300,330,360,390,
54430,470,510,560,620,680,750,820,910,1000,1100,1200,1300,1500,1600,1800,
552000,2200,2400,2700,3000,3300,3600,3900,4300,4700,5100,5600,6200,6800,
567500,8200,9100,10000,11000,12000,13000,15000,16000,18000,20000,22000,
5724000,27000,30000,33000,36000,39000,43000,47000,51000,56000,62000,68000,
5875000,82000,91000,100000,110000,120000,130000,150000,160000,180000,
59200000,220000,240000,270000,300000,330000,360000,390000,430000,470000,
60510000,560000,620000,680000,750000,820000,910000,1000000};
61int cdetect=0; //variable for detected component 1=R, 2=C
62int cselect=0; //to force component selection 0=auto, 1=R, 2=C
6364void setup() {
65lcd.begin(16, 2); //lcd
66lcdsplash();
67lcd.setCursor(0, 1);
68lcd.print(" Tester");
69delay(1000);
70}
7172void loop() {
73waitconnect(); // wait till something is connected
74if(cselect){cdetect=cselect;}else{cdetect=detect();} //goto selection if made, otherwise autodetect
75switch(cdetect){
76case 1:
77doresistor();
78lcdsplash(); //redo the splash screen in case it was written over
79break;
80case 2:
81docapacitor();
82lcdsplash(); //redo the splash screen in case it was written over
83break;
84default:
85doerror();
86break;
87}
88}
8990void doresistor(){
91while(1){ //do it all repeatedly till the resistor is disconnected (see return; below)
92int a1,a2,a3,a,diff;
93float rdiv,rcalc,af; //rdiv= Rof divider, rcalc is R of resistor under test, af is float version of analog reading
94pinMode(R1PIN,OUTPUT);
95pinMode(R2PIN,INPUT);
96pinMode(R3PIN,INPUT);
97digitalWrite(R1PIN,HIGH);
98delay(1);
99a1=analogRead(AIN); //read with 1st resistor as voltage divider
100pinMode(R1PIN,INPUT);
101pinMode(R2PIN,OUTPUT);
102digitalWrite(R2PIN,HIGH);
103delay(1);
104a2=analogRead(AIN); //read with 2nd resistor as voltage divider
105pinMode(R2PIN,INPUT);
106pinMode(R3PIN,OUTPUT);
107digitalWrite(R3PIN,HIGH);
108delay(1);
109a3=analogRead(AIN); //read with 3rd resistor as voltage divider
110pinMode(R3PIN,INPUT); //shut outputs down
111//find the resistor which gives an analog value closest to 512- middle of the range gives best accuracy
112a=a1;
113rdiv=R1VALUE;
114diff=abs(MIDRANGE-a1); //assume it's R1 and then see if there's a better match
115if(abs(MIDRANGE-a2)<diff){ //R2 is better
116a=a2;
117rdiv=R2VALUE;
118diff=abs(MIDRANGE-a2);
119}
120if(abs(MIDRANGE-a3)<diff){ //R3 is better
121a=a3;
122rdiv=R3VALUE;
123diff=abs(MIDRANGE-a3);
124}
125if(a>=1022){ //open circuit, resistor has probably been detached, so go back to main screen, avoid div/0 error
126return;
127}else{
128af=a;
129rcalc=(af/(1023-af))*rdiv;
130lcd.setCursor(0, 0);
131lcd.print("Resistor: ");
132lcdprintrval(rcalc);
133int i=rmatch(rcalc); //find index of R that matches rcalc best
134lcd.setCursor(0, 1);
135lcd.print("Try ");
136lcdprintpartno(i);
137lcd.print("(");
138lcdprintrval(rvals[i]);
139lcd.print(")");
140delay(300); //wait a bit so we get a steady display
141}
142}
143}
144145int rmatch(float r){
146int k=-1; //to store index of best match, default to -1
147float d=1e9; //very big number, representing difference from matches
148for(int j=0;j<j++){
149if(abs(rvals[j]-r)<d){
150d=abs(rvals[j]-r);
151k=j;
152}
153}
154return k;
155}
156157void docapacitor(){
158int alo,ahi;
159float esr;
160float c,ts,soc,t,ahif,alof,rvalue;
161lcd.setCursor(0, 0);
162lcd.print("Capacitor......."); //measuring caps might take a bit longer, so change display
163while(1){ //stay in this loop until disconnected
164pinMode(R1PIN,OUTPUT);
165digitalWrite(R1PIN,LOW); //R1 to discharge as much as possible
166pinMode(R2PIN,INPUT);
167pinMode(R3PIN,INPUT);
168delay(500);
169pinMode(R1PIN,INPUT);
170alo=analogRead(AIN); //to read ESR
171digitalWrite(R1PIN,HIGH); //turn on power to detect voltage drop across cap-probably not super accurate
172pinMode(R1PIN,OUTPUT);
173ahi=analogRead(AIN); //difference with power on
174digitalWrite(R1PIN,LOW); //R1 to discharge as much as possible
175if(ahi<alo){ahi=alo;} //to avoid negative values
176esr=0;
177if(ahi<1023){
178esr=((ahi-alo)*R1VALUE)/(1023-ahi);
179}
180//measure voltage on cap, charge up for t, measure state of charge, convert to tc's, work out C knowing R
181digitalWrite(R1PIN,HIGH); //charge it up
182alo=analogRead(AIN); //to read capacitance
183delay(CAPTIME*1000);
184ahi=analogRead(AIN); //to read capacitance
185digitalWrite(R1PIN,LOW); //discharge (in case we need to do again)
186rvalue=R1VALUE; //assume this is the one we're using
187if(ahi>1000){ //very high termination, probably get more accurate results with 2nd resistor
188rvalue=R2VALUE; //assume this is the one we're using
189delay(500); //discharge
190pinMode(R1PIN,INPUT);
191pinMode(R2PIN,OUTPUT);
192digitalWrite(R2PIN,HIGH); //charge it up
193alo=analogRead(AIN); //to read capacitance
194delay(CAPTIME*1000);
195ahi=analogRead(AIN); //to read capacitance
196digitalWrite(R1PIN,LOW); //discharge (in case we need to do again)
197}
198alof=alo;
199ahif=ahi;
200if((ahi==1023)||(alo>=ahi)){
201return; //cap has charged up too quick to be measured or is too high value to change voltage
202}else{
203soc=(1023-ahif)/(1023-alof); //work out level of charge obtained
204ts=-log(soc); //this is number of time constants elapsed
205t=CAPTIME/ts; //time elapsed in seconds
206c=t/rvalue; //capacitance is time constant divided by resistor
207}
208lcd.setCursor(0,1);
209lcd.print(" "); //clear the line so we don't have stuff from the last reading
210lcd.setCursor(5,1);
211int p; //find position of most significant digits using log10- make it an int speed up the maths
212float m; //multiplier to use
213p=log10(c);
214m=pow(10,p-2); //2 sf
215c=round(c/m+0.5)*m;
216if(c>1){ //show in Farads
217lcd.print(c,ndig(c));
218lcd.print("F");
219}else if(c>1e-6){ //show in uF
220c=c*1e6;
221lcd.print(c,ndig(c));
222lcd.print("uF");
223}else{ //show in nF
224c=c*1e9;
225lcd.print(c,ndig(c));
226lcd.print("nF");
227}
228delay(300);
229}
230}
231232int ndig(float c){ //work out how many decimal places to show
233if(c>100){return 0;}
234if(c>10){return 1;}
235return 2;
236}
237238int detect(){ //auto detect whether it's a cap or resistor connected
239int ahi,alo;
240lcd.setCursor(0, 1);
241lcd.print("Detecting R or C");
242pinMode(R1PIN,OUTPUT);
243pinMode(R2PIN,INPUT);
244pinMode(R3PIN,OUTPUT);
245digitalWrite(R3PIN,LOW); //pull low to discharge- R3 will be used to stop output floating later
246digitalWrite(R1PIN,LOW); //R1 to discharge as much as possible
247delay(500);
248pinMode(R1PIN,INPUT);
249delay(1);
250alo=analogRead(AIN); //should be near zero for a resistor
251pinMode(R1PIN,OUTPUT);
252digitalWrite(R1PIN,HIGH); //put some charge into it- we should be able to detect almost up to 1F, if not raise delay- not critical, just takes longer
253delay(300);
254pinMode(R1PIN,INPUT);
255delay(1);
256ahi=analogRead(AIN); //delay between turning output off and reading means very small caps might be discharge- smallest is about 1n
257if(ahi-alo>4){return 2;}else{return 1;} //small difference > resistor
258}
259260void doerror(){
261lcd.setCursor(0, 1);
262lcd.print("Can't autodetect ");
263delay(1000);
264}
265266void lcdsplash(){
267lcd.setCursor(0, 0);
268switch(cselect){
269case 1:
270lcd.print("Duinotech R mode");
271break;
272case 2:
273lcd.print("Duinotech C mode");
274break;
275default:
276lcd.print("Duinotech R & C ");
277break;
278}
279}
280281void waitconnect(){
282lcd.setCursor(0, 1);
283lcd.print("Detecting ");
284int ahi,alo;
285int d=0;
286pinMode(R1PIN,INPUT);
287pinMode(R2PIN,INPUT);
288pinMode(R3PIN,OUTPUT);
289while(1){
290digitalWrite(R3PIN,LOW);
291delay(1);
292alo=analogRead(AIN);
293digitalWrite(R3PIN,HIGH);
294delay(1);
295ahi=analogRead(AIN);
296if(ahi-alo<1000){return;}
297d++;
298if(d>13){d=0;}
299lcd.setCursor(9+d%7,1);
300if(d>6){lcd.print(" ");}else{lcd.print(".");}
301dobuttons();
302delay(100);
303}
304}
305306void lcdprintpartno(int index){
307//part number
308lcd.write('R');
309lcd.write('R');
310lcd.write('0');
311lcd.write((((index+524)/100)%10)+'0'); //part no's start at RR0524 for 10R
312lcd.write((((index+524)/10)%10)+'0');
313lcd.write((((index+524))%10)+'0');
314}
315316void lcdprintrval(long rval){ //print a value in 10k0 format, always outputs 4 characters
317long mult=1;
318long modval;
319if(rval>999){mult=1000;}
320if(rval>999999){mult=1000000;}
321modval=(10*rval)/mult; //convert to final format, save a decimal place
322if(modval>999){ //nnnM
323lcd.write(((modval/1000)%10)+'0');
324lcd.write(((modval/100)%10)+'0');
325lcd.write(((modval/10)%10)+'0');
326lcdprintmult(mult);
327}else{
328if(modval>99){ //nnMn
329lcd.write(((modval/100)%10)+'0');
330lcd.write(((modval/10)%10)+'0');
331lcdprintmult(mult);
332lcd.write(((modval)%10)+'0');
333}else{ //_nMn
334lcd.write(' ');
335lcd.write(((modval/10)%10)+'0');
336lcdprintmult(mult);
337lcd.write(((modval)%10)+'0');
338}
339}
340}
341342void lcdprintmult(long mult){ //helper function to print multiplier
343switch (mult){
344case 1: lcd.print('R');break;
345case 1000: lcd.print('k');break;
346case 1000000: lcd.print('M');break;
347default: lcd.print('?');break;
348}
349}
350351int read_LCD_buttons(){
352int adc_key_in = 0;
353adc_key_in = analogRead(KEYPIN); // read the value from the sensor
354delay(5); //switch debounce delay. Increase this delay if incorrect switch selections are returned.
355int k = (analogRead(KEYPIN) - adc_key_in); //gives the button a slight range to allow for a little contact resistance noise
356if (5 < abs(k)) return btnNONE; // double checks the keypress. If the two readings are not equal +/-k value after debounce delay, it tries again.
357// my buttons when read are centered at these values: 0, 144, 329, 504, 741
358// we add approx 50 to those values and check to see if we are close
359if (adc_key_in > 1000) return btnNONE; // We make this the 1st option for speed reasons since it will be the most likely result
360if (adc_key_in < 50) return btnRIGHT;
361if (adc_key_in < 195) return btnUP;
362if (adc_key_in < 380) return btnDOWN;
363if (adc_key_in < 555) return btnLEFT;
364if (adc_key_in < 790) return btnSELECT;
365return btnNONE; // when all others fail, return this...
366}
367368void dobuttons(){ //updates variables. debounces by only sampling at intervals
369int key;
370key = read_LCD_buttons();
371if(key==btnLEFT){cselect=1;} //force resistor mode
372if(key==btnRIGHT){cselect=2;} //force capacitor mode
373if(key==btnUP){}
374if(key==btnDOWN){}
375if(key==btnSELECT){cselect=0;} //auto detect
376if(key!=btnNONE){lcdsplash();} //update display to show setting
377}
Similar projects you may be interested in