michael_x:
Wenn die Treppen komplett unabhängig voneinander sind und du jurs' EVA magst, kannst du auch beliebig mehrere davon verwenden.
OK, die Idee greife ich mal auf. Wenn man es richtig macht, ist es ja praktisch kein zusätzlicher Aufwand, ein Programm "für beliebig viele Treppenbeleuchtungen" zu schreiben im Vergleich zu einem Programm "für zwei Treppenbeleuchtungen".
Ich packe dazu alle relevanten Variablen einer Treppe in ein "struct", und dann können beliebig viele Treppen geschaltet werden, solange die Treppen mit 2 Schaltern geschaltet werden und entweder eine dreiteilige mit Zeitversatz geschaltete oder eine einteilige Beleuchtung haben. Die Datenstruktur für eine Treppe sieht dabei so aus:
struct dreiSegmentTreppe_t {
byte schalterUntenPin; // Pin des Schalters unten an der Treppe
byte schalterObenPin; // Pin des Schalters oben an der Treppe
byte schalterState; // letzter Schaltzustand (in den beiden untersten Bits codiert
byte geschaltet; // NICHTGESCHALTET,UNTENGESCHALTET,OBENGESCHALTET}
unsigned long startZeit; // enthält die Zeit, wann das Licht eingeschaltet wurde
byte lichtA_Pin; // Pin für Lampe-A
byte lichtB_Pin; // Pin für Lampe-B (falls nur eine Lampe, identisch mit lichtA_Pin)
byte lichtC_Pin; // Pin für Lampe-C (falls nur eine Lampe, identisch mit lichtA_Pin)
};
Die relevanten Definitionen stehen hier für jede Treppe im Code als treppen-Array gespeichert:
// Ein Array mit 2 Elementen definieren und mit Werten belegen, entsprechend 2 Treppen
dreiSegmentTreppe_t treppen[]={
{2,3,0b00,NICHTGESCHALTET,0,8,9,10},
{4,5,0b00,NICHTGESCHALTET,0,11,11,11},
};
Die beiden ersten Zahlen in einer Zeile stehen für den Pin des unteren und oberen Lichtschalters.
Die letzten drei Zahlen in einer Zeile stehen für die Pins der angeschlossenen drei Lichtsegmente.
Wenn eine Treppe nur ein einziges Lichtsegment hat, einfach dreimal denselben Pin definieren.
Um den Code ohne angeschlossene Beleuchtung testen zu können, gibt es Debug-Ausgaben auf Serial.
Die Schalter müssen entweder per Push-Pull angesteuert werden oder es muß ein Taster mit PullDown-Widerstand angeschlossen sein. Für invertierte Logik mit Schaltern, die die internen PullUp-Widerstände des Atmegas nutzen, müßte der Code geringfügig geändert werden.
Die Anzahl der ansteuerbaren Treppen ist nur durch die Zahl der freien I/O-Pins begrenzt. Im Sketch selbst wird die Programmlogik jeweils in einer Schleife abgearbeitet, mit der Treppennummer als Schleifenindex.
for(int i=0;i<anzahlTreppen;i++)
{
// Hier der Code pro Treppe
}
Der vollständige Sketch:
#define TIMEOUT 10000L // Nach 60000 ms = 60 s Licht abschalten
#define TIMEDELAY 1000L // 1000 ms = 1 s Zeitverzögerung zwischen den Segmenten
// Eine Treppe als "struct" mit verschiedenen Elementen definieren
enum {NICHTGESCHALTET,UNTENGESCHALTET,OBENGESCHALTET};
struct dreiSegmentTreppe_t {
byte schalterUntenPin; // Pin des Schalters unten an der Treppe
byte schalterObenPin; // Pin des Schalters oben an der Treppe
byte schalterState; // letzter Schaltzustand (in den beiden untersten Bits codiert
byte geschaltet; // NICHTGESCHALTET,UNTENGESCHALTET,OBENGESCHALTET}
unsigned long startZeit; // enthält die Zeit, wann das Licht eingeschaltet wurde
byte lichtA_Pin; // Pin für Lampe-A
byte lichtB_Pin; // Pin für Lampe-B (falls nur eine Lampe, identisch mit lichtA_Pin)
byte lichtC_Pin; // Pin für Lampe-C (falls nur eine Lampe, identisch mit lichtA_Pin)
};
// Ein Array mit 2 Elementen definieren und mit Werten belegen, entsprechend 2 Treppen
dreiSegmentTreppe_t treppen[]={
{2,3,0b00,NICHTGESCHALTET,0,8,9,10},
{4,5,0b00,NICHTGESCHALTET,0,11,11,11},
};
int anzahlTreppen=sizeof(treppen)/sizeof(treppen[0]);
void eingabe()
{
byte schalterState;
for(int i=0;i<anzahlTreppen;i++)
{
if(treppen[i].geschaltet!=NICHTGESCHALTET) continue; // Schleifenindex abbrechen, falls bereits geschaltet
schalterState=0b00;
bitWrite(schalterState,0,digitalRead(treppen[i].schalterUntenPin));
bitWrite(schalterState,1,digitalRead(treppen[i].schalterObenPin));
if (schalterState!=0b00 && treppen[i].schalterState==0b00)
{
if(bitRead(schalterState,0)) treppen[i].geschaltet=UNTENGESCHALTET;
else if(bitRead(schalterState,1)) treppen[i].geschaltet=OBENGESCHALTET;
treppen[i].startZeit=millis();
}
treppen[i].schalterState=schalterState;
}
}
void ausgabeSegment(char treppe, char segment, boolean newState, byte pin)
{
if(digitalRead(pin)==newState) return; // keine Umschaltung notwendig, es bleibt wie es war
digitalWrite(pin,newState); // Lampe
float f=millis()/1000.0; // Aktuelle Zeit in Gleitkommazahl wandeln
Serial.print(treppe+1);Serial.print(segment);
if(newState) Serial.print(" EIN Pin-"); else Serial.print(" AUS Pin- ");
Serial.print(pin);Serial.print(" ");
Serial.print(f,3);
Serial.println("s");
}
void ausgabe()
{
boolean lichtA, lichtB, lichtC;
unsigned long now=millis(); // Millisekundentimer aktuell
for(int i=0;i<anzahlTreppen;i++)
{
// Erste Annahme: Das Treppenlicht sei nicht geschaltet und alle Lampen an dieser Treppe aus
lichtA=false;lichtB=false;lichtC=false;
// Zuerst prüfen, ob Abschaltzeit erreicht ist und ggf. abschalten
if (treppen[i].geschaltet && now-treppen[i].startZeit>TIMEOUT+2*TIMEDELAY) treppen[i].geschaltet=false;
if (treppen[i].geschaltet==UNTENGESCHALTET) // Es ist doch Licht geschaltet
{
if(now-treppen[i].startZeit<TIMEOUT) lichtA=true;
if(now-treppen[i].startZeit>TIMEDELAY && now-treppen[i].startZeit<TIMEOUT+TIMEDELAY) lichtB=true;
if(now-treppen[i].startZeit>2*TIMEDELAY) lichtC=true;
}
else if(treppen[i].geschaltet==OBENGESCHALTET) // Es ist doch Licht geschaltet
{
if(now-treppen[i].startZeit<TIMEOUT) lichtC=true;
if(now-treppen[i].startZeit>TIMEDELAY && now-treppen[i].startZeit<TIMEOUT+TIMEDELAY) lichtB=true;
if(now-treppen[i].startZeit>2*TIMEDELAY) lichtA=true;
if(treppen[i].lichtA_Pin==treppen[i].lichtB_Pin) lichtA=lichtC;
}
// Jetzt unterschiedliche Logik für Treppen mit 1 oder 3 Lampen
ausgabeSegment(i,'A', lichtA, treppen[i].lichtA_Pin);
if(treppen[i].lichtA_Pin!=treppen[i].lichtB_Pin)
{
ausgabeSegment(i,'B', lichtB, treppen[i].lichtB_Pin);
ausgabeSegment(i,'C', lichtC, treppen[i].lichtC_Pin);
}
}
}
void setup() {
Serial.begin(9600);
for(int i=0;i<anzahlTreppen;i++)
{
pinMode(treppen[i].schalterUntenPin,INPUT); // unterer Schalter ist INPUT
pinMode(treppen[i].schalterObenPin,INPUT); // oberer Schalter ist INPUT
pinMode(treppen[i].lichtA_Pin,OUTPUT); // Lampen als OUTPUT
pinMode(treppen[i].lichtB_Pin,OUTPUT);
pinMode(treppen[i].lichtC_Pin,OUTPUT);
}
}
void loop() {
eingabe();
ausgabe();
}