How to Serial print only once in a loop

I am trying to do a project whereby I am trying to maintain a fixed distance of an object for a fixed amount of time. This project makes use of the ultrasonic sensor, hence the use of a distance condition.

I want to print a Serial text only once under a if condition while continually printing the timer. Is there any way that a certain condition (e.g. for loop, if loop?) can be set up within the if condition to make it such that the serial text only print once? I know it will continue printing as the condition is met and that it is also within a while(1) loop, thus it will be constantly printed out.

Below is the void function which will be called into the main " void loop()".
The text that I want to print only once are --> Serial.println("Maintain Posture"); , Serial.println("Time:"); , Serial.println("Adjust Position"); and Serial.println("Timer Paused");.

void CountDownPlank()
{

 while(1)
 {
  digitalWrite(trigPin, LOW); // send out an ultra sonic sound for 5 microseconds and measure the time it took for the sound to go from the trigpin to the echo pin
  delayMicroseconds(5);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  unsigned long signalDurationPlank = pulseIn(echoPin, HIGH, 6000);  // Timeout good for 100 cm.
  int plankDist = signalDurationPlank / MicrosecondsPerRoundTripCM; //convert the time the signal took to travel to distance in cm
  
   if (plankDist >= 10 && plankDist <= 40)
  {
    resume();
    Serial.println("Maintain Posture");
    Serial.println("Time:");
    timerBT();                            //void timerBT() displays the time here
    
    lcd.setCursor(0, 0);
    lcd.print("Maintain Posture");
    lcd.setCursor(0, 1);
    lcd.print("Time:");
    timerLCD();                           //void timerLCD() displays the time here
    lcd.setCursor(11, 1);
    lcd.write(3);
  }
  else  // if outside of the above stated range of 10cm to 40cm, timer pauses as posture is improper
  {
    pause();
    Serial.println("Adjust Position");
    Serial.println("Timer Paused");
    lcd.setCursor(0, 0);
    lcd.print("Adjust Position");
    lcd.setCursor(0, 1);
    lcd.print("Timer Paused");
    lcd.setCursor(15, 0);
    lcd.write(2);
  }
}
}

Here is the display of the serial monitor. As you can see, the texts are constantly printed out.
COM3 2021-06-02 16-11-09

A good way to achieve printing under certain conditions is to declare a Variable like e.g. "printed" and initialize it with 0. Once you printed what you wanted you set the variable to 1 and you can only print if the condition is "printed == 0". After the whole process is done you reset the variable to 0 again.

1 Like

Why not do that printing in setup()?

Hi, it is because it has to happen in the condition whereby my distance is more than 10 and lesser than 40.

okay thank you, i'll try to work on it

Then use a boolean flag like oncePrintFlag = true, in setup.
Before doing the printing, check the flag. After one printing is done, set the flag to false.

1 Like
  static bool postureWasGood = false;
  bool postureIsGood = plankDist >= 10 && plankDist <= 40;

  if (postureIsGood != postureWasGood)
  {
    // Posture changed
    postureWasGood = postureIsGood;
    if (postureIsGood)
    {
      // Posture just changed from bad to good
      resume();
      Serial.println("Maintain Posture");
      Serial.println("Time:");
      timerBT();
    }
    else
   {
    // Posture just changed from good to bad
    pause();
    Serial.println("Adjust Position");
    Serial.println("Timer Paused");
    }
  }
1 Like

Thank you for your suggestion Mr Railroader! I will test it out :slight_smile:

Hi there Mr Johnwasser, thank you for always helping me with these codes! I will try them out :relaxed:

Hi there Mr Johnwasser, sorry for getting back to you this late. However, is there a way to solve the issue of the timer spamming as well? I have figured out a code to only print the texts once under "void CountDownPlank()" , but I still cannot seem to solve the issue of the timer spamming as seen from the GIF posted above.

void pause()                                                            //to pause timer when improper posture is met
{
  if (TimerRunning)
  {
    TimeRemaining = TimeRemaining - (millis() - TimeStarted);           //to calculate the time that was paused at
    TimerRunning = false;
  }
}

void resume1()                                                          //to resume timer from when it was paused
{
  if (!TimerRunning)
  {
    TimeStarted = millis();                                             //to assign to timerCD function to allow calculation of time that waas last paused
    TimerRunning = true;
  }
}


