Having Troubles with multiple timers

Hello Gents, I’m very new to the Arduino and as such, very new to the language. I’m trying to build a capturable device for airsoft games. It’s basically a cube with LEDs, an LCD screen , and 2 buttons. The cube will be lit green upon booting and will display a welcome message. If one of the buttons is held( there’s a red and a blue), the green LED will go off, the corresponding LED will light up, and a stopwatch will count the time that the particular LED is lit and display it on the LCD. If the other button is held, the LED will change to match the new button, a new corresponding stopwatch will start counting, and the initial stopwatch will be stopped.

I think I’m quite close to the desired end result, but when I switch from blue to red, the red stopwatch does not display properly, ie. it doesn’t display the count progressing. If I switch back to blue from red, the counter for blue works correctly, and the static display of the red score is correct, showing me that the stopwatch is running, just not displaying…

I’m hoping someone can show me where my problem is. I have other elements I’ll be adding later including a green button to activate a game countdown timer, but I don’t want to get ahead of myself. I’m thinking that if I can get the two working correctly, adding a third should make more sense and be that much easier.

I’m sure a read of my posted code will show how little I know, so I’m expecting criticism, especially in regards to use of runEvery (I was trying to avoid using delay, but it’s in the LEDblink instruction anyway… not sure how to resolve that) … please feel free to show me the error of my ways.

Not sure if this is the correct format for posting code , so please forgive if it’s offensive:

 //Domination CUbe
 #define runEvery(t) for (static uint16_t _lasttime;\
                         (uint16_t)((uint16_t)millis() - _lasttime) >= (t);\
                         _lasttime += (t))
                        

int redledPin = 13; // pin for red LED
int blueledPin = 6; // pin for blue LED
int greenledPin = 9; // pin for green LED
int redbuttonPin = 8; // input pin for red pushbutton
int bluebuttonPin = 7; // input pin for blue pushbutton
int greenbuttonPin = 10; //input pin for green button
int redbuttonval = 0;     // variable for reading the red button pin status
int bluebuttonval = 0;     // variable for reading the blue button pin status
int greenbuttonval = 0;  // variable for reading the green button pin status
int redledPinVal = 0;  // variable for reading the green LED pin status
int blueledPinVal = 0;  // variable for reading the green LED pin status
int greenledPinVal = 0;  // variable for reading the green LED pin status

int gamecount;  //Count game time
int greencurrent; //Current state of green button
int greencount;  //How long the button was held (secs)
byte greenprevious = HIGH;
unsigned long greenfirstTime;   // how long since the button was first pressed

int redcurrent; //Current state of the button (LOW is pressed b/c i'm using the pullup resistors
int redcount;   // How long the button was held (secs)
int redcapcount;  //Count possession time
byte redprevious = HIGH;
unsigned long redfirstTime;   // how long since the button was first pressed

int bluecurrent; //Current state of the button (LOW is pressed b/c i'm using the pullup resistors
int bluecount;   // How long the button was held (secs)
int bluecapcount;  //Count possession time
byte blueprevious = HIGH;
unsigned long bluefirstTime;   // how long since the button was first pressed

int redledcurrent;  //Current state of red LED pin
int blueledcurrent;  //Current state of blue LED pin
int greenledcurrent;  //Current state of green LED pin

#include <StopWatch.h>
StopWatch redsw_secs(StopWatch::SECONDS);
StopWatch bluesw_secs(StopWatch::SECONDS);
StopWatch gamesw_secs(StopWatch::SECONDS);

#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

void setup() {
  pinMode(redledPin, OUTPUT);  // declare red LED as output
  pinMode(blueledPin, OUTPUT);  // declare blue LED as output
  pinMode(greenledPin, OUTPUT);    // declare green LED as output
  pinMode(redbuttonPin, INPUT);    // declare red pushbutton as input
  pinMode(bluebuttonPin, INPUT);    // declare blue pushbutton as input
  pinMode(greenbuttonPin, INPUT);    // declare blue pushbutton as input
  
  digitalWrite(greenledPin, HIGH);  //Turn on green LED

  lcd.begin(20, 4);// set up the LCD's number of columns and rows:
  lcd.print("   BlackOpsElite");// Print a message to the LCD.
  lcd.setCursor(0, 1);
  lcd.print("  DOMINATION CUBE");
  lcd.setCursor(0, 2);
  lcd.print("Push GREEN to start");


}

