This experiment was inspired by a question in the Arduino forum where member twoll065 wanted to create a nautic card with lighthouses that blink with their proper timings.

The implementation combines ideas of the Knight Rider and the Persistence of Vision experiments.

Lets have a look at the code first.

//  Copyright 2013 Udo Klein
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  GNU General Public License for more details.
//  You should have received a copy of the GNU General Public License
//  along with this program. If not, see

#include <MsTimer2.h>

uint8_t setOutput(uint8_t pin) {
    pinMode(pin, OUTPUT);
    return 0;

template <uint8_t led, uint32_t d1, uint32_t d2, uint32_t d3, uint32_t d4,
                       uint32_t d5, uint32_t d6, uint32_t d7, uint32_t d8>
void light_my_fire() {
    static uint32_t phase = setOutput(led);
    phase = phase < d1+d2+d3+d4+d5+d6+d7+d8-1? phase+1: 0;

    digitalWrite(led, phase < d1                  ? HIGH:
                      phase < d1+d2               ? LOW:
                      phase < d1+d2+d3            ? HIGH:
                      phase < d1+d2+d3+d4         ? LOW:
                      phase < d1+d2+d3+d4+d5      ? HIGH:
                      phase < d1+d2+d3+d4+d5+d6   ? LOW:
                      phase < d1+d2+d3+d4+d5+d6+d7? HIGH:

void blink() {
    light_my_fire< 0,  200, 2800,  200, 2800,  200, 5800,    0,    0>();  // Norderney
    light_my_fire< 4, 3000, 3000, 3000, 3000,    0, 8500,    0,    0>();  // Pilsum
    light_my_fire< 8,  700, 2300,  700, 2300,  700, 2300,  700, 5300>();  // Campen
    light_my_fire<12, 6000, 6000,    0,    0,    0,    0,    0,    0>();  // Schillig
    light_my_fire<16, 6000, 3000,    0,    0,    0,    0,    0,    0>();  // Voslap
    light_my_fire<19, 6000, 1000,    0,    0,    0,    0,    0,    0>();  // Tossens

void setup() {
    MsTimer2::set(1, blink);

void loop() {}

Although this code looks imperative in style it is actually an object oriented design. The logical design is that each lighthouse is represented by an object. Each lighthouse object has only one private member: the phase.

The idea is to use the msTimer2 library to call each lighthouse object once per millisecond. The lighthouse object will then increment the phase by one. After this it will match the phase against its blink pattern and decide if the light is on or off.

If you look at the implementation you will not notice any C++ / OO classes. Instead I used templates. The point is that each set of parameters will give rise to a new instance of the templated code. With other words: I let the compiler create the instances at compile time instead of run time. This uses up more flash memory but consumes less RAM. Another nice feature of this approach is that the sums “d1+d2+…” will be computed at compile time.

Finally notice the declaration.

static uint16_t phase = setOutput(led);

The setOutput(led) function is just a wrapper to the pinMode statement. Since statics will be initialized only once this is the object constructor / initializer of the lighthouse. This way the initialization of the lighthouse is tightly linked to its execution and not in some other place which must be called from the setup method.

I think the result is pretty cool as you can now just enter the desired pin and blink patterns into the template calls. Thus I have no redundant pin declarations or nested arrays or other technical clutter that distracts to much from the desired blink patterns.

Now all you need to create your own lighthouse simulator is to find a list of the lighthouse patterns. I can recommend the following sources: The Lighthouse Directory
and especially for the Germany readers:

Have a look at the video to see the lighthouse patterns running on a Blinkenlighty.


5 Responses to Lighthouses

  1. Roman U. says:

    Ich checke das leider nicht 😦
    Ich bin leider kein Code-Experte… deswegen wahrscheinlich nicht…

    Ich will… fürs erste 5 LED’s gleichzeitig in unterschiedlichen Abständen blinken lassen.
    250ms AN
    50ms AUS
    50ms AN
    50ms AUS
    50ms AN
    250ms AUS

    und wieder von vorn bis es mir reicht… (taster für stop)

    wie zum geier kann ich das damit machen???
    bitte helft mir.

    LED’s an D5, D6, D7, D8, D9

    Board ist ein Arduino Nano V3

    • Roman says:

      Ok… got it to work with my blink pattern…

      next problem is: i have more than one blink pattern can be chosen by pressing a button (no. of pattern shows on a 7segment), then press start and the pattern runs.

      but i only can call the MsTimer2 out of the setup void… is there a way to call or start it from anywhere???

      • This is a generic question of general interest which is not really related to my blinking stuff. Please post it in the Arduino Forum. BTW: your statement that you can call MsTimer2 only in setup is definitely wrong. You can of course call it from anywhere. Please shift the discussion to the Arduino Forum though as this is MsTimer2 related.

  2. Tom says:

    I have figured out how to add more lighthouses(very simple). How many is too many? could i have 54? one for every pin on Mega board?Or would this cause issues?

    • Let’s do some math. The interrupt is triggered every 1 ms. The Arduino is running at 16 MHz. That is we have 16 000 cycles per interrupt. If you would add 100 lighthouses this would imply 160 cycles per lighthouse. Each lighthouse takes 8 comparisons and some time for digital write. This can be easily done in 160 cycles. This would be OK. If you add 1000 lighthouses this would imply 16 cycles per lighthouse. This would require a different algorithm (or switching to 1 interrupt every 10 ms). With 54 you definitely have plenty of headroom.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.