// LC meter based on Neil Heckt oscillator and RC/LC time constant measurer for high values
// four reed relays control mode
// Separate functions for HI/LO C/L ranges
// Algorithm for choosing best results OK- sometimes chooses Hi C as Lo L and vv
// working- collates data and outputs
// 20x4 I2C LCD connected
// when reading is stable, continues to measure and average
// repeated recalibration to account for drift
#include <EEPROM.h>
#include <Wire.h>
#include <LiquidCrystal_PCF8574.h>
LiquidCrystal_PCF8574 lcd(0x27); //default address is 0x27, could be 0x20-0x27
#define OHMSSYMBOL 0xF4
#define RELAY1 7
#define RELAY2 6
#define RELAY3 9
#define RELAY4 8
// relay combination modes
#define MODEHILC 0
#define MODECALNONE 2
#define MODECALC2 3
#define MODECTEST 6
#define MODELTEST 8
#define NOTHING 0
#define CAPACITOR 1
#define INDUCTOR 2
#include <FreqCount.h>
#define R1PIN A1
#define R2PIN A2
#define ASENSEPIN A3
#define LTHRESHOLD 138
#define R1VACT A0
#define NOTHING 0
#define CAPACITORHI 1
#define CAPACITORLO 2
#define INDUCTORHI 3
#define INDUCTORLO 4
#define CALDELAY 10000
//these ones are cal values that should be stored in eeprom
float r1value=130.0; //resistor 1 (R12)
float r2value=1300.0; //resistor 2 (R11)
float C2VAL=1.0e-9; //C2
float L1VAL=100.0e-6; //L1
float Cpara=0; //stray capacitance
float Lpara=0; //stray inductance
//general use variables
float C1VAL=1.0e-9; //not a calibration value, set by frequency
float F1=0;
float F2=0;
float FCmin=10000.0; //based on component value range
float FLmin=100.0; //seems to be stable
float F3C,F3L;
#define BUFSIZE 20
char buf[BUFSIZE+1]="";
char unit=0;
char eepromid[]="SC04106181";
char checkid[12]="";
unsigned long lastcalt;
void setup() {
relaySetup();
Wire.begin();
lcd.begin(20, 4);
lcd.clear();
lcd.setBacklight(255);
Serial.begin(115200);
loadFromEEPROM();
showCurrent(); //display calibration values
DIDR0=0xFF; //disable digital input buffers on analog pins. By default is 0x00, unchanged by Arduino code
doCalibration(2000);
lastcalt=millis();
}
void loop(){
float Clo,Chi,Llo,Lhi,val;
byte mode=NOTHING;
static float lastval=0;
static byte lastmode=0;
static bool isStable=0; //flag that we've got a stable component to do a rolling average reading
static float valSum=0; //keep track of rolling average
static unsigned long valCount=0;
//do periodic recalibation
if((millis()-lastcalt>CALDELAY)&&(!isStable)){ //only recalibrate if it's been >10s and we're not reading a component
doCalibration(1000);
lastcalt=millis();
}
//run through four test modes
Clo=testClo(100); //do fast test for C
Chi=testChi(); //RC method for C
Llo=testLlo(100); //do fast test for L
Lhi=testLhi(); //RL method for L
if((F3L>=FLmin)&&(F3L<=F1)){ //probably an inductor
mode=INDUCTOR;
if(Lhi<100e-3){ //valid range for oscillator method
mode=INDUCTORLO;
val=offset(Llo,Lpara);
}else{
mode=INDUCTORHI;
val=offset(Lhi,Lpara);
}
}else{ //probably a capacitor
if(Chi<2.0e-6){ //valid range for oscillator method
mode=CAPACITORLO;
val=offset(Clo,Cpara);
}else{
mode=CAPACITORHI;
val=offset(Chi,Cpara);
}
}
//is component stable?
if((abs(val-lastval)*20<lastval)&&(mode==lastmode)){ //if within 5% of last value and same mode
isStable=1;
}else{
valSum=0;
valCount=0;
isStable=0;
}
//do subsamples if stable
if(isStable){
switch(mode){
case CAPACITORLO:valSum+=offset(testClo(1000),Cpara);valCount++;break;
case CAPACITORHI:valSum+=offset(testChi(),Cpara);valCount++;break;
case INDUCTORLO:valSum+=offset(testLlo(1000),Lpara);valCount++;break;
case INDUCTORHI:valSum+=offset(testLhi(),Lpara);valCount++;break;
}
}
lastval=val;
lastmode=mode;
//LCD output
lcd.clear();
lcd.setCursor(0,0);
lcd.print(F("L:"));
if(Lhi<100e-3){ //valid range for oscillator
printSIlcd(offset(Llo,Lpara));
}else{
printSIlcd(offset(Lhi,Lpara));
}
lcd.print(F("H"));
lcd.setCursor(0,1);
lcd.print(F("C:"));
if(Chi<2.0e-6){ //valid range for oscillator
printSIlcd(offset(Clo,Cpara));
}else{
printSIlcd(offset(Chi,Cpara));
}
lcd.print(F("F"));
lcd.setCursor(0,2);
if((mode==INDUCTORHI)||(mode==INDUCTORLO)){lcd.print(F("--> Inductor"));}
if((mode==CAPACITORHI)||(mode==CAPACITORLO)){lcd.print(F("--> Capacitor"));}
lcd.setCursor(11,0);
lcd.print(F3L,0);
lcd.print(F("Hz"));
lcd.setCursor(11,1);
lcd.print(F3C,0);
lcd.print(F("Hz"));
if(valCount>0){
lcd.setCursor(0,3);
if((mode==INDUCTORHI)||(mode==INDUCTORLO)){
lcd.print(F("L="));
printSIlcd(valSum/valCount,5);
lcd.print(F("H "));
}
if((mode==CAPACITORHI)||(mode==CAPACITORLO)){
lcd.print(F("C="));
printSIlcd(valSum/valCount,5);
lcd.print(F("F "));
}
if(valCount<10000){
lcd.print(valCount);
}else{
lcd.print(F("9999"));
}
lcd.print(F(" samp"));
}
//check for command to enter calibration mode
while(Serial.available()){
if(Serial.read()=='C'){doCals();}
}
}
void relaySetup(){
pinMode(RELAY1,OUTPUT); //set to outputs, turn off
pinMode(RELAY2,OUTPUT);
pinMode(RELAY3,OUTPUT);
pinMode(RELAY4,OUTPUT);
relays(0);
}
float testClo(int n){ //use oscillator to test for C
float F3;
pinMode(R1PIN,INPUT); //turn off digital pins
pinMode(R2PIN,INPUT);
relays(MODECTEST); //set relays for capacitor on test pins
delay(500); //let oscillator stabilise
F3=GetFrequency(n); //get F3
F3C=F3;
return getCfromF3(F1,F3,C1VAL);
}
float testLlo(int n){ //use oscillator to test for L
float F3;
pinMode(R1PIN,INPUT); //turn off digital pins
pinMode(R2PIN,INPUT);
relays(MODELTEST); //set relays for inductor on test pins
delay(500); //let oscillator stabilise
F3=GetFrequency(n); //get F3
F3L=F3;
return getCfromF3(F1,F3,L1VAL);
}
float testChi(){ //use RC method for C
int a1,a2,a3;
unsigned long t0,t1;
float c=0; //default to zero if we can't read
relays(MODEHILC);
digitalWrite(R1PIN,LOW); //use R1 to discharge
pinMode(R1PIN,OUTPUT);
delay(500);
pinMode(R1PIN,INPUT);
digitalWrite(R2PIN,LOW);
pinMode(R2PIN,OUTPUT);
if(analogRead(ASENSEPIN)>300){delay(500);} //if not discharged, wait a bit more
a1=analogRead(ASENSEPIN);
a1=analogRead(ASENSEPIN); //double read to avoid glitches
digitalWrite(R2PIN,HIGH); //start charging
t0=micros(); //start timing
a2=analogRead(ASENSEPIN); //record value
delay(1);
while((micros()-t0<5000000)&&(analogRead(ASENSEPIN)<300)){delay(1);} //wait for reasonable rise and reasonable time
t1=micros(); //stop timing
a3=analogRead(ASENSEPIN); //record value
digitalWrite(R2PIN,LOW); //back to discharging for next time
if((a3>a2)&&(a3<1022)){ //log doesn't like negatives, low values will be unreliable
c=((t1-t0)/log((1023.0-a2)/(1023.0-a3))/(r2value));
}
return c/1000000; //because t is counted in us, c is in uF
}
float testLhi(){ // use RL method for L, time for about 2 tc's
byte saveADCSRA=ADCSRA; // save default value of ADCSRA, as we use faster prescaler for L calculations
int vact,vesr; // actual pin output due to sagging, voltage due to ESR
unsigned long t,tnew=0; // timing variables
float resr,kconst; // for L calculation
float l=0; // default to 0
relays(MODEHILC);
ADCSRA &= ~(bit (ADPS0) | bit (ADPS1) | bit (ADPS2)); // clear prescaler bits
ADCSRA |= bit (ADPS1); // prescaler of 4 for faster sampling (2 works on some boards)
digitalWrite(R1PIN,LOW); // ensure no current is flowing
pinMode(R1PIN,OUTPUT);
delay(300); // wait a bit
analogRead(ASENSEPIN); // let ADC settle
digitalWrite(R1PIN,HIGH); // start pulse
t=micros(); // start timer
tnew=t;
while((analogRead(ASENSEPIN)>LTHRESHOLD)&&(micros()-t<5000)){tnew=micros();}//timeout in case of open circuit
t=tnew-t;
analogRead(R1VACT); // do two readings to let it settle
vact=analogRead(R1VACT);
analogRead(ASENSEPIN);
analogRead(ASENSEPIN);
delay(200); // allow inductive effects to pass to measure ESR
vesr=analogRead(ASENSEPIN); // terminal V
resr=r1value*vesr/vact; // terminal R
digitalWrite(R1PIN,LOW); // ensure no current is flowing
if(vact!=vesr){
kconst=LTHRESHOLD/(float(vact-vesr)); // adjusted time constant
}
if(kconst>0){ // valid tc
l=(r1value+resr)*t*1023/(-log(kconst))/vact; // calculate L
}
delay(200);
ADCSRA=saveADCSRA; // restore ADCSRA to defaults
return l/1000000; // result in uH as t is in us
}
void relays(int n){ //set relays from bitwise pattern
digitalWrite(RELAY1,(n&1)?HIGH:LOW);
digitalWrite(RELAY2,(n&2)?HIGH:LOW);
digitalWrite(RELAY3,(n&4)?HIGH:LOW);
digitalWrite(RELAY4,(n&8)?HIGH:LOW);
}
long GetFrequency(long n) { //count pulses for n milliseconds (allows varying accuracies)
long Fcount;
if(n<1){n=1;} //no dividing by zero or negatives
FreqCount.begin(n);
while(!FreqCount.available()) {}
Fcount=FreqCount.read();
FreqCount.end();
return Fcount*1000.0/n;
}
float getF(float C, float L){ //calculate F from C and L
return 1/(TWO_PI*sqrt(C*L));
}
float getC(float F, float L){ //calculate C from F and L (is actually the same as getL(F,C))
return 1/(TWO_PI*TWO_PI*F*F*L);
}
float getCfromF3(float F1,float F3, float C1){ //get C based on Frequency change, can be used for L
if(F3<5){return 0;} //don't divide by zero
return C1*((F1*F1)/(F3*F3)-1);
}
void printSI(Stream &stream,float n){ //handle default case
printSI(stream,n,4);
}
void printSI(Stream &stream,float n,int s){ //print s sig figs with SI multiplier (do better with print to array and then format?)
float nmod=n;
char SImult=0;
if(n>1.0e9){nmod=n*1.0e-9;SImult='G';}
else if(n>1.0e6){nmod=n*1.0e-6;SImult='M';}
else if(n>1.0e3){nmod=n*1.0e-3;SImult='k';}
else if(n>1.0){nmod=n;SImult=' ';}
else if(n>1.0e-3){nmod=n*1.0e3;SImult='m';}
else if(n>1.0e-6){nmod=n*1.0e6;SImult='u';}
else if(n>1.0e-9){nmod=n*1.0e9;SImult='n';}
else if(n>1.0e-15){nmod=n*1.0e12;SImult='p';} //show less than 1pico
else {nmod=n;SImult=' ';} //n is close enough to 0
if(nmod>=100){stream.print(nmod,s<3?0:s-3);stream.write(SImult);}
else if(nmod>=10){stream.print(nmod,s<2?0:s-2);stream.write(SImult);}
else{stream.print(nmod,s<1?0:s-1);stream.write(SImult);}
}
void printSIlcd(float n){
printSIlcd(n,4); //default case
}
void printSIlcd(float n,int s){
float nmod=n;
char SImult=0;
if(n>1.0e9){nmod=n*1.0e-9;SImult='G';}
else if(n>1.0e6){nmod=n*1.0e-6;SImult='M';}
else if(n>1.0e3){nmod=n*1.0e-3;SImult='k';}
else if(n>1.0){nmod=n;SImult=' ';}
else if(n>1.0e-3){nmod=n*1.0e3;SImult='m';}
else if(n>1.0e-6){nmod=n*1.0e6;SImult='u';}
else if(n>1.0e-9){nmod=n*1.0e9;SImult='n';}
else if(n>1.0e-15){nmod=n*1.0e12;SImult='p';} //show less than 1pico
else {nmod=n;SImult=' ';} //n is close enough to 0
if(nmod>=100){lcd.print(nmod,s<3?0:s-3);lcd.write(SImult);}
else if(nmod>=10){lcd.print(nmod,s<2?0:s-2);lcd.write(SImult);}
else{lcd.print(nmod,s<1?0:s-1);lcd.write(SImult);}
}
void doCals(){ //this does the thorough setup cals
bool calsDone=0;
int m;
float n=0;
lcd.clear();
lcd.setCursor(0,0);
lcd.print(F("CALIBRATION MODE:"));
lcd.setCursor(0,1);
lcd.print(F("See serial monitor"));
Serial.println();
Serial.println(F("Calibration Mode:"));
delay(10);
while(Serial.available()){Serial.read();} //empty buffer for trailing CR/LF
while(!calsDone){
m=doMenu();
if(m<32){m='X';} //no valid input detected, exit
Serial.write(m);
Serial.println(F(" selected."));
lcd.setCursor(0,3);
lcd.write(m);
switch(m){
case 'A':
n=getEntry();
if((n>0)&&((unit=='R')||(unit==0))){ //valid value and suitable units
r1value=n;
Serial.print(F("130 Ohm changed to "));
printSI(Serial,r1value,7);
Serial.println(F("Ohms"));
}else{
Serial.println(F("Check value and units."));
}
break;
case 'B':
n=getEntry();
if((n>0)&&((unit=='R')||(unit==0))){ //valid value and suitable units
r2value=n;
Serial.print(F("1.3kOhm changed to "));
printSI(Serial,r2value,7);
Serial.println(F("Ohms"));
}else{
Serial.println(F("Check value and units."));
}
break;
case 'C':
n=getEntry();
if((n>0)&&((unit=='F')||(unit==0))){ //valid value and suitable units
C2VAL=n;
C1VAL=(C2VAL*F2*F2)/(F1*F1-F2*F2); //calculate C1 from new C2 value
Serial.print(F("C2 changed to "));
printSI(Serial,C2VAL,7);
Serial.println(F("F"));
}else{
Serial.println(F("Check value and units."));
}
break;
case 'D':
n=getEntry();
if((n>0)&&((unit=='H')||(unit==0))){ //valid value and suitable units
L1VAL=n;
Serial.print(F("L1 changed to "));
printSI(Serial,L1VAL,7);
Serial.println(F("H"));
}else{
Serial.println(F("Check value and units."));
}
break;
case 'E':
n=getEntry();
if((n>=0)&&((unit=='F')||(unit==0))){ //valid value and suitable units
Cpara=n;
Serial.print(F("Cpara changed to "));
printSI(Serial,Cpara,7);
Serial.println(F("F"));
}else{
Serial.println(F("Check value and units."));
}
break;
case 'F':
n=getEntry();
if((n>=0)&&((unit=='H')||(unit==0))){ //valid value and suitable units
Lpara=n;
Serial.print(F("Lpara changed to "));
printSI(Serial,Lpara,7);
Serial.println(F("H"));
}else{
Serial.println(F("Check value and units."));
}
break;
case 'G':
n=testClo(1000);
printSI(Serial,n);
Serial.println(F("F"));
if(confirm()){
Cpara=n;
Serial.print(F("Cpara changed to "));
printSI(Serial,Cpara,7);
Serial.println(F("F"));
lcd.clear();
lcd.setCursor(0,0);
lcd.print(F("Cpara updated"));
}else{
Serial.println(F("No change made"));
}
break;
case 'H':
n=testLlo(1000);
printSI(Serial,n);
Serial.println(F("H"));
if(confirm()){
Lpara=n;
Serial.print(F("Lpara changed to "));
printSI(Serial,Lpara,7);
Serial.println(F("H"));
lcd.clear();
lcd.setCursor(0,0);
lcd.print(F("Lpara updated"));
}else{
Serial.println(F("No change made"));
}
break;
case 'L':
setDefaults();
C1VAL=(C2VAL*F2*F2)/(F1*F1-F2*F2); //calculate C1 from new C2 value
lcd.clear();
lcd.setCursor(0,0);
lcd.print(F("Loaded from defaults"));
Serial.println(F("Loaded from defaults"));
break;
case 'P':showCurrent();break;
case 'S':
saveToEEPROM();
lcd.clear();
lcd.setCursor(0,0);
lcd.print(F("Saved to EEPROM"));
Serial.println(F("Saved to EEPROM"));
break;
default:
case 'X':
calsDone=1;
break;
}
}
lcd.clear();
lcd.setCursor(0,0);
lcd.print(F("Calibration done."));
Serial.println(F("Calibration finished."));
}
bool confirm(){ //ask Y/N on serial monitor, return true for Y
bool ret=0;
Serial.println(F("Proceed with change (Y/N)?"));
while(!Serial.available()){}
if(Serial.read()=='Y'){ret=1;} //only on Y, not y
delay(10);
while(Serial.available()){Serial.read();} //clear trailing CR/LF from buffer
return ret;
}
int doMenu(){ //displays menu and returns choice
int d,r=-1;
Serial.println();
Serial.println(F("A:Enter 130 Ohm value"));
Serial.println(F("B:Enter 1.3kOhm value"));
Serial.println(F("C:Enter C2 value"));
Serial.println(F("D:Enter L1 value"));
Serial.println(F("E:Enter Cparasitic value"));
Serial.println(F("F:Enter Lparasitic value"));
Serial.println(F("G:Auto detect Cparasitic (leave terminals open circuit)"));
Serial.println(F("H:Auto detect Lparasitic (short circuit leads)"));
Serial.println(F("L:Load defaults"));
Serial.println(F("P:Print current values"));
Serial.println(F("S:Save to EEPROM"));
Serial.println(F("X:Exit calibration"));
Serial.println(F("Choose an option"));
while(!Serial.available()){}
delay(10); //purge any extra characters like CR/LF
while(Serial.available()){
d=Serial.read();
if(d>31){r=toUpperCase(d);} //flag character
}
return r;
}
float getEntry(){ //awaits for a number to be entered
float f,m;
int d;
bool entryDone=0;
Serial.println(F("Enter a value:"));
lcd.clear();
lcd.setCursor(0,0);
lcd.print(F("Enter a value:"));
while(!entryDone){
while(Serial.available()){
d=Serial.read();
if(d==13){ //enter pressed
byte p=0;
entryDone=1;
m=1;
while((m==1)&&(buf[p]!=0)){
switch(buf[p]){
case 'p': m=1.0e-12;break;
case 'n': m=1.0e-9;break;
case 'u': m=1.0e-6;break;
case 'm': m=1.0e-3;break;
case 'k': m=1.0e3;break;
case 'M': m=1.0e6;break;
case 'G': m=1.0e9;break;
}
p++;
}
unit=0;
if(m==1){p=0;}
while((unit==0)&&(buf[p]!=0)){
switch(buf[p]){
case 'f':
case 'F': unit='F';break;
case 'h':
case 'H': unit='H';break;
case 'r':
case 'R': unit='R';break;
}
p++;
}
f=atof(buf);
Serial.print(f*m,13);
Serial.write((byte)unit);
Serial.println();
lcd.setCursor(0,1);
lcd.print(f*m,13);
if(unit){lcd.write((byte)unit);}
buf[0]=0;
}
if(d>31){ //only ascii
buf[strlen(buf)+1]=0;
buf[strlen(buf)]=d;
buf[BUFSIZE]=0; //keep inside buffer
}
}
}
return f*m;
}
float offset(float n, float a){ //adjusts n (down) by a, if result is negative, returns 0
n=n-a;
if(n<0){n=0;}
return n;
}
void loadFromEEPROM(){
bool eepromOK=1; //flag if there is a problem
readEEPROMid(checkid,strlen(eepromid)); //read id flag
if(!strmatch(checkid,eepromid)){
Serial.println(F("EEPROM signature not found, loading and saving defaults"));
lcd.setCursor(0,0);
lcd.print(F("Set EEPROM to init"));
setDefaults(); //load defaults
saveToEEPROM(); //save these values
writeEEPROMid(eepromid); //set id flag in EEPROM
}else{
Serial.println(F("EEPROM signature found"));
lcd.setCursor(0,0);
lcd.print(F("EEPROM ID OK"));
}
delay(300);
EEPROM.get(1,r1value); //start at 1 in case of errant EEPROM writing
EEPROM.get(5,r2value); //floats are 4 bytes
EEPROM.get(9,C2VAL);
EEPROM.get(13,L1VAL);
EEPROM.get(17,Cpara);
EEPROM.get(21,Lpara);
if(!(r1value>0)){eepromOK=0;} //use !sense to catch NAN etc.
if(!(r2value>0)){eepromOK=0;}
if(!(C2VAL>0)){eepromOK=0;}
if(!(L1VAL>0)){eepromOK=0;}
if(!(Cpara>=0)){eepromOK=0;}
if(!(Lpara>=0)){eepromOK=0;}
if(!eepromOK){
Serial.println(F("EEPROM Error, defaults loaded but not saved"));
lcd.setCursor(0,0);
lcd.print(F("EEPROM Error:"));
setDefaults();
}else{
Serial.println(F("EEPROM loaded OK"));
}
}
void saveToEEPROM(){
EEPROM.put(1,r1value); //start at 1 in case of errant EEPROM writing
EEPROM.put(5,r2value); //floats are 4 bytes
EEPROM.put(9,C2VAL);
EEPROM.put(13,L1VAL);
EEPROM.put(17,Cpara);
EEPROM.put(21,Lpara);
}
void setDefaults(){
r1value=130.0; //resistor 1 (R12)
r2value=1300.0; //resistor 2 (R11)
C2VAL=1.0e-9; //C2
L1VAL=100.0e-6; //L1
Cpara=0; //stray capacitance
Lpara=0; //stray inductance
}
void showCurrent(){ //display current values
//output to serial monitor
Serial.println();
Serial.print(F("R12:"));
printSI(Serial,r1value);
Serial.println(F("Ohms"));
Serial.print(F("R11:"));
printSI(Serial,r2value);
Serial.println(F("Ohms"));
Serial.print(F("C2:"));
printSI(Serial,C2VAL);
Serial.println(F("F"));
Serial.print(F("L1:"));
printSI(Serial,L1VAL);
Serial.println(F("H"));
Serial.print(F("Cp:"));
printSI(Serial,Cpara);
Serial.println(F("F"));
Serial.print(F("Lp:"));
printSI(Serial,Lpara);
Serial.println(F("H"));
//output to LCD
lcd.clear();
lcd.setCursor(0,0);
lcd.print(F("Calibration vals:"));
lcd.setCursor(0,1);
lcd.print(F("R12:"));
printSIlcd(r1value,2);
lcd.write(OHMSSYMBOL);
lcd.setCursor(10,1);
lcd.print(F("R11:"));
printSIlcd(r2value,2);
lcd.write(OHMSSYMBOL);
lcd.setCursor(0,2);
lcd.print(F("C2:"));
printSIlcd(C2VAL,3);
lcd.write('F');
lcd.setCursor(10,2);
lcd.print(F("L1:"));
printSIlcd(L1VAL,3);
lcd.write('H');
lcd.setCursor(0,3);
lcd.print(F("Cp:"));
printSIlcd(Cpara,3);
lcd.write('F');
lcd.setCursor(10,3);
lcd.print(F("Lp:"));
printSIlcd(Lpara,3);
lcd.write('H');
}
void writeEEPROMid(char* id){ //write id to end of eeprom
int i;
unsigned int s=EEPROM.length();
unsigned int n=strlen(id);
if(n>s-2){return;} //fail if it won't fit
for(i=0;i<n+1;i++){
EEPROM.write(s-n-1+i,id[i]);
}
}
void readEEPROMid(char* id,unsigned int idsize){ //read idsize+null bytes into id buffer
unsigned int i=0;
byte b=1; //to start in while loop
unsigned int s=EEPROM.length();
unsigned int p=s-idsize-1;
if(p<0){return;}
while(b&&(p<s)){
b=EEPROM.read(p);
id[i]=b;
i++;
p++;
}
}
bool strmatch(char* x, char* y){ //true if strings match
unsigned int n;
n=strlen(x);
if(n!=strlen(y)){return 0;} //can't match if different lengths
for(int i=0;i<n;i++){
if(x[i]!=y[i]){return 0;} //different at some point
}
return 1; //all match
}
void doCalibration(unsigned int t){
lcd.setCursor(0,0);
lcd.print(F("Self-calibrating "));
relays(MODECALNONE);
delay(1000);
F1=GetFrequency(t); //find F1 frequency
Serial.print(F("F1:"));
Serial.println(F1);
relays(MODECALC2);
delay(1000);
F2=GetFrequency(t); //find F2 frequency
Serial.print(F("F2:"));
Serial.println(F2);
C1VAL=(C2VAL*F2*F2)/(F1*F1-F2*F2); //calculate C1
Serial.print(F("C1:"));
printSI(Serial,C1VAL);
Serial.println(F("F"));
}