Oven Timer Functionality - Counting by 1's and 10s

Hey everybody! I’m new to the forum, new to Arduino, and new to programming in general.

I am working on a project where I would like to mimic the functionality of an oven timer as part of a larger project. I want it to increment by 1 second when pressed once, and when the button is held, continue increment at an increasing rate, until the timer reaches a multiple of 10, and then count by 10s. IE: 16,17,18,19,20, 30, 40, 50 etc.

I have figured out how to do the one shot button press, and how to have the counter continue to count up at an increasing rate when the button is held, but I am at a loss of how to do the change to counting by 10s.

My initial thoughts are to do something with changing the data type for my SetTime varible to a float, then divide SetTime by 10 to get a decimal number, then use the int() conversion function to truncate SetTime to a multiple of 10, multiply SetTime by 10 to get back to the correct value, then change the increment to 10 instead of 1.

My concerns with this are that it will always round downward, since the int() function always truncates downward. IE:: 169 seconds, divided by 10 is 16.9, which will truncate to 16, and will multiply back to 160, not 170.

Is there another, better way to do this? I would like to add the counting by 10s function to my existing time change subroutine, as it is working very well to count by increments of 1.

Varible Definitions:

int SpeedUp = A4; // Speed(+) Button Pin Location
int SpdUp = 0; // variable for Speed(+) pin status
int SpeedDown = A1; // Speed(-) Button Pin Location
int SpdDown = 0; // variable for Speed(-) pin status
int TimeUp = A5; // Time(+) Button Pin Location
int TUp = 0; // varible for Time(+) pin status
int TimeDown = A2; // Time(-) Button Pin Location
int TDown = 0; // varible for Time(-) pin status

unsigned long CT = 0; // Current Time (millisecs) - Current Clock Time, continuous running
unsigned long ST = 0; // Saved Time (millisecs) - clock time saved for next increment (Time buttons)
unsigned long PT = 0; // Pulse Time Varible (millisecs) - time between increments on button hold (Time buttons)
unsigned long ST2 = 0; // Saved Time (millisecs) - clock time saved for next increment (Speed buttons)
unsigned long PT2 = 0; // Pulse Time Varible (millisecs) - time between increments on button hold (Speed buttons)
int MinP = 25; // Minimum Pulse Time (millisecs) - minimum time between increments on button hold
int MaxP = 300; // Maximum Pulse Time (millisecs) - maximum time between increments on button hold
const float Ramp = .9; // Pulse Time Accel %
int MaxTime = 240; // Max Run Time for machine (seconds)

int RunState = 0; // Machine Running State for FSM use: 0=on 1=ready 2=running 3=paused 4=completed 5=canceled 6=diagnostic

//EEprom memory usage
int SpeedState = EEPROM.read(11); // read SpeedState stored in memory from before reset
int SetTime = EEPROM.read(10); // read SetTime stored in memory from before reset - SetTime is time set via Time+ and Time- buttons

Time Change Subroutine Code:

void TimeChange()
{
TUp = digitalRead(TimeUp); // read input value
TDown = digitalRead(TimeDown); // read input value
if (TUp == HIGH || TDown == HIGH) { // check if either input is HIGH (either button is pressed)
if (TUp == HIGH && SetTime < MaxTime) { // check if input is HIGH (button is pressed)
if (CT > ST){ // check if current time is higher than the time for next increment
SetTime++; // increment one
tone(Spkr,Freq1,ShortBeep); // Play short button press tone
ST = CT + PT; // set time for next increment to current time plus pulse time
if (PT > MinP){ // check that pulse time is above minium pulse time
PT = PT * Ramp; // decrease pulse time by Ramp% to decrease pulse time
}
}
}
if (TDown == HIGH && SetTime > 1) { // check if input is HIGH (button is pressed)
if (CT > ST){ // check if current time is higher than the time for next increment
SetTime–; // decrement one
tone(Spkr,Freq1,ShortBeep); // Play short button press tone
ST = CT + PT; // set time for next increment to current time plus pulse time
if (PT > MinP){ // check that pulse time is above minium pulse time
PT = PT * Ramp; // decrease pulse time by % to decrease pulse time
}
}
}
}
else {
ST = CT; // set time to next increment equal to current time
PT = MaxP; // reset pulse time to max pulse time
}
if (SetTime >= MaxTime){ // do not count higher than max run time
SetTime = MaxTime;
}
if (SetTime <= 1){ // set time cannot be less than 0
SetTime = 1;
}
if (SetTime != EEPROM.read(10)){ // if SetTime is different that stored value of SetTime
EEPROM.write(10, SetTime); // then write current SetTime to EEPROM
}
DispTime = SetTime; // time for display = to the set time
}

Any and all advice is greatly appreciated. Thanks!

