Immer wieder steht der Modellbahner vor ähnlich gelagerten Problemen, wenn es um die Beleuchtung der Szenerie geht. 

Hauszeile

Mal wird ein Lauflicht zur Absicherung einer Baustelle benötigt, unterschiedliche Blinklichter, Blitzer, eine Verkehrsampel, eine simulierte Hausbeleuchtung oder sonstige Effekte. Das alles lässt sich problemlos mit einem Arduino Nano realisieren.

Einerseits wäre der kleine Allrounder damit total unterfordert und andererseits stehen wir oft vor dem Problem, dass die unzähligen Leitungen zu den LEDs schnell zu unübersichtlichen Kabelsträngen ausarten.

Am Beispiel der geplanten Häuserzeile lassen sich sehr gut die Vorteile der I2C-Technik erklären. In jedem der vier Häuser sollen 10 – 16 Räume einzeln mit LEDs beleuchtet werden. Vor dem dritten Haus entsteht eine Baustelle, welche durch acht Warnbarken mit Lauflicht abgesichert werden soll. Als Querungshilfe für die Straße soll eine Fußgängerampel dienen. Wenn wir nun an zentraler Stelle eine Steuerung montieren, werden 68 Leitungen für die Häuser, 9 Leitungen für die Baustelle und nochmal 12 Leitungen für die Fußgängerampel benötigt. Das sind in Summe 89 Leitungen.

Mal davon abgesehen, dass der Arduino Nano über weit weniger Ausgänge verfügt, praktikabel scheint diese Lösung nicht zu sein.

MCP23017

Auf der kleinen ca. 20 x 25 mm kleinen Platine sitzt ein IC mit der Bezeichnung MCP 23017. Hierbei handelt es sich um einen I2C Portexpander mit 16 IO-Ports. An ihm können somit bis zu 16 LEDs direkt angeschlossen werden. Benötigt werden dann nur noch vier Leitungen +5V, GND, SDA und SCL.

Die kleine Platine wird in unmittelbarer Nähe zu den LEDs montiert. In Spur H0 kann sie sogar ins Gebäude eingeklebt werden. So kann die Elektroinstallation im Haus bequem am Arbeitstisch vorgenommen werden.

Insgesamt können am Arduino Nano acht Portexpander angeschlossen werden. Da wir allerdings eine Adresse für die Bedieneinheit benötigen bleiben nur noch sieben. Das ist allerdings ausreichend, da die Firmware gleich mehrere Funktionen zur Verfügung stellt.

Jeder der Portexpander wird durch die Firmware halbiert. Damit werden immer Gruppen zu acht IO-Pins gebildet. Jede Gruppe kann nun gezielt mit den im Arduino hinterlegten Effekten angesteuert werden. Dies sind derzeit verschiedene Blink-, Blitz- und Lauflichtfunktionen sowie belebtes Haus und triggerbarer Verkehrsampel.

Infos zum Thema im Web: 
Adafruit-Bibliothek 
Kurze Erklärung wie man den MCP 23017 mit dem Arduino nutzt

Quellcode:

#include "Arduino.h"
#include
#include "PCF8574.h" // IO Expander
#include
#include
// SDA -> A4
// SCL -> A5
// Set the LCD address to 0x27 for a 16 chars and 2 line display
//LiquidCrystal_I2C lcd(0x27, 16, 2);
char *infozeile0 = "MoBa-LiPro_I2C";
char *infozeile1 = "@ K. Oestreicher";
LiquidCrystal_I2C lcd(0x3F, 16, 2);
PCF8574 bediener(0x20);
#include
// Adressbit: A0 A1 A2 Adresse
Adafruit_MCP23017 mcp1; // 1 0 0 0x21
Adafruit_MCP23017 mcp2; // 0 1 0 0x22
Adafruit_MCP23017 mcp3; // 1 1 0 0x23
Adafruit_MCP23017 mcp4; // 0 0 1 0x24
Adafruit_MCP23017 mcp5; // 1 0 1 0x25
Adafruit_MCP23017 mcp6; // 0 1 1 0x26
Adafruit_MCP23017 mcp7; // 1 1 1 0x27
int pmcp[14][20]; // 0-7 = Zustand der Ausgänge, 8 = Programm, 9 = Dauer in Ticks, 10-17 Ticksder Ausgänge 0-7

// Menüsteuerung
const int TPr = A0; // Programmierschalter
const int TAuf = A2; // Taster links
const int TAb = A1; // Taser rechts
const int TSet = A3; // Taster Set

char *men[] = {"21a", "21b", "22a", "22b", "23a", "23b", "24a", "24b", "25a", "25b", "26a", "26b", "27a", "27b" };
char *prog[] = {"Lauf 1", "Lauf 2", "Lauf 3", "Lauf 4", "Blink 1", "Blink 2", "Blitz 1", "Blitz 2", "Blitz 3", "Haus", "Ampel", "FAmpel", "Ampel T", "FAmpel T" };
unsigned long lastDebounceTime[7] = {0,0,0,0,0,0,0}; // the last time the output pin was toggled
unsigned long debounceDelay = 50;
int lastButtonState[7] = {LOW, LOW, LOW, LOW, LOW, LOW, LOW};
int buttonState[7];
int reading[7];
bool isProg = 0;
int HMenp = 0; // Haupmenupunkt
int UMenp = 0; // Untermenupunkt
int MEbene = 0; // Wir sind im Hauptmenu

 

int m=0;
int wert = 0;
//bool isProg = 0;

int led = 0;
bool setled = false;
bool ein = false;

