For those who are new to this topic and wish to build this simple esr-meter I warmly recommend to read all the four pages because from the first post that I made, there were some significant changes that will improve the esr-meter, these changes were contributed and ironed out by the users of the forum, also reading the pages you will find a lot of answers. Thanks goes to the users who improved this simple solution and fixed bugs!
A short resume of what you will find on reading more than just the first page:
- a clear understanding off how this esr meter works and many questions answered;
- the correct formula for calculating the esr!; (the formula on the first sketch is not the correct one, you will find the correct one just a bit deeper in the topic)
- a better stand alone layout and code contributed by users;
- ...
ESR meter for capacitors with Arduino
Hi,
This is my first for a “project” on a forum and playing with electronics is a hobby so please take it as is because this is just amateur work, everything is perfectible.
I was searching for an easy to build ESR meter on the net, found some great projects which helped me understand the basics, than I thought this would be an excellent idea for an Arduino project, so here I am, but before I present this solution I’d like to write two-three more lines a bit off-topic:
Skip if you find this kind of boring.
First I’d like to thank to dr. Le Hung here (http://members.upc.hu/lethanh.hung/LCFESRmero/en/index.htm) for the idea of this simple ESR schematic, he sells a kit for the ERS-meter but also features capacitor and inductance measurement.
Second: I’d like to thank the user tinhead on this forum (http://www.eevblog.com/forum/index.php?topic=1571.0) for making it easy for me to choose which scope to buy for tinkering with the current project (thanks for his work on Hantek DSO50xxx series).
Third thanks for all those people who post and share useful info and projects on the net!
Skip end.
The ESR project:
For those who are wondering what is ESR -> Wikipedia (http://en.wikipedia.org/wiki/Equivalent_series_resistance).
The current project is intended to help measure resistors with low value (under 1 Ohm) and capacitor ESR for those times when we want to test capacitors in a SMPS or other similar situations. Another interesting thing about this project is that it shows that over sampling is useful and can give very good results and can be employed successfully in other projects without the need to use external hardware; I had repeatable results in measuring low ESR capacitors and low value resistor (0.05 to 1 Ohm can be accurately measured). For information on using oversampling I highly recommend reading (http://atmel.com/dyn/resources/prod_documents/doc8003.pdf)
The idea behind this ESR is this: Using the well known formula U=I*R, we will pulse very shortly with a known current the cap or resistor, measuring the voltage on the element we have the necessary information to calculate the resistance. There would be a lot to write about this method and why this is functioning but probably more interesting is hand on experience.
The code: I tried to comment it at every step, it is written only for the 50mA current but very easily can be modified to add more upper range to the measurement (the hardware part is ready for this). Code could be rewritten for better performance using interrupts, etc, here is just a basic idea that works.
The hardware: Schematic is provided below, I designed a shield to arduino, probably not the best layout, be aware that the pcb was not tested yet and I’m not 100% is correct, did not use auto route and tried to make it single side, the schematic is good for sure and tested.
The schematic and pcb are attached (you have to sign in to download the atachment)
The DUT should be connected to CN1 between GND (pin3,pin4) and pulse and AIN0 (pin1,pin2) using a setup with four wires.
Here comes the rudimentary code:
#include <LiquidCrystal595.h>
#include <avr/eeprom.h>
//we have to change prescaler for the ADC to make the conversion happen faster
//this code section was suggested on the arduino forum
#define FASTADC 1
// defines for setting and clearing register bits
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
//define the input and output pin we will use
#define DISCHARGE_PIN 7
#define ESR_PIN A0
#define PULSE_SMALL 8 //this is not used in the sketch, implement it as needed (for 5mA current needed for smaller cap value measurement)
#define PULSE_PIN 9
#define BUTTON_PIN 0
//function prototype
unsigned long measureESR(void);//measuring function, increases ADC to 16bit resolution through oversampling
//global variables
unsigned long esrSamples;
double miliVolt;
double esrVal;
double esrCal;
double vRef = 1.093;//voltage on the Vref pin (this sketch uses internal voltage reference 1.1V)
double current = 0.046200;//proper calibration can be done entering the right value for the current (U=I*R)
//idealy this is 0.05 A, this condition is fulfilled only if R10 is 100 Ohm, Vcc is exactly 5V and the transistor
//while fully saturated idealy is at 0 ohm.
//this is my display setup, I'm using Stephen Hobley's 3 wire setup and class
//exchange to what is good for you
LiquidCrystal595 lcd(6,4,2);
void setup(void)
{
lcd.begin(20,2);
lcd.setLED2Pin(HIGH);
lcd.setCursor(0,0);
lcd.print("ESR meter");
lcd.setCursor(5,1);
lcd.print("version 0.1");
delay(1000);
lcd.print("Seting up...");
analogReference(INTERNAL);//setting vRef to internal reference 1.1V
pinMode(ESR_PIN, INPUT);//reading miliVolt
pinMode(PULSE_PIN, OUTPUT);
digitalWrite(PULSE_PIN,HIGH);//low enables T1
pinMode(DISCHARGE_PIN, OUTPUT);
digitalWrite(PULSE_PIN,HIGH);//low disables T2
pinMode(BUTTON_PIN,INPUT);//setting up for a button (will use this for zeroing)
digitalWrite(BUTTON_PIN,HIGH);//enabling the pull up on the button, when button pressed to the ground zeroes out the cable
delay(1000);
lcd.clear();
lcd.print("Please Wait...");
//seting prescaller to 32 for faster adc (500khz)
//at 500khz results are still looking good (same values as if 250khz ADC clock)
// the shorter the pulse on a small value capacitor it has no time to charge and denaturate de result
if (FASTADC) {
sbi(ADCSRA,ADPS2);
cbi(ADCSRA,ADPS1);
sbi(ADCSRA,ADPS0);
}
//reading calibration value, it will be ok if already calibrated, else it might be bogus depends on the content of EEPROM
//but will be ok after first calibration
eeprom_read_block((void*)&esrCal, (void*)0, sizeof(esrCal));
}
void loop(void)
{
lcd.setLED1Pin(HIGH);
esrSamples = measureESR();//this function takes a while,)
// so we don't need other delay for the lcd (this functions time gives the refresh rate for display
miliVolt = (esrSamples * vRef) / 65.535;//calculating voltage on AIN0 pin
esrVal = (miliVolt)/current - esrCal;//calculate ESR in miliOhm (pls read forum for correct formula)
lcd.clear();
lcd.print(" V:");
lcd.print(miliVolt,4);
lcd.setCursor(13,0);
lcd.print("mV");
lcd.setCursor(0,1);
lcd.print("ESR:");
lcd.print(esrVal,4);
lcd.setCursor(13,1);
lcd.print("m");
lcd.print((char)244);
//for zeroing the cables, this can be quite a big resistance compared to the values we intend to measure
//so it is a good idea to try to reduce in any way possible this influence (short cables, soldering the cables, etc)
if(!digitalRead(BUTTON_PIN)){
lcd.clear();
lcd.print("Zeroing...");
esrCal = (miliVolt)/current;
lcd.print(" done!");
lcd.setCursor(0,1);
//writing calibration value into EEPROM so we don't have to calibrate on restart
eeprom_write_block((const void*)&esrCal, (void*)0, sizeof(esrCal));
lcd.print("saved to EEPROM");
delay(400);
}
}
//this is where the magic happens, it really works and gives some
//incredibly good results! if you need sub milivolt accuracy is a good way to go
//noise is good ;) if in doubt must read oversampling on ADC from AVR docs
unsigned long measureESR()
{
unsigned long samples = 0;
unsigned int acumulator = 0;
int i = 0;
//oversampling 4096 times (for 16 bit is 4^(desiredResolution - ADCresolution))
while(i < 4096) {
digitalWrite(DISCHARGE_PIN,LOW);//disable discharging
digitalWrite(PULSE_PIN,LOW);//making a miliVolt pulse of 50mA
delayMicroseconds(1);//on the scope it looks that after enabling the pulse a litle delay is
//recomended so the oscillations fade away
acumulator = analogRead(ESR_PIN);//reading value on AIN0
digitalWrite(PULSE_PIN,HIGH);//stopping pulse
digitalWrite(DISCHARGE_PIN,HIGH);//discharging the capacitors
delayMicroseconds(600);//waiting a bit longer to fully discharge before another pulse
samples += acumulator;//acumulating the readings
i++;
}
//we have samples, let's go and compute value
samples = samples >> 6;//decimating value
return samples;//all done returning sampled value
}
esr_meter.zip (131 KB)