int timerCD()                                                           //main function to determine the calculation of timer and display the time
{
  unsigned long currentTime = millis();                                 //assigns variable to millis() which stores the time it starts when it is activated
  long displayTime;

  if (TimerRunning)                                                     //if timer is still running, continue on with the code
  {
    unsigned long elapsedTime = currentTime - TimeStarted;              //variable assigned to keep track of time that has passed
    if (elapsedTime < TimeRemaining)                                    //if time that passed has not exceeded the initial time set, continue with the code
    {
      displayTime = TimeRemaining - elapsedTime;                        //calculation of the count down timer. Every second elapsed time increases, display time decreases.
    }
    else
    {
      displayTime = 0;                                                  //if time that has passed exceeded the initial time, it means that timer has ran out
    }
  }
  else                                                                  //if timer is not running, continue with code
  {                                                         
    displayTime = TimeRemaining;                                        // Timer is paused.  Show the remaining time 
  }

  byte countdown_minute = ((displayTime / 1000) / 60) % 60;             //To convert from miliseconds to seconds
  byte countdown_sec = (displayTime / 1000) % 60;                       //To convert from miliseconds to seconds

  lcd.setCursor(6, 1);
  if (countdown_minute < 10)                                            //to ensure proper display of numbers once tenth digit becomes single digit
  {
    Serial.print('0');
    lcd.print('0');
  }
  Serial.print(countdown_minute);
  lcd.print(countdown_minute);
  Serial.print(":");
  lcd.print(":");
  if (countdown_sec < 10)                                               //to ensure proper display of numbers once tenth digit becomes single digit
  {
    Serial.print('0');
    lcd.print('0');
  }
  Serial.println(countdown_sec);
  lcd.print(countdown_sec);
  
  
  if (displayTime == 0)                                                // Time has expired
  {
    pause();
    TimeRemaining = 0;                                                 //To ensure that timer does not restart
    CDTimerEnd = 1;                                                    //Flag state to show that timer has expired
    digitalWrite(GREEN, LOW);

    if (RingOnce == false)                                             //Ensure that buzzer only ring once everytime time has expired since it is in a continuous loop
    {
      digitalWrite(GREEN, LOW);
      RingOnce = true;
      tone(buzzer, 1000);
      digitalWrite(RED, HIGH);
      delay(200);
      noTone(buzzer);     // Stop sound...
      digitalWrite(RED, LOW);
      delay(100);
      tone(buzzer, 1000);
      digitalWrite(RED, HIGH);
      delay(200);
      noTone(buzzer);     // Stop sound...
      digitalWrite(RED, LOW);
      delay(100);
    }
    return CDTimerEnd;                                                //Value to return to CountDownPlank function
  }
  return 0;                                                           //to allow function to continue processing, else code will stall as it does not know what values to return
}


void CountDownPlank()                                                
{
  int CDTimerEndState = 0;                                            //variable to allow return value to be assigned

  while (1)
  {
    digitalWrite(trigPin, LOW);                                       // send out an ultra sonic sound for 5 microseconds and measure the time it took for the sound to go from the trigpin to the echo pin
    delayMicroseconds(5);
    digitalWrite(trigPin, HIGH);
    delayMicroseconds(10);
    digitalWrite(trigPin, LOW);
    unsigned long signalDurationPlank = pulseIn(echoPin, HIGH, 6000); 
    int plankDist = signalDurationPlank / MicrosecondsPerRoundTripCM; //convert the time the signal took to travel to distance in cm

    if (plankDist >= 10 && plankDist <= 40)                           //proper position has been met
    {
      resume1();                                                      //resume function will be called here
      PrintOnceCD2 = false;                                           
      
      if (PrintOnceCD1 == false)                                      //to ensure that display texts will only print once every positional change
      {
       PrintOnceCD1 = true;
       Serial.println("Time:");
      }
      
      lcd.setCursor(0, 0);
      lcd.print("Maintain Posture");
      lcd.setCursor(0, 1);
      lcd.print("Time:");
      lcd.setCursor(11, 1);
      lcd.write(3);
      CDTimerEndState = timerCD();                                    //void timerCD() displays the time here
      digitalWrite(YELLOW, LOW);
      digitalWrite(GREEN, HIGH);
      
    }
    else                                                              // if outside of the above stated range of 10cm to 40cm, timer pauses as posture is improper
    {
      pause();
      PrintOnceCD1 = false;

      if(PrintOnceCD2 == false)                                       //to ensure that display texts will only print once every positional change
      {
       PrintOnceCD2 = true;
       Serial.println("Adjust Position");
       Serial.println("Timer Paused");
      }
      
      lcd.setCursor(0, 0);
      lcd.print("Adjust Position");
      lcd.setCursor(0, 1);
      lcd.print("Timer Paused");
      lcd.setCursor(15, 0);
      lcd.print(" ");

      delay(1000);
      lcd.setCursor(0, 1);
      lcd.print("Time:");
      CDTimerEndState = timerCD();
      lcd.setCursor(11,1);
      lcd.write(2);
      digitalWrite(YELLOW, HIGH);
      digitalWrite(GREEN, LOW);
      delay(1000);
    }
    
      if(CDTimerEndState == 1)                                       //returned value is sent here
        {
          TimeRemaining = MINUTE;                                    //reset timer value to original
          RingOnce = false;
          PrintOnceCD1 = false;
          PrintOnceCD2 = false;
          break;                                                    //To end off count down planking exercise
        }
  }
}

It looks like you took out the state change detection from Reply #7 above. That is what stops the timer from spamming Serial.