// gibt den Programmtakt vor
unsigned long timeBase;
unsigned long timeBaseDelay = 10;
unsigned long timeBaseValue = 0;
int timeBaseCount = 100; // nach timeBaseCount wird der Zähler auf 0 gesetzt

int testLED=13;

void setup() {
Serial.begin(9600);
lcd.begin(); // initialize the LCD
lcd.setCursor(0,0);
lcd.print(infozeile0);
lcd.setCursor(0,1);
lcd.print(infozeile1);
bediener.pinMode(P0, INPUT); // ab
bediener.pinMode(P1, INPUT); // auf
bediener.pinMode(P2, INPUT); // go -> oder ret <-
bediener.pinMode(P3, INPUT); // SET
bediener.pinMode(P4, INPUT); // Bedien / Prog
bediener.begin();
mcp1.begin(1); // Start MCP 1 on Hardware address 0x21
for(int i=0; i<16; i++) mcp1.pinMode(i, OUTPUT);
mcp2.begin(2); // Start MCP 2 on Hardware address 0x22
for(int i=0; i<16; i++) mcp2.pinMode(i, OUTPUT);
mcp3.begin(3); // Start MCP 3 on Hardware address 0x23
for(int i=0; i<16; i++) mcp3.pinMode(i, OUTPUT);
mcp4.begin(4); // Start MCP 4 on Hardware address 0x24
for(int i=0; i<16; i++) mcp4.pinMode(i, OUTPUT);
mcp5.begin(5); // Start MCP 5 on Hardware address 0x25
for(int i=0; i<16; i++) mcp5.pinMode(i, OUTPUT);
mcp6.begin(6); // Start MCP 6 on Hardware address 0x26
for(int i=0; i<16; i++) mcp6.pinMode(i, OUTPUT);
mcp7.begin(7); // Start MCP 7 on Hardware address 0x27
for(int i=0; i<16; i++) mcp7.pinMode(i, OUTPUT);
for(int i=0; i<14; i++) pmcp[i][8] = 0; // interne Zähler auf 0 setzen
setProgramm();
//setInputs();

//for(int p=0; p<14; p++) pmcp[p][8] = 0; // Programm 0 als Standard setzen
//pmcp[0][8] = 2;
//pmcp[1][8] = 4;
//pmcp[1][9] = 200;
pinMode(testLED, OUTPUT);
noInterrupts(); // Interrupts ausschalten
TCCR1A = 0; // ---------------- Timer1 initialisieren ----------------------
TCCR1B = 0;
TCNT1 = 0;
OCR1A = 31250; // Vergleichsregister um die Zeit einzustellen 16MHz/256/2Hz
OCR1A = 312; // Vergleichsregister um die Zeit einzustellen 16MHz/256/200Hz
TCCR1B |= (1 << WGM12); // CTC mode
TCCR1B |= (1 << CS12); // 256 prescaler
TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
interrupts(); // Interrups einschalten
}

 

ISR(TIMER1_COMPA_vect) { // timer interrupt service routine
digitalWrite(testLED, !digitalRead(testLED)); // LED umschalten
timeBaseValue++;
if(timeBaseValue > timeBaseCount) timeBaseValue = 0;
}

 