TJ

Maybe a simpler/different idea using below sudo code.

When the button is initially pressed make a copy of the time and set a inc/dec amount to 1/-1 depending on if your counting up/down
do
add the inc/dec to the time.
If the altered time value is <> 10 from the initial copy you made then set inc/dec amount to 10/-10
Check if button is still pressed and exit loop if not
loop

You are in luck, because a long while ago another person had a similar problem, and I helped him with the code.

const byte buttonPin1 = 2; // Up button
const byte buttonPin2 = 3; // Down Button

boolean buttonState1 = 0;
boolean lastReading1 = 0;
boolean buttonState2 = 0;
boolean lastReading2 = 0;
unsigned long onTime1 = 0, onTime2 = 0;
unsigned long interval = 1000;
unsigned long holdAmount = 5;
int count = 0, lastCount;

void setup() { 
  //pinMode(ledPin, OUTPUT);      
  pinMode(buttonPin1, INPUT);
  pinMode(buttonPin2, INPUT);

  Serial.begin(115200);  
}

void loop()
{ 
  buttonState1 = digitalRead(buttonPin1);
  buttonState2 = digitalRead(buttonPin2);

  if (buttonState1 == HIGH && lastReading1 == LOW)
  {
    onTime1 = millis();
    count < 60 ? count++ : count = 0;
  }
  if (buttonState2 == HIGH && lastReading2 == LOW) 
  {
    onTime2 = millis();
    count > 0 ? count-- : count = 59;
  }

  //held
  if (buttonState1 == HIGH && lastReading1 == HIGH) 
  { 
    if ((millis() - onTime1) > interval )    
    {
      onTime1 = millis();
      count < 60? count += holdAmount : count = 0;
      lastReading1 = LOW;
    } 
  }
  if (buttonState2 == HIGH && lastReading2 == HIGH) 
  { 
    if ((millis() - onTime2) > interval )
    {
      onTime2 = millis();
      count > 0 ? count -= holdAmount : count = 59;
      lastReading2 = LOW;
    } 
  }
  if(count != lastCount)
  {
   Serial.println(count);
   lastCount = count;
  }
  lastReading1 = buttonState1;
  lastReading2 = buttonState2;
}

My initial thoughts are to do something with changing the data type for my SetTime varible to a float, then divide SetTime by 10 to get a decimal number, then use the int() conversion function to truncate SetTime to a multiple of 10, multiply SetTime by 10 to get back to the correct value, then change the increment to 10 instead of 1.

Or maybe

incval = count > 19 ? 10 : 1;
count += incval;

Rob

Thanks for the ideas, everyone. I will hopefully get started again on this project monday morning and I'll post back with what I decide to do.

Thanks!

Thanks again for the ideas guys. I tried HazardsMinds code, and it works well for the changing increments, but it changes based on holding the button, not based on what number the variable is. I used a similar approach to what Graynomad suggested, but using a large switch case to change the increment size. I tried to figure a way to rewrite the massive switch case as an array, but cannot figure out how to make that work. This is really messy and I’m certain there is a better way, but it works for now!

Is there an easy way to compare a single variable to all the variables in an array that would eliminate the switch case?
IE::

int ArrayTens = {10,20,30,40,50,60…etc};
if (ArrayTens[any stored value in entire array] == SetTime) {
SetTime += 10;
}

Here is the current version of the time change subroutine. It works very well, single button presses result in single digit increases, if you hold the button, it increases by 1’s at an increasing delay rate, and when it reaches a multiple of ten it counts by 10’s. Releasing the button resets the count increment to 1’s.

// pins and associated varibles for pushbuttons:

int TimeUp = A5;              // Time(+) Button Pin Location
int TUp = 0;                  // varible for Time(+) pin status
int TimeDown = A2;            // Time(-) Button Pin Location
int TDown = 0;                // varible for Time(-) pin status
unsigned long CT = 0;       // Current Time (millisecs) - Current Clock Time, continuous running
unsigned long ST = 0;       // Saved Time (millisecs) - clock time saved for next increment (Time buttons)
unsigned long PT = 0;       // Pulse Time Varible (millisecs) - time between increments on button hold (Time buttons)
unsigned long ST2 = 0;      // Saved Time (millisecs) - clock time saved for next increment (Speed buttons)
unsigned long PT2 = 0;      // Pulse Time Varible (millisecs) - time between increments on button hold (Speed buttons)
int MinP = 180;             // Minimum Pulse Time (millisecs) - minimum time between increments on button hold
int MaxP = 300;             // Maximum Pulse Time (millisecs) - maximum time between increments on button hold
int Jump = 200;             // pulse time to jump by 10s
const float Ramp = .9;      // Pulse Time Accel %
int MaxTime = 180;          // Max Run Time for machine (seconds)


