Arduino: Chasing LEDs with millis()

A popular LED project is the “Larson Scanner.”  This scanner emulates the effect seen on KIT from Knight Rider and the Cylons in Battlestar Galactica.  The code is usually written using “delay()” which means you can’t combine it with anything else.  The following code could be put into a function, called periodically and allow your code to scan while doing other things.

One thing to note, a proper Larson Scanner has some persistence to the next and previous LEDs, this code does not.  Maybe that would be a good exercise for the reader?

Inspired from this Arduino Forum post.

The Code

// Simple macros to remember which direction to shift LEDs
#define UP true
#define DOWN false

// Will be used to track how long since last event "fired"
unsigned long previousMillis=0;

// Delay to determine when we see the next LED
unsigned long interval = 250;

// Array with Arduino pins containing LEDs in sequence
byte LEDpins[] = {

// Variable to track which LED to turn on, start at 000001
int LEDstate=0x01;

// State variable to know which direction to shift
boolean direction=UP;

void setup() {
  // Optional: Push Button to turn on all LEDs (to test)
  pinMode(12, INPUT_PULLUP);

  // Set Pins with LEDs to OUTPUT
  for (int x=0; x < 6; x++)
    pinMode(LEDpins[x], OUTPUT);

void loop() {
  // Set the pins of each LED during each iteration
  // You'll only see something change when "LEDpins" gets updated
  for (int x=0; x < 6; x++)
    digitalWrite(LEDpins[x], bitRead(LEDstate,x));

  // Test Funciton to turn on all LEDs with pushbutton
  if (digitalRead(12) == LOW)

  // Get current time and determine how long since last check
  unsigned long currentMillis = millis();
  if ((unsigned long)(currentMillis - previousMillis) >= interval) {
    // We've waited "interval" amount of time, so let's do some stuff!

    // "Reset" our clock
    previousMillis = currentMillis;

    if (direction==UP) {
      // Use "<<" to "bit-shift" everything to the left once
      LEDstate = LEDstate << 1;
      // 0x20 is the "last" LED, another shift makes the value 0x40
      if (LEDstate == 0x40) {
        // turn on the one before "0x20" and reverse direction
        LEDstate = 0x10;
        direction = DOWN;
    else {
      // use ">>" to "bit-shift" all bits in LEDstate once to the right
      LEDstate = LEDstate >> 1;
      // This means we ran out of bits!
      if (LEDstate == 0x00) {
        // set one ahead so no extra delay
        LEDstate = 0x02;
        direction = UP;

void turnOnAll() {
  // Simple code to turn on all LEDs, this "blocks"
  // so when code returns, the same LED in LEDstate will be "saved"
  while (digitalRead(12)==LOW) {
    for (int x=0; x< 6; x++)
      digitalWrite(LEDpins[x], HIGH);


A couple of notes in this code.


The defines give us which direction the counter is running.  I used the arbitrary names “UP” and “DOWN”, but could have used “LEFT” and “RIGHT.”

Array of Pins

To simplify addressing which pins are connected to LEDs (and in which order) an array is created with the order which the LEDs are connected.  If this is the only thing you’re doing in your project, you’ll probably have the pins in order like the example.  Using the array lets you use whatever pins are available.

LEDstate and Shifting

The “magic” in this code is the shifting done with LEDstate.  The HEX value 0x01 is the initial state.  With each iteration, the variable is shifted once to the left or right.  So this means it’ll be:

0000 0001
0000 0010
0000 0100
0000 1000
0001 0000
0010 0000
0001 0000
0000 1000
0000 0010
0000 0001

When the sequence goes one bit too far, the sequence resets with one bit “seeded.”


To test to make sure the LEDs are connected correctly, I included a function to turn on all the LEDs.

Long comments, URLs, and code tend to get flagged for spam moderation. No need to resubmit.

ALL comments submitted with fake or throw-away services are deleted, regardless of content.

Don't be a dweeb.

Leave a comment

11 thoughts on “Arduino: Chasing LEDs with millis()

  1. There’s a trap for young players that tinker with this once you hit 16 LEDs .

    I figured out the up direction change point is 0x10000 and that makes the next LED sate 0x4000 for the reverse sweep. Uploaded and it sweeps one direction and that’s it????

    Had me going for a bit till I worked out that 0x10000 exceeds the value for an int. Changing to an unsigned int we still have the problem by a value of + one (65536). The solution is to make the LED state a 32bit value like “int32_t LEDstate = 0x01;”…………….. KIT rides once again!

  2. Hey James,

    Thanks so much for this super helpful and clear guide! I’ve been directed to your site from google quite a lot recently and your website is a great resource for clear descriptions of arduino concepts.

    I’ve been playing with this sketch and been having some difficulties…

    Could you let me know how you might approach creating two ‘Larsen Scanner’ chases which have independent interval times? I’m a bit new to using arrays so I think I’m going wrong somewhere routing a second set of 8 pins in the for loop..

    I’m ultimately trying to use this method to create a circular light installation where a 16-way relay has 2 independent chases of 8 wired lights, which chase in and out of phase by adjusting with a potentiometer.

    If there is any way you could let me know how you might expand this for a second independent chase pattern that would be very much appreciated!

    Thanks a lot!

    • Sorry that’s beyond the scope of one-on-one help I can provide. I would suggest posting the question in a forum, like’s “Project Help” so more people can weigh in.

    • In all of the for() loops, you would need to change the references from 6 to the number of LEDs you have. Then you would need to match the value in line 52 to be the binary or hex for the number of LEDs + 1. (8 = 0x100 or 10 = 0x400, I think).

  3. There is a typo in your sample code.

    in the if (direction == UP) branch, you have a <<1 for LEDstate
    But you also have <>1 here otherwise the state never decreases.



  4. how i can make this work with neopixel
    my code down here is perfect result i want but i need replace delay() by millis()

    any clue ?

     #define NUM_LEDS1 10
     #define NUM_LEDS2 6
     #define DATA_PIN1 6
     #define DATA_PIN2 7
     CRGB leds1[NUM_LEDS1];
     CRGB leds2[NUM_LEDS2];
     void setup() { 
           FastLED.addLeds(leds1, NUM_LEDS1);
           FastLED.addLeds(leds2, NUM_LEDS2);
       int dot_delay1[ ] = { 100,200,300,400,500,600,700,800,900,1000 };
       int dot_delay2[ ] = { 100,200,300,400,500,600 };
          void loop() {
            for(int dot = 0; dot &lt; NUM_LEDS1; dot++)
           for(int dot = 0; dot &lt; NUM_LEDS2; dot++) 
                leds1[dot] = CRGB::Blue;
                leds2[dot] = CRGB::Blue;
                leds1[dot] = CRGB::Black;
                leds2[dot] = CRGB::Black;
                delay( dot_delay1[ dot ] );
    // this is where i need to put the second delay but i cant put more then 1 delay
    // need to refork my code with millis() function instead delay()