Timer Problem

I’m having some issues getting my timer to work correctly. I am making a brewing system and need to turn a timer on once the temp of the mash gets to a certain temp. Then stay at that temp for the allotted time. Then it needs to heat up to boiling.

Right now the problem I am having is that my timer resets each time with the loop. I want MashTimer to only take the number once. startTime is the beginning time of the whole program.

#include <OneWire.h>

// OneWire DS18S20, DS18B20, DS1822 Temperature Example
//
// http://www.pjrc.com/teensy/td_libs_OneWire.html
//
// The DallasTemperature library can do all this work for you!
// http://milesburton.com/Dallas_Temperature_Control_Library

//User Inputs:
//MASH TEMP
const int MASHTEMP = 82; // Desired Mash Temp(deg F)
//MASH TIME
const int MASHTIME = 10000; //Desired Mash Time(milli sec.)
//BOIL TIME
const int BOILTIME = 10000; //Desired Boil Time(milli sec.)

boolean MashTimer = false; //used for MASH TIME
long MashStartTime; //used for MASH TIME
boolean BoilTimer = false; //used for BOIL TIME
long BoilStartTime; //used for BOIL TIME
int MASHTANKTEMP;
long startTime;//begins timer

OneWire  ds(10);  // on pin 10 (a 4.7K resistor is necessary)
const int heater = 12;

void setup(void) {
 Serial.begin(9600);
 pinMode(heater,OUTPUT);
}

void loop(void) {
startTime = millis();
 
 byte i;
 byte present = 0;
 byte type_s;
 byte data[12];
 byte addr[8];
 float celsius, fahrenheit, currentMashTemp;
 
 if ( !ds.search(addr)) {
   Serial.println(" ");
   Serial.println();
   ds.reset_search();
   delay(250);
   return;
 }
 
 Serial.print("ROM =");
 for( i = 0; i < 8; i++) {
   Serial.write(' ');
   Serial.print(addr[i], HEX);
 }

 if (OneWire::crc8(addr, 7) != addr[7]) {
     Serial.println("CRC is not valid!");
     return;
 }
 Serial.println();

 // the first ROM byte indicates which chip
 switch (addr[0]) {
   case 0x10:
     Serial.println("  Chip = DS18S20");  // or old DS1820
     type_s = 1;
     break;
   case 0x28:
     Serial.println("  Chip = DS18B20");
     type_s = 0;
     break;
   case 0x22:
     Serial.println("  Chip = DS1822");
     type_s = 0;
     break;
   default:
     Serial.println("Device is not a DS18x20 family device.");
     return;
 } 

 ds.reset();
 ds.select(addr);
 ds.write(0x44, 1);        // start conversion, with parasite power on at the end
 
 delay(1000);     // maybe 750ms is enough, maybe not
 // we might do a ds.depower() here, but the reset will take care of it.
 
 present = ds.reset();
 ds.select(addr);    
 ds.write(0xBE);         // Read Scratchpad

 Serial.print("  Data = ");
 Serial.print(present, HEX);
 Serial.print(" ");
 for ( i = 0; i < 9; i++) {           // we need 9 bytes
   data[i] = ds.read();
   Serial.print(data[i], HEX);
   Serial.print(" ");
 }
 Serial.print(" CRC=");
 Serial.print(OneWire::crc8(data, 8), HEX);
 Serial.println();

 // Convert the data to actual temperature
 // because the result is a 16 bit signed integer, it should
 // be stored to an "int16_t" type, which is always 16 bits
 // even when compiled on a 32 bit processor.
 int16_t raw = (data[1] << 8) | data[0];
 if (type_s) {
   raw = raw << 3; // 9 bit resolution default
   if (data[7] == 0x10) {
     // "count remain" gives full 12 bit resolution
     raw = (raw & 0xFFF0) + 12 - data[6];
   }
 } else {
   byte cfg = (data[4] & 0x60);
   // at lower res, the low bits are undefined, so let's zero them
   if (cfg == 0x00) raw = raw & ~7;  // 9 bit resolution, 93.75 ms
   else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
   else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
   //// default is 12 bit resolution, 750 ms conversion time
 }
 celsius = (float)raw / 16.0;
 fahrenheit = celsius * 1.8 + 32.0;
 MASHTANKTEMP = fahrenheit;
 Serial.print(" MASHTANKTEMP ");
Serial.print( MASHTANKTEMP );
 Serial.print("   startTime"   );
Serial.print(startTime);
  
;
if (MASHTANKTEMP < MASHTEMP && MashTimer < MASHTIME) { // Heat on before and during mash
digitalWrite (heater,HIGH);

 }
 

   if (MASHTANKTEMP > MASHTEMP && MashTimer < MASHTIME) { // heat off during mashing
digitalWrite (heater,LOW);
 }
 

 if(MASHTANKTEMP >= (MASHTEMP - 2.0) && MASHTANKTEMP <= (MASHTEMP + 2.0) && MashTimer < MASHTIME){ // starts timer for mash
   MashTimer = true; 
 }  
 
 if (MashTimer){ 
   MashStartTime = millis(); // starts mash timer   
   
   //Test to see if timer is working correctly:
   Serial.print("  MashStartTime  ");
   Serial.print(MashStartTime);
   Serial.print("time elapsed");
   Serial.print(startTime - MashStartTime);
   
 }
    
  if ((startTime-MashStartTime) >= MASHTIME && BoilTimer == false){ //mash is complete and before boil timer starts turns on heat
digitalWrite(heater,HIGH);

    }
    
// THE FOLLOWING CONTINUES AND CONTROLS THE BOIL PROCESS (PROCESS #3)
      
 if ((startTime-MashStartTime) > MASHTIME && MASHTANKTEMP >= 85 && MASHTANKTEMP <= 95){ 
   // Triggers after mash time is complete and once temp range is reached. 
   BoilTimer == true; //SHOULD only trigger the FIRST time this condition is met, not each time

 }
 if (BoilTimer){ ////Starts the Boil Timer if condition above is met (Boil Temp is reached, boolean Boil Timer = true)
    BoilStartTime = millis();
 }
 
 if ((startTime-BoilStartTime) >= BOILTIME && BoilTimer == true){ //Greater than or equal to ensures that you will hit and trigger this function
digitalWrite(heater,LOW);
   }

}

