User Tools

Site Tools


en:ec_metr

Table of Contents

EC metr

EC monitoring with two-point calibration. Without temperature compensation.

Schema

PCB overlay


Code

ecMetr.ino
#include <EEPROM.h>
#include "EEPROMAnything.h"
#include <LiquidCrystal.h>
 
 
LiquidCrystal lcd(12, 11, 8, 7, 6, 5);
 
#define ECInput 3
#define EC_enable 4
#define Buttons A5
#define BOUNCE_DURATION 300
 
#define FREQSAMPLES 1024
 
#define KeyUp    30
#define KeyDown  40
#define KeySel   50
#define KeyInv   60   //invalid key value
 
 
#define CalibMenuB 2
#define FirstStep 3
#define SecondStep 4
#define CalibMenu_P 0
#define GetLow 5
#define GetHigh 6
#define SuccessfulyDone 9
 
 
float ECa;            
float ECb;
 
float ec;
 
boolean showStatus;
 
volatile unsigned long bounceTime=0;
 
char tmp[8];
 
prog_char string_0[] PROGMEM =   "CALIB";  //0
prog_char string_1[] PROGMEM =   "EC";  //1
prog_char string_2[] PROGMEM =   "START";  //2
prog_char string_3[] PROGMEM =   "LOW";  //3
prog_char string_4[] PROGMEM =   "HIGH";  //4
prog_char string_5[] PROGMEM =   "GET LOW";  //5
prog_char string_6[] PROGMEM =   "GET HIGH";  //6
prog_char string_7[] PROGMEM =   "STANDART";  //7
prog_char string_8[] PROGMEM =  "VALUE"; //8
prog_char string_9[] PROGMEM =  "reading..."; //9
 
PROGMEM const char *StringTable[] = {
  string_0, //0
  string_1, //1
  string_2, //2
  string_3, //3         
  string_4, //4
  string_5, //5
  string_6, //6
  string_7, //7
  string_8, //8
  string_9, //9 
};
 
byte offset, whichkey;
 
void setup()                    // run once, when the sketch starts
{
 
pinMode(EC_enable,OUTPUT);
pinMode(ECInput,INPUT);
lcd.begin(8, 2);
 
EEPROM_readAnything(48, ECa);
EEPROM_readAnything(56, ECb);
attachInterrupt(0,show, RISING); 
delay(2000);
}
 
void loop()                     
{
if(showStatus)mainMenu();
digitalWrite(EC_enable,HIGH);
delay(100);
ec=ECread();
dtostrf(ec,1,1,tmp);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("EC:");
lcd.setCursor(0, 1);
lcd.print(tmp);
digitalWrite(EC_enable,LOW);
delay(20000); 
}
 
void show(){
  if (abs(millis() - bounceTime) > BOUNCE_DURATION)  
  {
   showStatus=!showStatus;
lcd.clear(); 
bounceTime = millis();  // set whatever bounce time in ms is appropriate
 }
 
}
 
