Arduino Countdown timer code problem?

I was using the Crazy Countdown Timer as a base for yet another project and I seem to have hit a dead end with the code.
I have taken an input (A3) that used to speed up the countdown time and tried to change the function to add five minutes to the remaining time. I have tried various methods and the results have not been the best. From setting the total time to 5 minutes to it's current state of not doing anything at all, I have limited knowledge of the coding and would appreciate some help if you would be so kind.

Thanks in advance :-)

The code so far is

/*
  Arduino clock on a standard 4-digit clock display
  Uses a Liteon LTC-617D1G clock display

Connections:
LTC - Arduino
1 - nc
2 - nc
3 - nc
4 - d7
5 - d3
6 - d2
7 - d11
8 - d10
9 - d4
10 - gnd
22 - d9
23 - d5
24 - d6
25 - A0  // because d13 already has a built-in LED getting in the way
26 - d8
27 - d12
28 - A1
29 - gnd

button:
5v - button - A5 - 10k resistor - gnd

crazy wires:
5v - red jumper wire - A4 - 10k resistor - gnd
5v - blue jumper wire - A3 - 10k resistor - gnd
5v - yellow jumper wire - A2 - 10k resistor - gnd

Action:
pin D13 is already hooked up to an LED

*/

#define DIGIT1 2
#define DIGIT2 3
#define DIGIT3 5
#define DIGIT4 6

#define SEGMENTA 7
#define SEGMENTB 8
#define SEGMENTC 9
#define SEGMENTD 10
#define SEGMENTE 11
#define SEGMENTF 12
#define SEGMENTG A0

#define COLON 4
#define AMPM A1

#define BUTTON A5

#define STOPWIRE  A2
#define PLUSFIVE A3
#define ZEROWIRE  A4

#define ACTION 13

#define ON  HIGH
#define OFF LOW

#define DELAYTIME 50


int FiveState;             // the current FiveRead from the input pin
int lastFiveState = LOW;   // the previous FiveRead from the input pin

long FivelastDebounceTime = 0;  // the last time the output pin was toggled
long FiveDebounceDelay = 50;    // the debounce time; increase if the output flickers

unsigned short hours, minutes, seconds;
unsigned long lastTime; // keeps track of when the previous second happened

int buttonState;             // the current reading from the button pin
int lastButtonState = LOW;   // the previous reading from the button pin
unsigned long button_down_start = 0; // how long the button was held down
unsigned long lastDebounceTime = 0;  // the last time the output pin was toggled
unsigned long debounceDelay = 50;    // the debounce time


byte flash;    // indicates when display should be flashing
byte flash_on; // indicates that display is current in "on" part of a flash
byte timer_stopped; // indicates that the timer is not counting down

#define ONE_SECOND 1000
#define FLASH_TIME 100 // 10 times as fast
unsigned long time_chunk;

void setup() {
 
// Serial.begin(9600);
 
  // initialize all the required pins as output.
  pinMode(DIGIT1, OUTPUT);
  pinMode(DIGIT2, OUTPUT);
  pinMode(DIGIT3, OUTPUT);
  pinMode(DIGIT4, OUTPUT);

  pinMode(SEGMENTA, OUTPUT);
  pinMode(SEGMENTB, OUTPUT);
  pinMode(SEGMENTC, OUTPUT);
  pinMode(SEGMENTD, OUTPUT);
  pinMode(SEGMENTE, OUTPUT);
  pinMode(SEGMENTF, OUTPUT);
  pinMode(SEGMENTG, OUTPUT);

  pinMode(COLON, OUTPUT);
  pinMode(AMPM, OUTPUT);
 
  // button is input
  pinMode(BUTTON, INPUT);
 
  // wires are inputs
  pinMode(STOPWIRE, INPUT);
  pinMode(PLUSFIVE, INPUT);
  pinMode(ZEROWIRE, INPUT);
 
  // the action is output
  pinMode(ACTION, OUTPUT);
 
  // set the initial time
  hours = 0;
  minutes = 25;
  seconds = 00;

  flash = 0;
  flash_on = 0;
  timer_stopped = 0;

  time_chunk = ONE_SECOND;

  lastTime = millis();
}