Here is the part of the code I am trying to solve.

//User Inputs:
//MASH TEMP
const int MASHTEMP = 82; // Desired Mash Temp(deg F)
//MASH TIME
const int MASHTIME = 10000; //Desired Mash Time(milli sec.)
//BOIL TIME
const int BOILTIME = 10000; //Desired Boil Time(milli sec.)

boolean MashTimer = false; //used for MASH TIME
long MashStartTime; //used for MASH TIME
boolean BoilTimer = false; //used for BOIL TIME
long BoilStartTime; //used for BOIL TIME
int MASHTANKTEMP;
long startTime;//begins timer


if (MASHTANKTEMP < MASHTEMP && MashTimer < MASHTIME) { // Heat on before and during mash
digitalWrite (heater,HIGH);

 }
 

   if (MASHTANKTEMP > MASHTEMP && MashTimer < MASHTIME) { // heat off during mashing
digitalWrite (heater,LOW);
 }
 

 if(MASHTANKTEMP >= (MASHTEMP - 2.0) && MASHTANKTEMP <= (MASHTEMP + 2.0) && MashTimer < MASHTIME){ // starts timer for mash
   MashTimer = true; 
 }  
 
 if (MashTimer){ 
   MashStartTime = millis(); // starts mash timer   
   
   //Test to see if timer is working correctly:
   Serial.print("  MashStartTime  ");
   Serial.print(MashStartTime);
   Serial.print("time elapsed");
   Serial.print(startTime - MashStartTime);
   
 }
    
  if ((startTime-MashStartTime) >= MASHTIME && BoilTimer == false){ //mash is complete and before boil timer starts turns on heat
digitalWrite(heater,HIGH);

    }
    
// THE FOLLOWING CONTINUES AND CONTROLS THE BOIL PROCESS (PROCESS #3)
      
 if ((startTime-MashStartTime) > MASHTIME && MASHTANKTEMP >= 85 && MASHTANKTEMP <= 95){ 
   // Triggers after mash time is complete and once temp range is reached. 
   BoilTimer == true; //SHOULD only trigger the FIRST time this condition is met, not each time

 }
 if (BoilTimer){ ////Starts the Boil Timer if condition above is met (Boil Temp is reached, boolean Boil Timer = true)
    BoilStartTime = millis();
 }
 
 if ((startTime-BoilStartTime) >= BOILTIME && BoilTimer == true){ //Greater than or equal to ensures that you will hit and trigger this function
digitalWrite(heater,LOW);
   }

}