void mainMenu() {
  showStatus=true;
  offset=CalibMenuB;
  do {
    delay(50);
    lcd.clear();
    PrintLCD_P(CalibMenu_P); 
    PrintLCDAt_P(offset, 0, 1);
    whichkey = PollKey();
    if(whichkey==KeySel) CalibFirstStep();   
  } while (showStatus);
}
 
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void CalibFirstStep() {
 int lowStandart;
   lowStandart=2;
   do {
    lcd.clear();
    PrintLCDAt_P(FirstStep, 0, 0);
    lcd.setCursor(0,1);
    lcd.print(lowStandart);
    whichkey = PollKey();
    switch(whichkey) {
       case KeyDown:lowStandart--;break;
       case KeyUp:lowStandart++;break;
       case KeySel:CalibSecondStep(lowStandart);break;
    }
 
  } while (showStatus);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void CalibSecondStep(int lowStandart) {
 int highStandart;
  highStandart=6;
  do {
    lcd.clear();
    PrintLCDAt_P(SecondStep, 0, 0);
    lcd.setCursor(0,1);
    lcd.print(highStandart);
    whichkey = PollKey();
    switch(whichkey) {
       case KeyDown:highStandart--;break;
       case KeyUp:highStandart++;break;
       case KeySel:CalibThirdStep(lowStandart, highStandart);break;
    }
 
  } while (showStatus);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void CalibThirdStep(int lowStandart, int highStandart ) {
   lcd.clear();
   PrintLCDAt_P(GetLow, 0, 0);
   do {
    //lowValue=getFrequency(ECInput);
 
    delay(300);
    ec= ECclear();
    //lcd.clear();
    lcd.setCursor(0,1);
    lcd.print(ec);
    whichkey = KeyScan();
  } while (whichkey!=KeySel);
 
 lcd.clear();
 PrintLCD_P(9);
 delay(1500);
 CalibFourthStep(lowStandart, highStandart, ec);
 
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void CalibFourthStep(int lowStandart, int highStandart, float  lowValue) {
  float highValue;
   lcd.clear(); 
   PrintLCDAt_P(GetHigh, 0, 0);
  do {
 
    delay(300);
    highValue=ECclear();
    lcd.setCursor(0,1);
    lcd.print(highValue);
   // PrintLCDAt_P(highValue, 0, 2);
    whichkey = KeyScan();     
  } while (whichkey!=KeySel);
 
 setECConstants(((highValue-lowValue)/(highStandart-lowStandart)),(highStandart-(highValue/((highValue-lowValue)/(highStandart-lowStandart)))));
 
 lcd.clear();
 PrintLCD_P(9);
 delay(1500);
 mainMenu();
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void PrintLCDAt(char *inStr, char x, char y) {
   lcd.setCursor( x,y ); 
   delay(20);
   lcd.print(inStr);
   delay(40);
}
 
void PrintLCDAt_P(int which, char x, char y) {
  lcd.setCursor( x,y );  
  delay(20);
  PrintLCD_P(which);  
}
 
void PrintLCD_P(int which) {
   char buffer[21];
   strcpy_P(buffer, (char*)pgm_read_word(&(StringTable[which])));
   lcd.print(buffer);
   delay(40);
}
 
char KeyScan() {
   int which, which2, diff,retVal;
   which = analogRead(Buttons);
   delay(0);
   which2 = analogRead(Buttons);
   retVal = KeyInv;
   diff = abs(which - which2);
   if (diff < 12) {
 
      if (which > 900 && which < 1024) retVal =  KeySel;
      if (which > 280  && which < 360) retVal =  KeyDown;
 
      if (which > 480 && which < 550) retVal =  KeyUp;
   }
   return retVal;
}
 
char PollKey() {
  char Whichkey;
    do {
     Whichkey = KeyScan();
     delay(60);
  } while ((Whichkey==KeyInv) && showStatus);
  delay(80);
  return Whichkey;
}
 
 
float ECread(){
float ECf;
ECf=(getFrequency(ECInput)/ECa)+ECb;
if(ECf>0) return ECf; 
else return 0;
}
 
float ECclear(){
float ECf;
ECf=getFrequency(ECInput);
return ECf; 
}
 
long getFrequency(int pin) {
long freqhigh = 0;
long freqlow =0;
long frequency=0;
digitalWrite(EC_enable, HIGH);
for(unsigned int j=0; j<FREQSAMPLES; j++){
freqhigh+= pulseIn(pin, HIGH);
freqlow+= pulseIn(pin, LOW);
}
frequency = 1000000 / ( (freqhigh / FREQSAMPLES) + (freqlow / FREQSAMPLES) );
digitalWrite(EC_enable, LOW);
return frequency;
}
 
void setECConstants(float a, float b)
{
  ECa=a;
  ECb=b; 
EEPROM_writeAnything(48, a);
EEPROM_writeAnything(56, b);
}

When starting EC metr reads the calibration constants from EEPROM. Before the first run and calibration there is need of write some numbers to EEPROM so code do not panic. For this purpose serves code below:

ECBareLoader
#include <EEPROM.h>
#include "EEPROMAnything.h"
float ECa=1;
float ECb=1;
 
void setup() {
 
EEPROM_writeAnything(48, ECa);
EEPROM_writeAnything(56, ECb);
Serial.begin(9600);  
Serial.println("writing done");
}
 
void loop() {
}

Menu is easy because it has just one part which is calibration.

→mainMenu→CalibrationFirstStep→CalibrationSecondStep→CalibrationThirdStep→CalibrationFourthStep

  • at first step user input EC value of less conducting solution
  • at second step user input EC value of more conducting solution
  • at third step put EC probe into less conducting calibration solution and wait for value stabilization (cca 10 min.)
  • at fourth step put pH probe into more conducting calibration solution and wait for value stabilization (cca 10 min.). At the moment the calibration is confirmed by user. New constants are save into EEPROM so there is no need of recalibration after reboot.

Box

en/ec_metr.txt · Last modified: 2018/01/29 10:12 (external edit)