void loop() {
//if(bediener.digitalRead(P0)) Serial.println("P1 on");
entprell(P0);
entprell(P1);
entprell(P2);
entprell(P3);
entprell(P4);
int p,i = 0;

for(p=0; p<14; p++){
progr(p);
if(p == 0) for(int i=0; i<8; i++) mcp1.digitalWrite(i, pmcp[p][i]);
if(p == 1) for(int i=0; i<8; i++) mcp1.digitalWrite(i+8, pmcp[p][i]);
if(p == 2) for(int i=0; i<8; i++) mcp2.digitalWrite(i, pmcp[p][i]);
if(p == 3) for(int i=0; i<8; i++) mcp2.digitalWrite(i+8, pmcp[p][i]);
if(p == 4) for(int i=0; i<8; i++) mcp3.digitalWrite(i, pmcp[p][i]);
if(p == 5) for(int i=0; i<8; i++) mcp3.digitalWrite(i+8, pmcp[p][i]);
if(p == 6) for(int i=0; i<8; i++) mcp4.digitalWrite(i, pmcp[p][i]);
if(p == 7) for(int i=0; i<8; i++) mcp4.digitalWrite(i+8, pmcp[p][i]);
if(p == 8) for(int i=0; i<8; i++) mcp5.digitalWrite(i, pmcp[p][i]);
if(p == 9) for(int i=0; i<8; i++) mcp5.digitalWrite(i+8, pmcp[p][i]);
if(p == 10) for(int i=0; i<8; i++) mcp6.digitalWrite(i, pmcp[p][i]);
if(p == 11) for(int i=0; i<8; i++) mcp6.digitalWrite(i+8, pmcp[p][i]);
if(p == 12) for(int i=0; i<8; i++) mcp7.digitalWrite(i, pmcp[p][i]);
if(p == 13) for(int i=0; i<8; i++) mcp7.digitalWrite(i+8, pmcp[p][i]);
//delay(100);
}

delay(1);
}
void progr(int p){
int pp = pmcp[p][8]; // Programmwahl
int tOSet = 0;
switch (pp){
case 0: lauf1(p); // lauf1
break;
case 1: lauf2(p);// lauf2
break;
case 2: lauf3(p); // lauf3
break;
case 3: lauf4(p); // lauf4
break;
case 4: blinker1(p); // Blinklicht
break;
case 5: blinker2(p); // Bliklicht
break;
case 6: blitz1(p); // Blitzlicht
break;
case 7: blitz2(p); // Blitzlicht
break;
case 8: blitz3(p); // Blitzlicht
break;
case 9: haus(p); // Haus
break;
case 10: ampel(p); // Ampel
break;
case 11: fampel(p); // Fußgängerampel
break;
case 12: ampel_r(p); // Ampel extern getriggert über In 7
break;
case 13: fampel_r(p); // Fußgängerampel extern getriggert über In 7
break;

}
}
void lauf1(int p){
if(timeBaseValue < timeBaseCount/10*10){ pmcp[p][0]=0; pmcp[p][1]=0; pmcp[p][2]=0; pmcp[p][3]=0; pmcp[p][4]=0; pmcp[p][5]=0; pmcp[p][6]=0; pmcp[p][7]=0; }
if(timeBaseValue < timeBaseCount/10*9) { pmcp[p][0]=0; pmcp[p][1]=0; pmcp[p][2]=0; pmcp[p][3]=0; pmcp[p][4]=0; pmcp[p][5]=0; pmcp[p][6]=0; pmcp[p][7]=0; }
if(timeBaseValue < timeBaseCount/10*8) { pmcp[p][0]=1; pmcp[p][1]=0; pmcp[p][2]=0; pmcp[p][3]=0; pmcp[p][4]=0; pmcp[p][5]=0; pmcp[p][6]=0; pmcp[p][7]=0; }
if(timeBaseValue < timeBaseCount/10*7) { pmcp[p][0]=0; pmcp[p][1]=1; pmcp[p][2]=0; pmcp[p][3]=0; pmcp[p][4]=0; pmcp[p][5]=0; pmcp[p][6]=0; pmcp[p][7]=0; }
if(timeBaseValue < timeBaseCount/10*6) { pmcp[p][0]=0; pmcp[p][1]=0; pmcp[p][2]=1; pmcp[p][3]=0; pmcp[p][4]=0; pmcp[p][5]=0; pmcp[p][6]=0; pmcp[p][7]=0; }
if(timeBaseValue < timeBaseCount/10*5) { pmcp[p][0]=0; pmcp[p][1]=0; pmcp[p][2]=0; pmcp[p][3]=1; pmcp[p][4]=0; pmcp[p][5]=0; pmcp[p][6]=0; pmcp[p][7]=0; }
if(timeBaseValue < timeBaseCount/10*4) { pmcp[p][0]=0; pmcp[p][1]=0; pmcp[p][2]=0; pmcp[p][3]=0; pmcp[p][4]=1; pmcp[p][5]=0; pmcp[p][6]=0; pmcp[p][7]=0; }
if(timeBaseValue < timeBaseCount/10*3) { pmcp[p][0]=0; pmcp[p][1]=0; pmcp[p][2]=0; pmcp[p][3]=0; pmcp[p][4]=0; pmcp[p][5]=1; pmcp[p][6]=0; pmcp[p][7]=0; }
if(timeBaseValue < timeBaseCount/10*2) { pmcp[p][0]=0; pmcp[p][1]=0; pmcp[p][2]=0; pmcp[p][3]=0; pmcp[p][4]=0; pmcp[p][5]=0; pmcp[p][6]=1; pmcp[p][7]=0; }
if(timeBaseValue < timeBaseCount/10*1) { pmcp[p][0]=0; pmcp[p][1]=0; pmcp[p][2]=0; pmcp[p][3]=0; pmcp[p][4]=0; pmcp[p][5]=0; pmcp[p][6]=0; pmcp[p][7]=1; }
}
void lauf2(int p){
if(timeBaseValue < timeBaseCount/10*10){ pmcp[p][0]=0; pmcp[p][1]=0; pmcp[p][2]=0; pmcp[p][3]=0; pmcp[p][4]=0; pmcp[p][5]=0; pmcp[p][6]=0; pmcp[p][7]=0; }
if(timeBaseValue < timeBaseCount/10*9) { pmcp[p][0]=0; pmcp[p][1]=0; pmcp[p][2]=0; pmcp[p][3]=0; pmcp[p][4]=0; pmcp[p][5]=0; pmcp[p][6]=0; pmcp[p][7]=0; }
if(timeBaseValue < timeBaseCount/10*8) { pmcp[p][0]=1; pmcp[p][1]=0; pmcp[p][2]=0; pmcp[p][3]=0; pmcp[p][4]=0; pmcp[p][5]=0; pmcp[p][6]=0; pmcp[p][7]=0; }
if(timeBaseValue < timeBaseCount/10*7) { pmcp[p][0]=0; pmcp[p][1]=1; pmcp[p][2]=0; pmcp[p][3]=0; pmcp[p][4]=0; pmcp[p][5]=0; pmcp[p][6]=0; pmcp[p][7]=0; }
if(timeBaseValue < timeBaseCount/10*6) { pmcp[p][0]=1; pmcp[p][1]=0; pmcp[p][2]=1; pmcp[p][3]=0; pmcp[p][4]=0; pmcp[p][5]=0; pmcp[p][6]=0; pmcp[p][7]=0; }
if(timeBaseValue < timeBaseCount/10*5) { pmcp[p][0]=1; pmcp[p][1]=0; pmcp[p][2]=0; pmcp[p][3]=1; pmcp[p][4]=0; pmcp[p][5]=0; pmcp[p][6]=0; pmcp[p][7]=0; }
if(timeBaseValue < timeBaseCount/10*4) { pmcp[p][0]=1; pmcp[p][1]=0; pmcp[p][2]=0; pmcp[p][3]=0; pmcp[p][4]=1; pmcp[p][5]=0; pmcp[p][6]=0; pmcp[p][7]=0; }
if(timeBaseValue < timeBaseCount/10*3) { pmcp[p][0]=1; pmcp[p][1]=0; pmcp[p][2]=0; pmcp[p][3]=0; pmcp[p][4]=0; pmcp[p][5]=1; pmcp[p][6]=0; pmcp[p][7]=0; }
if(timeBaseValue < timeBaseCount/10*2) { pmcp[p][0]=1; pmcp[p][1]=0; pmcp[p][2]=0; pmcp[p][3]=0; pmcp[p][4]=0; pmcp[p][5]=0; pmcp[p][6]=1; pmcp[p][7]=0; }
if(timeBaseValue < timeBaseCount/10*1) { pmcp[p][0]=1; pmcp[p][1]=0; pmcp[p][2]=0; pmcp[p][3]=0; pmcp[p][4]=0; pmcp[p][5]=0; pmcp[p][6]=0; pmcp[p][7]=1; }
}
void lauf3(int p){
if(timeBaseValue < timeBaseCount/10*10){ pmcp[p][0]=1; pmcp[p][1]=0; pmcp[p][2]=0; pmcp[p][3]=0; pmcp[p][4]=0; pmcp[p][5]=0; pmcp[p][6]=0; pmcp[p][7]=0; }
if(timeBaseValue < timeBaseCount/10*9) { pmcp[p][0]=0; pmcp[p][1]=0; pmcp[p][2]=0; pmcp[p][3]=0; pmcp[p][4]=0; pmcp[p][5]=0; pmcp[p][6]=0; pmcp[p][7]=0; }
if(timeBaseValue < timeBaseCount/10*8) { pmcp[p][0]=1; pmcp[p][1]=0; pmcp[p][2]=0; pmcp[p][3]=0; pmcp[p][4]=0; pmcp[p][5]=0; pmcp[p][6]=0; pmcp[p][7]=0; }
if(timeBaseValue < timeBaseCount/10*7) { pmcp[p][0]=0; pmcp[p][1]=1; pmcp[p][2]=1; pmcp[p][3]=0; pmcp[p][4]=0; pmcp[p][5]=0; pmcp[p][6]=0; pmcp[p][7]=0; }
if(timeBaseValue < timeBaseCount/10*6) { pmcp[p][0]=0; pmcp[p][1]=0; pmcp[p][2]=1; pmcp[p][3]=1; pmcp[p][4]=0; pmcp[p][5]=0; pmcp[p][6]=0; pmcp[p][7]=0; }
if(timeBaseValue < timeBaseCount/10*5) { pmcp[p][0]=0; pmcp[p][1]=0; pmcp[p][2]=0; pmcp[p][3]=1; pmcp[p][4]=1; pmcp[p][5]=0; pmcp[p][6]=0; pmcp[p][7]=0; }
if(timeBaseValue < timeBaseCount/10*4) { pmcp[p][0]=0; pmcp[p][1]=0; pmcp[p][2]=0; pmcp[p][3]=0; pmcp[p][4]=1; pmcp[p][5]=1; pmcp[p][6]=0; pmcp[p][7]=0; }
if(timeBaseValue < timeBaseCount/10*3) { pmcp[p][0]=0; pmcp[p][1]=0; pmcp[p][2]=0; pmcp[p][3]=0; pmcp[p][4]=0; pmcp[p][5]=1; pmcp[p][6]=1; pmcp[p][7]=0; }
if(timeBaseValue < timeBaseCount/10*2) { pmcp[p][0]=0; pmcp[p][1]=0; pmcp[p][2]=0; pmcp[p][3]=0; pmcp[p][4]=0; pmcp[p][5]=0; pmcp[p][6]=1; pmcp[p][7]=1; }
if(timeBaseValue < timeBaseCount/10*1) { pmcp[p][0]=0; pmcp[p][1]=0; pmcp[p][2]=0; pmcp[p][3]=0; pmcp[p][4]=0; pmcp[p][5]=0; pmcp[p][6]=0; pmcp[p][7]=1; }
}
void lauf4(int p){
if(timeBaseValue < timeBaseCount/10*10){ pmcp[p][0]=1; pmcp[p][1]=0; pmcp[p][2]=0; pmcp[p][3]=0; pmcp[p][4]=0; pmcp[p][5]=0; pmcp[p][6]=0; pmcp[p][7]=0; }
if(timeBaseValue < timeBaseCount/10*9) { pmcp[p][0]=1; pmcp[p][1]=1; pmcp[p][2]=0; pmcp[p][3]=0; pmcp[p][4]=0; pmcp[p][5]=0; pmcp[p][6]=0; pmcp[p][7]=0; }
if(timeBaseValue < timeBaseCount/10*8) { pmcp[p][0]=1; pmcp[p][1]=1; pmcp[p][2]=1; pmcp[p][3]=0; pmcp[p][4]=0; pmcp[p][5]=0; pmcp[p][6]=0; pmcp[p][7]=0; }
if(timeBaseValue < timeBaseCount/10*7) { pmcp[p][0]=1; pmcp[p][1]=1; pmcp[p][2]=1; pmcp[p][3]=1; pmcp[p][4]=0; pmcp[p][5]=0; pmcp[p][6]=0; pmcp[p][7]=0; }
if(timeBaseValue < timeBaseCount/10*6) { pmcp[p][0]=1; pmcp[p][1]=1; pmcp[p][2]=1; pmcp[p][3]=1; pmcp[p][4]=1; pmcp[p][5]=0; pmcp[p][6]=0; pmcp[p][7]=0; }
if(timeBaseValue < timeBaseCount/10*5) { pmcp[p][0]=1; pmcp[p][1]=1; pmcp[p][2]=1; pmcp[p][3]=1; pmcp[p][4]=1; pmcp[p][5]=1; pmcp[p][6]=0; pmcp[p][7]=0; }
if(timeBaseValue < timeBaseCount/10*4) { pmcp[p][0]=1; pmcp[p][1]=1; pmcp[p][2]=1; pmcp[p][3]=1; pmcp[p][4]=1; pmcp[p][5]=1; pmcp[p][6]=1; pmcp[p][7]=0; }
if(timeBaseValue < timeBaseCount/10*3) { pmcp[p][0]=1; pmcp[p][1]=1; pmcp[p][2]=0; pmcp[p][3]=1; pmcp[p][4]=1; pmcp[p][5]=1; pmcp[p][6]=1; pmcp[p][7]=1; }
if(timeBaseValue < timeBaseCount/10*2) { pmcp[p][0]=0; pmcp[p][1]=0; pmcp[p][2]=0; pmcp[p][3]=0; pmcp[p][4]=0; pmcp[p][5]=0; pmcp[p][6]=1; pmcp[p][7]=1; }
if(timeBaseValue < timeBaseCount/10*1) { pmcp[p][0]=0; pmcp[p][1]=0; pmcp[p][2]=0; pmcp[p][3]=0; pmcp[p][4]=0; pmcp[p][5]=0; pmcp[p][6]=0; pmcp[p][7]=1; }
}
void haus(int p){
int LEDon=0;
for(int i=0; i<8; i++) if(pmcp[p][i] == HIGH) LEDon++;
//Serial.println(LEDon);
for(int i=10; i<18; i++){
if(pmcp[p][i] == 0)
{
if((pmcp[p][i-10] == HIGH) && (LEDon < 5)) // Es sollen min 3 Zimmer beleuchtet bleiben
{
pmcp[p][i]++;
//Serial.print("not toggle");
}else
{
pmcp[p][i] = random (200,1000);
pmcp[p][i-10] = ! pmcp[p][i-10];
}
}
pmcp[p][i]--;
}
//Serial.print("t0Set:"); Serial.print(tOSet);
}
void blinker1(int p){
for(int i=10; i<18; i++){
if(pmcp[p][i] == 0)
{
//pmcp[p][i] = random (50);
pmcp[p][i] = 8+i*2%3;
pmcp[p][i-10] = ! pmcp[p][i-10];
}
pmcp[p][i]--;
}
//Serial.print("t0Set:"); Serial.print(tOSet);
}
void blinker2(int p){
for(int i=10; i<18; i++){
if(pmcp[p][i] == 0)
{
//pmcp[p][i] = random (50);
pmcp[p][i] = 3+i*5%3;
pmcp[p][i-10] = ! pmcp[p][i-10];
}
pmcp[p][i]--;
}
}
void blitz1(int p){
for(int i=10; i<18; i++){
if(pmcp[p][i] == 0)
{
//pmcp[p][i] = random (50);
pmcp[p][i-10] = ! pmcp[p][i-10];
if(pmcp[p][i-10] == HIGH)
pmcp[p][i] = 3;
else
pmcp[p][i] = random(2,10);
//pmcp[p][i-10] = ! pmcp[p][i-10];
}
pmcp[p][i]--;
}
}
void blitz2(int p){
for(int i=10; i<18; i++){
if(pmcp[p][i] == 0)
{
//pmcp[p][i] = random (50);
pmcp[p][i-10] = ! pmcp[p][i-10];
if(pmcp[p][i-10] == HIGH)
pmcp[p][i] = 3;
else
pmcp[p][i] = random(10,30);
//pmcp[p][i-10] = ! pmcp[p][i-10];
}
pmcp[p][i]--;
}
}
void blitz3(int p){
for(int i=10; i<18; i++){
if(pmcp[p][i] == 0)
{
//Serial.println("pmcp[p][i] == 0");
pmcp[p][i-10] = ! pmcp[p][i-10];
if(pmcp[p][i-10] == HIGH){
for(int ii=10; ii<18; ii++){ pmcp[p][ii] = 10;}
pmcp[p][i] = 2;
}
}
pmcp[p][i]--;
}
}
void ampel(int p){
// Ampelfasen 300, 100, 500, 100, 300, 100, 500, 100 Takte
// rot 1 x x x x x x
// gelb 1 x x
// grün 1 x
// rot 2 x x x x x x
// gelb 2 x x
// grün 2 x

if(pmcp[p][9] > 2000) pmcp[p][9] = 0; // rot 1 gelb 1 grün 1 rot 2 gelb 2 grün 2
if(pmcp[p][9] > 0 && pmcp[p][9] < 300) { pmcp[p][0]=1; pmcp[p][1]=0; pmcp[p][2]=0; pmcp[p][3]=1; pmcp[p][4]=0; pmcp[p][5]=0; pmcp[p][6]=0; pmcp[p][7]=1; }
if(pmcp[p][9] > 300 && pmcp[p][9] < 400) { pmcp[p][0]=1; pmcp[p][1]=1; pmcp[p][2]=0; pmcp[p][3]=1; pmcp[p][4]=0; pmcp[p][5]=0; pmcp[p][6]=0; pmcp[p][7]=0; }
if(pmcp[p][9] > 400 && pmcp[p][9] < 900) { pmcp[p][0]=0; pmcp[p][1]=0; pmcp[p][2]=1; pmcp[p][3]=1; pmcp[p][4]=0; pmcp[p][5]=0; pmcp[p][6]=0; pmcp[p][7]=0; }
if(pmcp[p][9] > 900 && pmcp[p][9] < 1000) { pmcp[p][0]=0; pmcp[p][1]=1; pmcp[p][2]=0; pmcp[p][3]=1; pmcp[p][4]=0; pmcp[p][5]=1; pmcp[p][6]=0; pmcp[p][7]=0; }
if(pmcp[p][9] >1000 && pmcp[p][9] < 1300) { pmcp[p][0]=1; pmcp[p][1]=0; pmcp[p][2]=0; pmcp[p][3]=1; pmcp[p][4]=0; pmcp[p][5]=0; pmcp[p][6]=0; pmcp[p][7]=0; }
if(pmcp[p][9] >1300 && pmcp[p][9] < 1400) { pmcp[p][0]=1; pmcp[p][1]=0; pmcp[p][2]=0; pmcp[p][3]=1; pmcp[p][4]=1; pmcp[p][5]=0; pmcp[p][6]=0; pmcp[p][7]=0; }
if(pmcp[p][9] >1400 && pmcp[p][9] < 1900) { pmcp[p][0]=1; pmcp[p][1]=0; pmcp[p][2]=0; pmcp[p][3]=0; pmcp[p][4]=0; pmcp[p][5]=1; pmcp[p][6]=0; pmcp[p][7]=0; }
if(pmcp[p][9] >1900 && pmcp[p][9] < 2000) { pmcp[p][0]=1; pmcp[p][1]=0; pmcp[p][2]=0; pmcp[p][3]=0; pmcp[p][4]=1; pmcp[p][5]=0; pmcp[p][6]=0; pmcp[p][7]=0; }
//pmcp[p][9]= pmcp[p][9]+10;
pmcp[p][9]++;

}
void fampel(int p){

}
void ampel_r(int p){
int trigger = 0;
if(p == 0){mcp1.pinMode(7, INPUT); mcp1.pullUp(7, HIGH); trigger = mcp1.digitalRead(7);}
if(p == 1){mcp1.pinMode(15, INPUT); mcp1.pullUp(15, HIGH); trigger = mcp1.digitalRead(15);}
if(p == 2){mcp2.pinMode(7, INPUT); mcp2.pullUp(7, HIGH); trigger = mcp2.digitalRead(7);}
if(p == 3){mcp2.pinMode(15, INPUT); mcp2.pullUp(15, HIGH); trigger = mcp2.digitalRead(15);}
if(p == 4){mcp3.pinMode(7, INPUT); mcp3.pullUp(7, HIGH); trigger = mcp3.digitalRead(7);}
if(p == 5){mcp3.pinMode(15, INPUT); mcp3.pullUp(15, HIGH); trigger = mcp3.digitalRead(15);}
if(p == 6){mcp4.pinMode(7, INPUT); mcp4.pullUp(7, HIGH); trigger = mcp4.digitalRead(7);}
if(p == 7){mcp4.pinMode(15, INPUT); mcp4.pullUp(15, HIGH); trigger = mcp4.digitalRead(15);}
if(p == 8){mcp5.pinMode(7, INPUT); mcp5.pullUp(7, HIGH); trigger = mcp5.digitalRead(7);}
if(p == 9){mcp5.pinMode(15, INPUT); mcp5.pullUp(15, HIGH); trigger = mcp5.digitalRead(15);}
if(p == 10){mcp6.pinMode(7, INPUT); mcp6.pullUp(7, HIGH); trigger = mcp6.digitalRead(7);}
if(p == 11){mcp6.pinMode(15, INPUT); mcp6.pullUp(15, HIGH); trigger = mcp6.digitalRead(15);}
if(p == 12){mcp7.pinMode(7, INPUT); mcp7.pullUp(7, HIGH); trigger = mcp7.digitalRead(7);}
if(p == 13){mcp7.pinMode(15, INPUT); mcp7.pullUp(15, HIGH); trigger = mcp7.digitalRead(15);}
if(trigger == 0){Serial.print("Ampel Trigger"); Serial.println(trigger);}

// Ampelfasen rot1 gelb1 grün1 rot2 gelb2 grün2
// 500 1 x x
// 100 2 x x
// 300 3 x x
// 100 4 x x x
// 500 5 x x
// 100 6 x x
// 300 7 x x
// 100 8 x x x

if(pmcp[p][9] > 1199) pmcp[p][9] = 0; // rot 1 gelb 1 grün 1 rot 2 gelb 2 grün 2
if(pmcp[p][9] >= 0 && pmcp[p][9] < 100) { pmcp[p][0]=0; pmcp[p][1]=0; pmcp[p][2]=1; pmcp[p][3]=1; pmcp[p][4]=0; pmcp[p][5]=0; pmcp[p][6]=0; pmcp[p][7]=0; }
if(pmcp[p][9] > 100 && pmcp[p][9] < 200) { pmcp[p][0]=0; pmcp[p][1]=1; pmcp[p][2]=0; pmcp[p][3]=1; pmcp[p][4]=0; pmcp[p][5]=0; pmcp[p][6]=0; pmcp[p][7]=0; }
if(pmcp[p][9] > 200 && pmcp[p][9] < 300) { pmcp[p][0]=1; pmcp[p][1]=0; pmcp[p][2]=0; pmcp[p][3]=1; pmcp[p][4]=0; pmcp[p][5]=0; pmcp[p][6]=0; pmcp[p][7]=0; }
if(pmcp[p][9] > 300 && pmcp[p][9] < 400) { pmcp[p][0]=1; pmcp[p][1]=0; pmcp[p][2]=0; pmcp[p][3]=1; pmcp[p][4]=1; pmcp[p][5]=0; pmcp[p][6]=0; pmcp[p][7]=0; }
if(pmcp[p][9] > 400 && pmcp[p][9] < 900) { pmcp[p][0]=1; pmcp[p][1]=0; pmcp[p][2]=0; pmcp[p][3]=0; pmcp[p][4]=0; pmcp[p][5]=1; pmcp[p][6]=0; pmcp[p][7]=0; }
if(pmcp[p][9] > 900 && pmcp[p][9] < 1000) { pmcp[p][0]=1; pmcp[p][1]=0; pmcp[p][2]=0; pmcp[p][3]=0; pmcp[p][4]=1; pmcp[p][5]=0; pmcp[p][6]=0; pmcp[p][7]=0; }
if(pmcp[p][9] >1000 && pmcp[p][9] < 1100) { pmcp[p][0]=1; pmcp[p][1]=0; pmcp[p][2]=0; pmcp[p][3]=1; pmcp[p][4]=0; pmcp[p][5]=0; pmcp[p][6]=0; pmcp[p][7]=0; }
if(pmcp[p][9] >1100 && pmcp[p][9] < 1200) { pmcp[p][0]=1; pmcp[p][1]=1; pmcp[p][2]=0; pmcp[p][3]=1; pmcp[p][4]=0; pmcp[p][5]=0; pmcp[p][6]=0; pmcp[p][7]=0; }
if(trigger == 0 && pmcp[p][9] == 0) pmcp[p][9]= pmcp[p][9]+10;
if(pmcp[p][9] < 1200 && pmcp[p][9] > 0) pmcp[p][9]= pmcp[p][9]+2;
//Serial.print("Zaehler: "); Serial.println(pmcp[p][9]);
//pmcp[p][9]++;
}
void fampel_r(int p){

}
void zeigeExpander(int p){
//Serial.print("zeigeExpander "); Serial.print(p);
delay(10);
if(p == 0) for(int i=0; i<8; i++) {mcp1.digitalWrite(i, HIGH); }else for(int i=0; i<8; i++) mcp1.digitalWrite(i, LOW);
if(p == 1) for(int i=0; i<8; i++) {mcp1.digitalWrite(i+8, HIGH);}else for(int i=0; i<8; i++) mcp1.digitalWrite(i+8, LOW);
if(p == 2) for(int i=0; i<8; i++) {mcp2.digitalWrite(i, HIGH); }else for(int i=0; i<8; i++) mcp2.digitalWrite(i, LOW);
if(p == 3) for(int i=0; i<8; i++) {mcp2.digitalWrite(i+8, HIGH);}else for(int i=0; i<8; i++) mcp2.digitalWrite(i+8, LOW);
if(p == 4) for(int i=0; i<8; i++) {mcp3.digitalWrite(i, HIGH); }else for(int i=0; i<8; i++) mcp3.digitalWrite(i, LOW);
if(p == 5) for(int i=0; i<8; i++) {mcp3.digitalWrite(i+8, HIGH);}else for(int i=0; i<8; i++) mcp3.digitalWrite(i+8, LOW);
if(p == 6) for(int i=0; i<8; i++) {mcp4.digitalWrite(i, HIGH); }else for(int i=0; i<8; i++) mcp4.digitalWrite(i, LOW);
if(p == 7) for(int i=0; i<8; i++) {mcp4.digitalWrite(i+8, HIGH);}else for(int i=0; i<8; i++) mcp4.digitalWrite(i+8, LOW);
if(p == 8) for(int i=0; i<8; i++) {mcp5.digitalWrite(i, HIGH); }else for(int i=0; i<8; i++) mcp5.digitalWrite(i, LOW);
if(p == 9) for(int i=0; i<8; i++) {mcp5.digitalWrite(i+8, HIGH);}else for(int i=0; i<8; i++) mcp5.digitalWrite(i+8, LOW);
if(p == 10) for(int i=0; i<8; i++) {mcp6.digitalWrite(i, HIGH); }else for(int i=0; i<8; i++) mcp6.digitalWrite(i, LOW);
if(p == 11) for(int i=0; i<8; i++) {mcp6.digitalWrite(i+8, HIGH);}else for(int i=0; i<8; i++) mcp6.digitalWrite(i+8, LOW);
if(p == 12) for(int i=0; i<8; i++) {mcp7.digitalWrite(i, HIGH); }else for(int i=0; i<8; i++) mcp7.digitalWrite(i, LOW);
if(p == 13) for(int i=0; i<8; i++) {mcp7.digitalWrite(i+8, HIGH);}else for(int i=0; i<8; i++) mcp7.digitalWrite(i+8, LOW);
delay(2000);
}

