millis() related question on a 16x2 RGB LCD screen

I am working with a 16x2 RGB LED screen, and a wrote a simple program to print “Sup bro.” on the first line, then have a countdown starting at 15 that prints “BOOM!” on the second line when the countdown reaches 0. I found that when it switches to 9 from 10, the zero on the second space is left over. I used an if statement to clear the board then continue with the countdown anew to get rid of that zero.

My question is that for some reason when I trigger the reset at millis() = 6000 (when the countdown switches from 10 to 9) the screen won’t refresh like it should. The lowest number I can put in and have it work is 6005. Why does this happen? Is it just due to the speed of the ATMEGA?

Here is the code that I wrote:

#include <LiquidCrystal.h>
#include <Serial.h>

LiquidCrystal lcd(2, 3, 4, 5, 6, 7);
const int ON = HIGH;
const int OFF = LOW;
int redLed = 9;
int greenLed = 10;
int blueLed = 11;

//The usage of serial was my attempt to see what was going on with the code
  void setup(){
    int ledPins[] = {9,10,11};
    int i=0;
    for( i=0; i<=2; i++){
      pinMode(ledPins[i], OUTPUT);
    }
    
    digitalWrite(redLed, ON);
    digitalWrite(greenLed, OFF);
    digitalWrite(blueLed, ON);
    lcd.begin(16,2);
    lcd.print("Sup bro.");
    Serial.begin(9600);  //Pours a big bowl of serial.
}

void loop(){
  int start = 15;
  int iTime = millis()/1000;
  int countdown = (start - iTime);
  int limit = 15000;
  int error = 5000;
  int refresh = 6005; //Lowest possible number where the screen will clear successfully.

//Prints the countdown from 15 to 10. Added second limit to avoid printing negative numbers. 
    if((millis() < error) && (countdown > 0)){
      lcd.setCursor(0,0);
      lcd.print("Sup bro.");
      lcd.setCursor(0,1);
      lcd.print(countdown);
      Serial.print("1st   ");
      Serial.println(countdown);
  }
 
 //Prints the countdown from 9 to 0.  Second if statement fixes the residual 0 left from "10" on point (1,1).  
    if((millis() >= error) && (millis() < limit)){
      if(millis() == refresh){
        lcd.clear();
        Serial.print("Cleared Successfully");
      }
      lcd.setCursor(0,0);
      lcd.print("Sup bro.");
      lcd.setCursor(0,1);
      lcd.print(countdown);
      Serial.print("2nd   ");
      Serial.println(countdown);
  }

//Prints the finale.
  if((millis() >= limit) &&(millis() < limit + 100)){
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Sup bro.");
    lcd.setCursor(0,1);
    lcd.print("BOOM!");
    Serial.print("Done   ");
    Serial.println(countdown);
  } 
}

Another way to do it is to write a blank over the second digit if the number is less than 10:

      lcd.print(countdown);
      if (countdown < 10)
          lcd.print(" ");

Yeah, that worked beautifully thanks, I can't believe I didn't think of that haha.

But I was still wondering on a purely conceptual level, where the 5 ms delay came from. As you can see from this handy sidebar, I am a newbie, so I am trying to get my head wrapped around all the little Arduino intricacies.

I think it's just a matter of timing. If the output takes a millisecond or two there is no guarantee that the bit of code that compares the current millisecond to 6000 or 6005 will happen to be executed during that millisecond.

If you are looking to trigger something at a particular time it is best to check for >=time because the exact time may have passed. Of course it will then trigger every time AFTER the specified time so you need a flag somewhere to keep track of the triggering. That way you can trigger only once:

boolean flag = false;  // Global variable.  'boolean' can only be 0/false/LOW or 1/true/HIGH

if (!flag && millis() >= 6000)
    {
    flag = true;  // Event triggered!
    //  This stuff is done once at 6 seconds after the Arduino starts.
    }

Ohh, that helps a lot! Thanks!

  int iTime = millis()/1000;

The millis() function returns an unsigned long value, which can be up to 4,294,967,295. Even after dividing by 1000, the maximum possible value will be 4,294,967, which you will have a very hard time fitting in an int.

    int ledPins[] = {9,10,11};
    int i=0;
    for( i=0; i<=2; i++){
      pinMode(ledPins[i], OUTPUT);
    }

Why is this array local to setup()? It you are setting the pin mode to output, presumably you want to write to those pins in some other function.

Creating an array, declaring an (oversize) index variable, and using three lines (should be 4) of code for a for loop, to eliminate the need to copy/paste the pinMode() call three times hardly seems efficient. Especially since you are using names globally for the pins, and now have to change two places if you want to use another pin number for one of the LEDs.

      if(millis() == refresh){

Hitting an exact value when calling millis() is a miracle that should not be relied on.