Help with Arduino, 7-segment display, countdown timer [SOLVED]

Here's what I am trying to achieve:

Until Button1 is pressed, the LED display reads "----"

Button1 - starts timer shown on LED display (30 minutes) - timer starts counting down.
Button2 - freezes timer
Button3 - starts timer counting down from where it was when button2 was pressed

LED1 - lights up while timer is counting down, stays on while frozen.
LED2 - lights up while timer is frozen, goes out when timer is resumed counting down.

When timer is started PIN7 is written HIGH
When timer reads 20 min, PIN 8 is written HIGH
at 10min left, PIN9 -> HIGH
at 5min left, PIN10 -> HIGH
at 1min left, PIN11 -> HIGH
Timer runs out completely , PIN12 -> HIGH

After time has run out, button1 can be pressed to restart the whole process.

What's working:

  • With the code below, the display shows "----" until Button1 is pressed.
  • Button1 successfully starts time at 30 minutes and lights up LED1.
  • Button2 successfully freezes the time and lights up LED2.

I cannot get button3 to start the time up again, and I have no idea how to mix in the timed digitalWrites for pins 7 - 12 shown above or how to get my Button1 to restart the whole process. I don't have a very good understanding of the whole "loop" function and how to pause it, restart it etc. I feel that my code I've written does it in a very roundabout incorrect way, with variable "timerRunning" and "pausePushed" being set to 1 from 0.

I have connected the Adafruit 1.2" 4-Digit 7-Segment Display w/I2C Backpack to the correct pins as instructed here and its working perfectly.

Using the following libraries (as you can see in the code):

  • Time.h
  • Wire.h
  • Adafruit_LEDBackpack.h
  • Adafruit_GFX.h"

Can someone help me edit this code to function how I've described above and in the most clean and streamlined way? At this point, I'm not getting any errors, but I have hit a wall as far as how to complete the rest of my goals with my current coding knowledge.

Thanks in advance!
-Kayden

#include <Time.h>
#include <Wire.h>
#include "Adafruit_LEDBackpack.h"
#include "Adafruit_GFX.h"
Adafruit_7segment matrix = Adafruit_7segment();
time_t t;
tmElements_t tm;
int seconds, minutes;

int startButton = 3;
int inProgLED = 4; 
int pausedLED = 5;
int pauseButton = 6;

int timerRunning = 0;
int pausePushed = 0;

void setup(void)
{  
  Serial.begin(9600); //begin Serial
  pinMode(startButton, INPUT);
  pinMode(pauseButton, INPUT);
  pinMode(inProgLED, OUTPUT);
  pinMode(pausedLED, OUTPUT);
  digitalWrite(startButton, HIGH);
  digitalWrite(pauseButton, HIGH);
  
    matrix.begin(0x70);
    
    tm.Second = 0;
    tm.Minute = 30;
    tm.Day = 24;
    tm.Month = 4;
    tm.Year = CalendarYrToTm(2015);
    
    t = makeTime(tm);
    
     
}

void loop(void)
{
   matrix.print(10000, DEC);
   matrix.writeDisplay();
   if (digitalRead(startButton) == LOW) {
     timerRunning = 1;
   }
   if (digitalRead(pauseButton) == LOW) {
     pausePushed= 1;
   }
  Serial.println(pauseButton);
  Serial.println(startButton);
  
  
  if(timerRunning == 1){
    digitalWrite(inProgLED, HIGH);
    seconds = second(t);
    minutes = minute(t);
    
    matrix.writeDigitNum(0, (minutes / 10) % 10, false);
    matrix.writeDigitNum(1, (minutes % 10), false);
    matrix.drawColon(true);
    matrix.writeDigitNum(3, (seconds / 10) % 10, false);
    matrix.writeDigitNum(4, seconds % 10, false);
    matrix.writeDisplay();
    --t; //subtract a second
    if (seconds + minutes == 0) {
        //digitalWrite(pin4, HIGH);
    }
    if(pausePushed == 1){
      digitalWrite(pausedLED, HIGH);
      while(1);
    }
    delay(1000);
 }
}
if(pausePushed == 1){
      digitalWrite(pausedLED, HIGH);
      while(1);
    }

while(1); is the last line of code that arduino will ever run until you press the reset button. That is an infinite loop.

You're going to need to think more in terms of a state machine.

I pulled that while() from another project I saw. I had a feeling I was using it incorrectly.

A state machine?

dboy5026:
A state machine?

Google knows what that is.

@Delta_G,

I understand that I can google State Machine, but the results speak of things that I do not understand, as I said before, my coding knowledge is very limited. That is why I am on this board to get help from people who's arduino coding knowledge vastly surpasses my own.