void TimeChange()
{
  TUp = digitalRead(TimeUp);                      // read input value
  TDown = digitalRead(TimeDown);                  // read input value
  if (TUp == HIGH || TDown == HIGH) {             // check if either input is HIGH (either button is pressed)
    if (TUp == HIGH && SetTime < MaxTime)  {      // check if input is HIGH (button is pressed)
      if (CT > ST){                               // check if current time is higher than the time for next increment
        if (PT <= Jump){                          // check if pulse time is smaller than designated jump by tens time
          switch(SetTime){                        // if SetTime is 10,20,30 etc, increment by tens

          case 10:
            SetTime += 10;
            break;

          case 20:
            SetTime += 10;
            break;

          case 30:
            SetTime += 10;
            break;        

          case 40:
            SetTime += 10;
            break;   

          case 50:
            SetTime += 10;
            break;     

          case 60:
            SetTime += 10;
            break;

          case 70:
            SetTime += 10;
            break;

          case 80:
            SetTime += 10;
            break;

          case 90:
            SetTime += 10;
            break;        

          case 100:
            SetTime += 10;
            break;   

          case 110:
            SetTime += 10;
            break;     

          case 120:
            SetTime += 10;
            break;

          case 130:
            SetTime += 10;
            break;

          case 140:
            SetTime += 10;
            break;

          case 150:
            SetTime += 10;
            break;        

          case 160:
            SetTime += 10;
            break;   

          case 170:
            SetTime += 10;
            break;     

          case 180:
            SetTime += 10;
            break;

          default:                                // if SetTime is not multiple of ten
          SetTime++;                              // increment one
          }
        }
        else{
          SetTime++;                              // increment one 
        }
        tone(Spkr,Freq1,ShortBeep);               // Play short button press tone
        ST = CT + PT;                             // set time for next increment to current time plus pulse time
        if (PT > MinP){                           // check that pulse time is above minium pulse time
          PT = PT * Ramp;                         // decrease pulse time by Ramp% to decrease pulse time
        }  
      }  
    }
    if (TDown == HIGH && SetTime > 1)  {          // check if input is HIGH (button is pressed)
      if (CT > ST){                               // check if current time is higher than the time for next increment
        if (PT <= Jump){                          // check if pulse time is smaller than designated jump by tens time
          switch(SetTime){                        // if SetTime is 10,20,30 etc, increment by tens

          case 10:
            SetTime -= 10;
            break;

          case 20:
            SetTime -= 10;
            break;

          case 30:
            SetTime -= 10;
            break;        

          case 40:
            SetTime -= 10;
            break;   

          case 50:
            SetTime -= 10;
            break;     

          case 60:
            SetTime -= 10;
            break;

          case 70:
            SetTime -= 10;
            break;

          case 80:
            SetTime -= 10;
            break;

          case 90:
            SetTime -= 10;
            break;        

          case 100:
            SetTime -= 10;
            break;   

          case 110:
            SetTime -= 10;
            break;     

          case 120:
            SetTime -= 10;
            break;

          case 130:
            SetTime -= 10;
            break;

          case 140:
            SetTime -= 10;
            break;

          case 150:
            SetTime -= 10;
            break;        

          case 160:
            SetTime -= 10;
            break;   

          case 170:
            SetTime -= 10;
            break;     

          case 180:
            SetTime -= 10;
            break;

          default:
            SetTime--;

          }
        }
        else{
          SetTime--;                                // increment one 
        }

        tone(Spkr,Freq1,ShortBeep);               // Play short button press tone
        ST = CT + PT;                             // set time for next increment to current time plus pulse time
        if (PT > MinP){                           // check that pulse time is above minium pulse time
          PT = PT * Ramp;                         // decrease pulse time by % to decrease pulse time
        }  
      }  
    }
  }
  else {
    ST = CT;                                      // set time to next increment equal to current time
    PT = MaxP;                                    // reset pulse time to max pulse time
  }
  if (SetTime >= MaxTime){                        // do not count higher than max run time
    SetTime = MaxTime;
  }
  if (SetTime <= 1){                              // set time cannot be less than 0
    SetTime = 1;
  }
  if (SetTime != EEPROM.read(10)){                // if SetTime is different that stored value of SetTime
    EEPROM.write(10, SetTime);                    // then write current SetTime to EEPROM
  }
  DispTime = SetTime;                             //  time for display = to the set time
}

Well I finally figured out the easy way to do this function. I had never heard the word “modulo” used for a mathematical method of finding the remainder of two numbers divided by each other. In C++ and Arduino it is the operator “%”. By dividing the SetTime variable by a divisor (10 in this case) using the % operator, the remainder is returned into the Remainder variable. When Remainder = 0, you know that you are at an even multiple of the divisor, and you can count up by adding the divisor instead of 1.

