RE: Arduino: Zeitsteuerungen ohne Delay - ein kleines Tutorial

#26 von MicroBahner , 18.11.2018 10:33

Weiter geht's
Im Prinzip könnten wir unsere Ampel jetzt genauso umsetzen, wie wir das beim Wechselblinker getan haben. Um Im Eisenbahnbild zu bleiben: Einen Bahnhof mit einer 8-fach Eingangsweiche. Dann in jedem Strang eine Weiche 'Zeit abgelaufen' und im 'abgelaufen' Gleis wieder die Aktionen.
Allerdings würden wir schnell feststellen, dass die Aktionen im Gleis 'Zeit abgelaufen' immer dieselben sind: Zeit neu aufziehen, Ampelausgänge schalten und auf nächsten Zustand stellen. Unterschiedlich sind eigentlich nur die Werte der jeweiligen Aktion: Zeitdauer, ob die Ampelausgänge ein- und ausgeschaltet werden sollen und die Nummer des nächsten Zustands. Wir können den Ablauf da auch eigentlich in einer Tabelle darstellen:

Der Merker oben zeigt dann immer auf den aktuellen Zustand. Wir brauchen für unsere Lok also eigentlich nur ein Gleis mit der Verzweigung 'Zeit abgelaufen'. Die Mehrfachweiche am Anfang sparen wir uns. Dafür hängen wir an der Station obige Tabelle für unseren Lokführer auf. Jedesmal wenn er vorbeikommt, setzt er Timer und Ausgänge entsprechend der Werte in der aktuellen Spalte und schiebt den Merker eins weiter. Ist er am Ende der Tabelle angekommen, schiebt er den Merker wieder auf den Tabellenanfang. Der Ablaufplan ist also recht einfach. (Den Gleiskreis zu schliessen habe ich mir auf dem Bildchen jetzt mal geschenkt ):


Im nächsten Schritt geht es dann darum, wie man so eine Tabelle programmtechnisch realisiert.


viele Grüße
Franz-Peter
Ein 'elektromechanisches' Stellwerk
Der (ehemalige) 'Eisberg'


hubedi hat sich bedankt!
 
MicroBahner
Metropolitan (MET)
Beiträge: 2.833
Registriert am: 28.11.2012
Ort: Mittelfranken
Gleise Tillig Elite
Steuerung Eigenbau
Stromart Analog


RE: Arduino: Zeitsteuerungen ohne Delay - ein kleines Tutorial

#27 von MicroBahner , 18.11.2018 14:44

Edit: Objektnamen an aktuelle MobaTools angepasst

Wem beim Programmieren schonmal 'Arrays' über den Weg gelaufen sind, der weis auch, wie wir unsere Tabelle realisieren werden.
Arrays - auch Felder genannt - sind eine Reihe von Daten, auf die über einen Index ( sozusagen die 'Spaltennummer' ) zugegriffen werden kann. Ein einfaches Array entspricht so also genau einer Tabellenzeile in unserer Tabelle. Die erste Zeile unserer Tabelle können wir z.B. so definieren:

1
2
 
const byte zeitDauer  [] = { 30  , 3  , 3  , 3  , 20 , 3  , 3  , 3  };
 
 

Die beiden eckigen Klammern sagen dem Compiler, das wir ein Array definieren. Üblicherweise steht dazwischen wieviele Elemente das Feld umfassen soll. Also z.B. [8]. Da wir das Array aber gleich mit Werten füllen, müssen wir die Länge des Feldes nicht angeben. Das erkennt der Compiler an der Zahl der Initiierungswerte zwischen den geschweiften Klammern {..}.
Beim Zugriff müssen wir aber beachten, dass - wie bei Computern üblich - die Zählweise bei 0 beginnt. Der erste Wert in der Zeile ( die '30' ) wird also über den Index '0' angesprochen. Mit der Programmzeile

1
 
a = zeitDauer[0];
 

weisen wir also der Variablen a den Wert '30' zu. Mit

1
 
a = zeitDauer[4];
 

wäre es in unserem Fall der Wert '20'.

Definieren wir nun für jede Tabellenzeile so ein Array, dann sieht die ganze Tabelle so aus:

1
2
3
4
5
6
7
8
9
10
11
 
// Tabelle für die Ampelzustände
// Ampelphase: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8
// Tabellenindex: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7
const byte zeitDauer [] = { 30 , 3 , 3 , 3 , 20 , 3 , 3 , 3 };
const bool hauptRot [] = { OFF ,OFF , ON , ON , ON , ON , ON , ON };
const bool hauptGelb [] = { OFF , ON ,OFF ,OFF ,OFF ,OFF ,OFF , ON };
const bool hauptGruen [] = { ON ,OFF ,OFF ,OFF ,OFF ,OFF ,OFF ,OFF };
const bool nebenRot [] = { ON , ON , ON , ON ,OFF ,OFF , ON , ON };
const bool nebenGelb [] = { OFF ,OFF ,OFF , ON ,OFF , ON ,OFF ,OFF };
const bool nebenGruen [] = { OFF ,OFF ,OFF ,OFF , ON ,OFF ,OFF ,OFF };
 
 


An die Fortgeschrittenen: natürlich ist das nicht die eleganteste, und vor allem nicht die platzsparendste Variante. Aber ich denke, für den Anfang am leichtesten nachzuvollziehen.

Die Umsetzung des gesamten Ablaufs der Ampelphasen entsprechend dem obigen Gleis- bzw Ablaufplans ist dann eigentlich recht kurz:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 

if( !AmpelTimer.running() ) {
// Zeit abgelaufen
// Ampel schalten
hRot.write( hauptRot[ampelTabIx] );
hGelb.write( hauptGelb[ampelTabIx] );
hGruen.write( hauptGruen[ampelTabIx] );
nRot.write( nebenRot[ampelTabIx] );
nGelb.write( nebenGelb[ampelTabIx] );
nGruen.write( nebenGruen[ampelTabIx] );
// Zeit setzen ( da der Timer in ms rechnet, müssen die Tabellenwerte mit 1000
// multipliziert werden )
AmpelTimer.setTime( zeitDauer[ampelTabIx] * 1000 );
// Merker weiterrückem
if( ampelTabIx >= tabMax ) {
// Tabellenende erreicht
ampelTabIx = 0;
} else {
ampelTabIx++;
}
}
 
 



So, nun müssen wir das nur noch mit den notwendigen Grunddefinitionen und Initiierungen kombinieren und bekommen dann den fertigen Ampelsketch:

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
 

// Ampelsteuerung
 
// Ampelsteuerung an einer einfachen Kreuzung
// Die Ampelphasen werden über eine Tabelle definiert
 
#include <MobaTools.h>
 
// Definition der Ausgangspins:
const byte hRotPin = A0; // Ampel an der Hauptstraße
const byte hGelbPin = A1;
const byte hGruenPin = A2;
const byte nRotPin = A3; // Ampel an der Nebenstraße
const byte nGelbPin = A4;
const byte nGruenPin = A5;
 

// Tabelle für die Ampelzustände
// Ampelphase: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8
// Tabellenindex: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7
const byte zeitDauer [] = { 30 , 3 , 3 , 3 , 20 , 3 , 3 , 3 };
const bool hauptRot [] = { OFF ,OFF , ON , ON , ON , ON , ON , ON };
const bool hauptGelb [] = { OFF , ON ,OFF ,OFF ,OFF ,OFF ,OFF , ON };
const bool hauptGruen [] = { ON ,OFF ,OFF ,OFF ,OFF ,OFF ,OFF ,OFF };
const bool nebenRot [] = { ON , ON , ON , ON ,OFF ,OFF , ON , ON };
const bool nebenGelb [] = { OFF ,OFF ,OFF , ON ,OFF , ON ,OFF ,OFF };
const bool nebenGruen [] = { OFF ,OFF ,OFF ,OFF , ON ,OFF ,OFF ,OFF };
 
const byte tabMax = sizeof(zeitDauer)-1; // Tabellenindex startet bei 0 ( deshalb die -1 für den höchsten Index )
byte ampelTabIx; // läuft von 0 .. 7
 
// Einrichten der notwendigen MoBaTools Objekte:
MoToTimer AmpelTimer;
MoToSoftLed hRot;
MoToSoftLed hGelb;
MoToSoftLed hGruen;
MoToSoftLed nRot;
MoToSoftLed nGelb;
MoToSoftLed nGruen;
 

void setup() {
// Softled Objekte initiieren
hRot.attach( hRotPin );
hRot.riseTime( 200 );
hGelb.attach( hGelbPin );
hGelb.riseTime( 200 );
hGruen.attach( hGruenPin );
hGruen.riseTime( 200 );
nRot.attach( nRotPin );
nRot.riseTime( 200 );
nGelb.attach( nGelbPin );
nGelb.riseTime( 200 );
nGruen.attach( nGruenPin );
nGruen.riseTime( 200 );
 
ampelTabIx = 0; // Das System startet mit freier Fahrt auf der Hauptstraße

}
 