I wrote what I have here by googling and putting things together, but as you can see, I've gone down the wrong path becuase i don't truly understand the way it SHOULD be coded.

Since it seems that this is the wrong place to ask for direct coding help, where would you guys suggest I go to get someone to do this for me. I can pay.

dboy5026:
Since it seems that this is the wrong place to ask for direct coding help, where would you guys suggest I go to get someone to do this for me. I can pay.

There is a section of this forum called Gigs and Collaborations.

What you want is dirt simple if you'd just give it a good try instead of waiting for someone to spoon feed it to you.

Okay, so here's where I am:

#include <FiniteStateMachine.h>
#include <Time.h>
#include <Wire.h>
#include "Adafruit_LEDBackpack.h"
#include "Adafruit_GFX.h"

Adafruit_7segment matrix = Adafruit_7segment();
time_t t;
tmElements_t tm;
int seconds, minutes;

const byte NUMBER_OF_STATES = 3; //how many states are we cycling through?
State pre = State(beforeTime);
State running = State(timeRun);
State paused = State(timePause);

FSM timerStateMachine = FSM(beforeTime);     //initialize state machine, start in state: On

byte startButtonPresses = 0;            //counter variable, holds number of button presses

int startButton = 1;
int pauseButton = 2;
int resumeButton = 3;
int inProgLED = 4;
int pausedLED = 5;

int timerRunning = 0;
int pausePushed = 0;

void setup(){
  Serial.begin(9600); //begin Serial
  pinMode(startButton, INPUT);
  pinMode(pauseButton, INPUT);
  pinMode(inProgLED, OUTPUT);
  pinMode(pausedLED, OUTPUT);
  digitalWrite(startButton, HIGH);
  digitalWrite(pauseButton, HIGH);

  matrix.begin(0x70);

  tm.Second = 0;
  tm.Minute = 30;
  tm.Day = 24;
  tm.Month = 4;
  tm.Year = CalendarYrToTm(2015);

  t = makeTime(tm);
}

void loop() {
  if (digitalRead(startButton) == LOW) {
    
  }
  timerStateMachine.update();
}

void beforeTime() {
  matrix.print(10000, DEC); //Print "----" on display
  matrix.writeDisplay();
}

void timeRun() {
  digitalWrite(inProgLED, HIGH);
  seconds = second(t);
  minutes = minute(t);

  matrix.writeDigitNum(0, (minutes / 10) % 10, false);
  matrix.writeDigitNum(1, (minutes % 10), false);
  matrix.drawColon(true);
  matrix.writeDigitNum(3, (seconds / 10) % 10, false);
  matrix.writeDigitNum(4, seconds % 10, false);
  matrix.writeDisplay();
  --t; //subtract a second
  delay(1000);

  if (seconds + minutes == 0) {
    //digitalWrite(pin4, HIGH);
  }
  if (minutes == 29) {
    //digitalWrite(pin4, HIGH);
  }
}

void timePause() {
  digitalWrite(pausedLED, HIGH);
  delay(500);
  digitalWrite(pausedLED, LOW);
  delay(500);
}

Does that look like the right direction?
How do I call each state to be entered?

I'm getting these errors:

Arduino: 1.6.3 (Mac OS X), Board: "Arduino Uno"

test2.ino.ino:17:39: error: no matching function for call to 'FiniteStateMachine::FiniteStateMachine(void (&)())'
test2.ino.ino:17:39: note: candidates are:
In file included from test2.ino.ino:1:0:
/Users/Kayden/Documents/Arduino/libraries/FSM/FiniteStateMachine.h:83:3: note: FiniteStateMachine::FiniteStateMachine(State&)
   FiniteStateMachine(State& current);
   ^
