Kitchen Timer with Relay and Magnetic Switch

Hello,
I am working on a program for my Arduino UNO R3.
My goals are the following:

my code looks like this so far:

#include <SoftwareSerial.h>



//CONFIGURATION:////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//Connect 7 Segment LED with RX at Pin 7 and SS at Pin 8
SoftwareSerial Serial7Segment(8, 7); 

//Configures the pins for the Encoder:
//Connect Pin A of encoder to Pin 14 (A0) and Pin C of encoder to Pin 15 (A1), Pin B goes to ground
//Connect Button to either encoder pins, other goes to ground
enum enDigitalPins
{
  dpInEncoderA=14,
  dpInEncoderB=15,
  dpInEncoderPress=12,
};

#define MagSwitch  13
#define Relay       9

// this value determines how many seconds are incremented each time the encoder is rotated
int increment = 10; 

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 //DEFINITIONS:

long millisTimer;
byte seconds = 00;
byte minutes = 00;
byte hours = 00;

int mode = 0;
char tempString[100]; //Used for sprintf

#define COLON       4
#define Set_Timer   0
#define Run_Timer   1

boolean colonOn = false;
boolean Timer_Pause = false;

static void _ResetPins()
{
  // Rotary encoder input lines
  // Configure as input, turn on pullup resistors
  pinMode(dpInEncoderA, INPUT);
  digitalWrite(dpInEncoderA, HIGH);

  pinMode(dpInEncoderB, INPUT);
  digitalWrite(dpInEncoderB, HIGH);

  pinMode(dpInEncoderPress, INPUT);
  digitalWrite(dpInEncoderPress, HIGH);

  digitalWrite(MagSwitch, INPUT);
  pinMode(MagSwitch, LOW);

  digitalWrite(Relay, OUTPUT);
  pinMode(Relay, LOW);

  Serial7Segment.write(0x77);  // Decimal, colon, apostrophe control command
  Serial7Segment.write(1<<COLON);
}


void _lowlevel_ReadEncoder(int &rotate, int& press)
{
  rotate = (digitalRead(dpInEncoderB) * 2) + digitalRead(dpInEncoderA);
  press = digitalRead(dpInEncoderPress);
}

//////////////////////////////////////////////////////////////////////////////////////////////
void ReadEncoder() //Reads the State of the Encoder and adjust the Display accordingly. CW rotation = + "increment" seconds, CCW = - "increment" seconds
{
  int Position, Press;
  int isForward = 0;
  seconds = constrain (seconds, -1, 60); //constrains the seconds value between -1 and 60

    _ResetPins();
  _lowlevel_ReadEncoder(Position, Press);
  int Position2, Press2;
  do
  {
    _lowlevel_ReadEncoder(Position2, Press2);
  } 
  while ((Position2 == Position) && (Press2 == Press));
  if (Position2 != Position) //if there is a poisition change:
  {
    // "Forward" is shown by the position going from (0 to 1) or (1 to 3)
    // or (3 to 2) or (2 to 0).  Anything else indicates that the user is
    // turning the device the other way.  Remember: this is Gray code, not
    // binary.
    int isFwd = ((Position == 0) && (Position2 == 1)) ||
      ((Position == 1) && (Position2 == 3)) ||
      ((Position == 3) && (Position2 == 2)) ||
      ((Position == 2) && (Position2 == 0));

    if (isFwd == 1) //if Encoder is moved forwards (CW), advance seconds by defined increment value
    {
      delay(50); // prevents bad readings
      seconds= seconds + increment;
    }
    if (isFwd == 0) // if encoder is moved backwards(CCW):
    {
      delay(50);
      if (seconds == 0)// if we are already at zero seconds, check to make sure we can reduce a minute
      {
        if (minutes > 0)// if the minutes can be reduced (i.e. not zero) then remove one minute and reset seconds to 59
        {       
          minutes --;
          seconds = 50;
        }
      }
      else
      {
        seconds = seconds - increment;//if seconds were not = 0, then decrease seconds value by the increment value
      }
    }
  }

  if (seconds>59)    // When seconds = 60:
  {
    minutes++;          // Add one minute
    seconds -= 60;      // Reset seconds
  }

  if (Press2 != Press) //if the encoder is pressed down:
  {
    mode = Run_Timer;
  }
  Position = Position2;
  Press = Press2;

  Serial7Segment.print('v');
  sprintf(tempString, "%02d%02d", minutes, seconds);
  Serial7Segment.print(tempString); //Send serial string out the soft serial port to the S7S
}

//////////////////////////////////////////////////////////////////////////////////////////////////////
void countdownTimer() //this will start counting down from the time set using the encoder. This begins when the encoder button is pressed.
{
  seconds = constrain (seconds, -1, 60);
  if (Timer_Pause == false)
  {
    if( (millis() - millisTimer) > 1000)
    {
      millisTimer += 1000; //Adjust the timer forward 1 second
      if (seconds == 0)// if we are already at zero seconds, check to make sure we can reduce a minute
      {
        if (minutes > 0)// if the minutes can be reduced (i.e. not zero) then remove one minute and reset seconds to 59
        {       
          minutes --;
          seconds = 59;
        }
      }
      else{
        seconds--;//if seconds were not = 0, then decrease seconds value by the increment value
      }

      sprintf(tempString, "%02d%02d", minutes, seconds);
      Serial7Segment.print('v'); //Send serial string out the soft serial port to the S7S
      Serial7Segment.write(0x77);  // Decimal, colon, apostrophe control command
      Serial7Segment.write(1<<COLON); // Turns on colon, apostrophoe, and far-right decimal
      Serial7Segment.print(tempString); //Send serial string out the soft serial port to the S7S
      //    Serial.println(tempString);    
    }

    if (minutes == 0 & seconds == 0)
    {
      //do nothing
    }
  }
  else
  {

  }
}


