Sketch Lauflichter, Reklamelichter, Kirmesbeleuchtungen - Modellbahn-Digitaltechnik

Sketch Lauflichter, Reklamelichter, Kirmesbeleuchtungen

Für Kirmes, Reklamelichter, … werden immer wieder nette Ideen benötigt, um die Modellbahn bunt und abwechslungsreich zu beleuchten. Viele Sketche werden kombiniert oder erhalten Erweiterungen, die wir an dieser Stelle nicht dokumentieren. Ein paar Ideengeber finden sich nachstehend.

Knight-Rider 1

void setup() {
    for (uint8_t pin=0; pin<20; ++pin) {
        pinMode(pin, OUTPUT);
    }
}
 
uint8_t brightness(const int8_t led, const int8_t pos) {    
    switch (abs(led-pos)) {
        case 0:     return 32;
        case 1:     return 16;
        case 2:     return 6;
        case 3:     return 2;
        default:    return 1;
    }
}
 
void pulse_width_modulation(const uint8_t pos) {
    for(uint8_t times=0; times<10; ++times) {
        for (uint8_t pass=0; pass<32; ++pass) {
            for (int8_t led=0; led<20; ++led) {
                digitalWrite(led, (brightness(led, pos) > pass));
            }
        }
    }
}
 
void loop() {
    static uint8_t pos=0;
 
    while(pos<20) {
        pulse_width_modulation(pos);
        ++pos;
    }
 
    while(pos>0) {
        --pos;
        pulse_width_modulation(pos);
    }
}

Knight Rider 2

uint8_t ledpin(const int8_t led) {
   return led<14? led: led+(54-14);
}
 
void setup() {
    for (uint8_t led=0; led<20; ++led) {
        pinMode(ledpin(led), OUTPUT);
    }
}
 
uint8_t brightness(const int8_t led, const int8_t pos) {    
    switch (abs(led-pos)) {
        case 0:     return 32;
        case 1:     return 16;
        case 2:     return 6;
        case 3:     return 2;
        default:    return 1;
    }
}
 
void pulse_width_modulation(const uint8_t pos) {
    for(uint8_t times=0; times<10; ++times) {
        for (uint8_t pass=0; pass<32; ++pass) {
            for (int8_t led=0; led<20; ++led) {
                digitalWrite(ledpin(led), (brightness(led, pos) > pass));
                 
            }
        }
    }
}
 
void loop() {
    static uint8_t pos=0;
 
    while(pos<20) {
        pulse_width_modulation(pos);
        ++pos;
    }
 
    while(pos>0) {
        --pos;
        pulse_width_modulation(pos);
    }
}

3fach Lauflicht

const uint8_t step_delay = 500;
const uint8_t phases     = 8;
const uint8_t led_count  = 20;
const uint8_t sync_input_pin = led_count - 1;
 
 
void display_phase(uint8_t phase) {
 
    for (uint8_t pin=0; pin< led_count; ++pin) {
        if ((pin+phase) % phases == sync_input_pin % phases) {
            digitalWrite(pin, HIGH);
            pinMode(pin, OUTPUT);
        } else {
            if (pin > 1) { // pins 0 and 1 are pulled by the 1k resistors from the FTDI chip
                pinMode(pin, INPUT);
            }
            digitalWrite(pin, LOW);
        }
    }
}
 
void soft_delay(uint32_t ms) {
    uint32_t start_time = millis();
    while (millis()-start_time < ms && !digitalRead(sync_input_pin)) {};
}
 
 
void setup() {
}
 
void loop() {
    display_phase(0);
    delay(step_delay);
    display_phase(1);
    delay(step_delay);
 
    for (uint8_t phase = 2; phase < phases; ++phase) {
        display_phase(phase);
        soft_delay(step_delay);
    }
}

Mehrere Effekte über EEProm

#include <EEPROM.h>
 
