Go Down

Topic: ESR meter with Arduino (Read 76 times) previous topic - next topic

szmeu

#5
Dec 21, 2011, 10:26 pm Last Edit: Dec 21, 2011, 11:09 pm by szmeu Reason: 1
Good question, the smallest capacitor I played with was 4,7uF value, this was not a problem to measure, the code presented here uses only the 50mA branch of the schematic (through R8 and the transistor), using the 5mA branch (through R4, the code must be adapted a bit) lower value capacitors can be measured (the smallest cap value that can be measured accurately I don't know). I don't have an reference instrument to compare with, but I guess if one needs to compare two capacitors and sort out the one with the smallest ESR this can be done easily with the current schematic, eventually the schematic can be modified for a lower current (increasing R4's value) so that when the current is applied to the DUT will not charge the small capacitor to quickly and distort the reading (increasing frequency should be necessary to), maybe another schematic with a true sine 100khz constant current generator or even at higher frequency as this is important for the small value capacitors can give better results. Sorry I don't have now this on my breadboard and can't test it. Probably the best way to know if this schematic is good for such small capacitance (pF, nF range) is necessary to study a bit the theory behind ESR measurement and make some calculation to know at least the theoretical limits of this device.

I just took a peak on the net and got to this page where is a calculator for reactance (http://www.electronics2000.co.uk/calc/reactance-calculator.php), as it turns out we must use a frequency where reactance will be negligible versus ESR, as this schematic uses aprox. something around 60khz (more or less) reactance becomes an issue beginning with the nF range, for pF we need something with several Mhz oscillations.


Sadly the answer is no measuring the ESR for (pF) range with this schematic, only the upper range of nF (even here reactance should be taken in account).

geotek

One question, how do you seperate ESR from ESL? 
Some capacitors, especially those designed for low frequency use, can have very high inductive reactance.  I don't think your device can distinguish this.  You may think you have a cap that has very high ESR, but, in fact works very well at 120Hz, not so good at 10KHz.

szmeu

Good point, probably one way would be to test the capacitors at two different freq. high an low plus measuring the capacitance (computing the ideal values from capacitance and freq to get the ideal reactance and inductance) and than analyze the outcome comparing all the values and decide upon this result for a proper verdict of what the cap is good for and where it can be used, would be nice to have some capacitors with the same value and different ESR and ESL to test for this variable, the sketch could be modified to use different freq. This gives me an idea of a sketch where we could analyze the capacitor's response on a frequency range and plot the value and compare this to the ideal capacitor.

grant1842

I am new to Arduino.
I have a  I2C 1602 LCD module.
Quote

http://www.dfrobot.com/index.php?route=product/product&keyword=DFR0063&category_id=0&description=1&model=1&product_id=135

It works.

I am trying to use it with your code.
I had to comment out 2 lines to get it to compile.
If you could look at it and tell me if I need to modify this code for it to work.
Thanks so much for your time.
Code: [Select]


#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 3
#define ESR_PIN A0
#define PULSE_SMALL 3
#define PULSE_PIN 5
#define BUTTON_PIN 7

//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
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27,16,2);  // set the LCD address to 0x27 for a 16 chars and 2 line display


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.536;//calculating voltage on AIN0 pin
  esrVal = (miliVolt)/current - esrCal;//calculate ESR in miliOhm

  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
}

szmeu

@grant1842

Hi, using your display setup is ok, looking at the code I saw that I made a mistake when specifying the columns and rows of my display (16x2) so this code: lcd.begin(20,2) should really be lcd.begin(16,2), as I saw from your lcd object initialization yours to is 16x2 display, for this reason the code should be:

Code: [Select]
lcd.begin(16,2);

The two lines that I suppose to which you refer to and commented out are:
Code: [Select]
//lcd.setLED2Pin(HIGH);
//lcd.setLED1Pin(HIGH);

they have no important role in the code, they just control the back light on my display and another LED.
If the code compiled, everything should be all right, you can test your setup using an 1 ohm resistor (or other small values resistors). If the cables are zero-ed your reading should be accurate (you can further calibrate the meter modifying the value for the double
Code: [Select]
current = 0.046200; variable.)
For any questions I can answer I will help gladly.

Respect,
szmeu

Go Up