void loop() {
// Tabellengesteuerte Ampel
if( !AmpelTimer.running() ) {
// Zeit abgelaufen
// Ampel schalten
hRot.write( hauptRot[ampelTabIx] );
hGelb.write( hauptGelb[ampelTabIx] );
hGruen.write( hauptGruen[ampelTabIx] );
nRot.write( nebenRot[ampelTabIx] );
nGelb.write( nebenGelb[ampelTabIx] );
nGruen.write( nebenGruen[ampelTabIx] );
// Zeit setzen ( da der Timer in ms rechnet, müssen die Tabellenwerte mit 1000
// multipliziert werden )
AmpelTimer.setTime( zeitDauer[ampelTabIx] * 1000 );
// Merker weiterrückem
if( ampelTabIx >= tabMax ) {
// Tabellenende erreicht
ampelTabIx = 0;
} else {
ampelTabIx++;
}
}
}
 
 



Das sollte jetzt erstmal bei Euch laufen. Wie immer: wenn etwas unklar ist: einfach fragen!

Als Nächstes werden wir dann beides kombinieren. Und ihr werdet sehen: man kann es einfach passend zusammenkopieren 8)


viele Grüße
Franz-Peter
Ein 'elektromechanisches' Stellwerk
Der (ehemalige) 'Eisberg'


hubedi und MobaPro59 haben sich bedankt!
 
MicroBahner
Metropolitan (MET)
Beiträge: 2.833
Registriert am: 28.11.2012
Ort: Mittelfranken
Gleise Tillig Elite
Steuerung Eigenbau
Stromart Analog

zuletzt bearbeitet 09.08.2021 | Top

RE: Arduino: Zeitsteuerungen ohne Delay - ein kleines Tutorial

#28 von ThKaS , 21.11.2018 09:41

Moin moin Franz-Peter,

danke auch hierfür.
Der Code ist durchaus verständlich und auch wieder gut beschrieben.
Mehr Mühe macht es, eine entsprechende Ampel hardwareseitig zusammen zu bauen
Da dauern die Versuche dann naturgemäß länger


lieben Gruss von südlich des Weisswurst-Äquators
Thomas

guckst: runderneuerte https://www.thkas-moba.de ‹(•¿•)› www.mucis.de

‹(•¿•)›

Mä-K-Gleis, Tams MC, Multi-Kulti Decoder, WDP


 
ThKaS
InterCityExpress (ICE)
Beiträge: 2.200
Registriert am: 28.04.2005
Homepage: Link


RE: Arduino: Zeitsteuerungen ohne Delay - ein kleines Tutorial

#29 von MicroBahner , 21.11.2018 14:00

Hallo Thomas,
nun ja, rein für den Test des Sketches würde ja ein minimalistischer Aufbau auf dem Steckbrett reichen :


Aber ich sehe ein, dass das einen echten Modellbahner nicht befriedigen kann


viele Grüße
Franz-Peter
Ein 'elektromechanisches' Stellwerk
Der (ehemalige) 'Eisberg'


hubedi hat sich bedankt!
 
MicroBahner
Metropolitan (MET)
Beiträge: 2.833
Registriert am: 28.11.2012
Ort: Mittelfranken
Gleise Tillig Elite
Steuerung Eigenbau
Stromart Analog


RE: Arduino: Zeitsteuerungen ohne Delay - ein kleines Tutorial

#30 von ThKaS , 21.11.2018 15:00

...ja, nee, is klar
... Steckbrett ist ja schon "im Zulauf"....


lieben Gruss von südlich des Weisswurst-Äquators
Thomas

guckst: runderneuerte https://www.thkas-moba.de ‹(•¿•)› www.mucis.de

‹(•¿•)›

Mä-K-Gleis, Tams MC, Multi-Kulti Decoder, WDP


 
ThKaS
InterCityExpress (ICE)
Beiträge: 2.200
Registriert am: 28.04.2005
Homepage: Link


RE: Arduino: Zeitsteuerungen ohne Delay - ein kleines Tutorial

#31 von Railcar ( gelöscht ) , 21.11.2018 16:20

Hallo Franz-Peter,
ist das links im Bild ein Widerstandsarray?
8 x wieviel Ohm?


Railcar

RE: Arduino: Zeitsteuerungen ohne Delay - ein kleines Tutorial

#32 von MicroBahner , 21.11.2018 16:29

Hallo Ulrich,
ja - 8x1k
Der Wert ist aber recht unkritisch, hängt auch von den Leds ab. Ich habe da LowCurrent Leds drin, da ist das schon eher zu wenig.


viele Grüße
Franz-Peter
Ein 'elektromechanisches' Stellwerk
Der (ehemalige) 'Eisberg'


 
MicroBahner
Metropolitan (MET)
Beiträge: 2.833
Registriert am: 28.11.2012
Ort: Mittelfranken
Gleise Tillig Elite
Steuerung Eigenbau
Stromart Analog


RE: Arduino: Zeitsteuerungen ohne Delay - ein kleines Tutorial

#33 von ThKaS , 26.11.2018 20:55

Zitat

Hallo Thomas,
..., ein minimalistischer Aufbau auf dem Steckbrett ...



so, kleine Rückmeldung.
Es ampelt

Zum Test habe ich die Lichtwechsel aber auf "hektisch" eingestellt, sonst bewegt sich ja nichts.


lieben Gruss von südlich des Weisswurst-Äquators
Thomas

guckst: runderneuerte https://www.thkas-moba.de ‹(•¿•)› www.mucis.de

‹(•¿•)›

Mä-K-Gleis, Tams MC, Multi-Kulti Decoder, WDP


 
ThKaS
InterCityExpress (ICE)
Beiträge: 2.200
Registriert am: 28.04.2005
Homepage: Link


RE: Arduino: Zeitsteuerungen ohne Delay - ein kleines Tutorial

#34 von ThKaS , 26.11.2018 22:31

und noch eine kleine Modifikation dazu.

Habe die Kreuzung um Fussgängerampeln erweitert.
Ziel: kurz vor Ende der Grünphase der "Autoampel" schaltet die zugehörige Fussgängerampel schon auf rot. Mit der Grünphase für die Autoampel wird auch die Fussgängerampel rot. 2 Sekunden sind alle Ampeln rot.

Array ist nun 10 Spalten breit und 10 Zeilen lang. Für die Fussgängerampel habe ich die Anschlüsse D2-D5 genutzt

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
105
106
107
108
109
110
 

// Ampelsteuerung mit Fussg&#228;ngerampel
 
// Ampelsteuerung an einer einfachen Kreuzung mit Fussg&#228;ngerampel.
// Die Ampelphasen werden &#252;ber eine Tabelle definiert
 
#include &lt;MobaTools.h&gt;
 
// Definition der Ausgangspins:
const byte hRotPin = A0; // Ampel an der Hauptstra&#223;e
const byte hGelbPin = A1;
const byte hGruenPin = A2;
const byte FhRotPin = 2; // Fussgaengerampel Hauptstrasse
const byte FhGruenPin = 3;
 
const byte nRotPin = A3; // Ampel an der Nebenstra&#223;e
const byte nGelbPin = A4;
const byte nGruenPin = A5;
const byte FnRotPin = 4; // Fussgaengerampel Nebenstrasse
const byte FnGruenPin = 5;
 

// Tabelle f&#252;r die Ampelzust&#228;nde
// Ampelphase: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |9 | 10
// Tabellenindex: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
// const byte zeitDauer [] = { 30 , 3 , 3 , 3 , 20 , 3 , 3 , 3 }; Vorgabe aus stummiforum
const byte zeitDauer [] = { 20 , 2 , 2 , 3 , 2 , 10 , 2 , 2 , 3 , 2 };
const bool hauptRot [] = { OFF ,OFF , OFF , ON, ON , ON , ON , ON , ON ,ON }; //
const bool hauptRotFRot [] = { OFF ,ON , ON , ON, ON , ON , ON , ON , ON, ON };
const bool hauptGelb [] = { OFF , OFF , ON ,OFF ,OFF ,OFF , OFF ,OFF ,OFF , ON };
const bool hauptGruen [] = { ON ,ON, OFF , OFF ,OFF ,OFF ,OFF ,OFF ,OFF ,OFF };
const bool hauptGruenFGruen [] = { ON ,OFF, OFF , OFF ,OFF ,OFF ,OFF ,OFF ,OFF ,OFF };
const bool nebenRot [] = { ON , ON , ON , ON ,ON , OFF , OFF ,OFF , ON , ON };
const bool nebenRotFRot [] = { ON , ON , ON , ON ,ON , OFF , ON ,ON , ON , ON };
const bool nebenGelb [] = { OFF ,OFF ,OFF , OFF, ON ,OFF , OFF , ON ,OFF ,OFF };
const bool nebenGruen [] = { OFF ,OFF ,OFF ,OFF , OFF , ON , ON ,OFF ,OFF ,OFF };
const bool nebenGruenFGruen [] = { OFF ,OFF ,OFF ,OFF , OFF , ON , OFF ,OFF ,OFF ,OFF };
 
const byte tabMax = sizeof(zeitDauer)-1; // Tabellenindex startet bei 0 ( deshalb die -1 f&#252;r den h&#246;chsten Index )
byte ampelTabIx; // l&#228;uft von 0 .. 9
 