void loop() {
 
  // Keep showing the display while waiting for timer to expire 
  while (millis() - lastTime < time_chunk) {
       
    if (!flash || flash_on) {
     
      if (hours > 0) {
        clock_show_time(hours, minutes);
   
        // and blink the colon every even second
        if (seconds % 2 == 0) {
          clock_show_colon();
        }
      }
      else {
        clock_show_time(minutes, seconds);
        clock_show_colon(); // show a steady colon
      }
     
    }
   
    // check the crazy wires
   
    if (digitalRead(STOPWIRE) == HIGH) {  // stops time
      timer_stopped = true;
    }
    else {
      timer_stopped = false;
    }
    /*
    if (digitalRead(SPEEDWIRE) == HIGH) { // speeds up the time and flashes display
      flash = 1;
      time_chunk = FLASH_TIME;
    }
    */
   
     // read the state of the switch into a local variable:
  int FiveRead = digitalRead(PLUSFIVE);

  // check to see if you just pressed the button
  // (i.e. the input went from LOW to HIGH),  and you've waited
  // long enough since the last press to ignore any noise: 

  // If the switch changed, due to noise or pressing:
  if (FiveRead != lastFiveState) {
    // reset the debouncing timer
    FivelastDebounceTime = millis();
  }
 
  if ((millis() - FivelastDebounceTime) > FiveDebounceDelay) {
    // whatever the FiveRead is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:

    // if the button state has changed:
    if (FiveRead != FiveState) {
      FiveState = FiveRead;

      // only toggle the LED if the new button state is HIGH
      if (FiveState == HIGH) {
        minutes += 5;
      if (minutes > 59) minutes = 59;
          }
         
          // button has been pressed
          incrementTime();
        }
 
  // save the FiveRead.  Next time through the loop,
  // it'll be the lastFiveState:
  lastFiveState = FiveRead;
  
}   
    if (digitalRead(ZEROWIRE) == HIGH) {  // sets time to zero
      hours = 0;
      minutes = 0;
      seconds = 0;
      time_chunk = FLASH_TIME;
    }
   
    // button presses increase minutes
    int reading = digitalRead(BUTTON);

     // If the switch changed, due to noise or pressing:
    if (reading != lastButtonState) {
      // reset the debouncing timer
      lastDebounceTime = millis();
    }
   
    if ((millis() - lastDebounceTime) > debounceDelay) {
      // whatever the reading is at, it's been there for longer
      // than the debounce delay, so take it as the actual current state:
     
      if (buttonState != reading) {
        button_down_start = millis(); // record the start of the current button state
      }
     
      buttonState = reading;
     
      // buttonState is now either on or off
      if (buttonState == HIGH) {
        flash = 0; // takes it out of panic mode
        digitalWrite(ACTION, OFF); // turns the action OFF.
        time_chunk = ONE_SECOND; // reset to regular time counting.
         
        // slow it down by only doing this every 10th millisecond
        if ((millis() % 10) == 0) {
          // if the button was held down more than 5 seconds, make it go faster
          if ((millis() - button_down_start) > 5000) {
            seconds += 10;
            if (seconds > 59) seconds = 59;
          }
         
          // button has been pressed
          incrementTime();
        }
      }
    }

    lastButtonState = reading;
  }

  lastTime += time_chunk;
 
  if (!timer_stopped) {
    decrementTime();
  }
 
  if (flash) {
    flash_on = !flash_on;
  }

}

//
// a call to decrementTime decreases time by one second.
//
void decrementTime() {

      if (seconds == 0) {
     
        if (minutes == 0) {
       
          if (hours == 0) {         
            // time is at 00:00, flash the zeroes
            flash = 1;
            time_chunk = FLASH_TIME;
                 
            // and do the action
            do_action();
          }
          else {
            minutes = 59;
            hours--;
          }
        }
        else {
          seconds = 59;
          minutes--;
        }
       
      }
      else {
        seconds--; 
      }
}

//
// a call to incrementTime increases time by one second.
//
void incrementTime() {
 
  if (seconds == 59) {
    seconds = 0;
   
    if (minutes == 59) {
      minutes = 0;
     
      if (hours == 12) {         
        hours = 1;
      }
      else {
        hours++;
      }
    }
    else {
      minutes++;
    }
  }
  else {
    seconds++; 
  }
}

//
// clock_show_time - displays the given time on the clock display
//   Note that instead of hr/min the user can also send min/sec
//   Maximum hr is 99, Maximum min is 59, and minimum is 0 for both (it's unsigned, heh).
//
void clock_show_time(unsigned short hours, unsigned short minutes) {
  unsigned short i;
  unsigned short delaytime;
  unsigned short num_leds[10] = { 6, 2, 5, 5, 4, 5, 6, 3, 7, 6 };
  unsigned short digit[4];
  unsigned short hide_leading_hours_digit;
   
  // convert minutes and seconds into the individual digits
  // check the boundaries
  if (hours > 99) hours = 99;
  if (minutes > 59) minutes = 59;
 
  // convert hr
  if (hours < 10 && hours > 0) {
    hide_leading_hours_digit = 1;
  }
  else {
    hide_leading_hours_digit = 0;
  }
 
  digit[0] = hours / 10;
  digit[1] = hours % 10; // remainder
  digit[2] = minutes / 10;
  digit[3] = minutes % 10; // remainder 

  for (i = hide_leading_hours_digit; i < 4; i++) {
    clock_all_off();
    clock_show_digit(i, digit[i]);

    // fewer leds = brighter display, so delay depends on number of leds lit.
    delaytime = num_leds[digit[i]] * DELAYTIME;  
    delayMicroseconds(delaytime);
  }
   
  clock_all_off();
}