void setup()
{
  // configure the pins
  _ResetPins();

  // init serial communication
  Serial.begin(9600); 
  Serial.println("Ready to begin");
  Serial7Segment.begin(9600); //Talk to the Serial7Segment at 9600 bps
  Serial7Segment.write('v'); //Reset the display - this forces the cursor to return to the beginning of the display
  Serial7Segment.print("0000"); //Send the hour and minutes to the display
}


void loop()
{
  if (digitalRead(MagSwitch) == LOW){ //if magnetic switch is detected
    // switches modes depending on button press
    switch(mode){
      case (Set_Timer): //reads encoder and sets time
      ReadEncoder();
      break;

      case (Run_Timer): //counts down timer
      Timer_Pause = false;
      countdownTimer();
      digitalWrite(Relay, HIGH); //SHOULD turn on the Relay (loops too fast?)
      break;
    }
  }
  else if (digitalRead(MagSwitch) == HIGH) //if no magnetic switch detected
  {
    Timer_Pause = true; //pause the timer
  }  
}

I pieced it together with various bits of code I found online. I am pretty new to Arduino programming, and would love some help.

Currently, my program works well to set the time and count down. I am having issues with the timer stopping when the magnetic switch isn't there. In addition, my Relay won't turn off!

Any help is appreciated!

Thanks,
Sam

Moderator edit:
</mark> <mark>[code]</mark> <mark>

</mark> <mark>[/code]</mark> <mark>
tags added.
edit: added links to parts

    if (minutes == 0 & seconds == 0)
    {
      //do nothing
    }

