Fun with Millis(): A Larson Scanner / KITT

In the previous Fun with Millis() you have learned how to blink several LEDs. In this example we will expand this Arduino example to a Larson Scanner like used in the '80s KITT.

A Larson Scanner / KITT Scanner

You could expand the Blink Without Sketch with several more LEDs. But let's see if we can do that smart.

First lets write down the requirements for our program

  • each LED should be on for a short period
  • if the period is over the active LED should be switched off an the next LED should be switched on
  • if the last LED was on, we switch the direction and count down
  • again each LED should be on for a short period
  • if the first LED is on, we change the direction and go up again

With just few code lines more we can program our Larson Scanner.

/*
  Fun with millis()

  A simple solution for a Larson Scanner
  KITT

*/

const int ledPin[] = {2, 3, 4, 5, 6, 7, 8}; // the number of the LED pins
byte ledState = 0;                          // ledState used to set active LED
char direction = 'U';                       // Up or Down
unsigned long previousMillis = 0;           // will store last time LED was updated
const long interval = 500;                  // interval at which to blink (milliseconds)
const size_t noOfLeds = sizeof(ledPin) / sizeof(ledPin[0]); // calculate the number of LEDs in the array

void setup() {
  for (size_t i = 0; i < noOfLeds; i++)
  {
    pinMode(ledPin[i], OUTPUT);
  }
}

void loop() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
    // if the LED A is on turn it off and vice-versa:
    
    digitalWrite(ledPin[ledState], LOW); 
    if (direction == 'U') {
      if (ledState < noOfLeds - 1) {
        ledState++;
      }
      else {
        ledState--;
        direction = 'D';
      }
    }
    else {      // this is an implicit direction == 'D' 
      if (ledState > 0) {
        ledState--;
      }
      else {
        ledState++;
        direction = 'U';
      }
    }
    digitalWrite(ledPin[ledState], HIGH); 
  }
}

Lets go through some code parts:

const int ledPin[] = {2, 3, 4, 5, 6, 7, 8}; // the number of the LED pins

We could declare the pins as ledAPin, ledBPin, ledCPin, ledDPin, ledEPin, ledFPin, ledGPin but for this sketch it is easier if we use an Array.

byte ledState = 0;                          // ledState used to set active LED

the ledState will hold the index of the active LED. Therefore it's of type byte now. We don't have an Arduino with more than 256 LEDs, so one byte is large enough.

char direction = 'U';                       // Up or Down

This variable stores if we are counting upwards or downwards.

const size_t noOfLeds = sizeof(ledPin) / sizeof(ledPin[0]); 

This line of code calculates the number of LEDs in the array. It uses the function sizeof() twice. Why is this necessary? The sizeof() will return the size of the array ledPin. But as we have defined it as an array of integers - it will have twice the size of elements, because an integer is two bytes large on an Arduino. Therefore we also retrieve the size of the first element sizeof(ledPin[0])  - which will be 2. Therefore 14 / 2 = 7. The variable will hold 7. You will see this line of code very often when you see code with arrays.

size_t is just the unsigned integer type of the result of sizeof(). If you use "sizeof()" - use size_t also.

Links

(*) Disclosure: Some of the links above are affiliate links, meaning, at no additional cost to you I will earn a (little) comission if you click through and make a purchase. I only recommend products I own myself and I'm convinced they are useful for other makers.

History

First upload: 2021-09-02 | Version: 2021-09-02