//
// clock_all_off - turns off all the LEDs on the clock to give a blank display
//
void clock_all_off(void) {
 
  // digits must be ON for any LEDs to be on
  digitalWrite(DIGIT1, OFF);
  digitalWrite(DIGIT2, OFF);
  digitalWrite(DIGIT3, OFF);
  digitalWrite(DIGIT4, OFF);
 
  // segments must be OFF for any LEDs to be on
  digitalWrite(SEGMENTA, ON);
  digitalWrite(SEGMENTB, ON);
  digitalWrite(SEGMENTC, ON);
  digitalWrite(SEGMENTD, ON);
  digitalWrite(SEGMENTE, ON);
  digitalWrite(SEGMENTF, ON);
  digitalWrite(SEGMENTG, ON);
 
  // turn off colon and alarm too
  digitalWrite(COLON, OFF);
  digitalWrite(AMPM, OFF);
}

//
// clock_show_digit - turns on the LEDs for the digit in the given position
//      position can be from 0 through 3: 0 and 1 being the hour, 2 and 3 being the seconds
//      value can be from 0 through 9, ie, a valid single digit.
//
//      (if value is out of range, it displays a 9. if digit is out of range display remains blank)
//
void clock_show_digit(unsigned short position, unsigned short value) {
  byte a;
  byte b;
  byte c;
  byte d;
  byte e;
  byte f;
  byte g;

  switch (position) {
    case 0:
      digitalWrite(DIGIT1, ON);
      break;
    case 1:
      digitalWrite(DIGIT2, ON);
      break;
    case 2:
      digitalWrite(DIGIT3, ON);
      break;
    case 3:
      digitalWrite(DIGIT4, ON);
      break;
  }

  a = !(value == 1 || value == 4);
  b = !(value == 5 || value == 6);
  c = !(value == 2);
  d = !(value == 1 || value == 4 || value == 7);
  e =  (value == 0 || value == 2 || value == 6 || value == 8);
  f = !(value == 1 || value == 2 || value == 3 || value == 7);
  g = !(value == 0 || value == 1 || value == 7);
 
  if (a) digitalWrite(SEGMENTA, OFF);
  if (b) digitalWrite(SEGMENTB, OFF);
  if (c) digitalWrite(SEGMENTC, OFF);
  if (d) digitalWrite(SEGMENTD, OFF);
  if (e) digitalWrite(SEGMENTE, OFF);
  if (f) digitalWrite(SEGMENTF, OFF);
  if (g) digitalWrite(SEGMENTG, OFF);
}

//
// clock_show_colon - shows the colon that separates minutes from seconds
//
void clock_show_colon(void) {
  unsigned short delaytime;

  digitalWrite(COLON, ON); 
                              // 2 leds = 2 delays needed
  delaytime = DELAYTIME * 2;  // must use variable to have similar delay to rest of clock
  delayMicroseconds(delaytime);   //   because use of variable slows it down slightly.
  digitalWrite(COLON, OFF);
}

//
// clock_show_alarm - shows the ampm dot (bottom right of clock display)
//
void clock_show_ampm(void) {
  unsigned short delaytime;

  digitalWrite(AMPM, ON);
                     
  delaytime = DELAYTIME;  // must use variable to have similar delay to rest of clock
  delayMicroseconds(delaytime);   //   because use of variable slows it down slightly.
  digitalWrite(AMPM, OFF);
}

//
// do_action - this function gets called when the timer completes.
//
static void do_action(void) {
  // the exciting action here is just to turn on a LED
  digitalWrite(ACTION, ON);
  Serial.println("ACTION!");
}

Djandco (author) 3 years ago

Hi Nico,

Thanks for coming back to me, I have left the resistors in, I prefer to do that than the digitalwrite because I know I have the right pins that way :-) I don't have the ability to write the code from scratch but adapting code in this way is how I learn, the hard way!

I have tried the below code that simply doesn't do anything which baffles me and I have tried a different code but the display changes from 25 minutes to 5 minutes, I just can;t seem to get it to add onto the remaining time.

More experimenting coming up :-)

Kind regards

Darren

ntewinkel3 years ago

Hi Darren,

Thanks for keeping the code alive! I'm happy that it's been useful for you :)

I had a quick look over your code and I don't see any obvious issue with it, but it's been a while since I wrote the original version.

One thing to maybe double check is that when you replaced the wire with the button, did you still keep the resistor to ground so that the pin is not floating when the button is open? That always makes for unpredictable fun! ;) You can do it without the resistor by using the internal pulldown resistor (which I learned much later), but you'd have to add a line of code for that.

Otherwise, I always find it helpful to print to the serial console and then test it while connected, to see when it's running the +5min code, and also to see when it's going into the different parts of that button click block. The first step is to make sure it's doing the basics the way you're expecting it, and then check out more details as you go.

I hope that helps! Hope you get it cleared up easily :)

Cheers,
-Nico