// Einrichten der notwendigen MoBaTools Objekte:
EggTimer AmpelTimer;
SoftLed hRot;
SoftLed hGelb;
SoftLed hGruen;
SoftLed nRot;
SoftLed nGelb;
SoftLed nGruen;
SoftLed fhRot;
SoftLed fhGruen;
SoftLed fnRot;
SoftLed fnGruen;
 
void setup() {
// Softled Objekte initiieren
hRot.attach( hRotPin );
hRot.riseTime( 200 );
hGelb.attach( hGelbPin );
hGelb.riseTime( 200 );
hGruen.attach( hGruenPin );
hGruen.riseTime( 200 );
fhRot.attach( FhRotPin );
fhRot.riseTime( 200 );
fhGruen.attach( FhGruenPin );
fhGruen.riseTime( 200 );

nRot.attach( nRotPin );
nRot.riseTime( 200 );
nGelb.attach( nGelbPin );
nGelb.riseTime( 200 );
nGruen.attach( nGruenPin );
nGruen.riseTime( 200 );
fnRot.attach( FnRotPin );
fnRot.riseTime( 200 );
fnGruen.attach( FnGruenPin );
fnGruen.riseTime( 200 );

ampelTabIx = 0; // Das System startet mit freier Fahrt auf der Hauptstra&#223;e

}
 
void loop() {
// Tabellengesteuerte Ampel
if( !AmpelTimer.running() ) {
// Zeit abgelaufen
// Ampel schalten
hRot.write( hauptRot[ampelTabIx] );
fhRot.write( hauptRotFRot[ampelTabIx] );
hGelb.write( hauptGelb[ampelTabIx] );
hGruen.write( hauptGruen[ampelTabIx] );
fhGruen.write( hauptGruenFGruen[ampelTabIx] );
nRot.write( nebenRot[ampelTabIx] );
fnRot.write( nebenRotFRot[ampelTabIx] );
nGelb.write( nebenGelb[ampelTabIx] );
nGruen.write( nebenGruen[ampelTabIx] );
fnGruen.write( nebenGruenFGruen[ampelTabIx] );
// Zeit setzen ( da der Timer in ms rechnet, m&#252;ssen die Tabellenwerte mit 1000
// multipliziert werden )
AmpelTimer.setTime( zeitDauer[ampelTabIx] * 1000 );
// Merker weiterr&#252;ckem
if( ampelTabIx &gt;= tabMax ) {
// Tabellenende erreicht
ampelTabIx = 0;
} else {
ampelTabIx++;
}
}
}
 
 



Danke, Franz-Peter, macht Spass


lieben Gruss von südlich des Weisswurst-Äquators
Thomas

guckst: runderneuerte https://www.thkas-moba.de ‹(•¿•)› www.mucis.de

‹(•¿•)›

Mä-K-Gleis, Tams MC, Multi-Kulti Decoder, WDP


 
ThKaS
InterCityExpress (ICE)
Beiträge: 2.200
Registriert am: 28.04.2005
Homepage: Link


RE: Arduino: Zeitsteuerungen ohne Delay - ein kleines Tutorial

#35 von MicroBahner , 28.11.2018 18:26

Edit: Objektnamen an aktuelle MobaTools angepasst

Hallo Thomas,
super, so ist's gedacht - Spass muss es machen, sonst wird's nix :D :D .
Zu deiner Erweiterung habe ich später auch noch einen Vorschlag


Nun wollen wir mal drangehen unsere beide Sketches ( Wechselblinker und Ampel ) zusammenzuführen.

Zuerst zur Veranschaulichung mal der Ablauf(Gleis )plan des gesamten Sketches.
Wir sehen da schon, dass die beiden Ablaufpläne einfach hintereinandergesetzt sind. Und genau so werden wir es später im Code machen.

Wobei der Ablaufplan ja eigentlich immer nur unseren 3. Block, den Loop, visualisiert. Wir hatten ja schonmal davon gesprochen (Post #13), dass ein Sketch - grob gesehen - aus 3 Blöcken besteht:

  1. Definitionen
  2. Setup
  3. Loop

Diesen Aufbau müssen wir auch bei unserem Gesamtsketch einhalten. Wir können also nicht einfach beide Sketche untereinander schreiben, denn dann wäre jeder Block doppelt vorhanden. Wir müssen die beiden Sketche ( den aus #13 ganz am Ende, und den aus #27 ) blockweise zusammenkopieren. Das ergibt dann den folgenden Gesamtsketch:

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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
 
// Wechselblinker + Ampelsteuerung
 
#include <MobaTools.h>
 
//vvvvvvvvvvvvvvvvvvvvvvvvv BEGIN WECHSELBLINKER vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
// Definitionen für den Wechselblinker
// 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 = 400;
const int BLINKZEIT = 500;
const int FADEZEIT = 450;
 
MoToTimer EntPrellung; // Zur Tasterentporellung
const int PRELLZEIT = 100;
 
// Variable
boolean bueBelegt; // = TRUE, wenn sich ein Zug im Bereich des Bue befindet
byte wBlinkerZustand; // aktueller Zustand unseres Blinkerautomaten
//^^^^^^^^^^^^^^^^^^^^^^^^ ENDE WECHSELBLINKER ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

//vvvvvvvvvvvvvvvvvvvvvvvv BEGIN AMPELSTEUERUNG vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
// Ampelsteuerung an einer einfachen Kreuzung
// Die Ampelphasen werden über eine Tabelle definiert
 
// Definitionen für die Ampelschaltung:
// Definition der Ausgangspins:
const byte hRotPin = A0; // Ampel an der Hauptstraße
const byte hGelbPin = A1;
const byte hGruenPin = A2;
const byte nRotPin = A3; // Ampel an der Nebenstraße
const byte nGelbPin = A4;
const byte nGruenPin = A5;
 

// Tabelle für die Ampelzustände
// Ampelphase: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8
// Tabellenindex: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7
const byte zeitDauer [] = { 30 , 3 , 3 , 3 , 20 , 3 , 3 , 3 };
const bool hauptRot [] = { OFF ,OFF , ON , ON , ON , ON , ON , ON };
const bool hauptGelb [] = { OFF , ON ,OFF ,OFF ,OFF ,OFF ,OFF , ON };
const bool hauptGruen [] = { ON ,OFF ,OFF ,OFF ,OFF ,OFF ,OFF ,OFF };
const bool nebenRot [] = { ON , ON , ON , ON ,OFF ,OFF , ON , ON };
const bool nebenGelb [] = { OFF ,OFF ,OFF , ON ,OFF , ON ,OFF ,OFF };
const bool nebenGruen [] = { OFF ,OFF ,OFF ,OFF , ON ,OFF ,OFF ,OFF };
 
const byte tabMax = sizeof(zeitDauer)-1; // Tabellenindex startet bei 0 ( deshalb die -1 für den höchsten Index )
byte ampelTabIx; // läuft von 0 .. 7
 
// Einrichten der notwendigen MoBaTools Objekte:
MoToTimer AmpelTimer;
MoToSoftLed hRot;
MoToSoftLed hGelb;
MoToSoftLed hGruen;
MoToSoftLed nRot;
MoToSoftLed nGelb;
MoToSoftLed nGruen;
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ENDE AMPELSTEUERUNG ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//----------------------------------------------------------------------
 
void setup() {
//vvvvvvvvvvvvvvvvvvvvvvvvv BEGIN WECHSELBLINKER vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
// Initiierungen Wechselblinker
// 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.
//^^^^^^^^^^^^^^^^^^^^^^^^ ENDE WECHSELBLINKER ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

//vvvvvvvvvvvvvvvvvvvvvvvv BEGIN AMPELSTEUERUNG vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
//Initiierungen für die Ampel
// Softled Objekte initiieren
hRot.attach( hRotPin );
hRot.riseTime( 200 );
hGelb.attach( hGelbPin );
hGelb.riseTime( 200 );
hGruen.attach( hGruenPin );
hGruen.riseTime( 200 );
nRot.attach( nRotPin );
nRot.riseTime( 200 );
nGelb.attach( nGelbPin );
nGelb.riseTime( 200 );
nGruen.attach( nGruenPin );
nGruen.riseTime( 200 );
 
ampelTabIx = 0; // Das System startet mit freier Fahrt auf der Hauptstraße
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ENDE AMPELSTEUERUNG ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//----------------------------------------------------------------------
}
 
void loop() {

//vvvvvvvvvvvvvvvvvvvvvvvvv BEGIN WECHSELBLINKER vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
// Wechselblinkerautomat
// 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.
//if ( not EntPrellung.running() ) {
// EntPrellung.setTime( PRELLZEIT );
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();
// Im 3. 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 sind aus!
// 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
} else {
LampeRechts.on();
StoppUhr.setTime( BLINKZEIT ); // Stoppuhr 'aufziehen'
// wieder in den 4. Zustand wechseln
wBlinkerZustand = 4; // Ab dem nächsten loop-Durchlauf werden nur die Anweisungen des case 3 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
LampeRechts.off();
// 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 sind aus!
// 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
} else {
LampeLinks.on();
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
}
}
break; // Ende der Anweisungen für den 4. Zustand
} // Ende des switch-Blockes
//^^^^^^^^^^^^^^^^^^^^^^^^ ENDE WECHSELBLINKER ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