uint8_t get_next_count(const uint8_t count_limit) {
    // n cells to use --> 1/n wear per cll --> n times the life time
    const uint16_t cells_to_use = 128;
 
    // default cell to change
    uint8_t change_this_cell  = 0;
    // value of the default cell
    uint8_t change_value = EEPROM.read(change_this_cell);
 
    // will be used to aggregate the count_limit
    // must be able to hold values up to cells_to_use*255 + 1
    uint32_t count = change_value;
 
    for (uint16_t cell = 1; cell < cells_to_use; ++cell) {
        uint8_t value = EEPROM.read(cell);
 
        // determine current count by cummulating all cells
        count += value;
 
        if (value != change_value ) {
            // at the same time find at least one cell that differs
            change_this_cell = cell;
        }
    }
 
    // Either a cell differs from cell 0 --> change it
    // Otherwise no cell differs from cell 0 --> change cell 0
 
    // Since a cell might initially hold a value of -1 the % operator must be applied twice
    EEPROM.write(change_this_cell, (EEPROM.read(change_this_cell) % count_limit + 1) % count_limit);
 
    // return the new count
    return (count + 1) % count_limit;
}
 
uint8_t brightness_pattern_1(const int8_t led, const int8_t pos) {
    switch (abs(led-pos)) {
        case 0:     return 32;
        case 1:     return 16;
        case 2:     return 6;
        case 3:     return 2;
        default:    return 1;
    }
}
uint8_t brightness_pattern_2(const int8_t led, const int8_t pos) {
    switch (min(abs(led-pos),abs(19-led-pos))) {
        case 0:     return 32;
        case 1:     return 16;
        case 2:     return 6;
        case 3:     return 2;
        default:    return 1;
    }
}
 
uint8_t brightness_pattern_3(const int8_t led, const int8_t pos) {
    int8_t tmp = pos - abs(2*led-19)+2;
    return (tmp>0? tmp+tmp>>1: 0);
}
 
 
typedef uint8_t (*brightness_pattern)(const int8_t, const int8_t);
 
brightness_pattern pattern[] = {  brightness_pattern_1,
                                  brightness_pattern_2,
                                  brightness_pattern_3 };
 
brightness_pattern brightness;
 
void setup() {
    for (uint8_t pin=0; pin<20; ++pin) {
        pinMode(pin, OUTPUT);   
    }
 
    brightness = pattern[get_next_count(sizeof(pattern)/sizeof(pattern[0]))];
}
 
void pulse_width_modulation(const uint8_t pos) {
    for(uint8_t times=0; times<10; ++times) {
        for (uint8_t pass=0; pass<32; ++pass) {
            for (int8_t led=0; led<20; ++led) {
                digitalWrite(led, (brightness(led, pos) > pass));
            }
        }
    }
}
 
void loop() {
    static uint8_t pos=0;
 
    while(pos<20) {
        pulse_width_modulation(pos);
        ++pos;
    }
 
    while(pos>0) {
        --pos;
        pulse_width_modulation(pos);
    }
}

Herzschlag

#include <MsTimer2.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
 
const uint8_t step_delay = 20;
 
const uint8_t ports = 3;
const uint8_t brightness_levels = 32;
 
 
#define brightness_by_phase(phase) \
    (phase==0?  1: \
     phase==1?  2: \
     phase==2?  3: \
     phase==3?  4: \
     phase==4?  6: \
     phase==5?  8: \
     phase==6? 12: \
     phase==7? 16: \
     phase==8? 24: \
               31)
 
#define LEDIndex(LED) (LED>9?LED-10: 9-LED)
 
#define brightness(LED, phase) (LEDIndex(LED)<=phase? brightness_by_phase(phase): 0)
 
// cycle will loop from 0 to brightness_level
#define LEDstate(LED, phase, cycle) (cycle>=brightness(LED, phase)? 0: 1)
 
#define PortstateC(phase, cycle) (    \
    (LEDstate(14, phase, cycle)   ) + \
    (LEDstate(15, phase, cycle)<<1) + \
    (LEDstate(16, phase, cycle)<<2) + \
    (LEDstate(17, phase, cycle)<<3) + \
    (LEDstate(18, phase, cycle)<<4) + \
    (LEDstate(19, phase, cycle)<<5) )
 
