Go Down

Topic: Pausing a Countdown Timer using Switch Case and A Rotary Encoder (Read 924 times) previous topic - next topic

sholland91

Hello, I am working on making a countdown timer using a rotary encoder and a 7 segment 4 digit led display.
The program works as follows:
Case 1: Set Time
     - Rotate encoder to change seconds and minutes on display
     - If the encoder is pressed in, switch to the Run Timer Case
Case 2: Run Timer
     - Counts down from the time set in Case 1
     - If the encoder is pressed in, switch to the Pause Timer Case
Case 3: Pause Timer
     - Stop the timer from counting down.
     - Rotate encoder to change seconds and minutes on display
     - If the encoder is pressed in, switch to the Run Timer Case

Case 1 and 2 work perfectly. Pausing the timer allows me to change the values of the timer. When I press the encoder in again, however, the timer jumps to how many seconds have elapsed.
ie. If I pause the timer at 1:30 and wait 25 seconds before pressing the encoder again, the display quickly counts down from 1:30 to 1:05 and then continues to count as usual. If I wait more than 1:30, the timer speeds all the way down to 0.

I have tried to store my seconds and minutes values as new integers while the encoder is pressed, and then reassign the values when I press the encoder again. This does nothing though.
Below is the snippet of code that's not working. "mode = " is my switch case command.
Code: [Select]

void ReadEncoder() //Reads the State of the Encoder and adjust the Display accordingly. CW rotation = + "increment" seconds, CCW = - "increment" seconds
{
  int Position, Press;
  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(Encoder_Sensitivity);
    if (isFwd == 1) //if Encoder is moved forwards (CW), advance seconds by defined increment value
    {
      seconds= seconds + increment;
    }
    if (isFwd == 0) // if encoder is moved backwards(CCW):
    {
      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 = 60-increment;
        }
      }
      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(Press_Sensitivity);
    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(Encoder_Press)== LOW)
  {
    delay(Press_Sensitivity);
    mode = Pause_Timer;
  }
}

//-----------------------------------------------------------------------------------------
void PauseTimer()
{
  seconds_hold = seconds;
  minutes_hold = minutes;

  sprintf(tempString, "%02d%02d", minutes_hold, seconds_hold);
  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(Encoder_Press) == LOW)
  {
    delay(Press_Sensitivity);
    seconds = seconds_hold;
    minutes = minutes_hold; 
    mode = Run_Timer;
  }

  mode = Set_Timer;
}


Any thoughts?
Thanks!

sholland91

And here is my entire code:
Code: [Select]
#include <SoftwareSerial.h>

//CONFIGURATION:
/// Pins From Components to Arduino:///
const int LCD_SS = 8;           //SS On LCD Board
const int LCD_RX = 7;           //RX On LCD Board
const int Encoder_A = 14;       //3rd Pin on the Top of Potentiometer to A0 on Arduino
const int Encoder_B = 15;       //1st Pin on the Top of Potentiometer to A1 on Arduino
const int Encoder_Press = 12;   //1st Pin on Bottom of Potentiometer
const int MagSwitch= 13;        //Either Lead from Magnet Switch
const int Relay = 2;            //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;

//////////////////////////////////////////////////////////////////////////////////////////////////////
SoftwareSerial Serial7Segment(LCD_SS, LCD_RX);
#define COLON       4
char tempString[4];

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

int mode = 0;
#define Set_Timer   0
#define Run_Timer   1
#define Pause_Timer 2

int seconds_hold;
int minutes_hold;

//---------------------------------------------------------------------------------------
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);
}

//---------------------------------------------------------------------------------------
void _lowlevel_ReadEncoder(int &rotate, int& press)
{
  rotate = (digitalRead(Encoder_B) * 2) + digitalRead(Encoder_A);
  press = digitalRead(Encoder_Press);
}

//-----------------------------------------------------------------------------------------
void SetTimer() //Reads the State of the Encoder and adjust the Display accordingly. CW rotation = + "increment" seconds, CCW = - "increment" seconds
{
  int Position, Press;
  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(Encoder_Sensitivity);
    if (isFwd == 1) //if Encoder is moved forwards (CW), advance seconds by defined increment value
    {
      seconds= seconds + increment;
    }
    if (isFwd == 0) // if encoder is moved backwards(CCW):
    {
      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 = 60-increment;
        }
      }
      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(Press_Sensitivity);
    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(Encoder_Press)== LOW)
  {
    delay(Press_Sensitivity);
    mode = Pause_Timer;
  }
}

//-----------------------------------------------------------------------------------------
void PauseTimer()
{
  seconds_hold = seconds;
  minutes_hold = minutes;

  sprintf(tempString, "%02d%02d", minutes_hold, seconds_hold);
  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(Encoder_Press) == LOW)
  {
    delay(Press_Sensitivity);
    seconds = seconds_hold;
    minutes = minutes_hold; 
    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
      SetTimer();
      break;

      case (Run_Timer): //counts down timer
      digitalWrite(Relay, HIGH); //relay on
      //      minutes = minutes_hold;
      //      seconds = seconds_hold;
      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;
  } 
}

Go Up