//vvvvvvvvvvvvvvvvvvvvvvvv BEGIN AMPELSTEUERUNG vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
// Tabellengesteuerte Ampel
if( !AmpelTimer.running() ) {
// Zeit abgelaufen
// Ampel schalten
hRot.write( hauptRot[ampelTabIx] );
hGelb.write( hauptGelb[ampelTabIx] );
hGruen.write( hauptGruen[ampelTabIx] );
nRot.write( nebenRot[ampelTabIx] );
nGelb.write( nebenGelb[ampelTabIx] );
nGruen.write( nebenGruen[ampelTabIx] );
// Zeit setzen ( da der Timer in ms rechnet, müssen die Tabellenwerte mit 1000
// multipliziert werden )
AmpelTimer.setTime( zeitDauer[ampelTabIx] * 1000 );
// Merker weiterrückem
if( ampelTabIx >= tabMax ) {
// Tabellenende erreicht
ampelTabIx = 0;
} else {
ampelTabIx++;
}
}
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ENDE AMPELSTEUERUNG ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
}
 

Voila - unser Arduino bedient Ampel und Wechselblinker 'parallel' und vollkommen unabhängig voneinander. Auch das lastet den Arduino noch bei weitem nicht aus - unsere 'Arduino-Lok' flitzt immer noch hauptsächlich durch die freien Gleise im Kreis, ohne etwas zu tun. 'HigSpeed'-Däumchendrehen
P.S. Den Wechselblinker habe ich noch ein bisschen 'getuned' . Auch im Gesamt-Ablaufplan ist das eingeflossen. Erkennt ihr, was anders ist, und wie es sich auswirkt?

Das Ziel dieses Tutorials ist damit eigentlich erreicht: Wenn man beim Programmieren auf 'delay()' verzichtet, kann man erreichen, dass der Arduino mehrere Dinge unabhängig und scheinbar 'parallel' erledigt. Ich hoffe, es war verständlich, und ihr könnt mit diesem Verfahren nun auch andere Projekte in Angriff nehmen.

P.P.S. Für die schöne Erweiterung von Thomas mit den Fußgängerampeln musste er ja nicht nur die Tabelle erweitern, sondern auch den Sketch selbst an einigen Stellen anpassen. Man kann den Sketch aber auch so schreiben, dass für solche Erweiterungen wirklich nur die Tabelle angepasst werden muss. Er wird dadurch sogar kürzer. Das möchte ich dann als nächstes mal demonstrieren.
also: Fortsetzung folgt...


viele Grüße
Franz-Peter
Ein 'elektromechanisches' Stellwerk
Der (ehemalige) 'Eisberg'


hubedi und MobaPro59 haben sich bedankt!
 
MicroBahner
Metropolitan (MET)
Beiträge: 2.833
Registriert am: 28.11.2012
Ort: Mittelfranken
Gleise Tillig Elite
Steuerung Eigenbau
Stromart Analog

zuletzt bearbeitet 09.08.2021 | Top

RE: Arduino: Zeitsteuerungen ohne Delay - ein kleines Tutorial

#36 von ThKaS , 28.11.2018 21:18

Zitat

.....
Zu deiner Erweiterung habe ich später auch noch einen Vorschlag
......
also: Fortsetzung folgt...



Spannungsaufbau....


lieben Gruss von südlich des Weisswurst-Äquators
Thomas

guckst: runderneuerte https://www.thkas-moba.de ‹(•¿•)› www.mucis.de

‹(•¿•)›

Mä-K-Gleis, Tams MC, Multi-Kulti Decoder, WDP


 
ThKaS
InterCityExpress (ICE)
Beiträge: 2.200
Registriert am: 28.04.2005
Homepage: Link


RE: Arduino: Zeitsteuerungen ohne Delay - ein kleines Tutorial

#37 von Reibuch , 29.11.2018 10:24

Hallo Franz Peter,

ja was soll ich sagen ,es funktioniert perfekt ,allerdings verstanden habe ich es noch nicht

Ich werde jetzt im Winter versuchen jeden Stepp noch einmal "nachzubauen" um dann ein besseres Verständnis für die Abläufe zu erhalten.

Trotzdem Vielen Vielen Dank füe das Tutorial



VG
Thomas


Gruß Thomas


 
Reibuch
InterRegioExpress (IRE)
Beiträge: 311
Registriert am: 27.08.2006
Ort: Hunsrück
Gleise Märklin C Gleis
Spurweite H0
Stromart AC, Digital


RE: Arduino: Zeitsteuerungen ohne Delay - ein kleines Tutorial

#38 von MicroBahner , 30.11.2018 10:43

Hallo Thomas,
dann waren meine Erklärung wohl doch noch nicht so ganz verständlich.
Wo klemmt's denn? Schon beim Verständnis der Ablauf(Gleis)pläne? Oder dann bei der Umsetzung in konkreten Code? Vielleicht kann ich ja noch etwas mehr Licht ins Dunkel bringen .


viele Grüße
Franz-Peter
Ein 'elektromechanisches' Stellwerk
Der (ehemalige) 'Eisberg'


 
MicroBahner
Metropolitan (MET)
Beiträge: 2.833
Registriert am: 28.11.2012
Ort: Mittelfranken
Gleise Tillig Elite
Steuerung Eigenbau
Stromart Analog


RE: Arduino: Zeitsteuerungen ohne Delay - ein kleines Tutorial

#39 von MicroBahner , 30.11.2018 14:55

Edit: Objektnamen an aktuelle MobaTools angepasst

Zwischendurch noch etwas zu den Erweiterungen von Thomas. Schön wär's doch, dass man NUR die Tabelle anpassen müsste, und schon hat man eine zusätzliche Ampel mit zusätzlichen Zuständen. Denn letztendlich werden die Abläufe ja nur durch die Tabelle beschrieben:

(Ich habe gegenüber der Tabelle von Thomas mal die Haupt- und Nebenfußgängerampel vertauscht. Ich gehe davon aus, dass die 'HauptFuß-AMpel auch an der Hauptstraße steht, und da sollte sie nicht gleichzeitig mit der Autoampel grün zeigen)
Nun ist das ja eine 2-dimensionale Tabelle. Im Programm haben wir aber bisher nur 1-dimensionale Felder erzeugt und untereinander geschrieben. Für uns sieht das im Programm zwar aus wie eine 2-dimensionale Tabelle. Aber der Arduino weis nichts davon, dass das zusammengehört. Für ihn sind des einzelne Zeilen ( die wir auch anders im Code hätten verteilen können. Für unser Vorhaben, alles über die Tabelle zu steuern, muss der Arduino aber den kompletten Zusammenhang kennen - also brauchen wir auch im Code eine 2-dimensionale Tabelle. Dann können wir nämlich auch die Ampel-Leds über einen Laufindex anwählen und nicht nur - wie bisher - die Ampelphasen. Dass wir ein Feld definieren wollen, haben wir bisher durch 2 eckige Klammern gekennzeichnet:

1
2
 
const byte zeitDauer  [] =      { 20  , 2  , 2  , 3  , 2 , 10  , 2  , 2 , 3 , 2 };
 
 

Wenn wir nun ein 2-dimensionales Feld definieren wollen, schreiben wir einfach 2 Klammern hin:

1
 
const byte AmpelTabelle [][]
 

Allerdings ergibt das so ein Problem: bei dem eindimensionalen Feld oben haben wir uns die Größe in der Klammer schenken können - Die Größe ergab sich aus der Zahl der Initiierungswerte. Das funktioniert aber jetzt nicht mehr: Z.B können 16 Werte sowohl als 4x4Feld aber auch als 2x8 Feld gemeint sein. Deshalb müssen wir da einen Wert eintragen:

1
 
const byte AmpelTabelle [][11]
 

Da haben wir nun die Zahl der Spalten festgelegt. Daraus kann jetzt die Zahl der Zeilen automatisch ermittelt werden. Die ganze Tabelle sieht nun so aus:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 
const byte AmpelTabelle [][11] = {
// Ampelphase: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8
// Tabellenindex: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8
{ A0 ,OFF ,OFF ,OFF , ON , ON , ON , ON , ON , ON , ON }, // hauptRot
{ 3 ,OFF , ON , ON , ON , ON , ON , ON , ON , ON , ON }, // hauptRotFRot
{ A1 ,OFF , OFF, ON ,OFF ,OFF ,OFF ,OFF ,OFF ,OFF , ON }, // hauptGelb
{ A2 , ON ,ON ,OFF ,OFF ,OFF ,OFF ,OFF ,OFF ,OFF ,OFF }, // hauptGruen
{ 2 , ON ,OFF ,OFF ,OFF ,OFF ,OFF ,OFF ,OFF ,OFF ,OFF }, // hauptGruenFGruen
{ A3 , ON , ON , ON , ON , ON ,OFF ,OFF ,OFF , ON , ON }, // nebenRot
{ 7 , ON , ON , ON , ON , ON ,OFF , ON , ON , ON , ON }, // nebenRotFRot
{ A4 ,OFF ,OFF ,OFF ,OFF , ON ,OFF ,OFF , ON ,OFF ,OFF }, // nebenGelb
{ A5 ,OFF ,OFF ,OFF ,OFF ,OFF , ON , ON ,OFF ,OFF ,OFF }, // nebenGruen
{ 6 ,OFF ,OFF ,OFF ,OFF ,OFF , ON ,OFF ,OFF ,OFF ,OFF }, // nebenGruenFGruen
{ 0 ,20 , 2 , 2 , 3 , 2 , 10 , 2 , 2 , 3 , 2 } // zeitDauer
};
 


Die Zeilennamen stehen jetzt nur noch als Kommentar am Ende. Der Arduino kann auf jedes Element dieser Tabelle über eine Zeilen- und Spaltennummer (2-facher Index) zugreifen. Z.B. weist

1
 
a=AmpelTabelle[10][1];
 

der Variablen a den Wert 20 zu ( 11. Zeile, 2. Spalte - Index beginnt bei 0! ).

1
 
a=AmpelTabelle[1][10];
 

wäre der Wert für ON.

Die Tabelle habe ich aber ein wenig verändert: Zum einen ist vorn eine Spalte dazugekommen, ausserdem habe ich die Zeit ans Ende verschoben.
In der ersten Spalte steht die PinNr, an der die Led angeschlossen ist. Damit sind alle notwendigen Informationen in der Tabelle zusammengefasst.
Die Zeitdauer habe ich ans Ende verschoben, damit die Softled-Objekte mit dem gleichen Index angesprochen werden können, wie die Tabelle. Denn die Softled-Objekte haben wir bisher so angelegt:

1
2
3
4
5
6
7
8
 
MoToSoftLed hRot;
MoToSoftLed hGelb;
MoToSoftLed hGruen;
MoToSoftLed nRot;
MoToSoftLed nGelb;
MoToSoftLed nGruen;
....
 
 

Damit wir die Led's genauso ansprechen können, wie die Zeilen in der Tabelle, müssen wir die auch in einer Art Feld anlegen:

1
 
MoToSoftLed AmpelLed[LedAnzahl];
 

Mit

1
 
AmpelLed[0}.on();
 

schalten wir nun z.B. die rote Ampel an der Hauptstraße ( Index 0 in der Tabelle ).

Jetzt einfach mal der komplette Sketch. In setup() und loop() greifen wir jetzt auf die Tabelle und auf die Leds nur noch indiziert zu.
Ich habe auch beide Tabellen ( mit und ohne Fußgängerampel ) im Code belassen. Natürlich darf nur eine Tabelle aktiv sein, die andere muss auskommentiert werden.
Je nachdem, welche Tabelle auskommentiert wird bekommt man die Steuerung mit oder ohne Fußgängerampel. Ansonsten sind keine Anpassungen im Sketch notwendig.

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
 
// Ampelsteuerung
 
// Ampelsteuerung an einer einfachen Kreuzung
// Die Ampelphasen werden über eine Tabelle definiert
 
#include <MobaTools.h>
 
// Definition der Ausgangspins in Spalte 0 der Ampeltabelle
// Tabelle für die Ampelzustände ( Index 1 ... )
/*
const byte AmpelTabelle [][9] = {
// Ampelphase: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8
// Tabellenindex: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8
{ A0 ,OFF ,OFF , ON , ON , ON , ON , ON , ON }, // hauptRot
{ A1 ,OFF , ON ,OFF ,OFF ,OFF ,OFF ,OFF , ON }, // hauptGelb
{ A2 , ON ,OFF ,OFF ,OFF ,OFF ,OFF ,OFF ,OFF }, // hauptGruen
{ A3 , ON , ON , ON , ON ,OFF ,OFF , ON , ON }, // nebenRot
{ A4 ,OFF ,OFF ,OFF , ON ,OFF , ON ,OFF ,OFF }, // nebenGelb
{ A5 ,OFF ,OFF ,OFF ,OFF , ON ,OFF ,OFF ,OFF }, // nebenGruen
{ 0 , 5 , 2 , 2 , 2 , 4 , 2 , 2 , 2 } // zeitDauer
};
*/
const byte AmpelTabelle [][11] = {
// Ampelphase: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10
// Tabellenindex: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10
{ A0 ,OFF ,OFF ,OFF , ON , ON , ON , ON , ON , ON , ON }, // hauptRot
{ 3 , ON , ON , ON , ON , ON ,OFF , ON , ON , ON , ON }, // hauptRotFRot
{ A1 ,OFF , OFF, ON ,OFF ,OFF ,OFF ,OFF ,OFF ,OFF , ON }, // hauptGelb
{ A2 , ON ,ON ,OFF ,OFF ,OFF ,OFF ,OFF ,OFF ,OFF ,OFF }, // hauptGruen
{ 2 ,OFF ,OFF ,OFF ,OFF ,OFF , ON ,OFF ,OFF ,OFF ,OFF }, // hauptGruenFGruen
{ A3 , ON , ON , ON , ON , ON ,OFF ,OFF ,OFF , ON , ON }, // nebenRot
{ 7 ,OFF , ON , ON , ON , ON , ON , ON , ON , ON , ON }, // nebenRotFRot
{ A4 ,OFF ,OFF ,OFF ,OFF , ON ,OFF ,OFF , ON ,OFF ,OFF }, // nebenGelb
{ A5 ,OFF ,OFF ,OFF ,OFF ,OFF , ON , ON ,OFF ,OFF ,OFF }, // nebenGruen
{ 6 , ON ,OFF ,OFF ,OFF ,OFF ,OFF ,OFF ,OFF ,OFF ,OFF }, // nebenGruenFGruen
{ 0 ,20 , 2 , 2 , 3 , 2 , 10 , 2 , 2 , 3 , 2 } // zeitDauer
};
 
// Die folgenden beiden Zeilen berechnen aus der Tabelle ( Spalten+Zeilenanzahl ) die
// Zahl der Ampelphasen ( Spaltenzahl-1) , und die Zahl der Leds ( Zeilenzahl - 1 )
const byte PhasenAnzahl = sizeof(AmpelTabelle[0])-1;
const byte LedAnzahl = sizeof(AmpelTabelle)/sizeof(AmpelTabelle[0]) -1;
const byte zeitDauerIx = LedAnzahl; // Index für die Zeit ist direkt hinter den Leds
byte ampelPhase; // läuft von 1 .. PhasenAnzahl (Index 0 ist die Pinnr )
 
// Einrichten der notwendigen MoBaTools Objekte:
MoToTimer AmpelTimer;
MoToSoftLed AmpelLed[LedAnzahl];
 

void setup() {
// Softled Objekte initiieren
for ( byte ledIx = 0; ledIx < LedAnzahl; ledIx ++ ) {
AmpelLed[ledIx].attach( AmpelTabelle[ledIx][0] );
AmpelLed[ledIx].riseTime( 200 );
}
ampelPhase = 1; // Das System startet mit freier Fahrt auf der Hauptstraße
}
 
void loop() {
// Tabellengesteuerte Ampel
if( !AmpelTimer.running() ) {
// Zeit abgelaufen
// Ampeln schalten
for ( byte ledIx = 0; ledIx < LedAnzahl; ledIx ++ ) {
AmpelLed[ledIx].write( AmpelTabelle[ledIx][ampelPhase] );
}
// Zeit setzen ( da der Timer in ms rechnet, müssen die Tabellenwerte mit 1000
// multipliziert werden )
AmpelTimer.setTime( AmpelTabelle[zeitDauerIx][ampelPhase] * 1000 );
// Merker weiterrückem
if( ampelPhase >= PhasenAnzahl ) {
// Tabellenende erreicht
ampelPhase = 1;
} else {
ampelPhase++;
}
}
}
 
 



Vielleicht ist das ja auch für den einen oder anderen interessant, wenn auch wohl nicht mehr unbedingt ein Einsteigerbeispiel.
Das funktioniert natürlich nicht nur für eine einfache Ampelsteuerung. Wieder als Beispiel mein 'elektromechanisches' Stellwerk: Da sind alle Fahrstraßenabhängigkeiten mit Tabellen definiert. Der Code ist damit für alle Fahrstraßen identisch und nur der Index bestimmt, welche Fahrstraße gerade bearbeitet wird.

P.S. Die PinnNr. habe ich gegenüber Thomas's Sketch etwas verändert, damit es keine Überschneidung mit dem Wechselblinker gibt. Wer Lust hat, kann ja auch diesen Sketch mit dem Wechselblinker kombinieren.


viele Grüße
Franz-Peter
Ein 'elektromechanisches' Stellwerk
Der (ehemalige) 'Eisberg'


hubedi und MobaPro59 haben sich bedankt!
 
MicroBahner
Metropolitan (MET)
Beiträge: 2.833
Registriert am: 28.11.2012
Ort: Mittelfranken
Gleise Tillig Elite
Steuerung Eigenbau
Stromart Analog

zuletzt bearbeitet 09.08.2021 | Top

RE: Arduino: Zeitsteuerungen ohne Delay - ein kleines Tutorial

#40 von ThKaS , 30.11.2018 15:36

Hallo Franz-Peter,

danke. Das sieht gut aus. Da hätte ich mir Tipparbeit sparen können.

Zu dem

Zitat
(Ich habe gegenüber der Tabelle von Thomas mal die Haupt- und Nebenfußgängerampel vertauscht. Ich gehe davon aus, dass die 'HauptFuß-AMpel auch an der Hauptstraße steht, und da sollte sie nicht gleichzeitig mit der Autoampel grün zeigen)


ist ja die Frage, wie sehe ich die Fussgängerampel.

Mein Ansatz war, wenn die Hauptstrassenampel grün zeigt, stelle ich auch die Fussgängerampel in Fahrtrichtung der Hauptstrassenampel grün.
Ich bin also von der Fahrt- und Laufrichtung ausgegangen, nicht vom Montageort. Deine Lösung beschreibt wohl nun den Montageort, dort habe ich dann natürlich "gegensätzliches" Leuchten.


lieben Gruss von südlich des Weisswurst-Äquators
Thomas

guckst: runderneuerte https://www.thkas-moba.de ‹(•¿•)› www.mucis.de

‹(•¿•)›

Mä-K-Gleis, Tams MC, Multi-Kulti Decoder, WDP


 
ThKaS
InterCityExpress (ICE)
Beiträge: 2.200
Registriert am: 28.04.2005
Homepage: Link


RE: Arduino: Zeitsteuerungen ohne Delay - ein kleines Tutorial

#41 von MicroBahner , 30.11.2018 15:40

Stimmt, alles eine Frage der Betrachtungsweise .
Lässt sich ja auch wahlweise über HW-Anschluß oder Tabelleneintrag leicht anpassen


viele Grüße
Franz-Peter
Ein 'elektromechanisches' Stellwerk
Der (ehemalige) 'Eisberg'


 
MicroBahner
Metropolitan (MET)
Beiträge: 2.833
Registriert am: 28.11.2012
Ort: Mittelfranken
Gleise Tillig Elite
Steuerung Eigenbau
Stromart Analog


RE: Arduino: Zeitsteuerungen ohne Delay - ein kleines Tutorial

#42 von ThKaS , 30.11.2018 21:58

Moin moin,

jetzt habe ich nochmal ein bisserl "geknobelt".

Ziel:
Ampelsteuerung mit Fussgängern
Ampelsteuerung Nacht mit Gelbblinken der Nebenstrasse
Wechselblinker für BÜ

Für Programmierer wahrscheinlich ein Klacks, für mich eine Herausforderung.

Zunächst habe ich den letzten Sketch von Franz-Peter an meinen HW-Aufbau angepasst (Pin A7 auf A5, Pin A6 auf A4)
Dann den Wechselblinker eingebaut
Dann Pin 9 neu definiert als weiteren Schalter für Tag/Nacht gegen GND
Dann das Array um eine weitere Spalte 12 (alle Ampel-LED OFF ergänzt)
Einen weiteren Switch eingefügt mit 2 Cases Tag/Nacht

... und es geht.
Mit den Blink und Fadezeiten des gelben Nachtlichtes muss man noch ein bisserl rumprobieren

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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
 

// Ampelsteuerung
 
// Ampelsteuerung an einer einfachen Kreuzung mit Fussg&#228;ngerampel, mit Tag/Nachtmodus, mit Wechselblinker
// Die Ampelphasen werden &#252;ber eine Tabelle definiert
 
#include &lt;MobaTools.h&gt;
//vvvvvvvvvvvvvvvvvvvvvvvvv BEGIN WECHSELBLINKER vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
// Definitionen f&#252;r den Wechselblinker
// Festlegen der Anschl&#252;sse (Pinnummer) f&#252;r Ein- und Ausg&#228;nge
const byte linksPin = 6; // linke Lampe
const byte rechtsPin = 7; // rechte Lampe
const byte belegtPin = 8; // Eingang 'Zug kommt'
 

// Ben&#246;tigte MobaTools Objekte:
EggTimer StoppUhr; // Zum Messen von Zeiten
EggTimer StoppUhr2; // Zum Messen von Zeit Nacht
SoftLed LampeLinks;
SoftLed LampeRechts;
SoftLed LampeAmpelGelbNeben;
 
// Zeiten f&#252;r den Blinkrhythmus ( in ms )
const int STARTZEIT = 400;
const int BLINKZEIT = 500;
const int FADEZEIT = 450;
 

EggTimer EntPrellung; // Zur Tasterentporellung
const int PRELLZEIT = 100;
 
// Variable
boolean bueBelegt; // = TRUE, wenn sich ein Zug im Bereich des Bue befindet
byte wBlinkerZustand; // aktueller Zustand unseres Blinkerautomaten
//^^^^^^^^^^^^^^^^^^^^^^^^ ENDE WECHSELBLINKER ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
//vvvvvvvvvvvvvvvvvvvvvvvvv BEGIN AmpelNacht vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
// Definitionen f&#252;r Ampelnacht, blinken nur Nebenstrasse
// Festlegen der Anschl&#252;sse (Pinnummer) f&#252;r Ein- und Ausg&#228;nge
const byte belegtPin2 = 9; // Eingang "es ist Nacht"
 
// Zeiten f&#252;r den Blinkrhythmus Nacht ( in ms )
const int STARTZEIT2 = 400;
const int BLINKZEIT2 = 1200;
const int FADEZEIT2 = 1200;
const byte NebenGelbPin = A4; // Nebenstrasse Ampel Gelb
 
// Variable
boolean bueBelegt2; // = TRUE, wenn D9 geschlossen, dann Nacht
byte wBlinkerZustand2; // aktueller Zustand unseres Blinkerautomaten Nacht
//^^^^^^^^^^^^^^^^^^^^^^^^ ENDE AmpelNacht ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 

//vvvvvvvvvvvvvvvvvvvvvvvv BEGIN AMPELSTEUERUNG vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
 
// Definition der Ausgangspins in Spalte 0 der Ampeltabelle
// Tabelle f&#252;r die Ampelzust&#228;nde ( Index 1 ... )
/*
const byte AmpelTabelle [][9] = {
// Ampelphase: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8
// Tabellenindex: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8
{ A0 ,OFF ,OFF , ON , ON , ON , ON , ON , ON }, // hauptRot
{ A1 ,OFF , ON ,OFF ,OFF ,OFF ,OFF ,OFF , ON }, // hauptGelb
{ A2 , ON ,OFF ,OFF ,OFF ,OFF ,OFF ,OFF ,OFF }, // hauptGruen
{ A3 , ON , ON , ON , ON ,OFF ,OFF , ON , ON }, // nebenRot
{ A4 ,OFF ,OFF ,OFF , ON ,OFF , ON ,OFF ,OFF }, // nebenGelb
{ A5 ,OFF ,OFF ,OFF ,OFF , ON ,OFF ,OFF ,OFF }, // nebenGruen
{ 0 , 5 , 2 , 2 , 2 , 4 , 2 , 2 , 2 } // zeitDauer
};
*/
const byte AmpelTabelle [][12] = {
// Ampelphase: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11
// Tabellenindex: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11
{ A0 ,OFF ,OFF ,OFF , ON , ON , ON , ON , ON , ON , ON , OFF}, // hauptRot
{ 3 , ON , ON , ON , ON , ON ,OFF , ON , ON , ON , ON , OFF}, // hauptRotFRot
{ A1 ,OFF , OFF, ON ,OFF ,OFF ,OFF ,OFF ,OFF ,OFF , ON , OFF}, // hauptGelb
{ A2 , ON ,ON ,OFF ,OFF ,OFF ,OFF ,OFF ,OFF ,OFF ,OFF , OFF}, // hauptGruen
{ 2 ,OFF ,OFF ,OFF ,OFF ,OFF , ON ,OFF ,OFF ,OFF ,OFF , OFF}, // hauptGruenFGruen
{ A3 , ON , ON , ON , ON , ON ,OFF ,OFF ,OFF , ON , ON , OFF}, // nebenRot
{ 5 ,OFF , ON , ON , ON , ON , ON , ON , ON , ON , ON , OFF}, // nebenRotFRot
{ A4 ,OFF ,OFF ,OFF ,OFF , ON ,OFF ,OFF , ON ,OFF ,OFF , OFF}, // nebenGelb
{ A5 ,OFF ,OFF ,OFF ,OFF ,OFF , ON , ON ,OFF ,OFF ,OFF , OFF}, // nebenGruen
{ 4 , ON ,OFF ,OFF ,OFF ,OFF ,OFF ,OFF ,OFF ,OFF ,OFF , OFF}, // nebenGruenFGruen
{ 0 ,20 , 2 , 2 , 3 , 2 , 10 , 2 , 2 , 3 , 2 , 60} // zeitDauer
};
 
// Die folgenden beiden Zeilen berechnen aus der Tabelle ( Spalten+Zeilenanzahl ) die
// Zahl der Ampelphasen ( Spaltenzahl-1) , und die Zahl der Leds ( Zeilenzahl - 1 )
const byte PhasenAnzahl = sizeof(AmpelTabelle[0])-2;
const byte PhasenAnzahl2 = sizeof(AmpelTabelle[0])-1;
const byte LedAnzahl = sizeof(AmpelTabelle)/sizeof(AmpelTabelle[0]) -1;
const byte zeitDauerIx = LedAnzahl; // Index f&#252;r die Zeit ist direkt hinter den Leds
byte ampelPhase; // l&#228;uft von 1 .. PhasenAnzahl (Index 0 ist die Pinnr )
 
// Einrichten der notwendigen MoBaTools Objekte:
EggTimer AmpelTimer;
SoftLed AmpelLed[LedAnzahl];
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ENDE AMPELSTEUERUNG ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 

void setup() {
 

//vvvvvvvvvvvvvvvvvvvvvvvvv BEGIN WECHSELBLINKER vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
// Initiierungen Wechselblinker
// 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 ); // &#220;berblendzeit einstellen
LampeRechts.riseTime( FADEZEIT );
 
wBlinkerZustand = 1; // Startzustand des Blinkautomaten.
//^^^^^^^^^^^^^^^^^^^^^^^^ ENDE WECHSELBLINKER ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
//vvvvvvvvvvvvvvvvvvvvvvvvv BEGIN Nacht vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
// Initiierungen Wechselblinker
// Pins einrichten
pinMode( belegtPin2, INPUT_PULLUP ); // Mit einem Schalter nach GND wird Blinker eingeschaltet
LampeAmpelGelbNeben.attach( NebenGelbPin ); // Zuordnung der Softleds zu den Ausgangspins
// LampeRechts.attach( rechtsPin );
LampeAmpelGelbNeben.riseTime( FADEZEIT ); // &#220;berblendzeit einstellen
// LampeRechts.riseTime( FADEZEIT );
 
wBlinkerZustand2 = 1; // Startzustand des Blinkautomaten.
//^^^^^^^^^^^^^^^^^^^^^^^^ ENDE WECHSELBLINKER ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 

//vvvvvvvvvvvvvvvvvvvvvvvv BEGIN AMPELSTEUERUNG vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
 

// Softled Objekte initiieren
for ( byte ledIx = 0; ledIx &lt; LedAnzahl; ledIx ++ ) {
AmpelLed[ledIx].attach( AmpelTabelle[ledIx][0] );
AmpelLed[ledIx].riseTime( 200 );
}
ampelPhase = 1; // Das System startet mit freier Fahrt auf der Hauptstra&#223;e
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ENDE AMPELSTEUERUNG ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//----------------------------------------------------------------------
 
}
 
void loop() {
 
//vvvvvvvvvvvvvvvvvvvvvvvvv BEGIN WECHSELBLINKER vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
// Wechselblinkerautomat
// 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&#246;nnte hier gegebenenfalls auch ein komplexere Logik stehen, um zu
// erkennen, ob ein Zug sich n&#228;hert oder den B&#252; wieder verlassen hat.
//if ( not EntPrellung.running() ) {
// EntPrellung.setTime( PRELLZEIT );
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&#228;hert ( z.B. &#252;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&#228;chsten loop-Durchlauf werden nur die Anweisungen des case 2 ausgef&#252;hrt
}
break; // Ende der Anweisungen f&#252;r den 1. Zustand
//-------------------------------------------------------------------------
case 2: // beide Lampen ein, wir fragen ab, ob die Stoppuhr abgelaufen ist.
if ( not StoppUhr.running() ) {
// Die Stoppuhr l&#228;uft nicht mehr, die Zeit ist um
LampeRechts.off();
StoppUhr.setTime( BLINKZEIT ); // Stoppuhr 'aufziehen'
// in den 3. Zustand wechseln
wBlinkerZustand = 3; // Ab dem n&#228;chsten loop-Durchlauf werden nur die Anweisungen des case 3 ausgef&#252;hrt
}
break; // Ende der Anweisungen f&#252;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&#228;uft nicht mehr, die Zeit ist um, Lampen umschalten
LampeLinks.off();
// Im 3. Zustand m&#252;ssen wir auch noch abfragen, ob der Zug den Belegtabschnitt verlassen hat
if ( not bueBelegt ) {
// Der Zug ist komplett &#252;ber den B&#252; gefahren, die Stra&#223;e ist wieder frei
// Beide Lampen sind aus!
// wieder in den 1. Zustand wechseln. Eine Zeit&#252;berwachung wird nicht gebraucht
wBlinkerZustand = 1; // Ab dem n&#228;chsten loop-Durchlauf werden nur die Anweisungen des case 1 ausgef&#252;hrt
} else {
LampeRechts.on();
StoppUhr.setTime( BLINKZEIT ); // Stoppuhr 'aufziehen'
// wieder in den 4. Zustand wechseln
wBlinkerZustand = 4; // Ab dem n&#228;chsten loop-Durchlauf werden nur die Anweisungen des case 3 ausgef&#252;hrt
}
}
break; // Ende der Anweisungen f&#252;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&#228;uft nicht mehr, die Zeit ist um, Lampen umschalten
LampeRechts.off();
// Im 4. Zustand m&#252;ssen wir auch noch abfragen, ob der Zug den Belegtabschnitt verlassen hat
if ( not bueBelegt ) {
// Der Zug ist komplett &#252;ber den B&#252; gefahren, die Stra&#223;e ist wieder frei
// Beide Lampen sind aus!
// wieder in den 1. Zustand wechseln. Eine Zeit&#252;berwachung wird nicht gebraucht
wBlinkerZustand = 1; // Ab dem n&#228;chsten loop-Durchlauf werden nur die Anweisungen des case 1 ausgef&#252;hrt
} else {
LampeLinks.on();
StoppUhr.setTime( BLINKZEIT ); // Stoppuhr 'aufziehen'
// wieder in den 3. Zustand wechseln
wBlinkerZustand = 3; // Ab dem n&#228;chsten loop-Durchlauf werden nur die Anweisungen des case 3 ausgef&#252;hrt
}
}
break; // Ende der Anweisungen f&#252;r den 4. Zustand
} // Ende des switch-Blockes
//^^^^^^^^^^^^^^^^^^^^^^^^ ENDE WECHSELBLINKER ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