/Users/Kayden/Documents/Arduino/libraries/FSM/FiniteStateMachine.h:83:3: note:   no known conversion for argument 1 from 'void()' to 'State&'
/Users/Kayden/Documents/Arduino/libraries/FSM/FiniteStateMachine.h:81:7: note: FiniteStateMachine::FiniteStateMachine(const FiniteStateMachine&)
 class FiniteStateMachine {
       ^
/Users/Kayden/Documents/Arduino/libraries/FSM/FiniteStateMachine.h:81:7: note:   no known conversion for argument 1 from 'void()' to 'const FiniteStateMachine&'
Error compiling.

  This report would have more information with
  "Show verbose output during compilation"
  enabled in File > Preferences.

The error is telling you that instead of the name of the function here, you need the name of the State instance you just created.

FSM timerStateMachine = FSM(beforeTime);
FSM timerStateMachine = FSM(pre);

Awesome! It compiles :slight_smile:
So now I've got this:

void loop() {
  if (digitalRead(startButton) == LOW) {
    //WHAT GOES HERE?
  }
  timerStateMachine.update();
}

What do I put inside the if statement to transfer between states?
The FSM wiki leaves quite a bit to the imagination...

Lets says I want it to switch to timeRun() when startButton is pressed. Would it be:

if (digitalRead(startButton) == LOW) {
  void immediateTransitionTo(timerRun);
}
timerStateMachine.update();

?

Can someone help me with this?

Sorry, I don't generally use libraries for simple tasks so I'm not too familiar with that one.

What I usually do is something like this:

int state = 0;

void loop() {

     // Code to read the buttons and alter the state variable if needed

     switch (state) {
          case 0:
               // Code here for waiting before start
          case 1:
               // Code here for the countdown part
          case 2:
               // Code here for the pause part. 
     }
}

Hey there!

With a little help I was able to get it working with the following code!

#include <Wire.h>
#include "Adafruit_LEDBackpack.h"
#include "Adafruit_GFX.h"

Adafruit_7segment matrix = Adafruit_7segment();
int seconds = 0;
int minutes = 30;
int num = 0;

int startButton = 1;
int pauseButton = 4;
int resumeButton = 5;
int inProgLED = 2;
int pausedLED = 3;
int speaker = 6;
int buttonPresses = 0;
long time = 0;

void setup() {
  pinMode(startButton, INPUT);
  pinMode(pauseButton, INPUT);
  pinMode(resumeButton, INPUT);
  pinMode(inProgLED, OUTPUT);
  pinMode(pausedLED, OUTPUT);
  pinMode(speaker, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(8, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);
  pinMode(11, OUTPUT);
  pinMode(12, OUTPUT);
  digitalWrite(pausedLED, LOW);
  digitalWrite(inProgLED, LOW);
  digitalWrite(startButton, HIGH);
  digitalWrite(pauseButton, HIGH);
  digitalWrite(resumeButton, HIGH);
  matrix.begin(0x70);

  beforeTime();
}

void loop() {
  if (digitalRead(startButton) == LOW) {
    beep();
    time = millis();
    digitalWrite(7, HIGH);
    buttonPresses = 1;
  }
  if (digitalRead(pauseButton) == LOW) {
    beep();
    time = millis();
    buttonPresses = 2;
  }
  if (digitalRead(resumeButton) == LOW) {
    beep();
    time = millis();
    buttonPresses = 3;
  }

  switch (buttonPresses) {
    case 1: 
      UpdateTime();
      timeRun();
      digitalWrite(pausedLED, LOW);
      break;
    case 2: 
      timePause();
      break;
    case 3: 
      UpdateTime();
      timeRun();
      time = millis();
      digitalWrite(pausedLED, LOW);
      break;
    default:
      beforeTime();
      time = millis();
  }
}

void beforeTime() {
  matrix.print(10000, DEC); //Print "----" on display
  matrix.writeDisplay();
  digitalWrite(pausedLED, LOW);
  digitalWrite(inProgLED, LOW);
  digitalWrite(7, LOW);
  digitalWrite(8, LOW);
  digitalWrite(9, LOW);
  digitalWrite(10, LOW);
  digitalWrite(11, LOW);
  digitalWrite(12, LOW);
}

void timeRun() {
  digitalWrite(inProgLED, HIGH);
  num = minutes * 100 + seconds;
  matrix.print(num);
  matrix.writeDisplay();
  if (seconds + minutes == 0) {
    digitalWrite(12, HIGH);
    delay(1000);
    buttonPresses = 0;
    beforeTime();
  }
  if (minutes == 20 && seconds == 0) {
    digitalWrite(8, HIGH);
  }
  if (minutes == 10 && seconds == 0) {
    digitalWrite(9, HIGH);
  }
  if (minutes == 5 && seconds == 0) {
    digitalWrite(10, HIGH);
  }
  if (minutes == 1 && seconds == 0) {
    digitalWrite(11, HIGH);
  }
  UpdateTime();
}

void timePause() {
  digitalWrite(pausedLED, HIGH);
  delay(500);
  digitalWrite(pausedLED, LOW);
  delay(500);
  time = millis();
}

void UpdateTime() {
  if ((millis() - time) >= 1000) {
    seconds--;
    time = millis();
    if (seconds == -1) {
      minutes--;
      seconds = 59;
    }
  }
}

void beep() {
  digitalWrite(speaker, HIGH);
  delay(100);
  digitalWrite(speaker, LOW);
  delay(1000);
}