#define PortstateB(phase, cycle) (    \
    (LEDstate( 8, phase, cycle)   ) + \
    (LEDstate( 9, phase, cycle)<<1) + \
    (LEDstate(10, phase, cycle)<<2) + \
    (LEDstate(11, phase, cycle)<<3) + \
    (LEDstate(12, phase, cycle)<<4) + \
    (LEDstate(13, phase, cycle)<<5) )
 
#define PortstateD(phase, cycle) (    \
    (LEDstate( 0, phase, cycle)   ) + \
    (LEDstate( 1, phase, cycle)<<1) + \
    (LEDstate( 2, phase, cycle)<<2) + \
    (LEDstate( 3, phase, cycle)<<3) + \
    (LEDstate( 4, phase, cycle)<<4) + \
    (LEDstate( 5, phase, cycle)<<5) + \
    (LEDstate( 6, phase, cycle)<<6) + \
    (LEDstate( 7, phase, cycle)<<7) )
 
#define Ports(phase, cycle) PortstateC(phase, cycle), PortstateB(phase, cycle), PortstateD(phase, cycle)
#define pwm(phase) \
    Ports(phase,  0), Ports(phase,  1), Ports(phase,  2), Ports(phase,  3), \
    Ports(phase,  4), Ports(phase,  5), Ports(phase,  6), Ports(phase,  7), \
    Ports(phase,  8), Ports(phase,  9), Ports(phase, 10), Ports(phase, 11), \
    Ports(phase, 12), Ports(phase, 13), Ports(phase, 14), Ports(phase, 15), \
    Ports(phase, 16), Ports(phase, 17), Ports(phase, 18), Ports(phase, 19), \
    Ports(phase, 20), Ports(phase, 21), Ports(phase, 22), Ports(phase, 23), \
    Ports(phase, 24), Ports(phase, 25), Ports(phase, 26), Ports(phase, 27), \
    Ports(phase, 28), Ports(phase, 29), Ports(phase, 30), Ports(phase, 31)
 
 
PROGMEM uint8_t const pov_pattern[] = {
    pwm( 0), pwm( 1), pwm( 1), pwm( 1), pwm( 2),
    pwm( 2), pwm( 3), pwm( 3), pwm( 4), pwm( 4),
    pwm( 5), pwm( 5), pwm( 6), pwm( 6), pwm( 7),
    pwm( 7), pwm( 8), pwm( 8), pwm( 9), pwm( 9),
    pwm( 8), pwm( 7), pwm( 6), pwm( 5), pwm( 4),
    pwm( 5), pwm( 6), pwm( 7), pwm( 8), pwm( 9),
    pwm( 9), pwm( 8), pwm( 8), pwm( 7), pwm( 7),
    pwm( 6), pwm( 6), pwm( 5), pwm( 5), pwm( 4),
    pwm( 4), pwm( 3), pwm( 3), pwm( 2), pwm( 2),
    pwm( 1), pwm( 1), pwm( 1), pwm( 0), pwm( 0),
};
 
 
volatile uint16_t base_index = 0;
 
void iterate() {
    base_index += ports*brightness_levels;
    if (base_index >= sizeof(pov_pattern)) { base_index = 0; }
}
 
void setup() {
    DDRD = 0b11111111; // set digital  0- 7 to output
    DDRB = 0b00111111; // set digital  8-13 to output
    DDRC = 0b00111111; // set digital 14-19 to output (coincidences with analog 0-5)
 
    MsTimer2::set(step_delay, iterate);
    MsTimer2::start();
}
 
void loop() {
    static uint16_t index;
    cli();
    index = base_index;
    sei();
 
    for (uint8_t cycle=0; cycle<brightness_levels; ++cycle) {
        PORTC = pgm_read_byte(pov_pattern+(index++));
        PORTB = pgm_read_byte(pov_pattern+(index++));
        PORTD = pgm_read_byte(pov_pattern+(index++));
    }
}