//vvvvvvvvvvvvvvvvvvvvvvvv BEGIN AMPELSTEUERUNG Tag / Nacht vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
 
//if ( not EntPrellung.running() ) {
// EntPrellung.setTime( PRELLZEIT );
bueBelegt2 = not digitalRead( belegtPin2 ); // ein LOW-Level am Eingangspin schaltet den Nachtmodus ein
 
switch ( wBlinkerZustand2 ) {
case 1: // NachtModus
if ( bueBelegt2 ) {
ampelPhase = 12; // In Array SPalte alles OFF setzen
for ( byte ledIx = 0; ledIx &lt; LedAnzahl; ledIx ++ ) {
AmpelLed[ledIx].write( AmpelTabelle[ledIx][ampelPhase] ); // Ampel-LEDs ausschalten
}
if ( not StoppUhr2.running() ) {
LampeAmpelGelbNeben.on();
StoppUhr2.setTime( BLINKZEIT2 ); // Stoppuhr 'aufziehen' f&#252;r GelbLicht Nebenstrasse
LampeAmpelGelbNeben.off();
wBlinkerZustand2 = 1;
}
}
else
wBlinkerZustand2 = 2;
break;

case 2: // TagModus

// Tabellengesteuerte Ampel

if ( not bueBelegt2 ) {
LampeAmpelGelbNeben.off();
if( !AmpelTimer.running() ) {
// Zeit abgelaufen
// Ampeln schalten
for ( byte ledIx = 0; ledIx &lt; LedAnzahl; ledIx ++ ) {
AmpelLed[ledIx].write( AmpelTabelle[ledIx][ampelPhase] );
}
// Zeit setzen ( da der Timer in ms rechnet, m&#252;ssen die Tabellenwerte mit 1000
// multipliziert werden )
AmpelTimer.setTime( AmpelTabelle[zeitDauerIx][ampelPhase] * 1000 );
// Merker weiterr&#252;ckem
if( ampelPhase &gt;= PhasenAnzahl ) {
// Tabellenende erreicht
ampelPhase = 1;
} else {
ampelPhase++;
}
wBlinkerZustand2 = 2;
}
wBlinkerZustand2 = 1;
}
break;

//^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ENDE AMPELSTEUERUNG ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
}
}
 
 



