#include #include //we have to change prescaler for the ADC to make the conversion happen faster this code section was sugested 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 pins used #define DISCHARGE_PIN 8 #define PULSE_HighRange_PIN 10 #define PULSE_LowRange_PIN 9 #define ESR_PIN A0 #define BUTTON_PIN A4 //function measure unsigned long measureESR(void); //measuring function, increases ADC to 14-bit resolution by oversampling //global variables unsigned long esrSamples; double milliVolts; double esrCalib; double vRef = 1.1; //voltage on the Vref pin (this sketch uses internal voltage reference 1.1V) double milliAmps = 48.48; // (in mA) needed only for "Zeroing". Proper calibration can be done entering the right value for the milliAmps, (U=I*R). double Rs = 1003.0; //proper calibration can be done entering the right value for Rs. Enter the value also in the "IF" branch! This is only the initialization of the Upper Range! double Vin = 5000; double Rm; boolean esrRange = false; int stabilizer = 0; //idealy milliAmps is 50 mA, this condition is fufiled only if R10 is 100 Ohm, Vcc is exactly 5V and the transistor while fully saturated idealy is at 0 ohm. LiquidCrystal lcd(13,11,6,4,3,2); //this is my display setup, I'm using standard 4-bit control. void setup(void) { if (FASTADC) { sbi(ADCSRA,ADPS2); //seting prescaler to 32 for faster adc (500khz) cbi(ADCSRA,ADPS1); //at 500khz results are still looking good (same values as if 250khz ADC clock) sbi(ADCSRA,ADPS0); // the shorter the pulse on a small value capacitor it has no time to charge and denaturate the result } pinMode(ESR_PIN, INPUT); //reading milliVolts pinMode(PULSE_HighRange_PIN, OUTPUT); digitalWrite(PULSE_HighRange_PIN,HIGH); //low enables Q1 pinMode(PULSE_LowRange_PIN, OUTPUT); digitalWrite(PULSE_LowRange_PIN,HIGH); //low enables Q2 pinMode(DISCHARGE_PIN, OUTPUT); digitalWrite(DISCHARGE_PIN,HIGH); //high enables Q3 pinMode(BUTTON_PIN,INPUT); //setting up for a button (for zeroing) digitalWrite(BUTTON_PIN,HIGH); //enabling the pull up on the button, when button pressed to the ground zeroes out the cable analogReference(INTERNAL); //setting vRef to internal reference 1.1V lcd.begin(16,2); lcd.setCursor(0,0); lcd.print("ESR meter"); lcd.setCursor(5,1); lcd.print("version 1.0"); delay(500); eeprom_read_block((void*)&esrCalib, (void*)0, sizeof(esrCalib)); //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 lcd.clear(); } //************************************************************************************************************************** void loop(void) { esrSamples = measureESR(); milliVolts = (esrSamples * vRef) / 16.384; //Divide by 16.384 due to a 14-bit oversampling Rm = Rs / ((Vin / milliVolts) - 1); //voltage divider (R2=R1(U2/(U1-U2))) Rm = Rm - esrCalib; //Compensate cable resistance if (Rm < 0) Rm = 0; //Do not show eventual negative values if (stabilizer == 3) { //Make three measurements before autoranging the ESR. This is hysteresis to avoid oscillation when autoranging. if (Rm < 5.5) { Rs = 100.2; //If needed, adjust this value for low range measurement (Below 6 Ohms) esrRange = false; } else if (Rm > 5.8) { Rs = 1003.0; //If needed, adjust this value for high range measurement (Above 6 Ohms and below 50 Ohms) esrRange = true; } stabilizer = 0; } lcd.clear(); lcd.setCursor(0,0); lcd.print("Vout = "); lcd.print(milliVolts); lcd.print("mV"); lcd.setCursor(1,1); if (Rm <= 50){ //If measurement is less than 50 Ohms show the result, otherwise show
    (Overload) on the display lcd.print("ESR = "); lcd.print(Rm,2); lcd.print((char)244); // print the greek character ohm. } else { lcd.print("ESR =
      "); } //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 posible this influence (short cables, soldering the cables, etc) if(!digitalRead(BUTTON_PIN)){ lcd.clear(); lcd.print("Zeroing..."); esrCalib = milliVolts/milliAmps; lcd.print(" done!"); lcd.setCursor(0,1); eeprom_write_block((const void*)&esrCalib, (void*)0, sizeof(esrCalib)); lcd.print("saved to EEPROM"); delay(1000); } } //************************************************************************************************************************** unsigned long measureESR() { unsigned long accumulator = 0; unsigned int sample = 0; int i = 0; // oversampling 256 times (for 14 bit is 4^(desiredResolution - ADCresolution) where is 4^(14-10) = 4^4 = 256) while ( i++ < 256 ) { digitalWrite(DISCHARGE_PIN, HIGH); // discharge the capacitors delayMicroseconds(600); // discharge wait time digitalWrite(DISCHARGE_PIN, LOW); // disable discharging if (esrRange == false) { digitalWrite(PULSE_LowRange_PIN,LOW); // start milliAmps pulse delayMicroseconds(5); // on the scope it appears that after enabling the pulse a small delay is needed for oscillations to fade away sample = analogRead(ESR_PIN); // read ADC value digitalWrite(PULSE_LowRange_PIN, HIGH); // stop milliAmps pulse } if (esrRange == true) { digitalWrite(PULSE_HighRange_PIN,LOW); // start milliAmps pulse delayMicroseconds(5); // on the scope it appears that after enabling the pulse a small delay is needed for oscillations to fade away sample = analogRead(ESR_PIN); // read ADC value digitalWrite(PULSE_HighRange_PIN, HIGH); // stop milliAmps pulse } accumulator += sample; // accumulate sampling values } esrSamples = accumulator >> 4; // decimate the accumulated result stabilizer ++; return esrSamples; }