void setProgramm(){
Serial.println("set Programm");
if(eepromReadInt(100) !=10)
{
Serial.println("setze alle Programme auf 0");
for(int p=0; p<14; p++)
{
pmcp[p][8] = 0; // Programm 0 als Standard setzen
eepromWriteInt(p*2, 0);
}
eepromWriteInt(100, 10);
}
else
{
Serial.println("lese Programm aus EEProm");
for(int p=0; p<14; p++)
{
pmcp[p][8] = eepromReadInt(p*2);
setPins(p);
Serial.print("MCP"); Serial.print(p); Serial.print(" Programm: "); Serial.println(prog[pmcp[p][8]]);
}
}
//delay(5000);
screen();
}
void setPins(int p)
{
if(p == 0) for(int i=0; i<8; i++) mcp1.pinMode(i, OUTPUT);
if(p == 1) for(int i=0; i<8; i++) mcp1.pinMode(i+8, OUTPUT);
if(p == 2) for(int i=0; i<8; i++) mcp2.pinMode(i, OUTPUT);
if(p == 3) for(int i=0; i<8; i++) mcp2.pinMode(i+8, OUTPUT);
if(p == 4) for(int i=0; i<8; i++) mcp3.pinMode(i, OUTPUT);
if(p == 5) for(int i=0; i<8; i++) mcp3.pinMode(i+8, OUTPUT);
if(p == 6) for(int i=0; i<8; i++) mcp4.pinMode(i, OUTPUT);
if(p == 7) for(int i=0; i<8; i++) mcp4.pinMode(i+8, OUTPUT);
if(p == 8) for(int i=0; i<8; i++) mcp5.pinMode(i, OUTPUT);
if(p == 9) for(int i=0; i<8; i++) mcp5.pinMode(i+8, OUTPUT);
if(p == 10) for(int i=0; i<8; i++) mcp6.pinMode(i, OUTPUT);
if(p == 11) for(int i=0; i<8; i++) mcp6.pinMode(i+8, OUTPUT);
if(p == 12) for(int i=0; i<8; i++) mcp7.pinMode(i, OUTPUT);
if(p == 13) for(int i=0; i<8; i++) mcp7.pinMode(i+8, OUTPUT);

}
void tBase(int tb){
if(millis() - timeBase > timeBaseDelay)
{
timeBase = millis();
//Serial.println("TBase"); Serial.print(timeBaseValue);
//timeBaseValue++;
if(timeBaseValue > timeBaseCount) timeBaseValue = 0;
}
//else timeBaseValue++;
//Serial.println("TBase"); Serial.print(timeBaseValue);
}

