Lighthouses

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.

//
//  www.blinkenlight.net
//
//  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
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//  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 http://www.gnu.org/licenses/

#include <MsTimer2.h>

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

template <uint8_t led, uint16_t d1, uint16_t d2, uint16_t d3, uint16_t d4, 
                       uint16_t d5, uint16_t d6, uint16_t d7, uint16_t d8>
void light_my_fire() {  
    static uint16_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:
                                                    LOW);                                                   
} 

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);
    MsTimer2::start();
}

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: www.leuchtturm-atlas.de/.

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

Leave a Reply

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

WordPress.com Logo

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

Twitter picture

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

Facebook photo

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

Google+ photo

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

Connecting to %s