Here is what I’m getting when I’m receiving the temps and times from my arduino.

ROM = 28 D1 5E B6 6 0 0 93
Chip = DS18B20
Data = 1 67 2 4B 46 7F FF 9 10 7C CRC=7C
MASHTANKTEMP 101 startTime49548 MashStartTime 50592time elapsed-1044

ROM = 28 D1 5E B6 6 0 0 93
Chip = DS18B20
Data = 1 5F 2 4B 46 7F FF 1 10 DC CRC=DC
MASHTANKTEMP 100 startTime50887 MashStartTime 51932time elapsed-1045

ROM = 28 D1 5E B6 6 0 0 93
Chip = DS18B20
Data = 1 56 2 4B 46 7F FF A 10 96 CRC=96
MASHTANKTEMP 99 startTime52228 MashStartTime 53271time elapsed-1043

ROM = 28 D1 5E B6 6 0 0 93
Chip = DS18B20
Data = 1 4E 2 4B 46 7F FF 2 10 9E CRC=9E
MASHTANKTEMP 98 startTime53567 MashStartTime 54610time elapsed-1043

You are comparing a boolean to a const int. A boolean is only going to have the values 1 and 0, so it is always going to be less than 10000.

const int MASHTIME = 10000; //Desired Mash Time(milli sec.)
boolean MashTimer = false; //used for MASH TIME
if (MASHTANKTEMP < MASHTEMP && MashTimer < MASHTIME) { // Heat on before and during mash

Also, if you are using a convention where constants are in caps and variables are not, you should fix the capitalization of MASHTANKTEMP.

Last, you seem to be calculating your time elapsed backwards. You want to subtract the start time from the current time, not the other way around.

Thank you so much!! I've been trying to find this error forever. I think I need to change MashTimer to MashStartTime??

I'd need to go through your code a lot more thoroughly to answer you for sure, but at a glace it seems you'd want to compare (millis() - MashStartTime) to MASHTIME?

I didn't go through your code to fully understand how you're setting MashStartTime, but typically you'd save the timer value when you start counting and subtract it from millis() to measure the elapsed time.

if(MashTankTemp >= (MASHTEMP - 2.0) && MashTankTemp <= (MASHTEMP + 2.0) && MashTimer= false){ // starts timer for mash
   MashTimer = true; 
 }  
 
 if (MashTimer){ 
   MashStartTime = millis(); // starts mash timer

The problem I am having is that the MashStartTime updates every time the loop runs. How would I store MashStartTime as just the value from the first time it ran?

Thanks again

You want to set MashStartTime once when MashTimer is changed from false to true?

The simplest way to do that, is to set MashStartTime in the same if statement where you set MashTimer to true.

If you must have those statements separated for some reason, you could have another variable called MashTimerLast and set MashStartTime when MashTimer is true but MashTimerLast is false:

if((MashTimerLast == false)  && (MashTimer == true)) {
    MashStartTime = millis();
}
MashTimerLast = MashTimer;

So do you think this would work? Thanks for the help this is my first real project using arduino.

if(MashTankTemp >= (MASHTEMP - 2.0) && MashTankTemp <= (MASHTEMP + 2.0) && MashTimer= false){ // starts timer for mash
  
 MashTimer = true; 

   MashStartTime = millis(); // starts mash timer  
}

You have a bug in your if statement ("MashTimer = false" should be "MashTimer == false"), but other than that it looks fine.

Thank you so much this helped me a ton.

The problem I’m having now is that my millis() is counting up so that causes my MashTime > MASHTIME before I even get to my MashStartTime. Any ideas on how to fix this?

MashTime =  millis() - MashStartTime ;
  

if (MashTankTemp < MASHTEMP && (MashTime) < MASHTIME) { // Heat on before and during mash
digitalWrite (heater,HIGH);

 }
 

   if (MashTankTemp > MASHTEMP && (MashTime) < MASHTIME) { // heat off during mashing
digitalWrite (heater,LOW);
 }
 

if(MashTankTemp >= (MASHTEMP - 2.0) && MashTimer == false){ // starts timer for mash
  
 MashTimer = true; 

   MashStartTime = millis(); // starts mash timer  

}

"Get to" MashStartTime? It should be in the past.

Yeah, before my other if statement became true to start the other timer. I ended up fixing it by using an extra && statement in my if statement for the timer and that fixed it.

thanks though for all the help guys