#include <LiquidCrystal.h> #include <avr/eeprom.h>
//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 register bits
// defines for setting and clearing
#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 2 #define PULSE_HighRange_PIN 11 #define PULSE_LowRange_PIN 10 #define ESR_PIN A0 // #define BUTTON_PIN 12 #define BUTTON_PIN 4
//function prototype 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 = 1065.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(6, 5, 10, 11, 12, 13); //this is my display setup, I'm using standard 4-bit control., como el mio
byte Omega[8] = {0b00000,0b01110,0b10001,0b10001,0b10001,0b01010,0b11011,0b00000 }; //Omega special character byte micro[8] = {0b00000,0b00000,0b10010,0b10010,0b10010,0b11100,0b10000,0b00000 }; //micro sign
void setup(void) { if (FASTADC) { sbi(ADCSRA,ADPS2); //seting prescaller 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 de result } pinMode(ESR_PIN, INPUT); miliVolts
//reading
pinMode(PULSE_HighRange_PIN, OUTPUT); digitalWrite(PULSE_HighRange_PIN,HIGH);
//low enables T1
pinMode(PULSE_LowRange_PIN, OUTPUT); digitalWrite(PULSE_LowRange_PIN,HIGH); T1'
//low enables
pinMode(DISCHARGE_PIN, OUTPUT); digitalWrite(DISCHARGE_PIN,HIGH); T2
//low disables
pinMode(BUTTON_PIN,INPUT); a button (will use this for zeroing)
//setting up for
digitalWrite(BUTTON_PIN,HIGH); //enabling the pull up on the button, when button pressed to the ground zeroes out the cable analogReference(INTERNAL); internal reference 1.1V lcd.createChar (0, Omega); lcd.createChar (1, micro); lcd.begin(16,2); lcd.setCursor(0,0); lcd.print("MEDIDOR ESR"); lcd.setCursor(5,1); lcd.print("C. SAN JOSE"); delay(1500);
//setting vRef to
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; 16.384 due to a 14-bit oversampling
//Divide by
Rm = Rs / ((Vin / milliVolts) - 1); Divider (R2=R1(U2/(U1-U2)))
//Voltage
Rm = Rm - esrCalib; Cable Resistance
//Compensate
if (Rm < 0) Rm = 0; show eventual negative values
//Do not
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 = 1065.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 <OL> (Overload) on the display lcd.print("ESR = "); lcd.print(Rm,2); lcd.write(byte(0)); } else { lcd.print("ESR = <OL>
");
}
//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); // start 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); // start milliAmps pulse } accumulator += sample; // accumulate sampling values } esrSamples = accumulator >> 4; // decimate the accumulated result stabilizer ++; return esrSamples; }