void entprell(int t)
{
reading[t] = bediener.digitalRead(t);
if(reading[t] != lastButtonState[t])
{
lastDebounceTime[t] = millis();
}
if ((millis() - lastDebounceTime[t]) > debounceDelay) {
if (reading[t] != buttonState[t]) {
buttonState[t] = reading[t];
if (buttonState[t] == HIGH) {
Serial.print("Taste: "); Serial.print(t); Serial.println(" Entprell ");
switch (t) {
case 0: _ab();
break;
case 1: _auf();

break;
case 2: _go();
break;
case 3: _ok();
break;
case 4: _prg();
break;
default:
break;
}
}
}
}
lastButtonState[t] = reading[t];
bediener.digitalRead(t);
if(bediener.digitalRead(t)) Serial.println(t);
}

void _auf()
{
if(MEbene == 0){
HMenp++;
if(HMenp > (sizeof(men) / sizeof(men[0]))-1) HMenp=0;
screen();
}else{
UMenp++;
if(UMenp > (sizeof(prog) / sizeof(prog[0]))-1) UMenp=0;
screen();
}
}
void _ab()
{
if(MEbene == 0){
HMenp--;
if(HMenp < 0) HMenp = sizeof(men) / sizeof(men[0])-1;
screen();
}else{
UMenp--;
if(UMenp < 0) UMenp = sizeof(prog) / sizeof(prog[0])-1;
screen();
}
}
void _go()
{
if(MEbene == 0){
MEbene = 1;
UMenp = pmcp[HMenp][8];
}
else{
MEbene = 0;
}
screen();
}
void _ok()
{
if(MEbene == 1){
eepromWriteInt(HMenp*2, UMenp);
pmcp[HMenp][8] = UMenp;
}
}
void _prg()
{
isProg = !isProg;
// der gesuchte Expander schaltet alle Ausgänge auf 1, die Ausgänge der anderen Expander gehen auf 0
zeigeExpander(HMenp);
screen();

//Serial.print("_prog: "); Serial.print(isProg); Serial.println(" P ");
}

 