Do nothing? I thought you wanted to turn the relay off.

  if (digitalRead(MagSwitch) == LOW){ //if magnetic switch is detected
  else if (digitalRead(MagSwitch) == HIGH) //if no magnetic switch detected

If the output from digtialRead() isn't HIGH and it isn't LOW, what is it?

No Serial.print() statements outside of setup(). I'm sure that there is a reason for that, but what it could possibly be escapes me.

PaulS:

    if (minutes == 0 & seconds == 0)

{
      //do nothing
    }



Do nothing? I thought you wanted to turn the relay off.

Yeah, I do, but it wasn't doing anything earlier when it was part of a loop statement. When I changed the HIGH to LOW's, I saw that the relay LED was flickering occasionally.

PaulS:

  if (digitalRead(MagSwitch) == LOW){ //if magnetic switch is detected

else if (digitalRead(MagSwitch) == HIGH) //if no magnetic switch detected



If the output from digtialRead() isn't HIGH and it isn't LOW, what is it?

No Serial.print() statements outside of setup(). I'm sure that there is a reason for that, but what it could possibly be escapes me.

I added some Serial.println() statements to debug earlier, making sure the switch was working and that my timer was correct. Is it bad to keep it in the setup right now?

Thanks for the advice

I added some Serial.println() statements to debug earlier, making sure the switch was working and that my timer was correct. Is it bad to keep it in the setup right now?

Is it bad to keep what in the setup()? The Serial.print() statement? No. In fact, you need more of them, in loop() and other functions to see what is happening.

PaulS:

I added some Serial.println() statements to debug earlier, making sure the switch was working and that my timer was correct. Is it bad to keep it in the setup right now?

Is it bad to keep what in the setup()? The Serial.print() statement? No. In fact, you need more of them, in loop() and other functions to see what is happening.

Okay, thanks

So I have worked some more on this project and can control the Relay now by using pinMode(Relay, LOW) and HIGH.
I noticed that sometimes when I turn on the timer, it is much faster than 1 second between counting down seconds. It quickly drops to zero. This only happens after I disconnect the switch and reconnect it a couple of times... Any ideas why this is happening?

Thanks!

#include <SoftwareSerial.h>



//CONFIGURATION:////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//Connect 7 Segment LED with RX at Pin 7 and SS at Pin 8
SoftwareSerial Serial7Segment(8, 7); 

//Configures the pins for the Encoder:
//Connect Pin A of encoder to Pin 14 (A0) and Pin C of encoder to Pin 15 (A1), Pin B goes to ground
//Connect Button to either encoder pins, other goes to ground
enum enDigitalPins
{
  dpInEncoderA=14,
  dpInEncoderB=15,
  dpInEncoderPress=12,
};

#define MagSwitch  13
#define Relay       2

// this value determines how many seconds are incremented each time the encoder is rotated
int increment = 10; 

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

long millisTimer;
byte seconds = 00;
byte minutes = 00;
byte hours = 00;

int mode = 0;
char tempString[100]; //Used for sprintf

#define COLON       4
#define Set_Timer   0
#define Run_Timer   1

boolean colonOn = false;
boolean Timer_Pause = false;
boolean Relay_On = false;

static void _ResetPins()
{
  // Rotary encoder input lines
  // Configure as input, turn on pullup resistors
  pinMode(dpInEncoderA, INPUT);
  digitalWrite(dpInEncoderA, HIGH);

  pinMode(dpInEncoderB, INPUT);
  digitalWrite(dpInEncoderB, HIGH);

  pinMode(dpInEncoderPress, INPUT);
  digitalWrite(dpInEncoderPress, HIGH);

  digitalWrite(MagSwitch, INPUT);
  pinMode(MagSwitch, LOW);

  digitalWrite(Relay, OUTPUT);
  //  pinMode(Relay, LOW);

  Serial7Segment.write(0x77);  // Decimal, colon, apostrophe control command
  Serial7Segment.write(1<<COLON);
}


void _lowlevel_ReadEncoder(int &rotate, int& press)
{
  rotate = (digitalRead(dpInEncoderB) * 2) + digitalRead(dpInEncoderA);
  press = digitalRead(dpInEncoderPress);
}

//////////////////////////////////////////////////////////////////////////////////////////////
void ReadEncoder() //Reads the State of the Encoder and adjust the Display accordingly. CW rotation = + "increment" seconds, CCW = - "increment" seconds
{
  int Position, Press;
  int isForward = 0;
  seconds = constrain (seconds, -1, 60); //constrains the seconds value between -1 and 60

    _ResetPins();
  _lowlevel_ReadEncoder(Position, Press);
  int Position2, Press2;
  do
  {
    _lowlevel_ReadEncoder(Position2, Press2);
  } 
  while ((Position2 == Position) && (Press2 == Press));
  if (Position2 != Position) //if there is a poisition change:
  {
    // "Forward" is shown by the position going from (0 to 1) or (1 to 3)
    // or (3 to 2) or (2 to 0).  Anything else indicates that the user is
    // turning the device the other way.  Remember: this is Gray code, not
    // binary.
    int isFwd = ((Position == 0) && (Position2 == 1)) ||
      ((Position == 1) && (Position2 == 3)) ||
      ((Position == 3) && (Position2 == 2)) ||
      ((Position == 2) && (Position2 == 0));

    if (isFwd == 1) //if Encoder is moved forwards (CW), advance seconds by defined increment value
    {
      delay(75); // prevents bad readings
      seconds= seconds + increment;
    }
    if (isFwd == 0) // if encoder is moved backwards(CCW):
    {
      delay(75);
      if (seconds == 0)// if we are already at zero seconds, check to make sure we can reduce a minute
      {
        if (minutes > 0)// if the minutes can be reduced (i.e. not zero) then remove one minute and reset seconds to 59
        {       
          minutes --;
          seconds = 50;
        }
      }
      else
      {
        seconds = seconds - increment;//if seconds were not = 0, then decrease seconds value by the increment value
      }
    }
  }

  if (seconds>59)    // When seconds = 60:
  {
    minutes++;          // Add one minute
    seconds -= 60;      // Reset seconds
  }

  if (Press2 != Press) //if the encoder is pressed down:
  {
    mode = Run_Timer;
  }
  Position = Position2;
  Press = Press2;

  Serial7Segment.print('v');
  sprintf(tempString, "%02d%02d", minutes, seconds);
  Serial7Segment.print(tempString); //Send serial string out the soft serial port to the S7S
}

//////////////////////////////////////////////////////////////////////////////////////////////////////
void countdownTimer() //this will start counting down from the time set using the encoder. This begins when the encoder button is pressed.
{
  seconds = constrain (seconds, -1, 60);
  if (Timer_Pause == false)
  {
    if( (millis() - millisTimer) > 1000)
    {
      millisTimer += 1000; //Adjust the timer forward 1 second
      if (seconds == 0)// if we are already at zero seconds, check to make sure we can reduce a minute
      {
        if (minutes > 0)// if the minutes can be reduced (i.e. not zero) then remove one minute and reset seconds to 59
        {       
          minutes --;
          seconds = 59;
        }
      }
      else{
        seconds--;//if seconds were not = 0, then decrease seconds value by the increment value
      }

      sprintf(tempString, "%02d%02d", minutes, seconds);
      Serial7Segment.write(0x77);  // Decimal, colon, apostrophe control command
      Serial7Segment.write(1<<COLON); // Turns on colon, apostrophoe, and far-right decimal
      Serial7Segment.print(tempString); //Send serial string out the soft serial port to the S7S
      //Serial.println(tempString);    
    }

    if (minutes == 0 & seconds == 0)
    {
      pinMode(Relay, LOW);
      Serial7Segment.print("----"); //Send the hour and minutes to the display
      mode = Set_Timer;
    }
  }
  else
  {
    mode = Set_Timer;
  }
}


void setup()
{
  // configure the pins
  _ResetPins();

  // init serial communication
  //  Serial.begin(9600); 
  //  Serial.println("Ready to begin");
  Serial7Segment.begin(9600); //Talk to the Serial7Segment at 9600 bps
  Serial7Segment.write('v'); //Reset the display - this forces the cursor to return to the beginning of the display
  Serial7Segment.print("----"); //Send the hour and minutes to the display
}


void loop()
{
  //    if (Relay_On == true)
  //  {
  //    pinMode(Relay, HIGH);
  //  }
  //  else 
  //  {
  //    pinMode(Relay, LOW);
  //  }
  if (digitalRead(MagSwitch) == LOW){ //if magnetic switch is detected
    // switches modes depending on button press
    Relay_On = false;

    switch(mode){
      pinMode(Relay, LOW);
      case (Set_Timer): //reads encoder and sets time
      ReadEncoder();
      break;

      case (Run_Timer): //counts down timer
      delay(175);
      pinMode(Relay, HIGH);
      countdownTimer();
      break;
    }
  }
  else if (digitalRead(MagSwitch) == HIGH) //if no magnetic switch detected
  {
    pinMode (Relay, LOW);
    minutes = 0;
    seconds = 0;
    Serial7Segment.print("----"); //Send the hour and minutes to the display
    mode = Set_Timer;
  }  
}

I don't know whether this is causing your problem, but you seem to be confusing pinMode and digitalWrite:

	digitalWrite(Relay, OUTPUT);
	pinMode(Relay, LOW);

Do you really mean to change the pin modes during the sketch?

PeterH:
I don't know whether this is causing your problem, but you seem to be confusing pinMode and digitalWrite:

	digitalWrite(Relay, OUTPUT);
pinMode(Relay, LOW);



Do you really mean to change the pin modes during the sketch?

I don't want to do it, but if I use digitalWrite(Relay, HIGH); or LOW, then the relay doesn't turn on or off at all. I'm using a Sparkfun Beefy Relay kit and can see the status LED quickly blink but that's it...

Is there a better way to do this? I tried making another if statement in my loop that uses a boolean Relay_On and would adjust the relay accordingly, but it doesn't work either.

sholland91:
Is there a better way to do this?

I'm not familiar with that relay board, but I assume it takes a digital output and uses it to control the relay. In that case you would call pinMode(Relay, OUTPUT); once within setup(), and then call digitalWrite(Relay, HIGH); and digitalWrite(Relay, LOW); to turn the relay on and off as required.

PeterH:

sholland91:
Is there a better way to do this?

I'm not familiar with that relay board, but I assume it takes a digital output and uses it to control the relay. In that case you would call pinMode(Relay, OUTPUT); once within setup(), and then call digitalWrite(Relay, HIGH); and digitalWrite(Relay, LOW); to turn the relay on and off as required.

So I was messing up and used pinMode(Relay, LOW) before and after fixing it, everything works out! There is still a problem though: when I start the timer, it quickly jumps a few seconds. Usually 3, but sometimes 15, and sometimes it counts really fast all the way down.

sholland91:
There is still a problem though: when I start the timer, it quickly jumps a few seconds. Usually 3, but sometimes 15, and sometimes it counts really fast all the way down.

Perhaps there's something wrong with your code. Difficult to see from here ...

UPDATE:
It seems as though the fast counting down occurs mostly after I let the device sit while powered on for a while. Could it be an issue with the millis() command?

Still can't see your code.

However, your functions are doing too much. ReadEncoder() should do exactly that and NOTHING more.

ReadEncoderAndDoABunchOfOtherCrap() would read the encoder and do a bunch of other crap. Of course, if you really had a function like that, I'd just hit the back button and move onto the next post.

You have very few Serial.print() statements to learn what the code is really doing.

Besides, it's hard to see the function of an encoder in a post titled "Kitchen Timer with Relay and Magnetic Switch", so some comments in the code would be helpful.

Still can't see your code.

It's posted above.... Not sure what's going on there.

However, your functions are doing too much. ReadEncoder() should do exactly that and NOTHING more.
ReadEncoderAndDoABunchOfOtherCrap() would read the encoder and do a bunch of other crap.

So you can see my code? Not sure what you mean here either. Does it matter? Is this causing problems with my program?

Of course, if you really had a function like that, I'd just hit the back button and move onto the next post.

What does this mean?

Besides, it's hard to see the function of an encoder in a post titled "Kitchen Timer with Relay and Magnetic Switch", so some comments in the code would be helpful.

There are comments all over my code... Read the first post for some background information. The encoder is used as an input device for incrementing the seconds on a kitchen timer. When the button on the encoder is pressed in, the timer starts and the relay turns on. My problem is that the timer sometimes counts down way faster than 1 second each second. Some times it races down 45 seconds and resumes counting normally. Sometimes is races all the way down to zero. I think this has to do with the millis() command, as I wrote above.

You have very few Serial.print() statements to learn what the code is really doing.

I removed them after I set up my code and got it working, thinking that it could be the reason why the numbers are counting so fast sometimes. The only issue right now is the counter, and a serial.println of that mirrors what the 7 segment display is showing me.

Here's the updated code:

#include <SoftwareSerial.h>

//CONFIGURATION:////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//Connect 7 Segment LED with RX at Pin 7 and SS at Pin 8
SoftwareSerial Serial7Segment(8, 7); 

//Configures the pins for the Encoder:
//Connect Pin A of encoder to Pin 14 (A0) and Pin C of encoder to Pin 15 (A1), Pin B goes to ground
//Connect Button to either encoder pins, other goes to ground
enum enDigitalPins
{
  dpInEncoderA=14,
  dpInEncoderB=15,
  dpInEncoderPress=12,
};

#define MagSwitch  13
#define Relay       2

// this value determines how many seconds are incremented each time the encoder is rotated
int increment = 10; 

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
long millisTimer;
byte seconds = 00;
byte minutes = 00;
byte hours = 00;

int mode = 0;
char tempString[100]; //Used for sprintf

#define COLON       4
#define Set_Timer   0
#define Run_Timer   1
#define Pause_Timer 2

boolean colonOn = false;

static void _ResetPins()
{
  // Rotary encoder input lines
  // Configure as input, turn on pullup resistors
  pinMode(dpInEncoderA, INPUT);
  digitalWrite(dpInEncoderA, HIGH);

  pinMode(dpInEncoderB, INPUT);
  digitalWrite(dpInEncoderB, HIGH);

  pinMode(dpInEncoderPress, INPUT);
  digitalWrite(dpInEncoderPress, HIGH);

  digitalWrite(MagSwitch, INPUT);
  pinMode(MagSwitch, LOW);

  pinMode(Relay, OUTPUT);

  Serial7Segment.write(0x77);  // Decimal, colon, apostrophe control command
  Serial7Segment.write(1<<COLON);
}


void _lowlevel_ReadEncoder(int &rotate, int& press)
{
  rotate = (digitalRead(dpInEncoderB) * 2) + digitalRead(dpInEncoderA);
  press = digitalRead(dpInEncoderPress);
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
void ReadEncoder() //Reads the State of the Encoder and adjust the Display accordingly. CW rotation = + "increment" seconds, CCW = - "increment" seconds
{
  int Position, Press;
  int isForward = 0;
  seconds = constrain (seconds, -1, 60); //constrains the seconds value between -1 and 60

    _ResetPins();
  _lowlevel_ReadEncoder(Position, Press);
  int Position2, Press2;
  do
  {
    _lowlevel_ReadEncoder(Position2, Press2);
  } 
  while ((Position2 == Position) && (Press2 == Press));
  if (Position2 != Position) //if there is a poisition change:
  {
    // "Forward" is shown by the position going from (0 to 1) or (1 to 3)
    // or (3 to 2) or (2 to 0).  Anything else indicates that the user is
    // turning the device the other way.  Remember: this is Gray code, not
    // binary.
    int isFwd = ((Position == 0) && (Position2 == 1)) ||
      ((Position == 1) && (Position2 == 3)) ||
      ((Position == 3) && (Position2 == 2)) ||
      ((Position == 2) && (Position2 == 0));
    delay(100);
    if (isFwd == 1) //if Encoder is moved forwards (CW), advance seconds by defined increment value
    {
      //      delay(200); // prevents bad readings
      seconds= seconds + increment;
    }
    if (isFwd == 0) // if encoder is moved backwards(CCW):
    {
      //      delay(200);
      if (seconds == 0)// if we are already at zero seconds, check to make sure we can reduce a minute
      {
        if (minutes > 0)// if the minutes can be reduced (i.e. not zero) then remove one minute and reset seconds to 59
        {       
          minutes --;
          seconds = 50;
        }
      }
      else
      {
        seconds = seconds - increment;//if seconds were not = 0, then decrease seconds value by the increment value
      }
    }
  }

  if (seconds>59)    // When seconds = 60:
  {
    minutes++;          // Add one minute
    seconds -= 60;      // Reset seconds
  }

  if (Press2 != Press) //if the encoder is pressed down:
  {
    delay(250);
    mode = Run_Timer;
  }
  Position = Position2;
  Press = Press2;

  Serial7Segment.print('v');
  sprintf(tempString, "%02d%02d", minutes, seconds);
  Serial7Segment.print(tempString); //Send serial string out the soft serial port to the S7S
  Serial.println(tempString);
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
void countdownTimer() //this will start counting down from the time set using the encoder. This begins when the encoder button is pressed.
{
  seconds = constrain (seconds, -1, 60);
  if( (millis() - millisTimer) > 1000)
  {
    millisTimer += 1000; //Adjust the timer forward 1 second
    if (seconds == 0)// if we are already at zero seconds, check to make sure we can reduce a minute
    {
      if (minutes > 0)// if the minutes can be reduced (i.e. not zero) then remove one minute and reset seconds to 59
      {       
        minutes --;
        seconds = 59;
      }
    }
    else{
      seconds--;//if seconds were not = 0, then decrease seconds value by the increment value
    }
    sprintf(tempString, "%02d%02d", minutes, seconds);
    Serial7Segment.write(0x77);  // Decimal, colon, apostrophe control command
    Serial7Segment.write(1<<COLON); // Turns on colon, apostrophoe, and far-right decimal
    Serial7Segment.print(tempString); //Send serial string out the soft serial port to the S7S
    
    Serial.println(tempString);
  }

  if (minutes == 0 & seconds == 0)
  {
    digitalWrite(Relay, LOW);
    Serial7Segment.print("0000"); //Send the hour and minutes to the display
    mode = Set_Timer;
  }

  if (digitalRead(dpInEncoderPress)== LOW)
  {
    delay(250);
    mode = Pause_Timer;
  }
}

void PauseTimer()
{
  int seconds_hold;
  int minutes_hold;
  seconds_hold = seconds;
  minutes_hold = minutes;

  minutes = minutes_hold;
  seconds = seconds_hold;
  sprintf(tempString, "%02d%02d", minutes, seconds);
  Serial7Segment.write(0x77);  // Decimal, colon, apostrophe control command
  Serial7Segment.write(1<<COLON); // Turns on colon, apostrophoe, and far-right decimal
  Serial7Segment.print(tempString); //Send serial string out the soft serial port to the S7S

  if (digitalRead(dpInEncoderPress)== LOW)
  {
    delay(75);
    mode = Run_Timer;
  }

  mode = Set_Timer;
}

void setup()
{
  // configure the pins
  _ResetPins();
  
  Serial.begin(9600);

  Serial7Segment.begin(9600); //Talk to the Serial7Segment at 9600 bps
  Serial7Segment.write('v'); //Reset the display - this forces the cursor to return to the beginning of the display
  Serial7Segment.print("0000"); //Send the hour and minutes to the display
}

void loop()
{
  if (digitalRead(MagSwitch) == LOW) //if magnetic switch is detected
    // switches modes depending on button press
  {
    switch(mode){
      digitalWrite(Relay, LOW); //Relay off
      case (Set_Timer): //reads encoder and sets time
      ReadEncoder();
      break;

      case (Run_Timer): //counts down timer
      digitalWrite(Relay, HIGH); //relay on
      countdownTimer(); //run countdown script (above)
      break;

      case (Pause_Timer): 
      digitalWrite(Relay, LOW);
      PauseTimer();
      break;      
    }
  }

  else if (digitalRead(MagSwitch) == HIGH) //if no magnetic switch detected
  {
    digitalWrite (Relay, LOW);
    minutes = 0;
    seconds = 0;
    Serial7Segment.print("OFF "); //Send the hour and minutes to the display
    mode = Set_Timer;
  }  
}

Hope this solves any issues you may have...

Hope this solves any issues you may have...

It does. But let's look at some of your comments.

So I was messing up and used pinMode(Relay, LOW) before and after fixing it, everything works out!

How did you fix this? By making code changes, right? So, we need to see them.

So you can see my code?

Your old code.

Not sure what you mean here either. Does it matter? Is this causing problems with my program?

Maybe it matters. Maybe it doesn't. If you have a function called ReadEncoder() and it uses no global variables, returns a value, and does exactly what the name says, and nothing else, then we can read through the code, determine if it is reasonable, and then forget it. When we later encounter a call to ReadEncoder(), we don't have to worry about what side effects and bizarre things that function is having on the rest of the code.

But, when we encounter a ReadEncoder() function that uses global variables and does several things, then each time a global variable appears in the code, we need to go see if ReadEncoder() is screwing with that variable. That is not conducive to quick debugging.

What does this mean?

It means that if you simply rename your function to admit that it is a grab bag of unrelated functionality, I'm not even going to make an attempt to read it, or help you.

I removed them after I set up my code and got it working,

But, your code isn't working, is it?

char tempString[100]; //Used for sprintf

A bit on the large side, isn't it?

  int seconds_hold;
  int minutes_hold;
  seconds_hold = seconds;
  minutes_hold = minutes;

  minutes = minutes_hold;
  seconds = seconds_hold;

No comments to explain this bizarre code. First, it is not necessary to declare and initialize variables as two separate steps.

int seconds_hold = seconds;
int minutes_hold = minutes;

looks better and is less typing.

Setting seconds and minutes to what they currently contain makes no sense.

  sprintf(tempString, "%02d%02d", minutes, seconds);
  Serial7Segment.write(0x77);  // Decimal, colon, apostrophe control command
  Serial7Segment.write(1<<COLON); // Turns on colon, apostrophoe, and far-right decimal
  Serial7Segment.print(tempString); //Send serial string out the soft serial port to the S7S

You do this a lot. Why not create a function to do it, once. Then, tempString could be a local variable. And, it would be clear that it was oversized.

  if (digitalRead(dpInEncoderPress)== LOW)
  {
    delay(75);
    mode = Run_Timer;
  }

Why are you delaying?

      case (Set_Timer): //reads encoder and sets time

Case values do not need parentheses around them.

void loop()
{
  if (digitalRead(MagSwitch) == LOW) //if magnetic switch is detected
    // switches modes depending on button press
  {
    switch(mode){
      digitalWrite(Relay, LOW); //Relay off
      case (Set_Timer): //reads encoder and sets time
      ReadEncoder();
      break;

      case (Run_Timer): //counts down timer
      digitalWrite(Relay, HIGH); //relay on
      countdownTimer(); //run countdown script (above)
      break;

      case (Pause_Timer): 
      digitalWrite(Relay, LOW);
      PauseTimer();
      break;      
    }
  }

  else if (digitalRead(MagSwitch) == HIGH) //if no magnetic switch detected
  {
    digitalWrite (Relay, LOW);
    minutes = 0;
    seconds = 0;
    Serial7Segment.print("OFF "); //Send the hour and minutes to the display
    mode = Set_Timer;
  }  
}

This is the heart of the program. The first comment is wrong. The Arduino can not tell if the magnetic switch is present or not. All it can tell is whether the pin that the switch is supposed to be attached to is HIGH or LOW.

Then the comment about the switch statement leaves a bit to be desired. Which switch press? There is only one statement in all of loop() that sets mode to a value. It is not clear where else mode gets set.

Basically, one of three functions gets called. ReadEncoder() to get the time to count down, countdownTimer() to count down time, and PauseTimer() to stop the counting down. Just a quick look at the previous sentence will reveal inconsistencies in your code. Some functions start with upper case letters. Some start with lower case letters. Why?

But the real question is where does the problem you are trying to resolve come in? When loop() runs, and determines that you want to just run the timer, is the time being counted down wrong? Is the time being counted down changing between ReadEncoder() and countdownTimer()?

countdownTimer() has some subtle issues.

  if( (millis() - millisTimer) > 1000)

If the function is called exactly 1000 milliseconds after the last call, it will not trigger the if statement. You most likely want >= there, not >.

    millisTimer += 1000; //Adjust the timer forward 1 second

But, more than 1000 milliseconds has elapsed. millisTimer should be set to millis(), not incremented by 1000. And even that isn't perfect. What should happen is that there should be a local variable set at the top of the function:

unsigned long now = millis();

Then, no further calls to millis() should be made during this function. Instead, the value in now should be used every time the clock is to be checked. Notice that millis() returns an unsigned long, not a long.

Constraining seconds at the start of the function is wrong. An unknown amount of time may be lost doing that. Enough to account for the change you are seeing? Probably not, but it is wrong to be doing it.

I don't see any reason for any of the delay() calls in the code. Perhaps you could explain why they are there.

First off, thanks for the help!
I am very new to Arduino and pieced this code together from other examples I have found online. This may explain any inconsistencies you saw. I went through the program and tried to clean things up a bit.
Here is the revised code:

#include <SoftwareSerial.h>

//CONFIGURATION:
/// Pins From Components to Arduino:///
const int LCD_TX = 9;          //TX On LCD Board 
const int LCD_RX = 8;           //RX On LCD Board
const int Encoder_A = 3;       //3rd Pin on the Top of Potentiometer 
const int Encoder_B = 2;       //1st Pin on the Top of Potentiometer 
const int Encoder_Press = 4;   //1st Pin on Bottom of Potentiometer
const int MagSwitch= 13;        //Either Lead from Magnet Switch
const int Relay = 16;            //CTRL from Relay Board

/*
Other Setup Information:
- VCC from LCD Board to 5v                        
- GND from LCD Board to Ground
- 1st Pin on Bottom of Potentiometer to Ground
- 2nd Pin of Potentiometer to Ground              
- Other Lead of Magnet Switch to Ground
- 5V of Relay Board to 5V
- GND of Relay Baord to Ground
*/

// VARIABLES:
const int increment = 30; //change this value to change the seconds increment when setting the timer
const int Encoder_Sensitivity = 150;
const int Press_Sensitivity = 150;

//DONT CHANGE THIS STUFF!////////////////////////////////////////////////////////////////////////////////////////////////////
SoftwareSerial Serial7Segment(LCD_TX, LCD_RX); 
#define COLON       4
char tempString[4];

long millisTimer;
byte seconds = 00;
byte minutes = 00;
byte seconds_hold;
byte minutes_hold;

int mode = 0;
#define Set_Timer   0
#define Run_Timer   1
#define Pause_Timer 2
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static void _ResetPins(){
  pinMode(Encoder_A, INPUT);
  digitalWrite(Encoder_A, HIGH);

  pinMode(Encoder_B, INPUT);
  digitalWrite(Encoder_B, HIGH);

  pinMode(Encoder_Press, INPUT);
  digitalWrite(Encoder_Press, HIGH);

  Serial7Segment.write(0x77);  // Decimal, colon, apostrophe control command
  Serial7Segment.write(1<<COLON);
}
///READ ENCODER:///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void _lowlevel_ReadEncoder(int &rotate, int& press){
  rotate = (digitalRead(Encoder_B) * 2) + digitalRead(Encoder_A);
  press = digitalRead(Encoder_Press);
}
///SET TIMER://///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void SetTimer(){ //Reads the State of the Encoder and adjust the Display accordingly. CW rotation = + "increment" seconds, CCW = - "increment" seconds
  int Position, Press;
  int Position2, Press2;

    _ResetPins();
  _lowlevel_ReadEncoder(Position, Press);

  do  {
    _lowlevel_ReadEncoder(Position2, Press2);
  } 
  while ((Position2 == Position) && (Press2 == Press));

  if (Position2 != Position){ //if there is a poisition change:
    // "Forward" is shown by the position going from (0 to 1) or (1 to 3)
    // or (3 to 2) or (2 to 0).  Anything else indicates that the user is
    // turning the device the other way.  Remember: this is Gray code, not
    // binary.
    int isFwd = ((Position == 0) && (Position2 == 1)) ||
      ((Position == 1) && (Position2 == 3)) ||
      ((Position == 3) && (Position2 == 2)) ||
      ((Position == 2) && (Position2 == 0));
    delay(Encoder_Sensitivity);
    if (isFwd == 1) {//if Encoder is moved forwards (CW), advance seconds by defined increment value
      seconds_hold += increment;
    }
    if (!isFwd){ // if encoder is moved backwards(CCW):
      if (seconds_hold == 0){// if we are already at zero seconds, check to make sure we can reduce a minute
        if (minutes_hold > 0){// if the minutes can be reduced (i.e. not zero) then remove one minute and reset seconds to 59       
          minutes_hold --;
          seconds_hold = 60-increment;
        }
      }
      else      {
        seconds_hold = seconds_hold - increment;//if seconds were not = 0, then decrease seconds value by the increment value
      }
    }
  }

  if (seconds_hold>59) {   // When seconds = 60:
    minutes_hold++;          // Add one minute
    seconds_hold -= 60;      // Reset seconds
  }

  //if the encoder is pressed down:
  if (digitalRead(Encoder_Press) == LOW)   {
    delay(Press_Sensitivity);
    seconds = seconds_hold;
    minutes = minutes_hold;
    mode = Run_Timer;
  }
  Position = Position2;
  Press = Press2;

  Serial7Segment.print('v');
  sprintf(tempString, "%02d%02d", minutes_hold, seconds_hold);
  Serial7Segment.print(tempString); //Send serial string out the soft serial port to the S7S
  //  Serial.println(tempString);
}

//COUNT DOWN///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void RunTimer() {    //this will start counting down from the time set using the encoder. This begins when the encoder button is pressed.

  if( (millis() - millisTimer) >= 1000)  {
    millisTimer += 1000;   //Adjust the timer forward 1 second
    if (seconds == 0){// if we are already at zero seconds, check to make sure we can reduce a minute
      if (minutes > 0){// if the minutes can be reduced (i.e. not zero) then remove one minute and reset seconds to 59   
        minutes --;
        seconds = 59;
      }
    }
    else{
      seconds--;//if seconds were not = 0, then decrease seconds value by the increment value
    }

    sprintf(tempString, "%02d%02d", minutes, seconds);
    Serial7Segment.write(0x77);  // Decimal, colon, apostrophe control command
    Serial7Segment.write(1<<COLON); // Turns on colon, apostrophoe, and far-right decimal
    Serial7Segment.print(tempString); //Send serial string out the soft serial port to the S7S
    //    Serial.println(tempString);
  }

  if (minutes == 0 & seconds == 0)  {
    digitalWrite(Relay, LOW);
    Serial7Segment.print("0000"); //Send the hour and minutes to the display
    mode = Set_Timer;
  }

  if (digitalRead(Encoder_Press)== LOW)  {
    delay(Press_Sensitivity);
    if (digitalRead(Encoder_Press)== LOW){
      mode = Pause_Timer;
    }
  }
}
//PAUSE:////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void PauseTimer()
{
  sprintf(tempString, "%02d%02d", minutes, seconds);
  Serial7Segment.write(0x77);  // Decimal, colon, apostrophe control command
  Serial7Segment.write(1<<COLON); // Turns on colon, apostrophoe, and far-right decimal
  Serial7Segment.write('v');  // clear screen
  Serial7Segment.print(tempString); //Send serial string out the soft serial port to the S7S

  if (digitalRead(Encoder_Press) == LOW)  {
    delay(Press_Sensitivity);
    if (digitalRead(Encoder_Press) == LOW) {
      mode = Run_Timer;
      return;
    }
  }
  mode = Set_Timer;
}

//SETUP:////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void setup(){
  // configure the pins
  _ResetPins();

  //  Serial.begin(9600);
  Serial7Segment.begin(57600); //Talk to the Serial7Segment at 9600 bps
  Serial7Segment.write(0x7A);  // Brightness control command
  Serial7Segment.write((byte) 80);  // Brightness control command

  pinMode(MagSwitch, INPUT);

  Serial7Segment.write('v'); //Reset the display - this forces the cursor to return to the beginning of the display
  Serial7Segment.print("0000"); //Send the hour and minutes to the display
}

