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 1980s 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; digitalWrite(ledPin[ledState], LOW); // switch off "old" LED if (direction == 'U') { if (ledState < noOfLeds - 1) { // we can increase ledState++; } else { ledState--; // we have to decrease direction = 'D'; // and turn direction } } else { // this is an implicit direction == 'D' if (ledState > 0) { // we can decrease ledState--; } else { ledState++; // we must increase direction = 'U'; // and turn direction } } 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.