vllt. gefällt es ja.


lieben Gruss von südlich des Weisswurst-Äquators
Thomas

guckst: runderneuerte https://www.thkas-moba.de ‹(•¿•)› www.mucis.de

‹(•¿•)›

Mä-K-Gleis, Tams MC, Multi-Kulti Decoder, WDP


 
ThKaS
InterCityExpress (ICE)
Beiträge: 2.200
Registriert am: 28.04.2005
Homepage: Link


RE: Arduino: Zeitsteuerungen ohne Delay - ein kleines Tutorial

#43 von Reibuch , 01.12.2018 08:57

Hallo Franz Peter,

Es hängt an der Umsetzung in den korrekten Code

Den Ablauf(Gleis) Plan habe ich verstanden

VG
Thomas


Gruß Thomas


 
Reibuch
InterRegioExpress (IRE)
Beiträge: 311
Registriert am: 27.08.2006
Ort: Hunsrück
Gleise Märklin C Gleis
Spurweite H0
Stromart AC, Digital


RE: Arduino: Zeitsteuerungen ohne Delay - ein kleines Tutorial

#44 von MicroBahner , 01.12.2018 10:59

Hallo Thomas (Reibuch),

Zitat

Es hängt an der Umsetzung in den korrekten Code

Dann schreib doch mal in den Code an den jeweiligen Stellen rein, was unklar ist. Dann können wir das durchdiskutieren. Hilft bestimmt auch vielen anderen.

