Running and monitoring two instances of a countdown timer at the same time in a arduino uno

Hello everyone, I have a question. I have this simple code. It is just a countdown from 122 to 0, when a sensor is activated.
My question is, is it possible to run this code but with a different sensor signal, that starts a different countdown but in the same program and in the same Arduino, so I could see both countdowns on the serial monitor working at the same time ?

const int Sensor1 = 4;
const int LED = 3;
int Estadosensor = 0;
int contador1 = 122 ;
int Sensoractivado = 0;

void  setup()
{
  Serial.begin(9600);
  pinMode(Sensor1, INPUT);
  pinMode(LED, OUTPUT);
   Serial.println("122 a 0");
}

void  loop()
{
  Estadosensor = digitalRead(Sensor1);
  if (Estadosensor == HIGH ) 
  { 
     Sensoractivado = 1;
     if(Sensoractivado == 1 && contador1 != 0)
     {

    contador1--;
      Serial.println(contador1);
      delay (1000);
      
}
*`strong text`*

Sure, just start the millis timer, set two different flags of the time intervals you want, print out the countdown timer and just tab the output of one timer relative to the other.

  • Please explain this more.


Something like this, countdown 1 is what the code shows. My question is, if there is a way to show 2 or more, working independent of each one, but where all are shown in the same serial monitoring.

  • If these are separate counter variables, you can do as requested.

  • You can use a tab character \t

Here's an example of what I mean. I included noted in the comments.
This should give you a general idea. Note I didn't use tab after all, you could just space it out and call for a Serial.println(); every once in a while as needed.
Note, this is coded in the brutal style but I think gives you somewhere to start. I'm just an amateur hobbyist but maybe it will help get you going in the direction you're looking for. This requires no hardware, set baud to 115200 (or change baud rate) and is not a rewrite of your code, just an example how I would begin approaching this part of a complete project.
I used switch/case stuff in there

  • a) because I had a similar sketch already open that had it already
  • b) because I use them in virtually everything because of the possibilities it allows. There's a note in the sketch comments about why I like them
byte s1level;
byte s2level;
unsigned long s1currentTime;
unsigned long s2currentTime;
unsigned long s1lastTimeAround;
unsigned long s2lastTimeAround;
unsigned long s1Counter;
unsigned long s2Counter;
unsigned long thisS1Counter = 0;
unsigned long thisS2Counter = 0;

void setup() {
  Serial.begin(115200);
  s1level = 0;
  s2level = 0;
  s1currentTime = 0;
  s2currentTime = 0;
  s1lastTimeAround = 0;
  s2lastTimeAround = 0;
  s1Counter = 200;
  s2Counter = 100;
}

void loop() {
  // start free running timers, like starting a stopwatch.
  s1currentTime = millis();
  s2currentTime = millis();
  // the first if below is the wrapper for your first sensorState
  // for this example, I just set a condition is to check time every 2 seconds
  // maybe you use a sensorState in place of this if condition
  if (s1currentTime - s1lastTimeAround > 2000) {
    // these switch/cases aren't needed, but do offer more options
    // like modes in a video game say single or multiplayer (case 0 and 1)
    switch (s1level) {
      case 0:
        modeZero();
        s1Counter -= 10;
        break;
      case 1:
        modeOne();
        s1Counter -= 10;
        break;
    }
    s1lastTimeAround = s1currentTime;
  }
  // this would be the wrapper for your second sensorState
  // why not use the same arbitrary two seconds in this general example?
  if (s2currentTime - s2lastTimeAround > 2000) {
    switch (s2level) {
      case 0:
        modeTwo();
        s2Counter -= 10;
        break;
      case 1:
        modeThree();
        s2Counter -= 10;
        break;
    }
    s2lastTimeAround = s2currentTime;
  }
}

void modeZero() {
  Serial.print(" Sensor 1: ");
  thisS1Counter = (s1currentTime - s1lastTimeAround + s1Counter);
  Serial.print(thisS1Counter);
  s1level += 1;
}
void modeOne() {
  // you could do other stuff in here before resetting
  s1level = 0;
}

void modeTwo() {
  thisS2Counter = (s2currentTime - s2lastTimeAround + s2Counter);
  Serial.print(" Sensor 2: ");
  Serial.print(thisS2Counter);
  s2level += 1;
}

void modeThree() {
// again maybe do other things, or don't
  Serial.println();
  s2level = 0;
}

Would something like this work?

When you need a sensor doing multitask on the same time, it is about how you use millis().
Millis is what you use to skip some part of your program when at certain milliseconds is reached to execute your program. If the time you set is not reached, the program will skip the execution and continue with next lines of your program.
For now, you probably cannot see what is difference with delay(); and seeing the projects on youtube gonna help.

If you kept the two countdowns synchronized, it could work using delays... sure.

For your own progress and use.... non-blocking timed code will solve a lot of future questions and enable sketches to do many things at the same time down to 10's of microseconds intervals.