void loop(){
  if (digitalRead(MagSwitch) == LOW) {
    switch(mode){
//      digitalWrite(Relay, LOW); //Relay off

      case Set_Timer: //reads encoder and sets time
      SetTimer();
      break;

      case Run_Timer: //counts down timer
      digitalWrite(Relay, HIGH); //relay on
      RunTimer(); //run countdown script (above)
      break;

      case Pause_Timer: 
      digitalWrite(Relay, LOW);
      PauseTimer();
      break;   

    default:
      break;
    }
  }

  else {
    digitalWrite (Relay, LOW);
    
    Serial7Segment.write(0x77);  // Decimal, colon, apostrophe control command
    Serial7Segment.write(1<<COLON); // Turns on colon, apostrophoe, and far-right decimal
    Serial7Segment.print("OFF "); //Send the hour and minutes to the display
    mode = Set_Timer;
  }  
}

I removed some unnecessary code for switching between minutes_hold and minutes and the same with the seconds_hold and seconds. What I was trying to do there was store the current variables and pause the timer. When the user presses the encoder in, I wanted the timer to resume from that time. For some reason, the timer seems to continue counting in the background even when the Pause function is selected. This is the main issue in the code right now. In addition, when the button is pressed in to first start the timer, the time displayed jumps down about 5 seconds or so.

I tried to stop the timer from counting down by putting a boolean "ispaused" and having the timer only run if "ispaused" = false. When the pause function is called, I would set "ispaused" = true. This did not fix anything.

Regarding the delays: I put them in to help with some responsiveness issues with the encoder. Without the delays, the encoder is too sensitive to rotation and the button presses are registered too frequently. I am sure they are not the ideal solution, and have been looking for a better solution.

I moved the encoders to pins 2 and 3 to allow me to try out interrupts. These did not make the encoder any more responsive and would have required a full rewrite of my SetTimer() function.

Thanks again, and sorry about the poor formatting and sloppy code.

Hi there,

Sorry this will not be a helpful reply but more of a request for help :~

I am completely new to this and some of what you are doing is what I want to do with my project, particularly setting the time with the rotary encoder displaying it on 4 x 4x7 segment LED's and then entering a countdown to zero when a button is pressed and once at zero performing an audio visual output.

Can you tell me where you got started on this and what resources you used?

Thanks

Dexter