Capacitance Meter Based on Arduino
This project shows how to build a capacitance meter based on Arduino board where the value of capacitor capacitance is displayed on 16×2 LCD screen and on the laptop through serial monitor software (for example Arduino IDE serial monitor).
Working Principle:
When a capacitor is connected in series with a simple resistor (series RC circuit) and by applying a certain voltage VS, the capacitor voltage VC increases exponentially towards VS according to the following equation:
RC Called time constant (Tau) which is time when VC = 0.632VS where R is in Ω and C in Farads.
So, from the previous function, if we know VS, VC, R and t we can calculate the value of C.
The Arduino microcontroller ATmega328P (uno, Nano, Mini …) has a built-in analog comparator which will be used in this project to detect the voltage of the capacitor when it goes above VS/2 (approximately 2.5V).
When VC = 0.5VS the capacitance value C = t/[R x ln(0.5)]
Timer1 module is used to count time t between VC = 0 and VC = VS/2.
To get a voltage of VS/2 we may use voltage divider using 2 similar resistors.
Project Hardware Required:
- Arduino board —> ATmega328P datasheet
- 1602 LCD screen
- 2 x 4.7k ohm resistor
- 100k ohm resistor
- 10k ohm resistor
- 1k ohm resistor
- 220 ohm resistor
- 330 ohm resistor
- 10k ohm variable resistor or potentiometer
- Breadboard
- Jumper wires
Arduino capacitance meter circuit:
Project circuit diagram is the one below.
warning: the capacitor should be fully discharged before placing it in the circuit!
The circuit shown above is for an autoranging capacitance meter, the capacitor under test is connected to the Probes terminals + and –. The – terminal is directly connected to Arduino GND pin.
The capacitor under test is charged using one of the three resistors: 1k, 10k or 100k. The Arduino initiates the charging of the capacitor through one resistor according to its capacity. The 220 ohm resistor is used for discharging the capacitor.
With these resistors the Arduino outputs a maximum current of 5/1k = 5mA (while charging the capacitor) and sinks a maximum current of 5/220 = 22.7mA (while discharging the capacitor).
The reference voltage (approximately 2.5V) comes from the 2 x 4.7k resistors voltage divider, it’s connected to Arduino digital pin 6, this is AIN0 pin of the Atmega328P MCU which is analog comparator positive input pin.
The capacitor positive terminal is connected to Arduino analog channel 5 (A5). This pin is used as negative input of the analog comparator and also to read capacitor voltage during discharge.
The 1602 LCD screen (2 rows and 16 columns) is used to display temperature values in degrees Celsius and degrees Fahrenheit where:
RS —> Arduino digital pin 2
E —> Arduino digital pin 3
D4 —> Arduino digital pin 4
D5 —> Arduino digital pin 5
D6 —> Arduino digital pin 8
D7 —> Arduino digital pin 9
VSS, RW, D0, D1, D2, D3 and K are connected to Arduino GND,
VEE to the 10k ohm variable resistor (or potentiometer) output,
VDD to Arduino 5V and A to Arduino 5V through 330 ohm resistor.
VEE pin is used to control the contrast of the LCD. A (anode) and K (cathode) are the back light LED pins.
Arduino capacitance meter code:
Hints:
Capacitor discharge pin is Arduino analog pin 1 (A1) and it’s connected to the capacitor positive terminal through 220 ohms resistor. Capacitor charging pins are A2, A3 and A4 and they’re connected to the capacitor positive terminal respectively through 1k, 10k and 100k. All those pins are defined in the code as shown below:
1
2
3
4
|
#define discharge_pin A1
#define channel0_pin A2
#define channel1_pin A3
#define channel2_pin A4
|
The 3 resistors (1k, 10k and 100k) are used in a table (array) of 3 elements as shown below:
1
|
const uint32_t res_table[3] = {1000, 10000, 100000};
|
At the beginning, the Arduino starts discharging the capacitor by writing logic low to discharge_pin until the capacitor is fully discharged through the 220 ohms resistor. While the discharge_pin is low, the ADC module keeps checking capacitor voltage (channel 5).
After the capacitor is fully discharged, the ADC module is disabled and analog comparator interrupt is enabled, a charging voltage is applied to the capacitor through one series resistor (1k, 10k or 100k) and Timer1 module starts counting until the analog comparator interrupt occurs. This interrupt tells the microcontroller that the capacitor voltage is approximately equal to the reference voltage which is equal to 2.5V.
So, we can calculate capacitance value since we know the values of the supply voltage (5V), series resistance (1k, 10k or 100k) and time.
Note that Timer1 module is configured to increment by 1 every 62.5 microseconds (prescaler = 1).
Full Arduino code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
|
/***********************************************************************
*
* Arduino based capacitance meter.
* Capacitance value is displayed on 16×2 LCD.
* This is a free software with NO WARRANTY.
* https://simple-circuit.com/
*
***********************************************************************/
#include <LiquidCrystal.h> // include Arduino LCD library
// LCD module connections (RS, E, D4, D5, D6, D7)
LiquidCrystal lcd(2, 3, 4, 5, 8, 9);
#define discharge_pin A1
#define channel0_pin A2
#define channel1_pin A3
#define channel2_pin A4
// variables
bool ok;
byte ch_number;
const uint32_t res_table[3] = {1000, 10000, 100000};
uint32_t res, t_mul;
char _buffer[9];
void setup(void) {
Serial.begin(9600);
lcd.begin(16, 2); // set up LCD’s number of columns and rows
lcd.setCursor(0, 0); // move cursor to column 0, row 0 [position (0, 0)]
lcd.print(“Capacitance =”);
pinMode(discharge_pin, OUTPUT);
digitalWrite(discharge_pin, LOW);
// Timer1 module configuration
TCCR1A = 0;
TCCR1B = 0;
TIMSK1 = 1; // enable Timer1 overflow interrupt
ADCSRA = 0x04; // disable ADC module
ADMUX = 0x45; // select channel 5
ADCSRB = (1 << ACME); // comparator negative input comes from ADC multiplexer
ACSR = 0x12; // configure analog comparator & its interrupt (interrupt on falling edge)
ch_number = 2;
}
// analog comparator ISR
ISR (ANALOG_COMP_vect) {
TCCR1B = 0; // disable Timer1
// disconnect all charging pins
pinMode(channel0_pin, INPUT);
pinMode(channel1_pin, INPUT);
pinMode(channel2_pin, INPUT);
// start discharging the capacitor
pinMode(discharge_pin, OUTPUT);
digitalWrite(discharge_pin, LOW);
ok = 1; // process completed
ACSR &= ~0x08; // disable analog comparator interrupt
}
// Timer1 overflow ISR
ISR(TIMER1_OVF_vect) {
t_mul++;
if(ch_number != 0) {
ch_number = 0;
ch_select(ch_number);
}
}
// main loop
void loop() {
// reset every thing
TCNT1 = 0;
t_mul = 0;
ok = 0;
// wait for capacitor discharge
ADCSRA |= 0x80; // enable ADC
uint16_t volt;
do {
ADCSRA |= 1 << ADSC; // start conversion
while(ADCSRA & 0x40) delay(1); // wait for conversion complete
volt = ADCL | ADCH << 8; // read analog data
} while (volt > 0);
ADCSRA &= ~0x80; // disable ADC
delay(100);
// disconnect discharging pin
pinMode(discharge_pin, INPUT);
ACSR |= 0x08; // enable analog comparator interrupt
TCCR1B = 1; // start Timer1 with prescaler = 1 (1 tick every 62.5 ns)
ch_select(ch_number);
while(ok == 0) delay(1); // wait for process complete (charging the capacitor)
int32_t _time = 65536 * t_mul + TCNT1;
uint32_t cap;
if(ch_number == 0)
cap = –62.5 * _time/(res * log(0.5)); // cap is in nF
else {
_time -= 385; // apply some correction
if(_time < 0) _time = 0;
cap = –62500.0 * _time/(res * log(0.5)); // cap is in pF
}
if( (ch_number == 1 && cap < 10000) || (ch_number == 0 && cap < 10) )
ch_number = 2;
if( (ch_number == 2 && cap > 12000) || (ch_number == 0 && cap < 500) )
ch_number = 1;
if(ch_number != 0) {
if(cap < 1000) // if cap < 1000 pF = 1 nF
sprintf(_buffer, “%03u pF “, (uint16_t)cap);
else
sprintf(_buffer, “%03u nF “, (uint16_t)(cap/1000) % 1000);
}
else {
if(cap < 1000000) // if cap < 1000000 nF = 1000 uF
sprintf(_buffer, “%03u.%1u uF”, (uint16_t)(cap/1000), (uint16_t)(cap/100)%10);
else
sprintf(_buffer, “%u uF “, (uint16_t)(cap/1000));
}
lcd.setCursor(0, 1); // move cursor to position (0, 1)
lcd.print(_buffer);
Serial.print(“Capacitance = “);
Serial.println(_buffer); Serial.println();
delay(1000); // wait a second
}
void ch_select(byte n) {
switch(n) {
case 0:
pinMode(channel1_pin, INPUT);
pinMode(channel2_pin, INPUT);
pinMode(channel0_pin, OUTPUT);
digitalWrite(channel0_pin, HIGH);
break;
case 1:
pinMode(channel0_pin, INPUT);
pinMode(channel2_pin, INPUT);
pinMode(channel1_pin, OUTPUT);
digitalWrite(channel1_pin, HIGH);
break;
case 2:
pinMode(channel0_pin, INPUT);
pinMode(channel1_pin, INPUT);
pinMode(channel2_pin, OUTPUT);
digitalWrite(channel2_pin, HIGH);
}
res = res_table[n];
}
// end of code.
|
The video below shows my protoboard circuit tests with some different capacitors:
Related Project:
Arduino Based Auto-Ranging Ohmmeter