Beginner level intro on do many things at once. It can be read through in an hour or less and save a long time over finding out by yourself!

Learning that first counts as Planning Saves Time Debugging.

Hello gaston77

Welcome to the world's best Arduino forum ever.

Take a view to this example to gain the knowledge:

//https://forum.arduino.cc/t/running-and-monitoring-two-instances-of-a-countdown-timer-at-the-same-time-in-a-arduino-uno/1255529
#define ProjectName "Running and monitoring two instances of a countdown timer at the same time in a arduino uno"
#define NotesOnRelease "Arduino MEGA tested"
// -- some useful text replacements used because I'm lazy with typing --
#define view(x) Serial.print(x)
#define viewLn(x) Serial.println(x)
#define is ==

// make names
enum TimerEvent {NotExpired, Expired};
enum TimerControl {Halt, Run};
enum ButtonStates {Released, Pressed};
enum ButtonNames {ButtonOne, ButtonTwo, NoButton};

// make variables
uint32_t currentMillis = millis();
constexpr uint8_t ButtonPins[] {A0, A1}; // [pin] --- [button] --- [gnd] 
constexpr uint16_t CountDownValue {122};

// make structures
//-----------------------------------------
struct TIMER
{
  uint32_t interval;
  uint8_t control;
  uint32_t now;
  void make (uint32_t interval_)
  {
    interval = interval_;
  }
  void launch(uint32_t currentMillis)
  {
    control = Run;
    now = currentMillis;
  }
  void halt()
  {
    control = Halt;
  }
  uint8_t expired(uint32_t currentMillis)
  {
    uint8_t timerEvent = currentMillis - now >= interval and control;
    if (timerEvent == Expired) now = currentMillis;
    return timerEvent;
  }
};
//-----------------------------------------
struct BUTTON
{
  uint8_t name;
  uint8_t pin;
  uint8_t stateOld;
  TIMER   debounce;
  void make()
  {
    pinMode(pin, INPUT_PULLUP);
    stateOld = digitalRead(pin) ? LOW : HIGH;
    debounce.interval = 20;
    debounce.control = Run;
    debounce.now = currentMillis;
  }
  uint8_t run()
  {
    uint8_t returnValue = NoButton;
    if (debounce.expired(currentMillis) == Expired)
    {
      uint8_t stateNew = digitalRead(pin) ? LOW : HIGH;
      if (stateOld != stateNew)
      {
        stateOld = stateNew;
        returnValue = name;
      }
    }
    return returnValue;
  }
};

//-----------------------------------------
// make objects
TIMER counterOne;
TIMER counterTwo;
BUTTON buttons[]
{
  {ButtonOne, ButtonPins[ButtonOne], LOW, 20, Run, 0},
  {ButtonTwo, ButtonPins[ButtonTwo], LOW, 20, Run, 0},
};

//-----------------------------------------
// make support
void heartBeat(const uint8_t LedPin, uint32_t currentMillis)
{
  static bool setUp = false;
  if (setUp == false) pinMode (LedPin, OUTPUT), setUp = true;
  digitalWrite(LedPin, (currentMillis / 500) % 2);
}
// make application
void setup()
{
  Serial.begin(115200);
  for (uint8_t n = 0; n < 32; n++) Serial.println("");
  Serial.print("Source: "), Serial.println(__FILE__);
  Serial.print(ProjectName), Serial.print(" - "), Serial.println(NotesOnRelease);

  // initialize timer
  counterOne.make(1000);
  counterTwo.make(1000);
  // initialize buttons
  for (auto &button : buttons) button.make();
  Serial.println("122 a 0");
  Serial.println("Press button to start");
}
void loop()
{
  currentMillis = millis();
  static uint16_t countOne = CountDownValue;
  static uint16_t countTwo = CountDownValue;
  heartBeat(LED_BUILTIN, currentMillis);

  if (counterOne.expired(currentMillis) is Expired)
  {
    if ((--countOne) == 0) counterOne.halt();
    view("counter 1 = "), view(countOne), view("\tcounter 2 = "), viewLn(countTwo);
  }
  if (counterTwo.expired(currentMillis) is Expired)
  {
    if ((--countTwo) == 0) counterTwo.halt();
    view("counter 1 = "), view(countOne), view("\tcounter 2 = "), viewLn(countTwo);
  }
  for (auto &button : buttons)
  {
    if (button.run() != NoButton)
    {
      switch (button.name)
      {
        case ButtonOne:
          if ( button.stateOld == Pressed )
          {
            counterOne.control = counterOne.control ? LOW : HIGH;
            if (counterOne.control == Run) counterOne.launch(currentMillis);
          }
          break;
        case ButtonTwo:
          if ( button.stateOld == Pressed )
          {
            counterTwo.control = counterTwo.control ? LOW : HIGH;
            if (counterTwo.control == Run) counterTwo.launch(currentMillis);
          }
          break;
      }
    }
  }
}

Have a nice day and enjoy coding in C++.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.