Edit: Objektnamen an aktuelle MobaTools angepasst
Hallo liebe Stummis und Arduino-Interessierte :D
nach den theoretischen Vorüberlegungen wollen wir uns jetzt daranmachen und das Ganze zu einem lauffähigen Sketch zusammenbauen. Dann bleibt das nicht so theoretisch, und es tut sich schon was, bevor wir das Ganze um eine unabhängige Ampelsteuerung erweitern (Multitasking 8) ).
Da rufen wir uns in Erinnerung, wie so ein Sketch aufgebaut ist. So ein Sketch besteht zumindest aus 3 Abschnitten:
- Im ersten Block sagen wir dem Arduino, was wir alles benutzen wollen. Wir binden Bibliotheken ein, definieren die globalen Variablen und Libraryobjekte, die wir verwenden und ordnen gegebenenfalls konstanten Zahlen auch einen Namen zu, damit man sie im Bedarfsfall einfacher ändern kann (z.B. die Pin-Nummern).
- der setup-Block. In der setup-Funktion werden alle die Dinge erledigt, die beim Starten des Sketches einmalig gemacht werden müssen. Dazu gehört die Festlegung ob die verwendeten Pins Ein- oder Ausgänge sind und das Initiieren der verwendeten Library-Objekte
- der loop-Block. Das eigentliche 'Herzstück' des Sketches. Hier dreht unsere 'Arduino-Lok' dann endlos ihre Runden :D :D
Was gehört bei unserem Sketch nun alles in den ersten Block?Da wir die
MobaTools Lib verwenden wollen, muss die als erstes mal eingebunden werden:
Wer sie noch nicht auf seinem Rechner hat, kann sie hier herunterladen. Die zip-Datei an einem beliebigen Ort speichern. Dann in der Arduino IDE unter 'Sketch'->'Bibliothek einbinden'->'.ZIP-Bibliothek hinzufügen...' zu der heruntergeladenen Datei navigieren und OK drücken. Den Rest macht die IDE, und nun kann die Lib verwendet werden.
Dann müssen wir festlegen, welche Pins wir verwenden wollen:
1
2
3
4
5
// Festlegen der Anschlüsse (Pinnummer) für Ein- und Ausgänge
const byte linksPin = 4; // linke Lampe
const byte rechtsPin = 5; // rechte Lampe
const byte belegtPin = 8; // Eingang 'Zug kommt'
Die könnt ihr gegebenenfalls anpassen. Der 'belegtPin' Eingang schaltet in unserer ersten Version den Warnblinker einfach an bzw. aus. Die Schaltung dazu ist recht simpel ( auf dem UNO funktioniert es mit den gleichen Pinnr. natürlich genauso ):
Von den MobaTools verwenden wir den MoToTimer für die Zeitmessung, und SoftLed für die 'weiche' Ansteuerung der Leds. Timer brauchen wir nur einen, Softleds aber 2 ( für rechts und links )
1
2
3
4
5
6
7
8
9
10
// Benötigte MobaTools Objekte:
MoToTimer StoppUhr; // Zum Messen von Zeiten
MoToSoftLed LampeLinks;
MoToSoftLed LampeRechts;
// Zeiten für den Blinkrhythmus ( in ms )
const int STARTZEIT = 500;
const int BLINKZEIT = 600;
const int FADEZEIT = 200;
Für die Lampen des Wechselblinkers habe ich da auch gleich noch die Zeiten festgelegt: wie lange sind beim Start beide gleichzeitig an, und in welchem Rhythmus blinken sie danach. Mit den Zeiten kann man dann auch ein wenig experimentieren. FADEZEIT gibt an, wie lange das auf/Abblenden dauert.
Ja, und dann brauchen wir noch 2 Variable, die wir oben im Code für unseren Zustandsautomaten schon verwendet haben:
1
2
3
4
// Variable
boolean bueBelegt; // = TRUE, wenn sich ein Zug im Bereich des Bue befindet
byte wBlinkerZustand; // aktueller Zustand unseres Blinkerautomaten
Damit ist unser erster Block komplett.
Im Setup
müssen wir den Eingangspin als 'Eingang' definieren, und unsere 'SoftLed Objekte initiieren. Das Schalten der Pins auf 'Ausgang' macht die MobaTools Lib. Als letztes setzen wir dann noch den Startzustand unseres Blinkautomaten:
1
2
3
4
5
6
7
8
9
10
11
12
void setup() {
// Pins einrichten
pinMode( belegtPin, INPUT_PULLUP ); // Mit einem Schalter nach GND wird Blinker eingeschaltet
LampeLinks.attach( linksPin ); // Zuordnung der Softleds zu den Ausgangspins
LampeRechts.attach( rechtsPin );
LampeLinks.riseTime( FADEZEIT ); // Überblendzeit einstellen
LampeRechts.riseTime( FADEZEIT );
wBlinkerZustand = 1; // Startzustand des Blinkautomaten.
}
Nun noch zum loop()
Der besteht im Wesentlichen ja nur aus der switch-Anweisung mit den case-Blöcken aus dem vorigen Post. Ganz am Anfang muss unser Lokführer aber noch kurz Station machen, unseren Eingangspin abfragen und den gelesenen Wert in der Variablen 'bueBelegt' ablegen:
1
2
bueBelegt = not digitalRead( belegtPin ); // ein LOW-Level am Eingangspin schaltet den Blinker ein
Der fertige Sketch
Damit haben wir jetzt den ganzen Sketch zusammem, den wir so in der IDE übersetzen und auf den Arduino laden können:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
/* Tutorial 'Zeitabläufe ohne delay() '
* Einfacher Wechselblinker ( unbeschrankter Bahnübergang )
*/
#include <MobaTools.h>
// Festlegen der Anschlüsse (Pinnummer) für Ein- und Ausgänge
const byte linksPin = 4; // linke Lampe
const byte rechtsPin = 5; // rechte Lampe
const byte belegtPin = 8; // Eingang 'Zug kommt'
// Benötigte MobaTools Objekte:
MoToTimer StoppUhr; // Zum Messen von Zeiten
MoToSoftLed LampeLinks;
MoToSoftLed LampeRechts;
// Zeiten für den Blinkrhythmus ( in ms )
const int STARTZEIT = 500;
const int BLINKZEIT = 600;
const int FADEZEIT = 200;
// Variable
boolean bueBelegt; // = TRUE, wenn sich ein Zug im Bereich des Bue befindet
byte wBlinkerZustand; // aktueller Zustand unseres Blinkerautomaten
void setup() {
// Pins einrichten
pinMode( belegtPin, INPUT_PULLUP ); // Mit einem Schalter nach GND wird Blinker eingeschaltet
LampeLinks.attach( linksPin ); // Zuordnung der Softleds zu den Ausgangspins
LampeRechts.attach( rechtsPin );
LampeLinks.riseTime( FADEZEIT ); // Überblendzeit einstellen
LampeRechts.riseTime( FADEZEIT );
wBlinkerZustand = 1; // Startzustand des Blinkautomaten.
}
void loop() {
// Belegtzusatnd abfragen. Das machen wir hier jetzterstmal ganz einfach: Letztendlich
// schalten wir mit dem Eingang einfach den Wechselblinker ein und aus.
// Im realen Praxisfall könnte hier gegebenenfalls auch ein komplexere Logik stehen, um zu
// erkennen, ob ein Zug sich nähert oder den Bü wieder verlassen hat.
bueBelegt = not digitalRead( belegtPin ); // ein LOW-Level am Eingangspin schaltet den Blinker ein
switch ( wBlinkerZustand ) {
// je nach Wert der Variable wBlinkerZustand, wird die entsprechende 'case' Zeile angesprungen
case 1: // Grundzustand, abfragen, ob sich ein Zug nähert ( z.B. über einen Belegtmelder )
if ( bueBelegt ) {
// Der Zug ist in den Belegtabschnitt vor der Schranke eingefahren
// beide Lampen einschalten
LampeLinks.on();
LampeRechts.on();
// Stoppuhr mit der Zeit die beide Lampen an sein sollen vorbelegen
StoppUhr.setTime( STARTZEIT ); // StoppUhr 'aufziehen'
// in den 2. Zustand wechseln
wBlinkerZustand = 2; // Ab dem nächsten loop-Durchlauf werden nur die Anweisungen des case 2 ausgeführt
}
break; // Ende der Anweisungen für den 1. Zustand
//-------------------------------------------------------------------------
case 2: // beide Lampen ein, wir fragen ab, ob die Stoppuhr abgelaufen ist.
if ( not StoppUhr.running() ) {
// Die Stoppuhr läuft nicht mehr, die Zeit ist um
LampeRechts.off();
StoppUhr.setTime( BLINKZEIT ); // Stoppuhr 'aufziehen'
// in den 3. Zustand wechseln
wBlinkerZustand = 3; // Ab dem nächsten loop-Durchlauf werden nur die Anweisungen des case 3 ausgeführt
}
break; // Ende der Anweisungen für den 2. Zustand
//-------------------------------------------------------------------------
case 3: // linke Lampen ist an, rechte aus: wir fragen ab, ob die Stoppuhr abgelaufen ist.
if ( not StoppUhr.running() ) {
// Die Stoppuhr läuft nicht mehr, die Zeit ist um, Lampen umschalten
LampeLinks.off();
LampeRechts.on();
StoppUhr.setTime( BLINKZEIT ); // Stoppuhr 'aufziehen'
// in den 4. Zustand wechseln
wBlinkerZustand = 4; // Ab dem nächsten loop-Durchlauf werden nur die Anweisungen des case 4 ausgeführt
}
break; // Ende der Anweisungen für den 3. Zustand
//-------------------------------------------------------------------------
case 4: // linke Lampen ist aus, rechte an: wir fragen ab, ob die Stoppuhr abgelaufen ist.
if ( not StoppUhr.running() ) {
// Die Stoppuhr läuft nicht mehr, die Zeit ist um, Lampen umschalten
LampeLinks.on();
LampeRechts.off();
StoppUhr.setTime( BLINKZEIT ); // Stoppuhr 'aufziehen'
// wieder in den 3. Zustand wechseln
wBlinkerZustand = 3; // Ab dem nächsten loop-Durchlauf werden nur die Anweisungen des case 3 ausgeführt
}
// Im 4. Zustand müssen wir auch noch abfragen, ob der Zug den Belegtabschnitt verlassen hat
if ( not bueBelegt ) {
// Der Zug ist komplett über den Bü gefahren, die Straße ist wieder frei
// Beide Lampen ausschalten
LampeLinks.off();
LampeRechts.off();
// wieder in den 1. Zustand wechseln. Eine Zeitüberwachung wird nicht gebraucht
wBlinkerZustand = 1; // Ab dem nächsten loop-Durchlauf werden nur die Anweisungen des case 1 ausgeführt
}
break; // Ende der Anweisungen für den 4. Zustand
} // Ende des switch-Blockes
}
Bevor es weitergeht, sollte das bei Euch so funktionieren. Deshalb mache ich hier jetzt erstmal etwas Pause. Über Rückmeldungen würde ich mich natürlich freuen. Ich habe versucht den Sketch möglichst ausführlich zu kommentieren, damit man - zusammen mit diesem Tutorial - auch versteht was da abläuft.
Wenn noch etwas unklar ist - einfach fragen. Ich weis, am Anfang klemmt es oft an Stellen, die einem später ganz selbstverständlich erscheinen.