Hallo Thomas (ThKaS) ,

Zitat

vllt. gefällt es ja.

Find ich absolut super .


viele Grüße
Franz-Peter
Ein 'elektromechanisches' Stellwerk
Der (ehemalige) 'Eisberg'


 
MicroBahner
Metropolitan (MET)
Beiträge: 2.833
Registriert am: 28.11.2012
Ort: Mittelfranken
Gleise Tillig Elite
Steuerung Eigenbau
Stromart Analog


RE: Arduino: Zeitsteuerungen ohne Delay - ein kleines Tutorial

#45 von Reibuch , 01.12.2018 11:12

Hallo Franz Peter,

Vielen Dank 🙏 für das Angebot

Ich werden nach und nach die Zeile durchspielen und sehen was passiert oder auch nicht

Wenn ich das dann immer noch nicht kapiere komme ich auf dein Angebot zurück

Aber Mann lernt am besten dich selber versuchen

VG
Thomas


Gruß Thomas


 
Reibuch
InterRegioExpress (IRE)
Beiträge: 311
Registriert am: 27.08.2006
Ort: Hunsrück
Gleise Märklin C Gleis
Spurweite H0
Stromart AC, Digital


RE: Arduino: Zeitsteuerungen ohne Delay - ein kleines Tutorial

#46 von HeWi123 ( gelöscht ) , 10.12.2018 12:43

Hallo Franz-Peter,
ich bin neu auf der Arduino-Strecke und über die <MobaTools.h> gestolpert.
Ist diese Datei erhältlich und wenn ja, wo.
Hab Deine Beiträge mit viel Interesse gelesen und schon einiges gelernt bzw aufgefrischt
Viele Grüsse
Helmut


HeWi123

RE: Arduino: Zeitsteuerungen ohne Delay - ein kleines Tutorial

#47 von MicroBahner , 10.12.2018 14:24

Hallo Helmut,
das hattest Du mich doch schon im MobaTools Thread gefragt. Hat das so nicht funktioniert?
Nur die MobaTools.h Datei hilft dir nicht, Du brauchst die komplette Library. Im Eingangspost des MobaTools Thread habe ich beschrieben, wie man die installiert.


viele Grüße
Franz-Peter
Ein 'elektromechanisches' Stellwerk
Der (ehemalige) 'Eisberg'


 
MicroBahner
Metropolitan (MET)
Beiträge: 2.833
Registriert am: 28.11.2012
Ort: Mittelfranken
Gleise Tillig Elite
Steuerung Eigenbau
Stromart Analog


RE: Arduino: Zeitsteuerungen ohne Delay - ein kleines Tutorial

#48 von DoubleDee , 25.08.2020 16:48

Zu dem Beispiel mit dem Bahnüberghang, wenn ich in meinem switch die Anweisung gebe in welchen Fall gewechselt werden soll funktioniert es nicht.
Hab ich was vergessen? Hier mein Code:

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
 

 
int MotstepPin= 7;
int MotdirPin= 6;
int RegSens= 14;
int Schalter= 5;
int wRegSensZustand= 1;
 
void setup() {
Serial.begin(9600);

pinMode(MotstepPin, OUTPUT);
pinMode(MotdirPin, OUTPUT);
pinMode(RegSens, INPUT);
 

}
 
void loop() {

switch (wRegSensZustand) {

case 1:

int RegSens = analogRead(14);

Serial.println(RegSens);

if (RegSens &gt;= 1015){

for (int x = 0; x &lt; 200; x++){


digitalWrite(MotdirPin, HIGH);
digitalWrite (MotstepPin, HIGH);
delayMicroseconds (800);
digitalWrite (MotstepPin, LOW);
delayMicroseconds (800);

wRegSensZustand = 2;
}
}

break;

case 2:
 
RegSens = analogRead(14);

Serial.println(RegSens);
delay (500);

if (RegSens &lt;1015) {
 

for (int x= 0; x &lt; 10; x++)
{
digitalWrite(MotdirPin, LOW);
digitalWrite (MotstepPin, HIGH);
delayMicroseconds (600);
digitalWrite (MotstepPin, LOW);
delayMicroseconds (600);
}

wRegSensZustand = 1;
}
else {
 
wRegSensZustand = 3;
}

break;
 
case 3:
if ( digitalRead(Schalter) == HIGH) {


for (int x= 0; x &lt; 10; x++)
{
digitalWrite(MotdirPin, LOW);
digitalWrite (MotstepPin, HIGH);
delayMicroseconds (600);
digitalWrite (MotstepPin, LOW);
delayMicroseconds (600);
}
 
delay (30000);

wRegSensZustand = 1;
}
else {
wRegSensZustand = 2;
}
break;
} //Ende switch
} // Ende loop
 

 



In diesem Code soll ein Fenster geöffnet werden wenn es trocken ist bzw geschlossen werden wenn es Regnet.

Im Fall 1 gehe ich davon aus das dass Fenster geschlossen ist.
Es soll über den RegSens geprüft werden ob es Regnet oder nicht, wenn nicht soll Fenster mit einem Steppermotor geöffnet werden.
Bis hier hin funktioniert es so wie ich es will, Wenn dann das Fenster geöffnet ist, soll er mit Fall 2 weiter machen und nachsehen ob es Regnet, wenn nicht soll er zu Fall 3 gehen und prüfen ob ein Taster gedrückt wurde. Der Taster dient zum “manuellen” schließen des Fensters falls es draußen noch trocken ist und das Fenster nich automatisch zu geht.
Mein Problem ist, das er nach dem Fall 1 nicht in den Fall 2 Wechselt.

Vieleicht findet jemand den Fehler der mir unterlaufen ist.
(Der fall 3 ist noch nicht vollständig, ich habe den Schalter noch nicht implementiert! Will erstmal erreichen, dass er in die Fälle springt in die er soll.)

Danke MfG DD


DoubleDee  
DoubleDee
Beiträge: 1
Registriert am: 22.08.2020


RE: Arduino: Zeitsteuerungen ohne Delay - ein kleines Tutorial

#49 von MicroBahner , 25.08.2020 17:33

Hallo DD,
1. solltest Du Code immer in Code-Tags einschließen, damit der auch ordentlich dargestellt wire. Das geht auch nachträglich noch ( Code-Bereich markieren, und den Button </> oben im Editor drücken ). Die Formatierung ist allerdings schon verloren gegangen.

2. Wenn Du wissen willst, wo dein Code gerade 'herumläuft' solltest Du entsprechende Printanweisungen einstreuen.

3. Das kann nicht funktionieren:

1
 
for (int x = 0; x = 10; x++)
 

Die for-Schleife hat keine Abbruchbedingung. x=10 ist eine Zuweisung und immer wahr.

4. Was hat die Frage mir delay-freier und blockadefreier Programmierung zu tun? ( um die geht es in diesem Tutorial ).

5. Da das Ganze auch nichts mit MoBa zu tun hat, wärst Du vielleicht in einem Arduino-Forum mit der Frage besser aufgehoben. Z.B. hier oder hier. Aber nicht in beiden gleichzeitig fragen, das mögen einige Leute dort gar nicht


viele Grüße
Franz-Peter
Ein 'elektromechanisches' Stellwerk
Der (ehemalige) 'Eisberg'


 
MicroBahner
Metropolitan (MET)
Beiträge: 2.833
Registriert am: 28.11.2012
Ort: Mittelfranken
Gleise Tillig Elite
Steuerung Eigenbau
Stromart Analog


RE: Arduino: Zeitsteuerungen ohne Delay - ein kleines Tutorial

#50 von MicroBahner , 27.08.2020 22:01

Du solltest mal die 'warnings' in der IDE einschalten, dann zeigt er dir wo es klemmt. Diese Zeile:

1
2
 
  int RegSens = analogRead(14);
 
 

da ist das 'int' zuviel. An dieser Stelle sind keine Variablendeklarationen erlaubt, da kommt er mit dem Switch auch ducheinander.


viele Grüße
Franz-Peter
Ein 'elektromechanisches' Stellwerk
Der (ehemalige) 'Eisberg'


 
MicroBahner
Metropolitan (MET)
Beiträge: 2.833
Registriert am: 28.11.2012
Ort: Mittelfranken
Gleise Tillig Elite
Steuerung Eigenbau
Stromart Analog


   

passende Stecker / Buchsen zum Arduino Nano
Märklin Sounddecoder defekt

  • Ähnliche Themen
    Antworten
    Zugriffe
    Letzter Beitrag
Xobor Einfach ein eigenes Forum erstellen
Datenschutz