void loop() {
  redbuttonval = digitalRead(redbuttonPin);  // read red button input value
  bluebuttonval = digitalRead(bluebuttonPin);  // read blue button input value
  greenbuttonval = digitalRead(greenbuttonPin); // read green button value
  redledPinVal = digitalRead(redledPin);  // read red LED input value
  blueledPinVal = digitalRead(blueledPin);  // read red LED input value
  greenledPinVal = digitalRead(greenledPin);  // read red LED input value

  //read conditions for red button
  if (redbuttonval == LOW && redprevious == HIGH && millis() - redfirstTime > 200) {
    redfirstTime = millis();    // if the buttons is pressed, remember the time
  }

  if (redbuttonval == LOW && ((millis() - redfirstTime) % 1000) < 20 && millis() - redfirstTime > 500) {
    ledblink(1, 50, redledPin); // Each second the button is held, blink the indicator led and
    redcount++;        // add 1 to the counter
  }

  if (redbuttonval == HIGH && redprevious == LOW && redcount >= 3) { // When the button is released ,if the counter is past seconds specified, do the following:
    digitalWrite(redledPin, HIGH);  // turn red LED On
    digitalWrite(blueledPin, LOW);  // turn red LED Off
    digitalWrite(greenledPin, LOW);  // turn green LED OFF
  }

  if (redbuttonval == HIGH) { // reset the counter if the button is not pressed
    redcount = 0;
  }


  //read conditions for blue button
  if (bluebuttonval == LOW && blueprevious == HIGH && millis() - bluefirstTime > 200) {
    bluefirstTime = millis();    // if the buttons becomes press remember the time
  }
  if (bluebuttonval == LOW && ((millis() - bluefirstTime) % 1000) < 20 && millis() - bluefirstTime > 500) {
    ledblink(1, 50, blueledPin); // Each second the button is held blink the indicator led and
    bluecount++;        // and 1 to the counter
  }
  if (bluebuttonval == HIGH && blueprevious == LOW && bluecount >= 3) { // When the button is released, if the counter is past seconds specified, do the following:
    digitalWrite(redledPin, LOW);  // turn red LED Off
    digitalWrite(blueledPin, HIGH);  // turn blue LED On
    digitalWrite(greenledPin, LOW);  // turn green LED OFF
  }
  if (bluebuttonval == HIGH) { // reset the counter if the button is not pressed
    bluecount = 0;
  }


  {
    redprevious = redcurrent;
    blueprevious = bluecurrent;

  }


  runEvery(1000) { //print to LCD every second without using delay

    //If BLUE captures:
    if (redledPinVal == LOW && greenledPinVal == LOW && blueledPinVal == HIGH) {//&&greenbutton
      bluecapcount ++;
      redsw_secs.stop();
      bluesw_secs.start();

      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("   BlackOpsElite");
      lcd.setCursor(0, 1);
      lcd.print("  DOMINATION CUBE");
      lcd.setCursor(0, 2);
      lcd.print("RED TEAM:Stopped ");
      lcd.print(redsw_secs.elapsed());
      lcd.setCursor(0, 3);
      lcd.print("BLUE TEAM:  ");
      lcd.print(bluesw_secs.elapsed());

    }
  }

  // If RED captures
  if (redledPinVal == HIGH && greenledPinVal == LOW && blueledPinVal == LOW) {//&&greenbutton
    redcapcount ++;
    redsw_secs.start();
    bluesw_secs.stop();

    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("   BlackOpsElite");
    lcd.setCursor(0, 1);
    lcd.print("  DOMINATION CUBE");
    lcd.setCursor(0, 2);
    lcd.print("RED TEAM:  ");
    lcd.print(redsw_secs.elapsed());
    lcd.setCursor(0, 3);
    lcd.print("BLUE TEAM:Stopped ");
    lcd.print(bluesw_secs.elapsed());
  }


  runEvery(1000) {
    //END of GAME
    if (gamecount == 30) {
      digitalWrite(blueledPin, LOW);  // turn blue LED Off
      bluesw_secs.stop();
      redsw_secs.stop(); \
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("  End of Exercise");
      lcd.setCursor(0, 1);
      lcd.print("    Final Score");
      lcd.setCursor(0, 2);
      lcd.print("RED TEAM:  ");
      lcd.print(redsw_secs.elapsed());
      lcd.setCursor(0, 3);
      lcd.print("BLUE TEAM: ");
      lcd.print(bluesw_secs.elapsed());
    }


  }
}
void ledblink(int times, int lengthms, int pinnum) {
  for (int x = 0; x < times; x++) {
    digitalWrite(pinnum, HIGH);
     delay (lengthms);
    digitalWrite(pinnum, LOW);
     delay(lengthms);
  }
}

Hello Krazjoka and Welcome to the forum.

No your code is not offensive. It's been posted correctly I can see many improvements that can be made, (you're right I don't like the runEvery idea :) ) I'm sure we can work out something much slmpler to maintain. But there's quite a bit of code there to trawl through.

Often I find in cases like this, I can spend quite a bit of time working on solving the various issues, only to find that the original poster never returns. So before I go any deeper, I'd like some assurance that you're actually still paying attention :)

I'm here, in sponge mode.

I'd be happy to Paypal you a few bucks for your time, if that's sufficient assurance..

krazjoka: I'd be happy to Paypal you a few bucks for your time, if that's sufficient assurance..