This would also work to count by any other number by changing the value of the divisor. This simple math function that I didn’t know existed cut out over 200 lines of code from my program.

int TimeUp = A5;              // Time(+) Button Pin Location
int TUp = 0;                  // varible for Time(+) pin status
int TimeDown = A2;            // Time(-) Button Pin Location
int TDown = 0;                // varible for Time(-) pin status
unsigned long CT = 0;       // Current Time (millisecs) - Current Clock Time, continuous running
unsigned long ST = 0;       // Saved Time (millisecs) - clock time saved for next increment (Time buttons)
unsigned long PT = 0;       // Pulse Time Varible (millisecs) - time between increments on button hold (Time buttons)
unsigned long ST2 = 0;      // Saved Time (millisecs) - clock time saved for next increment (Speed buttons)
unsigned long PT2 = 0;      // Pulse Time Varible (millisecs) - time between increments on button hold (Speed buttons)
int MinP = 180;             // Minimum Pulse Time (millisecs) - minimum time between increments on button hold
int MaxP = 300;             // Maximum Pulse Time (millisecs) - maximum time between increments on button hold
int Jump = 200;             // pulse time to jump by 10s
const float Ramp = .9;      // Pulse Time Accel %
int Divisor = 10;           // Varible for size of time jump other than 1 second
int Remainder = 0;          // Varible for determining if SetTime is divisible by divisor
int MaxTime = 300;          // Max Run Time for machine (seconds)



//EEprom memory usage

int SetTime = EEPROM.read(10);        // read SetTime stored in memory from before reset - SetTime is time set via Time+ and Time- buttons
int DispTime = 0;                     // Time that is actually displayed on LCD - initial time set via SetTime varible




void setup() 
{

  pinMode(TimeUp, INPUT);             // set pin to input
  pinMode(TimeDown, INPUT);           // set pin to input

}

void TimeChange()
{
  TUp = digitalRead(TimeUp);                      // read input value
  TDown = digitalRead(TimeDown);                  // read input value
  if (TUp == HIGH || TDown == HIGH) {             // check if either input is HIGH (either button is pressed)
    if (TUp == HIGH && SetTime < MaxTime)  {      // check if input is HIGH (button is pressed)
      if (CT > ST){                               // check if current time is higher than the time for next increment
        if (PT <= Jump){                          // check if pulse time is smaller than designated jump by tens time
          Remainder = SetTime % Divisor;          // Determine the remainder of SetTime divided by the Divisor
          if (Remainder == 0){                    // if the remainder is zero, you are at a multiple of the divisor
            SetTime += Divisor;                   // add the Divisor to SetTime
          }        
          else{                                   
            SetTime++;                            // increment one
          }
        }
        else{
          SetTime++;                              // increment one 
        }
        tone(Spkr,Freq1,ShortBeep);               // Play short button press tone
        ST = CT + PT;                             // set time for next increment to current time plus pulse time
        if (PT > MinP){                           // check that pulse time is above minium pulse time
          PT = PT * Ramp;                         // decrease pulse time by Ramp% to decrease pulse time
        }  
      }  
    }
    if (TDown == HIGH && SetTime > 1)  {          // check if input is HIGH (button is pressed)
      if (CT > ST){                               // check if current time is higher than the time for next increment
        if (PT <= Jump){                          // check if pulse time is smaller than designated jump by tens time
          Remainder = SetTime % Divisor;          // Determine the remainder of SetTime divided by the Divisor
          if (Remainder == 0){                    // if the remainder is zero, you are at a multiple of the divisor
            SetTime -= Divisor;                   // subtract the Divisor from SetTime
          }        
          else{
            SetTime--;                            // decrement one
          }
        }
        else{
          SetTime--;                              // decrement one 
        }

        tone(Spkr,Freq1,ShortBeep);               // Play short button press tone
        ST = CT + PT;                             // set time for next increment to current time plus pulse time
        if (PT > MinP){                           // check that pulse time is above minium pulse time
          PT = PT * Ramp;                         // decrease pulse time by % to decrease pulse time
        }  
      }  
    }
  }
  else {
    ST = CT;                                      // set time to next increment equal to current time
    PT = MaxP;                                    // reset pulse time to max pulse time
  }
  if (SetTime >= MaxTime){                        // do not count higher than max run time
    SetTime = MaxTime;
  }
  if (SetTime <= 1){                              // set time cannot be less than 0
    SetTime = 1;
  }
  if (SetTime != EEPROM.read(10)){                // if SetTime is different that stored value of SetTime
    EEPROM.write(10, SetTime);                    // then write current SetTime to EEPROM
  }
  DispTime = SetTime;                             //  time for display = to the set time
}