void screen()
{
//int mmenu = (sizeof(men) / sizeof(men[0]))-1;
//int m2 = m+1;
String ok ="\176";
String prg ="Bed";
String prg1 =">";

//if(m<0){ m=mmenu; m2=0;}
//if(m>mmenu){ m=0 ; m2 = mmenu;}
if(MEbene == 1){ ok ="\177"; prg1 = "*";}
//if(isProg == 1){ prg = "Prg"; prg1 = "*";}

prg = " \77"; // wird in dieser Fimware nicht benötigt
lcd.clear();
lcd.setCursor(0,0);

lcd.print(prg1+" ");
lcd.print(men[HMenp]);
if(MEbene == 1){
if(UMenp == pmcp[HMenp][8])lcd.print(": *"); else lcd.print(": >");
lcd.print(prog[UMenp]);
}else
{
lcd.print(" ");
lcd.print(prog[pmcp[HMenp][8]]);
}
lcd.setCursor(0,1);
lcd.print("< > "+ok+" SET "+prg);

}
// --------------------------------- EEProm lesen und schreiben -------------------------
void eepromWriteInt(int adr, int wert) {
byte low, high;
low=wert&0xFF;
high=(wert>>8)&0xFF;
EEPROM.write(adr, low); // dauert 3,3ms
EEPROM.write(adr+1, high);
return;
} //eepromWriteInt

int eepromReadInt(int adr) {
byte low, high;
low=EEPROM.read(adr);
high=EEPROM.read(adr+1);
delay(30);
return low + ((high << 8)&0xFF00);
} //eepromReadInt