/* brauduino semi automated single vessel RIMS created by s.mathison Copyright (C) 2012 Stephen Mathison compiled on Arduino V1.0 This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see .*/ //libraries #include #include #include #include OneWire ds(11); LiquidCrystal lcd(2, 3, 4, 5, 6, 7); // push buttons const char Button_up = A3; const char Button_dn = A2; const char Button_prev = A1; const char Button_nxt = A0; // outputs const int Heat = 9; const int Pump = 8; const int Buzz = 10; // global variables unsigned int WindowSize; unsigned long windowStartTime; unsigned long start; double Setpoint, Input, Output,eepromKp, eepromKi, eepromKd; //boolean autoLoop = false; boolean manualLoop = false; boolean waterAdd = false; boolean Conv_start = false; boolean mpump = false; boolean mheat = false; boolean wtBtn = false; boolean autoEnter = false; boolean tempReached = false; boolean pumpRest = false; //boolean boilLoop = false; boolean resume = false; float mset_temp = 35; float Temp_c, stageTemp,pumptempError,Temp_PID; int x; int stageTime,hopTime; byte mainMenu = 0; byte pumpTime; byte data[9]; byte second; //byte minute; //byte i; byte Busy = 0; byte nmbrStgs; byte nmbrHops; byte tempHAddr; byte tempLAddr; byte timeAddr; byte blhpAddr; byte hopAdd; char* stgName[] ={ "MashIn","Stage1","Stage2","Stage3","Stage4","Stage5","Stage6","Stage7","Stage8","Boil "}; // degree c sybmol byte degc[8] = { B01000, B10100, B01000, B00011, B00100, B00100, B00011, B00000, }; //Specify the links and initial tuning parameters PID myPID(&Input, &Output, &Setpoint,100,20,5, DIRECT); //****** start of the funtions************** void Buzzer(int number) { for (int i=0; i < number; i++) { digitalWrite (Buzz,HIGH); delay (500); digitalWrite(Buzz,LOW); delay(100); } } void pause_stage(void){ boolean stage_pause = false; if (Button_1sec_press(Button_prev)){ Buzzer(1); stage_pause = true; digitalWrite(Heat,LOW); digitalWrite(Pump,LOW); display_lcd(0,0," Paused " ); while (stage_pause) { if (Button_1sec_press(Button_prev))stage_pause=false; } } } void display_lcd (int pos , int line ,const char* lable){ lcd.setCursor(pos,line); lcd.print(lable); } // 1 second button press int Button_1sec_press (int Button_press){ if (digitalRead(Button_press)==0){ delay (1000); if (digitalRead(Button_press)==0){ lcd.clear(); while(digitalRead(Button_press)==0){ } return 1; } } return 0; } // repeat button press int Button_repeat (int Button_press){ if (digitalRead(Button_press)==0){ delay(200); return 1; } return 0; } // holds whilst button pressed int Button_hold_press (int Button_press){ if (digitalRead (Button_press)==0){ delay(50); while (digitalRead (Button_press)==0){ } return 1; } return 0; } // reads the DS18B20 temerature probe void Temperature(void){ ds.reset(); ds.skip(); // start conversion and return if (!(Conv_start)){ ds.write(0x44,0); Conv_start = true; return; } // check for conversion if it isn't complete return if it is then convert to decimal if (Conv_start){ Busy = ds.read_bit(); if (Busy == 0){ return; } ds.reset(); ds.skip(); ds.write(0xBE); for ( int i = 0; i < 9; i++) { // we need 9 bytes data[i] = ds.read(); } if ( OneWire::crc8(data, 8) != data[8]) { //if checksum fails start a new conversion right away ds.reset(); ds.skip(); ds.write(0x44,0); Conv_start = true; return; } unsigned int raw = (data[1] << 8) + data[0]; Temp_PID = (raw&0xFFFF)*0.0625; Temp_c = (raw & 0xFFFC) * 0.0625; Conv_start = false; return; } } void PID_HEAT (void){ if(autoEnter){ Setpoint = stageTemp; } else{ Setpoint = mset_temp; } Input = Temp_PID; if((Setpoint - Input)>5){ digitalWrite(Heat,HIGH); if ((Setpoint - Input)<6) { myPID.Compute(); } } else{ myPID.Compute(); unsigned long now = millis(); if(now - windowStartTime>WindowSize) { //time to shift the Relay Window windowStartTime += WindowSize; } if((Output*(WindowSize/100)) > now - windowStartTime) digitalWrite(Heat,HIGH); else digitalWrite(Heat,LOW); } } void load_pid_settings (void) { eepromKp = word(EEPROM.read(0),EEPROM.read(1));// read the PID settings from the EEPROM eepromKi = word(EEPROM.read(2),EEPROM.read(3)); eepromKd = word(EEPROM.read(4),EEPROM.read(5)); eepromKi = eepromKi/100; myPID.SetTunings(eepromKp,eepromKi,eepromKd); // send the PID settings to the PID WindowSize = word(EEPROM.read(33),EEPROM.read(34)); myPID.SetOutputLimits(0, 100); myPID.SetSampleTime(5000); } boolean wait_for_confirm (boolean& test) { wtBtn = true; while (wtBtn){ // wait for comfirmation if (Button_hold_press(Button_prev)){ test = true; wtBtn = false; lcd.clear(); } if (Button_hold_press(Button_nxt)){ test = false; wtBtn = false; lcd.clear(); } } } float change_temp(float& temp_change,int upper_limit,int lower_limit) { // Increase set temp if (Button_repeat(Button_up)){ if (temp_change>=100){ temp_change++; } else{ temp_change+=0.25; } if (temp_change > upper_limit)temp_change = upper_limit; } // decrease temp if (Button_repeat(Button_dn)) { if(temp_change>=100){ temp_change--; } else{ temp_change-=0.25; } if ( temp_change < lower_limit) temp_change = lower_limit; } } void quit_mode (boolean& processLoop) { if ((digitalRead(Button_dn)==0) && (digitalRead(Button_up)==0)){ digitalWrite(Heat,LOW); digitalWrite(Pump,LOW); processLoop = false; lcd.clear(); } } void heat_control(void) { //turns heat on or off if (Button_hold_press(Button_prev)){ if (mheat==false){ mheat = true; windowStartTime = millis(); } else{ mheat = false; digitalWrite(Heat,LOW); } } } void pump_control(void) { //turns the pump on or off if (Button_hold_press(Button_nxt)){ if (mpump == false){ mpump = true; digitalWrite(Pump,HIGH); } else{ mpump = false; digitalWrite(Pump,LOW); } } } void prompt_for_water (void){ display_lcd(0,0," Water added? "); Buzzer(3); display_lcd(0,1," Ok Quit"); } void pump_prime(void) { lcd.clear(); lcd.print(" Pump Prime "); // priming the pump digitalWrite(Pump,HIGH); delay (1000); digitalWrite(Pump,LOW); delay(200); digitalWrite(Pump,HIGH); delay (1000); digitalWrite(Pump,LOW); delay(200); digitalWrite(Pump,HIGH); delay (1000); digitalWrite(Pump,LOW); lcd.clear(); } void pump_rest (int stage) { if (stage==9){ pumpRest = false; if (Temp_c<94.0) digitalWrite(Pump,HIGH); else digitalWrite(Pump,LOW); if (Temp_c >= 95)tempReached = true; } else{ pumptempError = stageTemp-Temp_c; if (pumptempError <= 0)tempReached = true; if ((pumpTime < 10)){ // starts pumps and heat digitalWrite(Pump,HIGH); pumpRest =false; } if ((pumpTime >= 10)){ // pump rest digitalWrite(Pump,LOW); digitalWrite(Heat,LOW); pumpRest = true; if(pumpTime>=12 || (pumptempError > 1.0))pumpTime = 0; } } } void check_for_resume(void){ if(EEPROM.read(35)){ // read the auto started byte to see if it has been set and if so ask to resume display_lcd (0,0," Resume Process?"); display_lcd (0,1," Yes No"); wait_for_confirm(resume); if(resume==true){ tempHAddr = (EEPROM.read(36)*3)+6; tempLAddr = tempHAddr+1; timeAddr = tempHAddr+2; x = EEPROM.read(36); autoEnter = true; lcd.clear(); } } } void load_stage_settings (void){ tempHAddr = 6; // setup intitial stage addresses tempLAddr = 7; timeAddr = 8; nmbrStgs = EEPROM.read(38);// read the number of steps nmbrHops = EEPROM.read(39);//read the number of hop additions } void start_time (void) { start = millis(); // windowStartTime = millis(); second = 0; // minute = 0; } void stage_timing (int stage) { if ((millis()-start)>1000){ // timing routine start = millis(); second++; if(!(tempReached))second=0;// starts counting down when temp reached if (second>59){ display_lcd(10,0," "); second = 0; pumpTime++; if(stage == 0)pumpTime = 0; stageTime--; EEPROM.write(37,lowByte(stageTime));// saves stage time incase of interuption } } } void hop_add (void) { if(hopAdd <= nmbrHops){ if (stageTime == hopTime){ Buzzer(3); lcd.clear(); lcd.print(" Add Hops"); delay(2000); Buzzer(3); hopAdd++; EEPROM.write(49,hopAdd); blhpAddr++; hopTime = EEPROM.read(blhpAddr); lcd.clear(); } } } void stage_loop (int stage, float H_temp=80, float L_temp=30){ int lastminute; while ((stageTime>0)&&(autoEnter)){ lastminute=stageTime; stage_timing(stage); Temperature();// get temp pause_stage(); if (pumpRest){ display_lcd(0,0," Pump Rest "); display_lcd(0,1," "); } else{ display_lcd(0,0,stgName[stage]); display_lcd(6,0," "); display_lcd(11,0,"T="); lcd.print(stageTime); display_lcd(0,1,"S/A="); lcd.print(stageTemp); display_lcd(9,1,"/"); lcd.print(Temp_c); lcd.write((uint8_t)0); } change_temp(stageTemp,H_temp,L_temp); pump_rest(stage); if (pumpRest==false)PID_HEAT(); if (stage==9){ if(stageTime upper_limit)set_change = upper_limit; // decrease temp if (Button_repeat(Button_dn)) { set_change-=step_size; display_lcd(0,1," "); } if ( set_change < lower_limit) set_change = lower_limit; } int change_set(byte& set_change,int upper_limit,int lower_limit,int step_size) { // Increase set temp if (Button_repeat(Button_up)){ set_change+=step_size; display_lcd(0,1," "); } if (set_change > upper_limit)set_change = upper_limit; // decrease temp if (Button_repeat(Button_dn)) { set_change-=step_size; display_lcd(0,1," "); } if ( set_change < lower_limit) set_change = lower_limit; } void unit_set (void) { int param[] ={ 100,-100,1,100,-100,1,100,-100,1,5000,500,500,9,1,1,8,0,1 }; int a = 0; boolean pidLoop = false; int pidSet,setaddr; int windowSizeSet; char* setName[] ={ "Kp = ","Ki = ","Kd = ","Windowsize= ","Num of Stages=","Num of Hops=" }; setaddr = 0; for(int i=0;i<6;i++){ if((i>=0) && (i<=3)){ if (i==3) setaddr = 33; pidSet=word(EEPROM.read(setaddr),EEPROM.read((setaddr+1))); } if (i==4)setaddr = 38; if((i>=4) && (i<6)){ pidSet= EEPROM.read(setaddr); } pidLoop= true; display_lcd(0,1," "); while (pidLoop){ display_lcd(0,1,setName[i]); lcd.print(pidSet); change_set(pidSet,param[a],param[a+1],param[a+2]); quit_mode(pidLoop); if (!(pidLoop))i=6; if(Button_hold_press(Button_nxt)){ if (i >= 4){ save_settings(setaddr,lowByte(pidSet)); pidLoop = false; } else{ save_settings(setaddr,pidSet); pidLoop = false; } } } if (i>=4){ setaddr+=1; } else{ setaddr+=2; } a+=3; } } void set_stages (void) { boolean autotempLoop = false; boolean autotimeLoop = false; tempHAddr = 6; tempLAddr = 7; timeAddr = 8; float stgtmpSet; int stgtmpSetword; int stgtimSet; nmbrStgs = EEPROM.read(38); for (int i=0; i