Search code examples
cloopsarduinodelayled

Replace delay() with millis inside a for loop Arduino


In my code I want to replace the effect of delay() with millis or any other method that allows the use of button inputs while the code still runs. I am making an obstacle-type game where the player has to dodge incoming LEDs.

int LEDrows[4][4] = {{9, 8, 7, 6}, {5, 4, 3, 2}};
int Button = 1;
int ButtonCheck = 0;
int playerPosition = 0;

void setup()
{
  pinMode(Button, INPUT);
  for(int p=0; p>=1; p++){
    for(int b=0; b>=3; b++){
      pinMode(LEDrows[p][b], OUTPUT);
    }
  }
}

void loop()
{
  ButtonCheck = digitalRead(Button);
  if(ButtonCheck != 0){
    playerPosition += 1;
    
    if (playerPosition == 1){
      digitalWrite(LEDrows[0][3], HIGH);
      digitalWrite(LEDrows[1][3], LOW);
    }
    if (playerPosition > 1){
      playerPosition = 0;
      digitalWrite(LEDrows[1][3], HIGH);
      digitalWrite(LEDrows[0][3], LOW);
    }
  }
  
  int i = random(0, 2);
  for (int j = 0; j <= 3; j++) {
    digitalWrite(LEDrows[i][j], HIGH);
    delay(250);
    digitalWrite(LEDrows[i][j], LOW);
    delay(250);
  }
  delay(500);
}

I have two rows of 4 LEDS, stored in a nested list which i am iterating through. The LEDs will light up in a random row. I want to make the LED light up, wait 250ms, then make it disappear again, and wait 250ms. If this delay()-like effect can be achieved without using the delay function, then i would be pleased to learn how to do so.


Solution

  • Use static variables to retain state and timestamps of the events you want to be periodic. For example, the following will set an LED in a random column on row zero, and every 250ms will move it to the next row until after reaching row 3, it will restart at a new random column.

      static int j = 0 ;
      static int i = 0 ;
      
      // When j == 0, set initial LED
      if( j == 0 )
      {
          i = random(0, 2);
          digitalWrite(LEDrows[i][j], HIGH ) ;
      }
      
         
      // Get current millisecond tick
      unsigned long now = millis() ;
    
      // Every 250ms move the LED     
      static unsigned long led_timestamp = millis() ;
      if( now - led_timestamp > 250 )
      {
          led_timestamp = now ;
    
          digitalWrite(LEDrows[i][j], LOW ) ;
          j++ ;
          if( j > 3 )
          {
              j = 0 ;
          }
          else
          {
              digitalWrite(LEDrows[i][j], HIGH ) ;
          }
      }
    

    The general pattern is:

    static unsigned long timestamp = millis() ;
    unsigned long now = millis() ;
    
    if( now - timestamp > PERIOD_MS )
    {
        timestamp = now ;
    
        // do something every PERIOD_MS here
        ...
    }
    

    With multiple timestamp variables you can perform tasks at various independent intervals.