592 lines
18 KiB
C++
592 lines
18 KiB
C++
|
|
/*************************************************************************************
|
|
|
|
Kevin Lo, March 2015
|
|
|
|
This program will show PH , Room Temperature and Water Temperature on the LCD panel.
|
|
Also support serial communication.
|
|
|
|
Connection:
|
|
1) Plug the LCD Keypad to the UNO
|
|
2) Connect Arduino D2 to PH Meter Board T2 (DS18B20)
|
|
3) Connect Arduino A1 to PH Meter Board T1 (LM35)
|
|
4) Connect Arduino A2 to PH Meter Board P0 (PH)
|
|
5) Connect Arduino 5V to PH Meter Board Vcc
|
|
6) Connect Arduino GND to PH Meter Board GND
|
|
|
|
Require Library :
|
|
LiquidCrystal : http://arduino.cc/en/Reference/LiquidCrystal
|
|
OneWire : http://www.pjrc.com/teensy/td_libs_OneWire.html
|
|
DallasTemperature : http://milesburton.com/Dallas_Temperature_Control_Library
|
|
|
|
Serial Communication :
|
|
Send command in HEX format .
|
|
AA 01 01 BB , Enquiry DS18B20 temperature
|
|
AA 01 02 BB , Enquiry LM35 temperature
|
|
AA 01 03 BB , Enquiry PH reading
|
|
AA 01 04 BB , Enqyiry DS18B20 , LM35 and Ph
|
|
|
|
Version :
|
|
v0.1 5/3/2015 First Version
|
|
|
|
**************************************************************************************/
|
|
|
|
#include <LiquidCrystal.h>
|
|
//#include <OneWire.h>
|
|
//#include <DallasTemperature.h>
|
|
#include <EEPROM.h>
|
|
|
|
LiquidCrystal lcd(8, 9, 4, 5, 6, 7); // select the pins used on the LCD panel
|
|
//#define ONE_WIRE_BUS 2 // DS18B20 connect to Pin 2
|
|
#define MOTOR1 3 // jfs Pumpenrelais 1 Kontrolle
|
|
#define MOTOR2 2 // jfs Pumpenrelais 2 An/Aus
|
|
|
|
int Pumpe = 0; // jfs Pumpenkontrolle 0=aus 1=Kontrolle 2=an
|
|
|
|
#define FLOWRATE 20
|
|
#define MAXTUB 25
|
|
double tub[] = {0.13,0.19,0.25,0.38,0.44,0.51,0.57,0.64,0.76,0.89,0.95,1.02,1.09,1.14,1.22,1.30,1.42,1.52,1.65,1.75,1.85,2.06,2.29,2.54,2.79,3.17};
|
|
double ml[] = {0.0011,0.0023,0.0041,0.0094,0.013,0.017,0.021,0.026,0.036,0.049,0.056,0.063,0.072,0.078,0.088,0.098,0.11,0.13,0.15,0.16,0.17,0.20,0.24,0.27,0.31,0.35};
|
|
int tubid = 0;
|
|
int ee_tubid = 0;
|
|
double korrf = 0.915; // 22.09.2020 vorher 0.71
|
|
unsigned long start_timer; // jfs Timer start im Automodus
|
|
unsigned long time_flow; // aktuelle Zeitsapnne
|
|
double flow; // zugeflossene Menge ml[tubid]*20 -> ml/min
|
|
// msec/60000 -> min
|
|
|
|
//OneWire oneWire(ONE_WIRE_BUS);
|
|
//DallasTemperature sensors(&oneWire);
|
|
|
|
// the current address in the EEPROM (i.e. which byte
|
|
// we're going to write to next)
|
|
int addrph4 = 10;
|
|
int addrph7 = 20;
|
|
|
|
#define STX 0xAA // define STX for serial communication
|
|
#define ETX 0XBB // define ETX for serial communication
|
|
|
|
byte RxCmd [4] = {0,0,0,0};
|
|
|
|
// define some values used by the panel and buttons
|
|
int lcd_key = -1;
|
|
int adc_key_in = 0;
|
|
int adc_key_prev = -1;
|
|
int CurrentMode = 0; // 0 = Normal Display , 1 = Debug1 , 2 = Debug2
|
|
int CalSelect = 0; // 0 = PH4 Calibration Select , 1 = PH7 Calibration Select
|
|
|
|
const int NumReadings = 20; // number of reading for LM35
|
|
int Index = 0; // index
|
|
//int TempReadings[NumReadings]; // array for store LM35 readings
|
|
//int TempTotal = 0; // LM35 running total
|
|
//int TempAverage = 0; // LM35 average reading
|
|
//double TempValue = 0; // LM35 Temperature Data in Human Reading Format after calculation
|
|
|
|
int PhReadings[NumReadings]; // array for store PH readings
|
|
int PhTotal = 0; // PH running total
|
|
int PhAverage = 0; // PH average reading
|
|
|
|
double Ph7Buffer = 6.86; // For PH7 buffer solution's PH value , 7 or 6.86
|
|
double Ph4Buffer = 4.01; // For PH4 buffer solution's PH value , 4 or 4.01
|
|
|
|
//double Ph7Reading = 625; // PH7 Buffer Solution Reading.
|
|
//double Ph4Reading = 727; // PH4 Buffer Solution Reading.
|
|
|
|
int Ph7Reading = 625; // PH7 Buffer Solution Reading.
|
|
int Ph4Reading = 727; // PH4 Buffer Solution Reading.
|
|
|
|
|
|
|
|
|
|
|
|
//double Ph4Reading = EEPROM.read(addrph4); // PH7 Buffer Solution Reading.
|
|
//double Ph7Reading = EEPROM.read(addrph7);
|
|
|
|
|
|
double PhRatio = 0; // PH Step
|
|
double PhValue = 0; // Ph Value in Human Reading Format after calculation
|
|
|
|
#define btnRIGHT 0
|
|
#define btnUP 1
|
|
#define btnDOWN 2
|
|
#define btnLEFT 3
|
|
#define btnSELECT 4
|
|
#define btnNONE 5
|
|
|
|
int read_LCD_buttons(){ // read the buttons
|
|
adc_key_in = analogRead(0); // read the value from the sensor
|
|
delay(10); // switch debounce delay. Increase this delay if incorrect switch selections are returned.
|
|
int k = (analogRead(0) - adc_key_in); // gives the button a slight range to allow for a little contact resistance noise
|
|
if (5 < abs(k)) return btnNONE; // double checks the keypress. If the two readings are not equal +/-k value after debounce delay, it tries again.
|
|
//lcd.print(adc_key_in); // read button value and print for calibrate
|
|
|
|
// my buttons when read are centered at these valies: 0, 144, 329, 504, 741
|
|
// we add approx 50 to those values and check to see if we are close
|
|
// We make this the 1st option for speed reasons since it will be the most likely result
|
|
|
|
if (adc_key_in > 1000) return btnNONE;
|
|
if (adc_key_in < 50) return btnRIGHT;
|
|
if (adc_key_in < 150) return btnUP;
|
|
if (adc_key_in < 350) return btnDOWN;
|
|
if (adc_key_in < 550) return btnLEFT;
|
|
if (adc_key_in < 750) return btnSELECT;
|
|
return btnNONE; // when all others fail, return this.
|
|
}
|
|
|
|
int hys = 1; // Hysterese zur Messwertglättung
|
|
int lcv = 0;
|
|
|
|
int reading(){ // Reading LM35 and PH Data
|
|
// Samplin LM35 and PH Value
|
|
//TempTotal= TempTotal - TempReadings[Index]; // subtract the last reading:
|
|
PhTotal= PhTotal - PhReadings[Index]; // subtract the last reading:
|
|
//TempReadings[Index] = analogRead(1); // read from the sensor : LM35
|
|
PhReadings[Index] = analogRead(2); // read from the sensor : PH
|
|
//TempTotal= TempTotal + TempReadings[Index]; // add the reading to the temperature total:
|
|
PhTotal= PhTotal + PhReadings[Index]; // add the reading to the ph total:
|
|
Index = Index + 1; // advance to the next position in the array:
|
|
|
|
if (Index >= NumReadings){ // if we're at the end of the array...
|
|
Index = 0; // ...wrap around to the beginning:
|
|
//TempAverage = TempTotal / NumReadings; // calculate the average:
|
|
lcv = PhTotal / NumReadings; // calculate the average:
|
|
}
|
|
//TempValue = (double) TempAverage / 3.4 * (5/10.24); // LM35 connect to CA3140 for amplify 3 time Serial.print(PhAverage);
|
|
//Serial.print(PhAverage);
|
|
if (PhAverage == 0){
|
|
PhAverage = lcv;
|
|
} else {
|
|
if (lcv+1 > PhAverage ){
|
|
PhAverage=lcv;
|
|
}
|
|
if (lcv-1 < PhAverage ){
|
|
PhAverage=lcv;
|
|
}
|
|
}
|
|
|
|
//Serial.print(" ");
|
|
//Serial.print(lcv);
|
|
//Serial.print(" ");
|
|
|
|
|
|
PhValue = (Ph7Reading - PhAverage) / PhRatio + Ph7Buffer; // Calculate PH vorher PhAverage
|
|
|
|
//Serial.println(PhValue);
|
|
}
|
|
|
|
|
|
|
|
void setup(){
|
|
EEPROM.get(ee_tubid, tubid);
|
|
if ((tubid <0) || (tubid>MAXTUB)){
|
|
tubid=0;
|
|
}
|
|
pinMode(MOTOR1, OUTPUT);
|
|
pinMode(MOTOR2, OUTPUT);
|
|
pinMode(MOTOR1,HIGH);
|
|
pinMode(MOTOR2,LOW);
|
|
Pumpe = 1;
|
|
|
|
EEPROM.get(addrph4,Ph4Reading);
|
|
|
|
EEPROM.get(addrph7,Ph7Reading);
|
|
|
|
lcd.begin(16, 2); // start LCD library
|
|
|
|
//for (int TempThisReading = 0; TempThisReading < NumReadings; TempThisReading++) // initialize all the LM35 readings to 0:
|
|
//TempReadings[TempThisReading] = 0;
|
|
|
|
for (int PhThisReading = 0; PhThisReading < NumReadings; PhThisReading++) // initialize all the Ph readings to 0:
|
|
PhReadings[PhThisReading] = 0;
|
|
|
|
PhRatio = (double)(Ph4Reading - Ph7Reading) / (Ph7Buffer - Ph4Buffer); // Calculate Ph Ratio
|
|
|
|
// Debug output at startup
|
|
Serial.print("Setup - Ph4Reading: ");
|
|
Serial.print(Ph4Reading);
|
|
Serial.print(", Ph7Reading: ");
|
|
Serial.print(Ph7Reading);
|
|
Serial.print(", PhRatio: ");
|
|
Serial.println(PhRatio, 4);
|
|
|
|
Serial.begin(9600);
|
|
while(Serial.available()) Serial.read(); // empty RX buffer
|
|
Serial.println("Starting");
|
|
PhAverage = 0;
|
|
}
|
|
|
|
|
|
void loop(){
|
|
|
|
for (int i = 0 ; i < 4 ; i++) {
|
|
RxCmd[i] = 0;
|
|
}
|
|
|
|
if (Serial.available()) {
|
|
delay(2);
|
|
RxCmd[0] = Serial.read();
|
|
if (RxCmd[0] == '<') {
|
|
int i =1;
|
|
while(Serial.available()) {
|
|
delay(1);
|
|
RxCmd[i] = Serial.read();
|
|
//if (RxCmd[i]>127 || i>7) break; //Communication error
|
|
if (RxCmd[i]== '>') {
|
|
break; //Read all data
|
|
}
|
|
i++;
|
|
|
|
}
|
|
}
|
|
}
|
|
if ( RxCmd[1] == '1' ){
|
|
switch (RxCmd[2]) {
|
|
case '1':{ // Pumpe an
|
|
pinMode(MOTOR1,HIGH);
|
|
pinMode(MOTOR2,HIGH);
|
|
Pumpe=2;
|
|
Serial.println("<P1>"); // Bestätigung
|
|
break;
|
|
}
|
|
case '2':{ // Pumpe aus
|
|
pinMode(MOTOR1,HIGH);
|
|
pinMode(MOTOR2,LOW);
|
|
Serial.println("<P0>"); // Bestätigung
|
|
Pumpe=1;
|
|
break;
|
|
}
|
|
case '3': {
|
|
Serial.print("<T");
|
|
Serial.print(tubid); // Return current Tubid
|
|
Serial.println(">");
|
|
break;
|
|
}
|
|
case '4':{// PH - Daten anfordern
|
|
Serial.print("<#");
|
|
Serial.print(PhValue,2); // Return PH Data
|
|
Serial.println(">");
|
|
break;
|
|
}
|
|
case '5':{// pH4 Kalibrierung starten
|
|
Ph4Reading = (int) PhAverage;
|
|
EEPROM.put(addrph4, Ph4Reading);
|
|
PhRatio = (double)(Ph4Reading - Ph7Reading) / (Ph7Buffer - Ph4Buffer); // Recalculate ratio
|
|
Serial.print("<CAL4>");
|
|
Serial.print(" Ph4R:");
|
|
Serial.print(Ph4Reading);
|
|
Serial.print(" Ph7R:");
|
|
Serial.print(Ph7Reading);
|
|
Serial.print(" Ratio:");
|
|
Serial.print(PhRatio, 4);
|
|
Serial.println(">");
|
|
break;
|
|
}
|
|
case '6':{// pH7 Kalibrierung starten
|
|
Ph7Reading = (int) PhAverage;
|
|
EEPROM.put(addrph7, Ph7Reading);
|
|
PhRatio = (double)(Ph4Reading - Ph7Reading) / (Ph7Buffer - Ph4Buffer); // Recalculate ratio
|
|
Serial.print("<CAL7>");
|
|
Serial.print(" Ph4R:");
|
|
Serial.print(Ph4Reading);
|
|
Serial.print(" Ph7R:");
|
|
Serial.print(Ph7Reading);
|
|
Serial.print(" Ratio:");
|
|
Serial.print(PhRatio, 4);
|
|
Serial.println(">");
|
|
break;
|
|
}
|
|
case '7':{
|
|
int a = RxCmd[3]-'0';
|
|
Serial.println(a);
|
|
int b = RxCmd[4] -'3';
|
|
Serial.println(b);
|
|
// int c = RxCmd[5]-'0';
|
|
//Serial.println(c);
|
|
if (b>9){ // only one diget
|
|
tubid = a;
|
|
} else {
|
|
tubid = a* 10 + b;
|
|
}
|
|
if (tubid >= 0 && tubid <= MAXTUB) {
|
|
EEPROM.put(ee_tubid, tubid);
|
|
Serial.print("<T");
|
|
Serial.print(tubid);
|
|
Serial.println(">"); // Bestätigung
|
|
}
|
|
break;
|
|
}
|
|
case '8':{// Flow Rate anfordern (ml/sec)
|
|
Serial.print("<F");
|
|
double mlpersec = (ml[tubid] * korrf * 20) / 60; // tube * korrektur * 20 rpm / 60 sec
|
|
Serial.print(mlpersec, 4); // 4 decimal places
|
|
Serial.println(">");
|
|
break;
|
|
}
|
|
case '9':{// Debug: Kalibrierungswerte anzeigen
|
|
Serial.print("<DEBUG>");
|
|
Serial.print(" PhAvg:");
|
|
Serial.print(PhAverage);
|
|
Serial.print(" Ph4R:");
|
|
Serial.print(Ph4Reading);
|
|
Serial.print(" Ph7R:");
|
|
Serial.print(Ph7Reading);
|
|
Serial.print(" Ratio:");
|
|
Serial.print(PhRatio, 4);
|
|
Serial.print(" PhVal:");
|
|
Serial.print(PhValue, 2);
|
|
Serial.println(">");
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
if (CurrentMode == 0){ // Nomral Display Mode
|
|
|
|
reading(); // Reading LM35 and PH Data for display
|
|
//lcd.setCursor(13,0);
|
|
//lcd.print("PH ");
|
|
lcd.setCursor(0,0);
|
|
lcd.print("Pumpe ");
|
|
lcd.setCursor(7,0);
|
|
lcd.print(Pumpe);
|
|
lcd.setCursor(0,1);
|
|
lcd.print(tub[tubid]);
|
|
|
|
//lcd.setCursor(0,0); // set the LCD cursor position
|
|
//lcd.print("Room");
|
|
//lcd.setCursor(0,1);
|
|
//lcd.print("Water");
|
|
//lcd.setCursor(6,0);
|
|
//lcd.print(TempValue); // display room temperature value (LM35)
|
|
delay(1); // delay in between reads for stability
|
|
|
|
// Display 18B20 Temperature
|
|
//lcd.setCursor(6,1); // move cursor to second line "1" and 6 spaces over
|
|
//sensors.requestTemperatures(); // Read DS18B20 data
|
|
//lcd.print(sensors.getTempCByIndex(0)); // Display DS18B20 Data
|
|
|
|
// Display PH Data
|
|
lcd.setCursor(13,0);
|
|
lcd.print("PH");
|
|
lcd.setCursor(12,1);
|
|
lcd.print(PhValue); // display PH value
|
|
delay(1); // delay in between reads for stability
|
|
|
|
}
|
|
|
|
if (CurrentMode == 1){ // Pumpe aus Kontrolle an
|
|
lcd.setCursor(0,0);
|
|
lcd.print("Pumpe aus >>");
|
|
}
|
|
|
|
if (CurrentMode == 2){ // Pumpenkontrolle aus
|
|
lcd.setCursor(0,0);
|
|
lcd.print("Kontrolle aus >>");
|
|
}
|
|
|
|
if (CurrentMode == 3){ // Pumpe an Kontrolle an
|
|
lcd.setCursor(0,0);
|
|
lcd.print("Pumpen an >>");
|
|
}
|
|
|
|
if (CurrentMode == 4){ // PH4 Calibration Mode
|
|
reading();
|
|
lcd.setCursor(0,0);
|
|
lcd.print("PH4 Cal. Mode");
|
|
lcd.setCursor(0,1);
|
|
lcd.print("C:");
|
|
lcd.setCursor(2,1);
|
|
lcd.print(Ph4Reading);
|
|
lcd.setCursor(9,1);
|
|
lcd.print("R:");
|
|
lcd.setCursor(11,1);
|
|
lcd.print(PhAverage);
|
|
}
|
|
|
|
if (CurrentMode == 5){ // PH7 Calibration Mode
|
|
reading();
|
|
lcd.setCursor(0,0);
|
|
lcd.print("PH7 Cal. Mode");
|
|
lcd.setCursor(0,1);
|
|
lcd.print("C:");
|
|
lcd.setCursor(2,1);
|
|
lcd.print(Ph7Reading);
|
|
lcd.setCursor(9,1);
|
|
lcd.print("R:");
|
|
lcd.setCursor(11,1);
|
|
lcd.print(PhAverage);
|
|
}
|
|
|
|
if (CurrentMode == 6){ // Schlauchauswahl vorschlagen
|
|
lcd.clear();
|
|
lcd.setCursor(0,0);
|
|
lcd.print("Schlauch >>");
|
|
}
|
|
|
|
if (CurrentMode == 10){ // Schlauchauswählen
|
|
lcd.setCursor(0,0);
|
|
lcd.print(tub[tubid]);
|
|
lcd.setCursor(0,1);
|
|
lcd.print(ml[tubid]);
|
|
}
|
|
if (CurrentMode == 11){ // Auto modus läuft
|
|
reading(); // Reading LM35 and PH Data for display
|
|
time_flow=millis() - start_timer ;
|
|
flow = (20*time_flow)/60000; // vergangene sec
|
|
flow = ml[tubid]*flow*korrf; // ml/min
|
|
lcd.setCursor(0,0);
|
|
lcd.print("ml");
|
|
lcd.setCursor(0,1);
|
|
lcd.print(flow);
|
|
// Display PH Data
|
|
lcd.setCursor(13,0);
|
|
lcd.print("PH");
|
|
lcd.setCursor(12,1);
|
|
lcd.print(PhValue); // display PH value
|
|
delay(10); // delay in between reads for stability
|
|
|
|
}
|
|
if (CurrentMode == 12) { // Auto modus stopped
|
|
delay(100);
|
|
//reading();
|
|
//lcd.setCursor(4,0);
|
|
//lcd.print("Stop");
|
|
lcd.setCursor(0,0);
|
|
lcd.print("used ml");
|
|
lcd.setCursor(0,1);
|
|
lcd.print(flow);
|
|
// Display PH Data
|
|
lcd.setCursor(13,0);
|
|
lcd.print("PH");
|
|
lcd.setCursor(12,1);
|
|
lcd.print(PhValue); // display PH value
|
|
delay(100);
|
|
}
|
|
|
|
lcd.setCursor(0,1); // move to the begining of the second line
|
|
adc_key_prev = lcd_key ; // Looking for changes
|
|
|
|
lcd_key = read_LCD_buttons(); // read the buttons
|
|
|
|
if (adc_key_prev != lcd_key)
|
|
{
|
|
switch (lcd_key){
|
|
case btnDOWN:{
|
|
if (CurrentMode==10){
|
|
tubid -=1;
|
|
if (tubid == -1){
|
|
tubid = MAXTUB;
|
|
}
|
|
} else {
|
|
lcd.clear();
|
|
CurrentMode +=1;
|
|
if (CurrentMode == 7){
|
|
CurrentMode = 0;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case btnUP:{
|
|
if (CurrentMode==10){
|
|
tubid += 1;
|
|
if (tubid == MAXTUB){
|
|
tubid=0;
|
|
}
|
|
} else {
|
|
lcd.clear();
|
|
CurrentMode -= 1;
|
|
if (CurrentMode == -1){
|
|
CurrentMode = 6;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case btnLEFT:{
|
|
lcd.clear();
|
|
CurrentMode =0;
|
|
break;
|
|
}
|
|
case btnRIGHT:{
|
|
lcd.clear();
|
|
if ( CurrentMode == 1){ //Pumpe aus
|
|
pinMode(MOTOR1,HIGH);
|
|
pinMode(MOTOR2,LOW);
|
|
Pumpe=1;
|
|
CurrentMode = 0;
|
|
break;
|
|
}
|
|
if ( CurrentMode == 2) { //Pumpenkotrolle
|
|
pinMode(MOTOR1,LOW);
|
|
pinMode(MOTOR2,LOW);
|
|
Pumpe=0;
|
|
CurrentMode = 0;
|
|
break;
|
|
}
|
|
if ( CurrentMode == 3) { //Pumpe an
|
|
pinMode(MOTOR1,HIGH);
|
|
pinMode(MOTOR2,HIGH);
|
|
Pumpe=2;
|
|
CurrentMode = 0;
|
|
break;
|
|
}
|
|
if ( CurrentMode == 4) { //ph 4 wert speichern
|
|
Ph4Reading = (int) PhAverage;
|
|
Serial.println(Ph4Reading);
|
|
EEPROM.put(addrph4,Ph4Reading);
|
|
int p ;
|
|
EEPROM.get(addrph4,p);
|
|
Serial.println(p);
|
|
|
|
CurrentMode = 0;
|
|
break;
|
|
}
|
|
if ( CurrentMode == 5) { //ph 7 wert speichern
|
|
Ph7Reading = (int) PhAverage;
|
|
Serial.println(Ph7Reading);
|
|
EEPROM.put(addrph7,Ph7Reading);
|
|
int p ;
|
|
EEPROM.get(addrph7,p);
|
|
Serial.println(p);
|
|
|
|
CurrentMode = 0;
|
|
break;
|
|
}
|
|
if (CurrentMode == 6 ) { // nun die Schläuche auswählen
|
|
CurrentMode = 10;
|
|
break;
|
|
}
|
|
if ( CurrentMode == 10) { // Schlauchindex speichern
|
|
// todo
|
|
EEPROM.put(ee_tubid,tubid);
|
|
CurrentMode = 0;
|
|
break;
|
|
}
|
|
}
|
|
case btnSELECT:{
|
|
if (CurrentMode == 0){ // Automodus starten
|
|
pinMode(MOTOR1,HIGH);
|
|
pinMode(MOTOR2,HIGH);
|
|
lcd.clear();
|
|
start_timer = millis();
|
|
CurrentMode = 11;
|
|
break;
|
|
}
|
|
if (CurrentMode == 11){
|
|
pinMode(MOTOR1,HIGH);
|
|
pinMode(MOTOR2,LOW);
|
|
CurrentMode = 12;
|
|
break;
|
|
}
|
|
if (CurrentMode == 12){
|
|
CurrentMode = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|