haha, No need. But this is not going to be a quick fix. The issues I've noticed so far are:

you have a multitude of individually named inputs, that could be grouped into arrays, to make reading them much simpler.

Your code is very looooooong for what it actually achieves. So it can be condensed quite a bit

You're still using delays in your blinking routine. That can be fixed

The overall sketch lacks structure. It needs breaking down into manageable pieces that all do specific tasks.

I'll see if I can come up with a basic structure that will give you something more manageable to work on.

That's about what I expected.. I knew I was doing everything the really long way. Thanks a million, I'm eagerly awaiting your input.

May be of use to you, tricky to work in with your current structure, but a core of primitives for delays and button debounce which could be of use to you:

// Blink without "delay()" - multi!

const int led1Pin =  13;    // LED pin number
const int led2Pin =  10;
const int led3Pin =  11;
const int button1 =  4;
int led1State = LOW;        // initialise the LED
int led2State = LOW;
int led3State = LOW;
char bstate1 = 0;
unsigned long count1 = 0;   // will store last time LED was updated
unsigned long count2 = 0;
unsigned long count3 = 0;
unsigned long bcount1 = 0; // button debounce timer.  Replicate as necessary.

// Have we completed the specified interval since last confirmed event?
// "marker" chooses which counter to check 
boolean timeout(unsigned long *marker, unsigned long interval) {
  if (millis() - *marker >= interval) { 
    *marker += interval;    // move on ready for next interval
    return true;       
  } 
  else return false;
}

// Deal with a button read; true if button pressed and debounced is a new event
// Uses reading of button input, debounce store, state store and debounce interval.
boolean butndown(char button, unsigned long *marker, char *butnstate, unsigned long interval) {
  switch (*butnstate) {               // Odd states if was pressed, >= 2 if debounce in progress
  case 0: // Button up so far, 
    if (button == HIGH) return false; // Nothing happening!
    else { 
      *butnstate = 2;                 // record that is now pressed
      *marker = millis();             // note when was pressed
      return false;                   // and move on
    }

  case 1: // Button down so far, 
    if (button == LOW) return false; // Nothing happening!
    else { 
      *butnstate = 3;                 // record that is now released
      *marker = millis();             // note when was released
      return false;                   // and move on
    }

  case 2: // Button was up, now down.
    if (button == HIGH) {
      *butnstate = 0;                 // no, not debounced; revert the state
      return false;                   // False alarm!
    }
    else { 
      if (millis() - *marker >= interval) {
        *butnstate = 1;               // jackpot!  update the state
        return true;                  // because we have the desired event!
      }
      else 
        return false;                 // not done yet; just move on
    }

  case 3: // Button was down, now up.
    if (button == LOW) {
      *butnstate = 1;                 // no, not debounced; revert the state
      return false;                   // False alarm!
    }
    else { 
      if (millis() - *marker >= interval) {
        *butnstate = 0;               // Debounced; update the state
        return false;                 // but it is not the event we want
      }
      else 
        return false;                 // not done yet; just move on
    }
  default:                            // Error; recover anyway
    {  
      *butnstate = 0;
      return false;                   // Definitely false!
    }
  }
}

void setup() {
  pinMode(led1Pin, OUTPUT);      
  pinMode(led2Pin, OUTPUT);      
  pinMode(led3Pin, OUTPUT);      
  pinMode(button1, INPUT);      
  digitalWrite(button1,HIGH);        // internal pullup all versions
}

void loop() {
  // Toggle LED if button debounced
  if (butndown(digitalRead(button1), &bcount1, &bstate1, 10UL )) {
    if (led1State == LOW) {
      led1State = HIGH;
    }
    else {
      led1State = LOW; 
    } 
    digitalWrite(led1Pin, led1State);
  } 

  // Act if the latter time (ms) has now passed on this particular counter,
  if (timeout(&count2, 300UL )) {
    if (led2State == LOW) {
      led2State = HIGH;
    }
    else {
      led2State = LOW; 
    } 
    digitalWrite(led2Pin, led2State);
  } 

  if (timeout(&count3, 77UL )) {
    if (led3State == LOW) {
      led3State = HIGH;
    }
    else {
      led3State = LOW; 
    } 
    digitalWrite(led3Pin, led3State);
  } 
}

Still here :)

krazjoka:
Still here

So am I. Did you have a play with my code?

I did, sort of. Right after my last post, I realized I had a PM from Ken with a sketch for me. His code worked better for me in that it simplified what I was trying to do drastically by arraying most of the hardware and eliminating the delay in the blink section. I'm still having an issue with the display rapidly blinking instead of updating every second, which is strange because there appears to be a mechanism to deal with that. Here's the portion I'm referring to :

  //update Display if it's due
  if((t-lastReport)>1000)
  {
    lastReport=t;
    updateDisplay();
  }
}

void updateDisplay()
{
  lcd.clear();
...etc.

Any ideas?

Did you change the micros to millis like I told you to?