RE: Arduino: Schrankensteuerung - DCC-Ansteuerung für Betrieb und Justage

#126 von MicroBahner , 22.11.2015 11:38

Hallo Marko,
ich denke, dass dein Problem an der Adressierung liegt. Im Gegensatz zu dem 8-fach Servodecoder, der als Zubehördecoder arbeitet, ist die NmraDcc-Lib hier als Multifunktionsdekoder eingerichtet und verwendet daher eine Lokadresse (was Du ja auch gemacht hast). Auch die Adressauswertung macht hier die NmraDcc-Lib selbst - Telegramme an die 'falsche' Adresse kommen gar nicht beim Sketch an. So wie die CV's lt. den Debugausgaben gesetzt sind, verwendet die Lib lange Lokadressen (Bit 5 in CV29 ist gesetzt). Dann steht die Adresse in in CV17/CV18. Die dort hinterlegten Werte entsprechen einer Lokadresse 1000. Die '3' in CV1 wird bei langer Adressierung ignoriert. Nur wenn Bit5 in CV29 auf 0 steht, wird der Wert in CV1 als Adresse verwendet.
Du kannst entweder die Adresse im Sketch anpassen. In der Zeile

1
 
#define DCC_ADDR       9999 // bis 99 wird kurze Adressierung verwendet, ab 100 die lange
 

die 9999 durch 3 ersetzten. Danach musst Du aber den Sketch mit gesteckter Justagebrücke starten, damit die CV's gesetzt werden.
Oder Du änderst die CV's über die Zentrale entsprechend (das sollte mit der Standard NmraDcc-Lib auch gehen, da sie auf CV-Telegramme reagiert).

Wenn Du in Zeile 639 das Kommentarzeichen entfernst:

1
 
    //DB_PRINT( " Adresse: %u, F%d, Status %xnr", Addr, FuncNum, FuncState );
 

kannst Du erkennen, ob die Lib überhaupt ein empfangenes Telegramm an den Sketch weitergibt.

Da ich inzwischen wieder daheim bin, kann ich das bei mir auch mal verifizieren. Ich glaube mit kurzen Adressen habe ich das noch gar nicht getestet ops:


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: Schrankensteuerung - DCC-Ansteuerung für Betrieb und Justage

#127 von digi_thomas2003 , 22.11.2015 15:04

Hallo Zusammen,

so, nun habe ich es geschafft: Die BÜ-Steuerung für Servos V0.3 mit einer DCC-Ansteuerung zu verknüpfen. Abweichend von der DCC-Variante für die Schrittmotoren reagiert der "DCC-BÜ-Decoder" von mir auf eine Zubehör-Adresse (nämlich die 50).
Also: "Weiche 50" auf gerade --> BÜ schliesst
"Weiche 50" auf abzweig --> BÜ öffnet

Die Endlagenjustierung habe ich noch nicht angepast, die erfolgt noch über die beiden Justiertaster, wie von Franz-Peter vorgesehen.
Danke an Franz-Peter für die vorbildliche Dokumentation seines Codes, darauf habe ich aufgesetzt. Die Anpassungen an die DCC-Steuerung war dann relativ einfach.
Als Libs kommen auch bei meinem Sketch die MobaTools V0.6 zum Einsatz und die Nmra-Lib, so wie sie bei Mrrwa verfügbar ist, also auf Timer 0 basierend. Die beiden PWM-Pins 3 und 11 sind noch verfügbar und werden für die LEDs genutzt.
Folgende Arduino-Pins nutze ich:
Pin 2: Eingang des DCC-Signales aus dem Optokoppler
Pin 3: Ausgang LED1
Pin 4: Ausgang für das Decoder ACK (wenn der Decoder über die Digitalzentrale per CV programmiert wird)
Pin 5: Ausgang Servo1
Pin 6: Ausgang Servo2
Pin 7: Ausgang Glocke
Pin 9: Eingang Justiertaster Servo1
Pin 10: Eingang Justiertaster Servo2
Pin 11: Ausgang LED2

Hier der 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
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
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
 

/* Schrankensteuerung mit Servo und DCC-Ansteuerung V0.4 20.11.2015
* Die Schrankensteuerung benötigt die 'MobaTools' - library ab der Version 0.6
* und die NmraDcc Lib (Standard-Version ohne Timer 0 Modifikation)
*
* V0.4: Umstellung von Ansteuerung auf Tastendruck auf DCC-Ansteuerung. Der Schranke wird eine DCC-Zubehör-
* Adresse (Weichendecoder) zuordnet, 'gerade' oder 'grün' schließen die Schranke, 'abzweig' oder 'rot' öffnen sie
* Die Justierung erfolgt zunächst weiterhin über die beiden separaten Taster
* To be done:
* Die Werte sollen in CVs gespeichert werden:
* Der Zustand (offen/geschlossen) in CV 46
* Die Position ZU in CV 47 + 48
* Die Position AUF in CV 49 + 50
*
* V0.3: Mit Justierung der Endlagen und Speichern der Werte im EEPROM, vorbereitet für 4 Schrankenbäume.
* Die gesamte Bewegungskontrolle der Schrankenbäume ist in ein eigenes Unterprogramm ausgelagert.
* Dies erleichtert die Umstellung auf einen anderen Antrieb, z.b. mit einem Schrittmotor.
* Die Endlagenjustierung ist ebenfalls in diesem UP enthalten und kann jederzeit während des Betriebes vorgenommen
* werden. Pro Schranke wird ein Taster benötigt. Wird während der Schrankenbewegung der Taster gedrückt und
* gehalten, so läuft die Schranke verlangsamt weiter, bis die Taste losgelassen wird. Das ist dann die neue
* Endlage. Dies funktioniert sowohl beim Öffnen, als auch beim Schliessen der Schranke.
*
* V0.2: Version mit erweiterter Ablaufsteuerung: mit Vorlauf für Glocke und
* Wechselblinker.
*
* Für eine bessere Übersicht und Erweiterbarkeit ist das Programm logisch in einzelen Blöcke aufgeteilt.
* Diese Blöcke sind im loop hintereinander angeordnet, arbeiten aber weitgehend unabhängig. Damit dies
* möglich ist, dürfen innerhalb der Blöcke keine Warteschleifen/Delays werwendet werden, die den
* Programmablauf temporär anhalten.
*
* 1.Block: Einschaltlogik.
* Hier wird bestimmt, ob die Schranke geschlossen oder geöffnet werden soll, über eine DCC-Zubehör-Adresse
* Ergebnis der Einschaltlogik ist ein Flag 'schrankeSchliessen'
*
* 2. Block Ablaufsteuerung Schrankenlogik
* zentraler Block, der den Ablauf des Schrankenschliessens bzw -öffnens steuert. Der Block agiert abhängig
* von dem Flag 'schrankeSchliessen' und dem momentanen Zustand der Schrankenlogik
* Hier werden auch die Flags gesetzt, mit denen die Glocke (glAktiv) und der Wechselblinker (wbAktiv)
* ein- bzw ausgeschaltet werden.
*
* 3. Block Ansteuerung der Glocke
* abhängig vom Flag 'glAktiv' wird der Impulsausgang für die Glocke ein- bzw ausgeschaltet. Je nach ange-
* schlossenem Audio-Modul muss gegebenenfalls auch darauf geachtet werden, dass der letzte Glockenschlag
* nicht abgeschnitten wird.
*
* 4. Block Wechselblinker
* abhängig vom Flag 'wbAktiv' wird der Wechselblinker ein- bw ausgeschaltet. Beim Einschalten sind kurz beide
* Blinker gleichzeitig an, bevor sie dann abwechselnd blinken.
*
* Verwendete Anschlüsse:
* Pin2: DCC-Eingang
* Pin4: ACK-Ausgang
* Pin7: Ausgang Glocke
* Pin3 + Pin11: LED-Ausgänge
* Pin5 + Pin6: Servo-Ausgänge
* Pin9 + Pin10: Tastereingänge zum Justieren der Servos
*
*
*/
#include <MobaTools.h>
#include <NmraDcc.h>
 
#define DCC_ADDR 50 // Zubehör-Adresse, Weichendecoder
#define DEBUG ; // Wenn dieser Wert gesetzt ist, werden Debug ausgaben auf dem ser. Monitor ausgegeben
 
#define SCHRANKENZAHL 2 // Zahl der Schrankenbäume
 
// gegebenenfalls anzupassende Werte (weitere Werte können im Abschnitt 'Portzuordnungen und Konstante' angepasst werden)
#define PULS_ZU1 1200 // Initiale Pulslängen für die Endpositionen. Die Werte können über die Justierung
#define PULS_AUF1 1800 // angepasst werden. Die Drehrichung kann durch Vertauschen der Werte für ZU / AUF
#define PULS_ZU2 1200 // umgedreht werden. Dies ist über die Justierung NICHT anpassbar.
#define PULS_AUF2 1800
 
#define GLOCKE_ZYK 1000 // Glockenzyklus und Impulslänge muss an das angeschlossene Soundmodul
#define GLOCKE_PULS 200 // angepasst werden.
 
////////////////////////////////////////////////////////////////////////
//////////////// Portzuordnungen und Konstante /////////////////////////
// 1. Einschaltlogik --------------------------------------------------
const byte DccInputP = 2; // IRQ-Pin 2 des Arduino
 
// 2. Ablaufsteuerung --------------------------------------------------
const byte ServoPort[SCHRANKENZAHL] = { 5, 6 };
const byte schrTempo[SCHRANKENZAHL] = { 5, 4 };
const int schrVerzZU[SCHRANKENZAHL] = { 10, 500 }; // Verzögerung für die Schrankenbewegung (ms)
// damit laufen die Schranken nicht exakt gleichzeitig los.
// bei 4 Schrankenbäumen kann dies genutzt werden, um die in Auto-Fahrtrichtung
// hinteren Schranken später schliessen zu lassen
const int vorlaufZu = 6000; // Vorlaufzeit: Glocke und Wechselblinker aktiv, Schranke noch ruhend
const int nachlaufZu = 2000; // Nachlaufzeit: Schranke zu, Glocke nochaktiv
const byte Justage1P = 9; // Taster zum Justieren von Servo1
const byte Justage2P = 10; // Taster zum Justieren von Servo2
 
// 3. Glocke -------------------------------------------------------------
const byte glockeP = 7; // Impulsausgang zur Ansteuerung einer Glocke
const int glZykl = GLOCKE_ZYK; // Glockenrythmus
const int glImp = GLOCKE_PULS; // Impulslänge am Glockenausgang
 
// 4. Wechselblinker ----------------------------------------------------
const byte led1P = 3; // Ausgänge für den Wechselblinker ( Ports müssen PWM-fähig sein )
const byte led2P = 11;
const int wbZykl = 1100; // Zykluszeit des Wechselblinkers
const int wbSoft = 300; // Auf/Abblendzeit der Lampen
 
// sonst. ----------------------------------------------------------------
 
////////////////////// globale Variable //////////////////////////////////////
// 1. Einschaltlogik ----------------------------------------------------
bool schrankeSchliessen; // Wird über DCC Zubehördecoder angesteuert
 
NmraDcc DCC;
DCC_MSG Packet ;
 
// 2. Ablaufsteuerung ---------------------------------------------------
// EEPROM Aufteilung
// Das EEProm enthält die Endpositionen der Servos und den momentanen Zustand des Bü
// ( offen oder geschlossen ) für den nächsten Programmstart.
// Das Schlüsselwort EEMEM definiert die Variablen als Werte im EEPROM
#define EE_ISVALID 0x55
byte eeValid EEMEM ; // hex55 wenn EEprom gültige Daten enthält (Erstbeschreibung)
byte eeZustand EEMEM ; // aktueller Bue Zustand ( nur OFFEN und GESCHLOSSEN )
word eePosZu[SCHRANKENZAHL] EEMEM ;
word eePosAuf[SCHRANKENZAHL] EEMEM ;
 
// Variable im RAM
int positionZu[SCHRANKENZAHL] = {PULS_ZU1, PULS_ZU2}; // Servopostionen, über Justiervorgang einstellbar
int positionAuf[SCHRANKENZAHL] = {PULS_AUF1, PULS_AUF2}; // Servopostionen, über Justiervorgang einstellbar
byte justageAktiv[SCHRANKENZAHL];
Servo8 Schranke[SCHRANKENZAHL]; // Für die Schrankenservos
EggTimer SchrankeT[SCHRANKENZAHL]; // Schrankenspezifische Zeiten
// Aufrufparameter für das Unterprogramm 'Schrankenbewegung':
#define SB_INIT 0 // Servoansteuerung initiieren
#define SB_START_AUF 1 // Schranke öffnen starten
#define SB_START_ZU 2 // Schranke schliessen starten
#define SB_ENDE 3 // Bewegung überwachen und Ende erkennen. Ggfs. Endlagen justieren
 
EggTimer VorlaufT;
 
// Zustand, in dem sich die Ablaufsteuerung gerade befindet
byte bueZustand; // Aktueller Zustand
byte bueVorZustand; // vorheriger Zustand des Bue ( noch nicht verwendet)
#define OFFEN 50
#define VORLAUF_ZU 51 // Wechselblinker und Glocke, aber noch keine Bewegung
#define SCHRANKE_SCHLIESST 52 // Bewegung Schrankenbaum zu
#define NACHLAUF_ZU 53 // Beide Schrankenbäume in Endpos, Glocke läutet noch.
#define GESCHLOSSEN 54 // Schranke geschlossen
#define SCHRANKE_OEFFNET 56 // Bewegung Schrankenbaum auf
 
// 3. Glocke -------------------------------------------------------------
EggTimer glockeT;
byte glAktiv = false; // Flag ob Glocke aktiv ist
 
// 4. Wechselblinker ------------------------------------------------------
SoftLed Wblinker[2]; // 2 Leds für den Wechselblinker
EggTimer BlinkerT;
byte wbAktiv = false; // Flag ob Wechselblinker aktiv ist
byte ledState = LOW; // Status Wechselblinker
// Zustand Wechselblinker
byte wblZustand = 0;
#define WBL_AUS 0
#define WBL_START 1 // Beim Start sind kurz beide Lampen an
#define WBL_BLINKT 2
 
// sonst. -----------------------------------------------------------------
// für debugging
#ifdef DEBUG
#define DB_PRINT( ... ) sprintf( dbgbuf,"Dbg: " __VA_ARGS__ ) ; Serial.println( dbgbuf )
byte debug;
char dbgbuf[60];
#else
#define DB_PRINT ;
#endif
 
//###################### Ende der Definitionen ##############################
//###########################################################################
 
void setup()
{
byte i;
#ifdef DEBUG
Serial.begin(38400); //Debugging
Serial.println( "start of Program" );
#endif
// 1. Einschaltlogik ----------------------------------------------------
DCC.pin(digitalPinToInterrupt(DccInputP), DccInputP, 1); // Dcc-Signal mit Pullup
DCC.init( MAN_ID_DIY, 01, FLAGS_OUTPUT_ADDRESS_MODE | FLAGS_DCC_ACCESSORY_DECODER, 0 ); // Zubehördecoder, 11bit-Adresse
 
// 2. Ablaufsteuerung ---------------------------------------------------
pinMode(Justage1P, INPUT_PULLUP); //Zur Justage der Endlage Schranke 1
pinMode(Justage2P, INPUT_PULLUP); //dto, Schranke 2
//////////////////////////////////////////////////////
// Testen ob gültige Werte im EEProm. Wenn nicht, Grundinitiierung mit default-Werten
// Initiiert wird auch, wenn während des Programmstarts einer der Justageschalter
// betätigt ist
if ( eeprom_read_byte( &eeValid ) != EE_ISVALID ||
digitalRead( Justage1P) == LOW ||
digitalRead( Justage2P) == LOW ) {
// Grundinitiierung
DB_PRINT( "EEProm Initiierung" );
eeprom_write_byte( &eeValid, EE_ISVALID );
eeprom_write_byte( &eeZustand, OFFEN );
for ( i = 0; i < SCHRANKENZAHL; i++ ) {
eeprom_write_word( &eePosZu[i], positionZu[i] );
eeprom_write_word( &eePosAuf[i], positionAuf[i] );
}
}
/////////////////////////////////////
// Positionswerte aus EEProm lesen
for ( i = 0; i < SCHRANKENZAHL; i++ ) {
positionZu[i] = eeprom_read_word( &eePosZu[i] );
positionAuf[i] = eeprom_read_word( &eePosAuf[i] );
}
 
/////////////////////////////////////
// DCC-Adresse setzen
DCC.setCV( 1, DCC_ADDR % 256 );
DCC.setCV( 9, DCC_ADDR / 256 );
 
#ifdef DEBUG
// CV-Werte ausgeben
DB_PRINT( "CV1:%d, CV9:%d, CV29:%x, CV7=%d, CV8=%d", DCC.getCV(1), DCC.getCV(9), DCC.getCV(29), DCC.getCV(7), DCC.getCV(8) );
#endif
 
//////////////////////////////////////
/////// Antriebs-Initiierung ////////////
Schrankenbewegung( SB_INIT );
 
// Anfangsstellung der Schranke setzen
bueZustand = eeprom_read_byte( &eeZustand );
if ( bueZustand == GESCHLOSSEN ) {
Schrankenbewegung( SB_START_ZU );
while ( !Schrankenbewegung( SB_ENDE ) );
wbAktiv = true;
} else {
Schrankenbewegung( SB_START_AUF );
while ( !Schrankenbewegung( SB_ENDE ) );
}
// 3. Glocke -------------------------------------------------------------
pinMode( glockeP, OUTPUT );
 
// 4. Wechselblinker ------------------------------------------------------
Wblinker[0].attach(led1P); // Portzuordnung für den WEchselblinker
Wblinker[1].attach(led2P);
Wblinker[0].riseTime(wbSoft); // Weiches Auf/Abblenden der Lampen
Wblinker[1].riseTime(wbSoft);
 
// sonst. -----------------------------------------------------------------
 
} // End Setup
//############################### ENDE SETUP ##################################
//#############################################################################
 
void loop()
{
// 1. Einschaltlogik ----------------------------------------------------
////////////// Eingang zur Steuerung des Bahnübergangs /////////////////
DCC.process();
// schrankeSchliessen wird in notifyDccFunc gesetzt
 
// 2. Ablaufsteuerung ---------------------------------------------------
justageAktiv[0] = ( digitalRead( Justage1P ) == LOW ) ;
justageAktiv[1] = ( digitalRead( Justage2P ) == LOW ) ;
 
//////////// Ablaufsteuerung des Bue - Haupt-Zustandsautomat ///////////////////
switch ( bueZustand ) {
case OFFEN:
// Schranke ist geöffnet, warten auf Eingang
if ( schrankeSchliessen ) {
// Schranke soll sich schliessen, Glocke und Wechselblinker startet.
wbAktiv = true; // Wechselblinker einschalten
glAktiv = true; // Glocke einschalten. Diesen Befehl auskommentieren wenn die Glocke erst
// mit der Schrankenbewegung starten soll
VorlaufT.setTime( vorlaufZu );
bueZustand = VORLAUF_ZU;
DB_PRINT("Zustandswechsel: %d", bueZustand );
}
break; //----------------------------------------------------------
case VORLAUF_ZU:
// Warten bis die Vorlaufzeit abgelaufen ist, dann die Schrankenbewegung starten
if ( !VorlaufT.running() ) {
// Vorlaufzeit abgelaufen, Schrankenbewegung starten.
// spätestens hier muss auch die Glocke aktiviert werden
glAktiv = true; // wurde sie schon aktivert, machts auch nichts ;-)
wbAktiv = true;
Schrankenbewegung(SB_START_ZU); // Überwachung initiieren
bueZustand = SCHRANKE_SCHLIESST;
}
break; //----------------------------------------------------------
case SCHRANKE_SCHLIESST:
// Schrankenbaum schliesst sich.
if ( ( Schrankenbewegung( SB_ENDE ) ) ) {
// beide Schrankenbäume haben ihre Endposition erreicht
VorlaufT.setTime( nachlaufZu );
bueZustand = NACHLAUF_ZU;
}
break; //----------------------------------------------------------
case NACHLAUF_ZU:
// Schrankenbaum geschlossen, kurzer Nachlauf für Glocke.
if ( !VorlaufT.running() ) {
glAktiv = false;
bueZustand = GESCHLOSSEN;
eeprom_write_byte( &eeZustand, bueZustand );
}
break; //----------------------------------------------------------
case GESCHLOSSEN:
// Schranke ist zu, warten auf Eingang
if ( schrankeSchliessen == false ) {
// Schranke soll sich öffnen, Bewegung einleiten
Schrankenbewegung(SB_START_AUF); // Überwachung initiieren
wbAktiv = false; // Wechselblinker ausschalten
bueZustand = SCHRANKE_OEFFNET;
}
break; //----------------------------------------------------------
case SCHRANKE_OEFFNET:
// Schrankenbaum öffnet sich, warten bis offen
if ( schrankeSchliessen == true ) {
// Notfall: beim Öffnen der Schranke kommt wieder der Befehl Schranke schliessen
bueZustand = VORLAUF_ZU; // Da der Vorlauftimer nicht läuft, schliesst die Schranke sofort
 
}
if ( Schrankenbewegung( SB_ENDE ) ) {
// beide Schrankenbäume haben ihre Endposition erreicht
bueZustand = OFFEN;
eeprom_write_byte( &eeZustand, bueZustand );
}
break; //----------------------------------------------------------
} ////////////// Ende Zustandsautomat Bahnübergang /////////////////////
 
// 3. Glocke -------------------------------------------------------------
////////////////// Glockenimpuls erzeugen ////////////////////////////////
if ( glAktiv ) {
if ( !glockeT.running() ) {
// Glockentimer abgelaufen, Impuls erzeugen
if ( digitalRead( glockeP ) == HIGH ) {
// Port ist gesetzt, abschalten
digitalWrite( glockeP, LOW );
glockeT.setTime( glZykl - glImp );
} else {
// Port ist aus, einschalten
digitalWrite( glockeP, HIGH );
glockeT.setTime( glImp );
}
}
} else {
// Glocke inaktiv, Ausgang abschalten wenn Timer nicht mehr läuft
if ( !glockeT.running() ) {
// Die Timerabfrage stellt sicher, dass auch der letzte Impuls immer in
// voller Länge ausgegeben wird
digitalWrite( glockeP, LOW );
}
}
 
// 4. Wechselblinker ------------------------------------------------------
/////////////// Wechselblinker (Zustandsautomat ) //////////////////
switch (wblZustand) {
case WBL_AUS:
// Beide Lampen sind aus, warten auf einschalten
if ( wbAktiv ) {
// Beide Leds einschalten, Timer für gemeinsames Startleuchten
Wblinker[0].on();
Wblinker[1].on();
BlinkerT.setTime( wbSoft / 2 );
wblZustand = WBL_START;
}
break;
case WBL_START:
// Startphase: Nach Zeitablauf erste Led wieder aus
if ( !BlinkerT.running() ) {
// Übergang zur normalen Blinkphase
ledState = HIGH;
Wblinker[1].off();
BlinkerT.setTime(wbSoft);
wblZustand = WBL_BLINKT;
}
break;
case WBL_BLINKT:
if ( !BlinkerT.running() ) {
BlinkerT.setTime(wbZykl / 2);
if ( ledState == LOW ) {
Wblinker[0].on();
Wblinker[1].off();
ledState = HIGH;
} else {
ledState = LOW;
Wblinker[1].on();
Wblinker[0].off();
}
}
if ( !wbAktiv ) {
// Wechselblinker abschalten
Wblinker[0].off();
Wblinker[1].off();
wblZustand = WBL_AUS;
}
break;
 
} /////////// Ende switch Wechselblinker ////////////////////////
} // End Loop
//#################### ENDE LOOP ##################################################
//#################################################################################
 
byte Schrankenbewegung( byte mode ) {
// Bewegungsvorgang der Schranken überwachen, gegebenenfalls auch die Endlage
// justieren. Das Unterprogramm wird im Loop während der Bewegung zyklisch aufgerufen
// Der Funktionswert ist 'true', wenn die Bewegung aller Schranken abgeschlossen ist,
// sonst immer 'false'
// mode:SB_INIT Grundinitiierung
// SB_START_ZU Schliessen der Schranken einleiten
// SB_START_AUF Öffnen der Schranken einleiten
// SB_ENDE Bewegung überwachen, meldet 'true' wenn alle Bewegungen abgeschlossen
// sind
// -------------------------------------------------------------------------
//
static enum { WAIT, NORMAL, JUSTAGE_AKTIV, JUSTAGE_ENDE, WIPPEN } ssZustand[SCHRANKENZAHL] ;
static int startPos[SCHRANKENZAHL] ; // Position der Schranke zu Bewegungsbeginn
static enum { AUF, ZU } richtung;
 
byte bewegung = 0, sn;
int tmp;
for ( sn = 0; sn < SCHRANKENZAHL; sn++ ) {
// für alle Schranken durchlaufen
switch ( mode ) {
case SB_INIT: // Initiierung der Schranken
Schranke[sn].attach(ServoPort[sn], 1); //Servos an Pin 5 / 6
Schranke[sn].setSpeed( schrTempo[sn] );
bewegung = 1;
break; //---------------------------------------------
case SB_START_ZU: // Schliessen der Schranken einleiten
richtung = ZU;
Schranke[sn].setSpeed( schrTempo[sn]);
SchrankeT[sn].setTime( schrVerzZU[sn] ); //Wartezeit bis Schrankenbewegung
DB_PRINT( "Start Wartezeit %d mit %d ms", sn, schrVerzZU[sn] );
ssZustand[sn] = WAIT;
bewegung = 1;
break; //---------------------------------------------
case SB_START_AUF: // Öffnen der Schranken einleiten
richtung = AUF;
Schranke[sn].setSpeed( schrTempo[sn]);
Schranke[sn].write( positionAuf[sn]);
ssZustand[sn] = NORMAL;
startPos[sn] = Schranke[sn].readMicroseconds();
DB_PRINT( "Schranke %d, Position: %d, Richtung= %d", sn, startPos[sn], richtung );
bewegung = 1;
break; //---------------------------------------------
case SB_ENDE: // Bewegung überwachen, auf Ende prüfen
// Schrankenbewegung
switch ( ssZustand[sn] ) {
case WAIT: // Verzögerungszeit bis zum Schrankenstart abwarten
// Wird nur beim Schliessen der Schranke durchlaufen
if ( SchrankeT[sn].running() == false ) {
// Zeit abgelaufen, Bewegung starten
Schranke[sn].write( positionZu[sn]);
ssZustand[sn] = NORMAL;
startPos[sn] = Schranke[sn].readMicroseconds();
DB_PRINT( "Schranke %d, Position: %d, Richtung= %d", sn, startPos[sn], richtung );
ssZustand[sn] = NORMAL;
}
bewegung = 1;
break; //......................................
case NORMAL:
bewegung += Schranke[sn].moving();
if ( justageAktiv[sn] ) {
// Justageschalter betätigt, Speed auf 1, Servobewegung um 10% weitersetzen,
// sodass die neue Endposition auch hinter der alten liegen kann.
Schranke[sn].setSpeed( 1 );
ssZustand[sn] = JUSTAGE_AKTIV;
if ( richtung == ZU ) tmp = (positionZu[sn] * 3 - positionAuf[sn]) / 2;
else tmp = (positionAuf[sn] * 3 - positionZu[sn]) / 2;
DB_PRINT( "Schranke %d, Justage Endpso=%d", sn, tmp );
Schranke[sn].write( tmp );
}
// if ( bewegung < 5 ) ssZustand[SchrNr] = WIPPEN;
break; // .....................................
case WIPPEN:
// to be defined ;-)
break; //......................................
case JUSTAGE_AKTIV:
bewegung += 1; // keine Endemeldung während der Justage
if ( !justageAktiv[sn] ) {
// Justageschalter wurde wieder losgelassen. Momentane Servo-Position
// als neuen Endpunkt speichern und Servo anhalten
tmp = Schranke[sn].readMicroseconds();
DB_PRINT( "Schranke %d, Justage ende, Pos = %d", sn, tmp );
Schranke[sn].write( tmp );
if ( richtung == ZU ) {
positionZu[sn] = tmp;
eeprom_write_word( &eePosZu[sn], tmp );
} else {
positionAuf[sn] = tmp;
eeprom_write_word( &eePosAuf[sn], tmp );
}
ssZustand[sn] = JUSTAGE_ENDE;
}
break; //......................................
case JUSTAGE_ENDE:
bewegung += Schranke[sn].moving();
 
break; //......................................
} // ..... Ende switch 'Schrankenzustand' ......
 
break; //---------------------------------------------
default:
// falscher Programmaufruf, keine Reaktion
;
} // --- Ende Switch 'mode' --------
} // ........Ende forschleife der Schranken........
 
if ( bewegung == 0 ) DB_PRINT( "Endpositionen erreicht");
return ( bewegung == 0 );
}
 
//###################################################################################
//###################### DCC - Funktionen ###########################################
// Auswertung des Zubehördecoders
void notifyDccAccState( uint16_t Addr, uint16_t BoardAddr, uint8_t OutputAddr, uint8_t State)
{
if (Addr == DCC_ADDR) {
schrankeSchliessen = ((OutputAddr & 0x1) != 0);
DB_PRINT( " Adresse: %u, Status %x", Addr, schrankeSchliessen );
}
}
 

 
 



Was ich noch machen möchte:

  • Bisher werden die Auf- und Zu-Positionen der Servos direkt im EEPROM gespeichert. Das möchte ich auf Speicherung in CVs umstellen, damit auch eine Programmierung mit der Digitalzentrale möglich ist.
  • Um das zu erreichen, muß ich die Positionierung der Servos von Impulsen auf Winkel im Sketch umstellen, da eine CV nur Werte bis max. 255 aufnehmen kann.
  • Und natürlich die Justierung per Digitalzentrale statt per Taster, ähnlich wie in der Variante für die Schrittmotoren. Allerdings fehlt mir hier noch eine zündende Idee, wie das am sinnvollsten zu bewerkstelligen ist.


Ein Bild vom Versuchsaufbau folgt noch...

Viel Spaß beim Testen. Rückmeldungen sind natürlich sehr erwünscht!!

Freundliche Grüße
Thomas

Edit: Den Pin für die Glocke von Pin4 auf Pin7 geändert, da Pin4 für das ACK vorgesehen ist.


Thomas
------------------
Anlage H0: U-Form, im kreativen Bau
Fahren: Tams MC
Schalten: IB
Melden: HSI 88
Steuern: TrainController 9.0 Gold
Denken: Brain 4.1


Majestix hat sich bedankt!
 
digi_thomas2003
InterRegioExpress (IRE)
Beiträge: 305
Registriert am: 03.05.2005
Gleise sind vorhanden
Spurweite H0
Steuerung TrainController
Stromart AC, Digital


RE: Arduino: Schrankensteuerung - DCC-Ansteuerung für Betrieb und Justage

#128 von Mape71 ( gelöscht ) , 22.11.2015 16:39

Hallo Franz-Peter,

vielen Dank für die Hinweise - nun habe ich schon einige Funktionen herstellen können. Was noch nicht gelingt ist die Endlageneinstellung mit dem Fahrregler (ich kann den Motor zwar mit dem Regler in beide Richtungen bewegen, jedoch bleiben die Endlagen nicht gespeichert). Darüber hinaus bewegt sich der Motor beim Drücken von F0 in eine Richtung, wenn ich F0 aber ein zweites Mal drücke, so fährt der Motor nicht wieder zurück. Die Blinklichter verhalten sich hingegen korrekt. Ich habe auch einmal versucht in Zeile 63 den Wert für die Drehrichtung auf -1 zu setzen - dann verhält sich der Motor auch anders herum, d.h. fährt in eine, dann die entgegen gesetzte, Richtung aber nicht wieder zurück. Kann es sein, dass hier die Einstellung der Endlagen etwas durcheinander bringt, indem dass über die Programmierung der Endlagen z.B. die Vorzeichen falsch gesetzt werden und somit eine Bewegungsrichtung blockiert wird?

Vielen Dank und Grüße

Marko


Mape71

RE: Arduino: Schrankensteuerung - DCC-Ansteuerung für Betrieb und Justage

#129 von Mape71 ( gelöscht ) , 22.11.2015 16:42

..und noch eine kurze Frage zu den Lichtschranken - wenn die Lichtschranke unterbrochen ist, habe ich eine Spannung an A2 von knapp 5Volt. Wenn sie geöffnet ist, liegt die Spannung bei 2.5 Volt. Sind die Werte so OK und werden vom Arduino korrekt ausgewertet - oder muss die Spannung noch weiter absinken?

Danke und Grüße

Marko


Mape71

RE: Arduino: Schrankensteuerung - DCC-Ansteuerung für Betrieb und Justage

#130 von Mape71 ( gelöscht ) , 22.11.2015 17:15

Hallo zusammen,

bevor sich jemand bemüht mir zu antworten - ich habe den Widerstand des Fototransistors von 47k auf 100k erhöht - somit ist die Spannung an A3 noch einmal deutlich niedriger. Und: Es funktioniert! Das emint zumindest erst einmal grob - nun mache ich mich an die Feineinstellung.

Viele Grüße

Marko


Mape71

RE: Arduino: Schrankensteuerung - DCC-Ansteuerung für Betrieb und Justage

#131 von MicroBahner , 22.11.2015 17:24

Hallo Marko,
zu den Lichtschranken: 2,5V bei geöffneter Lichtschranke ist definitiv zu viel. Da liegt so gerade die Schaltschwelle der Eingänge. Über ca 1V sollte es auf keinen Fall sein - besser weniger.
Das Öffnen/Schliessen funktioniert auch nur bei korrekter Lichtschrankenauswertung. In der einen Endstellung muss die Lichtschranke als 'Offen' erkannt werden, in der anderen Endstellung als 'unterbrochen'. Sonst dreht der Motor nicht richtig.

P.S. - Sehe gerade, dass Du es schon selbst gefunden hast . Sicherer wäre es aber, wenn Du die Beleuchtung besser justierst. Bei mir liegt die Spannung am Fototransister auch mit 47kOhm deutlich unter 1V.


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: Schrankensteuerung - DCC-Ansteuerung für Betrieb und Justage

#132 von Mape71 ( gelöscht ) , 22.11.2015 23:32

Hallo zusammem,

erst noch einmal vielen Dank an franz-Peter für die Unterstützung. Ich habe noch einmal ein wenig an der Lichtschranke gewerkelt, jedoch bekomme ich mit 47k Widerstand nicht weniger als 2.5Volt zustande - und LED und Fototransistor liegen sich wirklich sehr präzise gegenüber. Evtl. habe ich aber beim Aufbau irgendetwas zerstört, aber ich werde jetzt noch mehrere Antriebe bauen und dann mal sehen. Mit dem 100k Widerstand läuft es aber anscheinend auch ganz gut.
Nachdem Feinjustieren bin ich mit den ersten Ergebnissen schon ganz zufrieden, obwohl es nicht so gut aussieht wie bei Franz-Peter. In Teilen mag das aber auch an der Spurgröße liegen - N ist im Vergleich zu H0 doch etwas filigraner und der Schrankenbaum hat so gut wie kein Gewicht. Mit einer Feder und einem Gummiband habe ich mich auch mal versucht, allerdings ist mein Schrittmotor so wenig belastbar, dass der Einsatz von Feder oder Gummiband immer den Motor zum Stillstand brachte.
Anbei nun mal ein paar Videos, die einen Schranken-Prototyp bei der Arbeit zeigen. Andreaskreuze sind nicht montiert, aber die LEDs sind im Hintergrund zu sehen. Darüber hinaus auch die 3D Zeichnung vom Halter - den STL-File zum Drucken gebe ich gerne auf Nachfrage per PN.

Vielen Dank und schöne Grüße

Marko



https://youtu.be/anlblPSzbp8

https://youtu.be/gHk8mznQQFQ

https://youtu.be/lQymlozNOn4


Mape71

RE: Arduino: Schrankensteuerung - DCC-Ansteuerung für Betrieb und Justage

#133 von UweS , 23.11.2015 10:11

Hallo Marko,

druckst Du die Halter selbst, oder lässt Du sie drucken?


Uwe

Lenz Digital seit 1993, seit 2020 Roco z21 und steuern mit der Z21 App, Traincontroller Gold, Mikromodellbau, Car Motion


 
UweS
InterRegioExpress (IRE)
Beiträge: 340
Registriert am: 02.02.2012
Spurweite H0, 1
Stromart Digital


RE: Arduino: Schrankensteuerung - DCC-Ansteuerung für Betrieb und Justage

#134 von Mape71 ( gelöscht ) , 23.11.2015 10:13

Hallo Uwe,

selbst ist der Mann[emoji1]

viele Grüße

Marko


Mape71

RE: Arduino: Schrankensteuerung - DCC-Ansteuerung für Betrieb und Justage

#135 von MicroBahner , 23.11.2015 20:02

Hallo,
das ist ja super, jetzt haben wir gleich 2 funktionierende Schranken

@Thomas:

Zitat von digi_thomas2003
Bisher werden die Auf- und Zu-Positionen der Servos direkt im EEPROM gespeichert. Das möchte ich auf Speicherung in CVs umstellen, damit auch eine Programmierung mit der Digitalzentrale möglich ist.

Das solltest Du auf jeden Fall machen. So wie es jetzt ist, ist es problematisch, da der Sketch und die Lib das EEPROM unabhängig voneinander benutzen. Da besteht die Gefahr der Überschneidung. Die Lib verwendet das gesamte EEPROM für die Speicherung der CV's wobei CV-Nummer = EEPROM-Adresse. Da der Sketch auch ins EEPROM schreibt, sind Konflikte vorprogrammiert.

Zitat von digi_thomas2003
Um das zu erreichen, muß ich die Positionierung der Servos von Impulsen auf Winkel im Sketch umstellen, da eine CV nur Werte bis max. 255 aufnehmen kann.

Wobei man die Endlagenwerte auch auf 2 CV's aufteilen könnte. Das wird bei Werten>255 auch bei den Standard CV's öfters gemacht.

@Marko:

Zitat von Mape71
Ich habe noch einmal ein wenig an der Lichtschranke gewerkelt, jedoch bekomme ich mit 47k Widerstand nicht weniger als 2.5Volt zustande - und LED und Fototransistor liegen sich wirklich sehr präzise gegenüber.

Ob 100k oder 47k macht ja jetzt auch nicht sooo den großen Unterschied. Tendenziell ist halt niederohmiger besser, da da die Störeinflüsse geringer sind. Evtl. könnte auch die spektrale Abstimmung Fototransistor - Led ein Rolle spielen. Der LPT80 hat seine höchste Empfindlichkeit im IR-Bereich, ideal als LED ist also eine IR Led. Leuchtet die Led in einem anderen Spektralbereich, wird die Lichtschranke unempfindlicher.

Zitat von Mape71
In Teilen mag das aber auch an der Spurgröße liegen - N ist im Vergleich zu H0 doch etwas filigraner und der Schrankenbaum hat so gut wie kein Gewicht.

Das macht sicher einiges aus. Bei mir hat der Schrankenbaum so viel Gewicht, dass er von alleine zufällt, und der Motor beim Schliessen eigentlich bremst, und nicht antreibt. Deshalb brauche ich auch zur Verbindung mit dem Schrankenbaum nur einen Faden, da der immer auf Zug beansprucht ist - was auch dort das mechanische Spiel eliminiert. Wenn Du aber gar keine Vorspannung auf das Getriebe legen kannst, ist der Motor vielleicht doch etwas schwachbrüstig . Aber alles in allem sieht's doch ganz ordentlich aus


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: Schrankensteuerung - DCC-Ansteuerung für Betrieb und Justage

#136 von garti62 , 23.11.2015 21:04

Hallo Marko,

Zitat von Mape71

N ist im Vergleich zu H0 doch etwas filigraner und der Schrankenbaum hat so gut wie kein Gewicht.



Ist der Schrankenbaum aus Kunststoff? Dann könntest Du ihn durch ein passendes Messingrohr oder noch besser Rundmaterial ersetzen, das habe ich bei meinen Viessmann-Schranken (allerdings H0) auch gemacht und bin mit dem Ergebnis eigentlich recht zufrieden.

Schöne Grüße

Ulli


erste Versuche: Weichenbau


 
garti62
InterCity (IC)
Beiträge: 645
Registriert am: 08.11.2011


RE: Arduino: Schrankensteuerung - DCC-Ansteuerung für Betrieb und Justage

#137 von Mape71 ( gelöscht ) , 23.11.2015 21:25

Hallo Ulli,

vielen Dank für den Tip, werde ich mal ausprobieren. Eigentlich wollte ich vier Halbschranken bauen, womit sich das Gewicht weiter reduzieren würde. Evtl. kaufe ich mir noch einen Messingbausatz mit Vollschranken - damit wird es dann bestimmt noch mal besser. Ein weiteres Problem ist sicher auch noch der deutlich kürzere Stellweg bei Spur N. Wie in den Videos zu sehen nutze ich nur einen Bruchteil des möglichen Weges, womit weitere Ungenauigkeiten entstehen. Evtl. Versuche ich doch noch mal die Servoversion und baue noch einen Umlenkhebel mit ein - mal sehen.

Viele Grüße

Marko


Mape71

RE: Arduino: Schrankensteuerung - DCC-Ansteuerung für Betrieb und Justage

#138 von digi_thomas2003 , 23.11.2015 22:27

Hallo Franz-Peter,

Zitat von MicroBahner
Hallo,
das ist ja super, jetzt haben wir gleich 2 funktionierende Schranken

@Thomas:

Zitat von digi_thomas2003
Bisher werden die Auf- und Zu-Positionen der Servos direkt im EEPROM gespeichert. Das möchte ich auf Speicherung in CVs umstellen, damit auch eine Programmierung mit der Digitalzentrale möglich ist.

Das solltest Du auf jeden Fall machen. So wie es jetzt ist, ist es problematisch, da der Sketch und die Lib das EEPROM unabhängig voneinander benutzen. Da besteht die Gefahr der Überschneidung. Die Lib verwendet das gesamte EEPROM für die Speicherung der CV's wobei CV-Nummer = EEPROM-Adresse. Da der Sketch auch ins EEPROM schreibt, sind Konflikte vorprogrammiert.
...



Genauso ist es, das habe ich gemerkt, als ich die CVs mit der Zentrale ausgelesen habe.
Den Sketch habe ich (auf dem Papier und im Kopf) schon angepasst, ich muß ihn nur noch austesten.

Zitat von MicroBahner
...

Zitat von digi_thomas2003
Um das zu erreichen, muß ich die Positionierung der Servos von Impulsen auf Winkel im Sketch umstellen, da eine CV nur Werte bis max. 255 aufnehmen kann.

Wobei man die Endlagenwerte auch auf 2 CV's aufteilen könnte. Das wird bei Werten>255 auch bei den Standard CV's öfters gemacht.
...



Richtig, auch das wäre möglich. Aber Deine MobaTools bieten ja auch die Steuerung der Servos über den Winkel an - daher nutze ich dieses Feature. Wie oben schon geschrieben muß der Sketch nur noch den Weg in den Arduino finden und ausgetestet werden.
Das wird allerdings geschäftlich bedingt noch etwas dauern...

Ich arbeite übrigens gerade an einer ausführlicheren Doku der DCC-NMRA-Library. Bei den Geschwindigkeitsstufen und den langen Adressen gibt es ein paar Ungereimtheiten, ich habe da auch schon mit dem Programmierer der Lib (Alex Shepherd) Kontakt aufgenommen. Eventuell wird es demnächst eine angepasste Version geben, mal sehen.

Herzliche Grüße
Thomas


Thomas
------------------
Anlage H0: U-Form, im kreativen Bau
Fahren: Tams MC
Schalten: IB
Melden: HSI 88
Steuern: TrainController 9.0 Gold
Denken: Brain 4.1


 
digi_thomas2003
InterRegioExpress (IRE)
Beiträge: 305
Registriert am: 03.05.2005
Gleise sind vorhanden
Spurweite H0
Steuerung TrainController
Stromart AC, Digital


RE: Arduino: Schrankensteuerung - DCC-Ansteuerung für Betrieb und Justage

#139 von Mape71 ( gelöscht ) , 29.11.2015 18:10

Halo zusammen,

nachdem ich mit meinem Micro-Steppermotor noch nicht so ganz zufrieden war habe ich mich noch einmal an dem größeren Modell versucht. Mit dem dafür angefertigten Halter ist die Konstruktion insgesamt gar nicht so viel größer, aber der größere Motor wirkt deutlich präziser, die Halterung war viel einfacher zu bauen und auch die Bewegung der Schranke gefällt mir so besser. Anbei einmal für Euch die 3D Zeichnung von Halter und Stellhebel und ein Link zu einem Video, wo der Prototyp in Funktion zu sehen ist. Ich denke so wird das ganze dann auch unter meine Anlage wandern. Wenn jemand Bedarf an den STL-Files für den Drucker hat - bitte einfach PN schicken.
Eine Frage habe ich dann aber doch noch - wie kann ich die Schranken denn über eine Weichenadresse schalten? Das würde mir bei der Steuerung per Computer das Leben deutlich vereinfachen. Lässt sich das einfach machen?

Viele Grüße

Marko

https://youtu.be/yXOd1T2NYSg




Mape71

RE: Arduino: Schrankensteuerung - DCC-Ansteuerung für Betrieb und Justage

#140 von digi_thomas2003 , 29.11.2015 20:08

Hallo Marko,

Zitat von Mape71
...
Eine Frage habe ich dann aber doch noch - wie kann ich die Schranken denn über eine Weichenadresse schalten? Das würde mir bei der Steuerung per Computer das Leben deutlich vereinfachen. Lässt sich das einfach machen?
...



schau Dir mal meinen Sketch für die Ansteuerung des BÜs an, ich habe zwar Servomotoren, aber die Ansteuerung erfolgt über als Zubehör-Decoder mit einer "Weichenadresse".
Franz-Peter hat seine Vorlage so gut dokumentiert, darauf habe ich aufgebaut. Du solltest also relativ einfach den Code für die Servos gegen den Code für die Schrittmotoren austauschen können.

Freundliche Grüße
Thomas


Thomas
------------------
Anlage H0: U-Form, im kreativen Bau
Fahren: Tams MC
Schalten: IB
Melden: HSI 88
Steuern: TrainController 9.0 Gold
Denken: Brain 4.1


 
digi_thomas2003
InterRegioExpress (IRE)
Beiträge: 305
Registriert am: 03.05.2005
Gleise sind vorhanden
Spurweite H0
Steuerung TrainController
Stromart AC, Digital


RE: Arduino: Schrankensteuerung - DCC-Ansteuerung für Betrieb und Justage

#141 von digi_thomas2003 , 29.11.2015 21:12

Hallo Zusammen,

ich habe den Sketch für die BÜ-Ansteuerung mit Servos überarbeitet. Der Decoder arbeitet nun vollständig mit CVs und kann über Programmiergleis und über das Hauptgleis (POM) programmiert werden. Der Decoder ist als Zubehör-Decoder (Accessory Decoder) konfiguriert.
Folgende CVs werden verwendet:
CV 1: LSB der Zubehör-Digitaladresse (Default: 50)
CV 9: MSB der Zubehör-Digitaladresse (Default: 0)
CV 7: Versions-ID (aktuell 5)
CV 8: Hersteller-ID (13 für DIY-Decoder)
CV 29: Decoder ist ein Zubehör-Decoder mit 11bit-Adresse (Wert 192)
CV 44: LSB der Lokadresse (für POM) (Default: 50)
CV 45: MSB der Lokadresse (Default: 50)
CV 46: aktueller Zustand des BÜ (offen / geschlossen)
CV 47: Position ZU für Servo1 (in Grad, 0 - 180)
CV 48: Position ZU für Servo2 (in Grad, 0 - 180)
CV 49: Position AUF für Servo1 (in Grad, 0 - 180)
CV 50: Position AUF für Servo2 (in Grad, 0 - 180)

Weiterhin ist die Justierung auch über die beiden Taster möglich.

Basis ist die NmraDcc-Library in der aktuellsten "normalen" Version (http://www.mrrwa.org) und die MobaTools von Franz-Peter.
Achtung: Es gibt seit dem 28.11.2015 eine überarbeitete NmraDcc-Library, in der die Behandlung von Geschwindigkeitsstufen korrigiert wurde. Dies hat auf diesen Sketch keine Auswirkung, da der Decoder hier als Zubehör-Decoder konfiguriert ist.
Aber beim Sketch von Franz-Peter muß die notifyDccSpeed- und die notifyDccFunc-Funktion angepasst werden, wenn mit der neuen Lib gearbeitet wird.

Hier der 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
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
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
 

/* Schrankensteuerung mit Servo und DCC-Ansteuerung V0.5 28.11.2015
* Die Schrankensteuerung benötigt die 'MobaTools' - library ab der Version 0.6
* und die NmraDcc Lib (Standard-Version ohne Timer 0 Modifikation)
*
* V0.5: Speicherung der Position ZU und Position AUF in CVs
* Der Zustand (offen/geschlossen) in CV 46
* Die Position ZU in CV 47 + 48
* Die Position AUF in CV 49 + 50
* Lok-Adresse für POM-Programmierung eines Zubehördecoders in CV 44 und 45
*
* V0.4: Umstellung von Ansteuerung auf Tastendruck auf DCC-Ansteuerung. Der Schranke wird eine DCC-Zubehör-
* Adresse (Weichendecoder) zuordnet, 'gerade' oder 'grün' schließen die Schranke, 'abzweig' oder 'rot' öffnen sie
* Die Justierung erfolgt zunächst weiterhin über die beiden separaten Taster
*
* V0.3: Mit Justierung der Endlagen und Speichern der Werte im EEPROM, vorbereitet für 4 Schrankenbäume.
* Die gesamte Bewegungskontrolle der Schrankenbäume ist in ein eigenes Unterprogramm ausgelagert.
* Dies erleichtert die Umstellung auf einen anderen Antrieb, z.b. mit einem Schrittmotor.
* Die Endlagenjustierung ist ebenfalls in diesem UP enthalten und kann jederzeit während des Betriebes vorgenommen
* werden. Pro Schranke wird ein Taster benötigt. Wird während der Schrankenbewegung der Taster gedrückt und
* gehalten, so läuft die Schranke verlangsamt weiter, bis die Taste losgelassen wird. Das ist dann die neue
* Endlage. Dies funktioniert sowohl beim Öffnen, als auch beim Schliessen der Schranke.
*
* V0.2: Version mit erweiterter Ablaufsteuerung: mit Vorlauf für Glocke und
* Wechselblinker.
*
* Für eine bessere Übersicht und Erweiterbarkeit ist das Programm logisch in einzelen Blöcke aufgeteilt.
* Diese Blöcke sind im loop hintereinander angeordnet, arbeiten aber weitgehend unabhängig. Damit dies
* möglich ist, dürfen innerhalb der Blöcke keine Warteschleifen/Delays werwendet werden, die den
* Programmablauf temporär anhalten.
*
* 1.Block: Einschaltlogik.
* Hier wird bestimmt, ob die Schranke geschlossen oder geöffnet werden soll, über eine DCC-Zubehör-Adresse
* Ergebnis der Einschaltlogik ist ein Flag 'schrankeSchliessen'
*
* 2. Block Ablaufsteuerung Schrankenlogik
* zentraler Block, der den Ablauf des Schrankenschliessens bzw -öffnens steuert. Der Block agiert abhängig
* von dem Flag 'schrankeSchliessen' und dem momentanen Zustand der Schrankenlogik
* Hier werden auch die Flags gesetzt, mit denen die Glocke (glAktiv) und der Wechselblinker (wbAktiv)
* ein- bzw ausgeschaltet werden.
*
* 3. Block Ansteuerung der Glocke
* abhängig vom Flag 'glAktiv' wird der Impulsausgang für die Glocke ein- bzw ausgeschaltet. Je nach ange-
* schlossenem Audio-Modul muss gegebenenfalls auch darauf geachtet werden, dass der letzte Glockenschlag
* nicht abgeschnitten wird.
*
* 4. Block Wechselblinker
* abhängig vom Flag 'wbAktiv' wird der Wechselblinker ein- bw ausgeschaltet. Beim Einschalten sind kurz beide
* Blinker gleichzeitig an, bevor sie dann abwechselnd blinken.
*
* Verwendete Anschlüsse:
* Pin2: DCC-Eingang
* Pin4: ACK-Ausgang
* Pin3 + Pin11: LED-Ausgänge
* Pin5 + Pin6: Servo-Ausgänge
* Pin9 + Pin10: Tastereingänge zum Justieren der Servos
* Pin7: Ausgang für die Ansteuerung der Glocke
*
*
*/
#include <MobaTools.h>
#include <NmraDcc.h>
 
#define DCC_DECODER_VERSION_ID 5 // Versions-ID zur Speicherung in CV 7
#define DCC_ADDR 50 // Zubehör-Adresse, Weichendecoder
#define CV_DCC_POM_PROG 44 // CV 44 beinhalten die Digitaladresse, unter der der Decoder auf dem Hauptgleis programmiert werden kann (POM)
#define DEBUG ; // Wenn dieser Wert gesetzt ist, werden Debug ausgaben auf dem ser. Monitor ausgegeben
 
#define SCHRANKENZAHL 2 // Zahl der Schrankenbäume
 
// gegebenenfalls anzupassende Werte (weitere Werte können im Abschnitt 'Portzuordnungen und Konstante' angepasst werden)
#define PULS_ZU1 50 // Initiale Winkel für die Endpositionen. Die Werte können über die Justierung
#define PULS_AUF1 100 // angepasst werden. Die Drehrichung kann durch Vertauschen der Werte für ZU / AUF
#define PULS_ZU2 50 // umgedreht werden. Dies ist über die Justierung NICHT anpassbar.
#define PULS_AUF2 100
 
#define GLOCKE_ZYK 1000 // Glockenzyklus und Impulslänge muss an das angeschlossene Soundmodul
#define GLOCKE_PULS 200 // angepasst werden.
 
////////////////////////////////////////////////////////////////////////
//////////////// Portzuordnungen und Konstante /////////////////////////
// 1. Einschaltlogik --------------------------------------------------
const byte DccInputP = 2; // IRQ-Pin 2 des Arduino
const byte DccAckPin = 4; // Ausgang für das ACK
 
// 2. Ablaufsteuerung --------------------------------------------------
const byte ServoPort[SCHRANKENZAHL] = { 5, 6 };
const byte schrTempo[SCHRANKENZAHL] = { 5, 4 };
const int schrVerzZU[SCHRANKENZAHL] = { 10, 500 }; // Verzögerung für die Schrankenbewegung (ms)
// damit laufen die Schranken nicht exakt gleichzeitig los.
// bei 4 Schrankenbäumen kann dies genutzt werden, um die in Auto-Fahrtrichtung
// hinteren Schranken später schliessen zu lassen
const int vorlaufZu = 6000; // Vorlaufzeit: Glocke und Wechselblinker aktiv, Schranke noch ruhend
const int nachlaufZu = 2000; // Nachlaufzeit: Schranke zu, Glocke nochaktiv
const byte Justage1P = 9; // Taster zum Justieren von Servo1
const byte Justage2P = 10; // Taster zum Justieren von Servo2
 
// 3. Glocke -------------------------------------------------------------
const byte glockeP = 7; // Impulsausgang zur Ansteuerung einer Glocke
const int glZykl = GLOCKE_ZYK; // Glockenrythmus
const int glImp = GLOCKE_PULS; // Impulslänge am Glockenausgang
 
// 4. Wechselblinker ----------------------------------------------------
const byte led1P = 3; // Ausgänge für den Wechselblinker ( Ports müssen PWM-fähig sein )
const byte led2P = 11;
const int wbZykl = 1100; // Zykluszeit des Wechselblinkers
const int wbSoft = 300; // Auf/Abblendzeit der Lampen
 
// sonst. ----------------------------------------------------------------
 
////////////////////// globale Variable //////////////////////////////////////
// 1. Einschaltlogik ----------------------------------------------------
bool schrankeSchliessen; // Wird über DCC Zubehördecoder angesteuert
 
NmraDcc DCC;
DCC_MSG Packet ;
 
// 2. Ablaufsteuerung ---------------------------------------------------
 
// Aufteilung der CV-Variablen (Standardadressen werden in der NmraDcc.h definiert)
// CV-Adresse für die Speicherung des BÜ-Zustandes
const word CvBueZustand = 46; // CV 46, Werte: 50 = offen, 54 = geschlossen
 
// CV-Adressen für die Speicherung der Endlagen (Winkel des Servos)
const word CvPosZu = 47; // CV 47, Werte zwischen 0 und 180, 255 gilt als ungültig (leeres EEPROM)
const word CvPosAuf = CvPosZu + (SCHRANKENZAHL);
 
static uint8_t FactoryDefaultCVIndex;
 
// Variable im RAM
int positionZu[SCHRANKENZAHL] = {PULS_ZU1, PULS_ZU2}; // Servopostionen, über Justiervorgang einstellbar
int positionAuf[SCHRANKENZAHL] = {PULS_AUF1, PULS_AUF2}; // Servopostionen, über Justiervorgang einstellbar
byte justageAktiv[SCHRANKENZAHL];
Servo8 Schranke[SCHRANKENZAHL]; // Für die Schrankenservos
EggTimer SchrankeT[SCHRANKENZAHL]; // Schrankenspezifische Zeiten
EggTimer VorlaufT;
 
// Aufrufparameter für das Unterprogramm 'Schrankenbewegung':
#define SB_INIT 0 // Servoansteuerung initiieren
#define SB_START_AUF 1 // Schranke öffnen starten
#define SB_START_ZU 2 // Schranke schliessen starten
#define SB_ENDE 3 // Bewegung überwachen und Ende erkennen. Ggfs. Endlagen justieren
 
// Zustand, in dem sich die Ablaufsteuerung gerade befindet
byte bueZustand; // Aktueller Zustand
byte bueVorZustand; // vorheriger Zustand des Bue ( noch nicht verwendet)
#define OFFEN 50
#define VORLAUF_ZU 51 // Wechselblinker und Glocke, aber noch keine Bewegung
#define SCHRANKE_SCHLIESST 52 // Bewegung Schrankenbaum zu
#define NACHLAUF_ZU 53 // Beide Schrankenbäume in Endpos, Glocke läutet noch.
#define GESCHLOSSEN 54 // Schranke geschlossen
#define SCHRANKE_OEFFNET 56 // Bewegung Schrankenbaum auf
 
// CV Speicher Struktur
struct CVPair
{
uint16_t CV;
uint8_t Value;
};
 
// CV Default-Werte
CVPair FactoryDefaultCVs [] =
{
{CV_ACCESSORY_DECODER_ADDRESS_LSB, DCC_ADDR},
{CV_ACCESSORY_DECODER_ADDRESS_MSB, 0},
{CV_VERSION_ID, DCC_DECODER_VERSION_ID},
{CV_MANUFACTURER_ID, MAN_ID_DIY},
{CV_29_CONFIG, 192},
{CV_DCC_POM_PROG, DCC_ADDR},
{CV_DCC_POM_PROG + 1, 0 },
{CvBueZustand, OFFEN},
{CvPosZu, PULS_ZU1},
{CvPosZu + 1, PULS_ZU2},
{CvPosAuf, PULS_AUF1},
{CvPosAuf + 1, PULS_AUF2},
};
 
// 3. Glocke -------------------------------------------------------------
EggTimer glockeT;
byte glAktiv = false; // Flag ob Glocke aktiv ist
 
// 4. Wechselblinker ------------------------------------------------------
SoftLed Wblinker[2]; // 2 Leds für den Wechselblinker
EggTimer BlinkerT;
byte wbAktiv = false; // Flag ob Wechselblinker aktiv ist
byte ledState = LOW; // Status Wechselblinker
// Zustand Wechselblinker
byte wblZustand = 0;
#define WBL_AUS 0
#define WBL_START 1 // Beim Start sind kurz beide Lampen an
#define WBL_BLINKT 2
 
// sonst. -----------------------------------------------------------------
// für debugging
#ifdef DEBUG
#define DB_PRINT( ... ) sprintf( dbgbuf,"Dbg: " __VA_ARGS__ ) ; Serial.println( dbgbuf )
byte debug;
char dbgbuf[80];
#else
#define DB_PRINT ;
#endif
 
//###################### Ende der Definitionen ##############################
//###########################################################################
 
void setup()
{
byte i;
#ifdef DEBUG
Serial.begin(38400); //Debugging
Serial.println( "start of Program" );
#endif
// 1. Einschaltlogik ----------------------------------------------------
DCC.pin(digitalPinToInterrupt(DccInputP), DccInputP, 1); // Dcc-Signal mit Pullup
DCC.init( MAN_ID_DIY, DCC_DECODER_VERSION_ID,
FLAGS_OUTPUT_ADDRESS_MODE | FLAGS_DCC_ACCESSORY_DECODER,
CV_DCC_POM_PROG ); // Zubehördecoder, 11bit-Adresse
 
/////////////////////////////////////
// DCC-Adresse setzen
if ( DCC.getCV( 1 ) == 255 ) { // wenn keine gültige Adresse gespeichert ist
DCC.setCV( 1, DCC_ADDR % 256 );
DCC.setCV( 9, DCC_ADDR / 256 );
}
if ( DCC.getCV( CV_DCC_POM_PROG ) == 255 ) { // wenn keine gültige Adresse gespeichert ist
DCC.setCV( CV_DCC_POM_PROG, DCC_ADDR );
DCC.setCV( CV_DCC_POM_PROG + 1, 0 );
}
 
#ifdef DEBUG
// CV-Werte ausgeben
DB_PRINT( "CV1:%d, CV9:%d, CV29:%d, CV7=%d, CV8=%d", DCC.getCV(1), DCC.getCV(9), DCC.getCV(29), DCC.getCV(7), DCC.getCV(8) );
#endif
 
pinMode(DccAckPin, OUTPUT);
digitalWrite( DccAckPin, LOW ); // Der ACK Pin wird auf LOW gesetzt,damit ein definierter Zustand vorhanden ist
 
// 2. Ablaufsteuerung ---------------------------------------------------
pinMode(Justage1P, INPUT_PULLUP); // Zur Justage der Endlage Schranke 1
pinMode(Justage2P, INPUT_PULLUP); // dto, Schranke 2
 
////////////////////// Grundinitiierung ////////////////////////////
// Testen ob gültige Werte in den CVs abgelegt sind. Wenn nicht, Grundinitiierung mit default-Werten
// Initiiert wird auch, wenn während des Programmstarts einer der Justageschalter betätigt ist
if ( DCC.getCV( CvPosZu ) == 255 ||
digitalRead( Justage1P) == LOW ||
digitalRead( Justage2P) == LOW ) {
// Grundinitiierung
DB_PRINT( "CV Initiierung" );
// Endlagen auf Default-Werte setzen
for ( i = 0; i < SCHRANKENZAHL; i++ ) {
DCC.setCV( CvPosZu + i, PULS_ZU1 );
DCC.setCV( CvPosAuf + i, PULS_AUF1 );
}
DCC.setCV(CvBueZustand, OFFEN);
}
 
/////////////////////////////////////
// Positionswerte aus CV lesen
for ( i = 0; i < SCHRANKENZAHL; i++ ) {
positionZu[i] = DCC.getCV( CvPosZu + i );
positionAuf[i] = DCC.getCV( CvPosAuf + i );
DB_PRINT( "Setup // Schr.%d - PosZu=%d PosAuf=%d", i, positionZu[i], positionAuf[i] );
DB_PRINT( "Zustand: %d", DCC.getCV( CvBueZustand ));
}
 
#ifdef DEBUG
// CV-Werte ausgeben
DB_PRINT( "CV1:%d, CV29:%d, CV7=%d, CV8=%d", DCC.getCV(1), DCC.getCV(29), DCC.getCV(7), DCC.getCV(8) );
#endif
 
/////////////////////////////////////////
/////// Antriebs-Initiierung ////////////
Schrankenbewegung( SB_INIT );
 
// Anfangsstellung der Schranke setzen
bueZustand = DCC.getCV( CvBueZustand );
if ( bueZustand == GESCHLOSSEN ) {
Schrankenbewegung( SB_START_ZU );
while ( !Schrankenbewegung( SB_ENDE ) );
wbAktiv = true;
} else {
Schrankenbewegung( SB_START_AUF );
while ( !Schrankenbewegung( SB_ENDE ) );
}
// 3. Glocke -------------------------------------------------------------
pinMode( glockeP, OUTPUT );
 
// 4. Wechselblinker ------------------------------------------------------
Wblinker[0].attach(led1P); // Portzuordnung für den WEchselblinker
Wblinker[1].attach(led2P);
Wblinker[0].riseTime(wbSoft); // Weiches Auf/Abblenden der Lampen
Wblinker[1].riseTime(wbSoft);
 
// sonst. -----------------------------------------------------------------
 
} // End Setup
//############################### ENDE SETUP ##################################
//#############################################################################
 
void loop()
{
// 1. Einschaltlogik ----------------------------------------------------
////////////// Eingang zur Steuerung des Bahnübergangs /////////////////
DCC.process();
// schrankeSchliessen wird in notifyDccFunc gesetzt
 
// 2. Ablaufsteuerung ---------------------------------------------------
justageAktiv[0] = ( digitalRead( Justage1P ) == LOW ) ;
justageAktiv[1] = ( digitalRead( Justage2P ) == LOW ) ;
 
//////////// Ablaufsteuerung des Bue - Haupt-Zustandsautomat ///////////////////
switch ( bueZustand ) {
case OFFEN:
// Schranke ist geöffnet, warten auf Eingang
if ( schrankeSchliessen ) {
// Schranke soll sich schliessen, Glocke und Wechselblinker startet.
wbAktiv = true; // Wechselblinker einschalten
glAktiv = true; // Glocke einschalten. Diesen Befehl auskommentieren wenn die Glocke erst
// mit der Schrankenbewegung starten soll
VorlaufT.setTime( vorlaufZu );
bueZustand = VORLAUF_ZU;
DB_PRINT("Zustandswechsel: %d", bueZustand );
}
break; //----------------------------------------------------------
case VORLAUF_ZU:
// Warten bis die Vorlaufzeit abgelaufen ist, dann die Schrankenbewegung starten
if ( !VorlaufT.running() ) {
// Vorlaufzeit abgelaufen, Schrankenbewegung starten.
// spätestens hier muss auch die Glocke aktiviert werden
glAktiv = true; // wurde sie schon aktivert, machts auch nichts ;-)
wbAktiv = true;
Schrankenbewegung(SB_START_ZU); // Überwachung initiieren
bueZustand = SCHRANKE_SCHLIESST;
}
break; //----------------------------------------------------------
case SCHRANKE_SCHLIESST:
// Schrankenbaum schliesst sich.
if ( ( Schrankenbewegung( SB_ENDE ) ) ) {
// beide Schrankenbäume haben ihre Endposition erreicht
VorlaufT.setTime( nachlaufZu );
bueZustand = NACHLAUF_ZU;
}
break; //----------------------------------------------------------
case NACHLAUF_ZU:
// Schrankenbaum geschlossen, kurzer Nachlauf für Glocke.
if ( !VorlaufT.running() ) {
glAktiv = false;
bueZustand = GESCHLOSSEN;
DCC.setCV( CvBueZustand, bueZustand );
}
break; //----------------------------------------------------------
case GESCHLOSSEN:
// Schranke ist zu, warten auf Eingang
if ( schrankeSchliessen == false ) {
// Schranke soll sich öffnen, Bewegung einleiten
Schrankenbewegung(SB_START_AUF); // Überwachung initiieren
wbAktiv = false; // Wechselblinker ausschalten
bueZustand = SCHRANKE_OEFFNET;
}
break; //----------------------------------------------------------
case SCHRANKE_OEFFNET:
// Schrankenbaum öffnet sich, warten bis offen
if ( schrankeSchliessen == true ) {
// Notfall: beim Öffnen der Schranke kommt wieder der Befehl Schranke schliessen
bueZustand = VORLAUF_ZU; // Da der Vorlauftimer nicht läuft, schliesst die Schranke sofort
 
}
if ( Schrankenbewegung( SB_ENDE ) ) {
// beide Schrankenbäume haben ihre Endposition erreicht
bueZustand = OFFEN;
DCC.setCV( CvBueZustand, bueZustand );
}
break; //----------------------------------------------------------
} ////////////// Ende Zustandsautomat Bahnübergang /////////////////////
 
// 3. Glocke -------------------------------------------------------------
////////////////// Glockenimpuls erzeugen ////////////////////////////////
if ( glAktiv ) {
if ( !glockeT.running() ) {
// Glockentimer abgelaufen, Impuls erzeugen
if ( digitalRead( glockeP ) == HIGH ) {
// Port ist gesetzt, abschalten
digitalWrite( glockeP, LOW );
glockeT.setTime( glZykl - glImp );
} else {
// Port ist aus, einschalten
digitalWrite( glockeP, HIGH );
glockeT.setTime( glImp );
}
}
} else {
// Glocke inaktiv, Ausgang abschalten wenn Timer nicht mehr läuft
if ( !glockeT.running() ) {
// Die Timerabfrage stellt sicher, dass auch der letzte Impuls immer in
// voller Länge ausgegeben wird
digitalWrite( glockeP, LOW );
}
}
 
// 4. Wechselblinker ------------------------------------------------------
/////////////// Wechselblinker (Zustandsautomat ) //////////////////
switch (wblZustand) {
case WBL_AUS:
// Beide Lampen sind aus, warten auf einschalten
if ( wbAktiv ) {
// Beide Leds einschalten, Timer für gemeinsames Startleuchten
Wblinker[0].on();
Wblinker[1].on();
BlinkerT.setTime( wbSoft / 2 );
wblZustand = WBL_START;
}
break;
case WBL_START:
// Startphase: Nach Zeitablauf erste Led wieder aus
if ( !BlinkerT.running() ) {
// Übergang zur normalen Blinkphase
ledState = HIGH;
Wblinker[1].off();
BlinkerT.setTime(wbSoft);
wblZustand = WBL_BLINKT;
}
break;
case WBL_BLINKT:
if ( !BlinkerT.running() ) {
BlinkerT.setTime(wbZykl / 2);
if ( ledState == LOW ) {
Wblinker[0].on();
Wblinker[1].off();
ledState = HIGH;
} else {
ledState = LOW;
Wblinker[1].on();
Wblinker[0].off();
}
}
if ( !wbAktiv ) {
// Wechselblinker abschalten
Wblinker[0].off();
Wblinker[1].off();
wblZustand = WBL_AUS;
}
break;
 
} /////////// Ende switch Wechselblinker ////////////////////////
 
/* Prüfen, ob die default CV-Werte benötigt werden */
if ( FactoryDefaultCVIndex && DCC.isSetCVReady())
{
FactoryDefaultCVIndex--; // Zunächst verringern, da es zu Beginn die Größe des Arrays ist
DCC.setCV( FactoryDefaultCVs[FactoryDefaultCVIndex].CV,
FactoryDefaultCVs[FactoryDefaultCVIndex].Value);
}
} // End Loop
//#################### ENDE LOOP ##################################################
//#################################################################################
 
byte Schrankenbewegung( byte mode ) {
// Bewegungsvorgang der Schranken überwachen, gegebenenfalls auch die Endlage
// justieren. Das Unterprogramm wird im Loop während der Bewegung zyklisch aufgerufen
// Der Funktionswert ist 'true', wenn die Bewegung aller Schranken abgeschlossen ist,
// sonst immer 'false'
// mode:SB_INIT Grundinitiierung
// SB_START_ZU Schliessen der Schranken einleiten
// SB_START_AUF Öffnen der Schranken einleiten
// SB_ENDE Bewegung überwachen, meldet 'true' wenn alle Bewegungen abgeschlossen
// sind
// -------------------------------------------------------------------------
//
static enum { WAIT, NORMAL, JUSTAGE_AKTIV, JUSTAGE_ENDE, WIPPEN } ssZustand[SCHRANKENZAHL] ;
static int startPos[SCHRANKENZAHL] ; // Position der Schranke zu Bewegungsbeginn
static enum { AUF, ZU } richtung;
 
byte bewegung = 0, sn;
int tmp;
for ( sn = 0; sn < SCHRANKENZAHL; sn++ ) {
// für alle Schranken durchlaufen
switch ( mode ) {
case SB_INIT: // Initiierung der Schranken
Schranke[sn].attach(ServoPort[sn], 1); //Servos an Pin 5 / 6 mit AutoOff
Schranke[sn].setSpeed( schrTempo[sn] );
bewegung = 1;
break; //---------------------------------------------
case SB_START_ZU: // Schliessen der Schranken einleiten
richtung = ZU;
Schranke[sn].setSpeed( schrTempo[sn]);
SchrankeT[sn].setTime( schrVerzZU[sn] ); //Wartezeit bis Schrankenbewegung
DB_PRINT( "Start Wartezeit %d mit %d ms", sn, schrVerzZU[sn] );
ssZustand[sn] = WAIT;
bewegung = 1;
break; //---------------------------------------------
case SB_START_AUF: // Öffnen der Schranken einleiten
richtung = AUF;
Schranke[sn].setSpeed( schrTempo[sn]);
Schranke[sn].write( DCC.getCV( CvPosAuf + sn ));
ssZustand[sn] = NORMAL;
startPos[sn] = Schranke[sn].read();
DB_PRINT( "Schranke %d, Position: %d, Richtung= %d", sn, startPos[sn], richtung );
bewegung = 1;
break; //---------------------------------------------
case SB_ENDE: // Bewegung überwachen, auf Ende prüfen
// Schrankenbewegung
switch ( ssZustand[sn] ) {
case WAIT: // Verzögerungszeit bis zum Schrankenstart abwarten
// Wird nur beim Schliessen der Schranke durchlaufen
if ( SchrankeT[sn].running() == false ) {
// Zeit abgelaufen, Bewegung starten
Schranke[sn].write( DCC.getCV( CvPosZu + sn ));
ssZustand[sn] = NORMAL;
startPos[sn] = Schranke[sn].read();
DB_PRINT( "Schranke %d, Position: %d, Richtung= %d", sn, startPos[sn], richtung );
ssZustand[sn] = NORMAL;
}
bewegung = 1;
break; //......................................
case NORMAL:
bewegung += Schranke[sn].moving();
if ( justageAktiv[sn] ) {
// Justageschalter betätigt, Speed auf 1, Servobewegung um 10% weitersetzen,
// sodass die neue Endposition auch hinter der alten liegen kann.
Schranke[sn].setSpeed( 1 );
ssZustand[sn] = JUSTAGE_AKTIV;
if ( richtung == ZU ) tmp = (positionZu[sn] * 3 - positionAuf[sn]) / 2;
else tmp = (positionAuf[sn] * 3 - positionZu[sn]) / 2;
DB_PRINT( "Schranke %d, Justage Endpso=%d", sn, tmp );
Schranke[sn].write( tmp );
}
// if ( bewegung < 5 ) ssZustand[SchrNr] = WIPPEN;
break; // .....................................
case WIPPEN:
// to be defined ;-)
break; //......................................
case JUSTAGE_AKTIV:
bewegung += 1; // keine Endemeldung während der Justage
if ( !justageAktiv[sn] ) {
// Justageschalter wurde wieder losgelassen. Momentane Servo-Position
// als neuen Endpunkt speichern und Servo anhalten
tmp = Schranke[sn].readMicroseconds();
DB_PRINT( "Schranke %d, Justage ende, Pos = %d", sn, tmp );
Schranke[sn].write( tmp );
if ( richtung == ZU ) {
positionZu[sn] = tmp;
DCC.setCV( CvPosZu + sn, tmp );
} else {
positionAuf[sn] = tmp;
DCC.setCV( CvPosAuf + sn, tmp );
}
ssZustand[sn] = JUSTAGE_ENDE;
}
break; //......................................
case JUSTAGE_ENDE:
bewegung += Schranke[sn].moving();
 
break; //......................................
} // ..... Ende switch 'Schrankenzustand' ......
 
break; //---------------------------------------------
default:
// falscher Programmaufruf, keine Reaktion
;
} // --- Ende Switch 'mode' --------
} // ........Ende forschleife der Schranken........
 
if ( bewegung == 0 ) DB_PRINT( "Endpositionen erreicht");
return ( bewegung == 0 );
}
 
//###################################################################################
//###################### DCC - Funktionen ###########################################
// Auswertung des Zubehördecoders
void notifyDccAccState( uint16_t Addr, uint16_t BoardAddr, uint8_t OutputAddr, uint8_t State)
{
if (Addr == DCC.getAddr()) {
schrankeSchliessen = ((OutputAddr & 0x1) != 0);
DB_PRINT( " Adresse: %u, Status %x", Addr, schrankeSchliessen );
}
}
 
// Diese Funktion wird von der Nmra-Lib aufgerufen, wenn ein DCC ACK gesendet werden muss
// z.B. beim Programmieren des Decoders über die Digitalzentrale
void notifyCVAck(void)
{
digitalWrite( DccAckPin, HIGH );
delay( 6 );
digitalWrite( DccAckPin, LOW );
}
 
// Ein Decoder Reset wird angefordert
void notifyCVResetFactoryDefault()
{
// Setze FactoryDefaultCVIndex ungleich Null und auf die Anzahl der CVs, die zurückgesetzt werden müssen
// damit die Funktion im loop erkennt, dass ein Reset durchzuführen ist
FactoryDefaultCVIndex = sizeof(FactoryDefaultCVs) / sizeof(CVPair);
}
 

 
 



Ich würde mich freuen, wenn der eine oder andere mit dem Code was anfangen kann...
Rückmeldungen erwünscht!

Herzliche Grüße
Thomas


Thomas
------------------
Anlage H0: U-Form, im kreativen Bau
Fahren: Tams MC
Schalten: IB
Melden: HSI 88
Steuern: TrainController 9.0 Gold
Denken: Brain 4.1


Majestix hat sich bedankt!
 
digi_thomas2003
InterRegioExpress (IRE)
Beiträge: 305
Registriert am: 03.05.2005
Gleise sind vorhanden
Spurweite H0
Steuerung TrainController
Stromart AC, Digital


RE: Arduino: Schrankensteuerung - DCC-Ansteuerung für Betrieb und Justage

#142 von Mape71 ( gelöscht ) , 30.11.2015 14:18

Hallo Thomas,

vielen Dank für den neuen Sketch. Ich habe ihn mal an meinen bestehenden Bahnübergang, der bereits mit Servoce gesteuert wird "angeschlossen". Was mir dabei nicht gelingen mag ist die Änderung der Drehrichtung von einem der beiden Servos (ein Schrankenbaum schließt, während der andere öffnet). Ich habe in den Zeilen 71-74 die Werte verändert, aber auch über die CV-Programmierung bei den CVs 47-50 - aber die Drehrichtung ändert sich nicht. Hast Du da noch einen Hinweis für mich?

Vielen Dank und Grüße

Marko


Mape71

RE: Arduino: Schrankensteuerung - DCC-Ansteuerung für Betrieb und Justage

#143 von digi_thomas2003 , 30.11.2015 15:32

Hallo Marko,

Zitat von Mape71
...
Hast Du da noch einen Hinweis für mich?
...



auf die Schnelle: Vertausche mal bei dem Servo, der verkehrt herum läuft die Werte für Auf und Zu.
Das sollte eignelich funktionieren.

Wenn ich wieder an meiner Testumgebung bin, prüfe ich es nach.

Herzliche Grüße
Thomas


Thomas
------------------
Anlage H0: U-Form, im kreativen Bau
Fahren: Tams MC
Schalten: IB
Melden: HSI 88
Steuern: TrainController 9.0 Gold
Denken: Brain 4.1


 
digi_thomas2003
InterRegioExpress (IRE)
Beiträge: 305
Registriert am: 03.05.2005
Gleise sind vorhanden
Spurweite H0
Steuerung TrainController
Stromart AC, Digital


RE: Arduino: Schrankensteuerung - DCC-Ansteuerung für Betrieb und Justage

#144 von Mape71 ( gelöscht ) , 30.11.2015 17:14

Hallo Thomas,

habe ich erfolglos versucht. Ich habe auch einmal alle CVs (47-50) auf den identischen Wert gesetzt, nur um zu prüfen, ob sich am Ausschlag etwas verändert (die Schrankenbäume dürften sich dann ja eigentlich nicht mehr bewegen), jedoch bleiben die Ausschläge komplett unverändert. Von daher vermute ich, dass irgendetwas mit der CV Endlagenprogrammierung nicht hinhaut. Adresse per CV zu verändern funktioniert aber problemlos.

VieleGrüße

Marko


Mape71

RE: Arduino: Schrankensteuerung - DCC-Ansteuerung für Betrieb und Justage

#145 von MicroBahner , 30.11.2015 19:21

Hallo Marko, hallo Thomas,
um die Drehrichtung eines Servos zu ändern, sollte es schon reichen, die Startwerte in Zeile 71-74 für den jeweiligen Servo zu vertauschen. Gespeichert wird ja nicht die Drehrichtung, sondern nur die Servopositionen für AUF bzw ZU. Die Drehrichtung ergibt sich dann daraus.
Nach der Änderung muss aber auch eine Grundinitiierung gemacht werden, sonst werden die geänderten Werte nicht übernommen (Sketch mit aktivem Justagetaster starten). Allerdings gibt es da noch ein Problem: Thomas schreibt bei der Grundinitiierung die Werte für Servo1 in die CV's für beide Servos:

1
2
3
4
5
6
 
    // Endlagen auf Default-Werte setzen
for ( i = 0; i < SCHRANKENZAHL; i++ ) {
DCC.setCV( CvPosZu + i, PULS_ZU1 );
DCC.setCV( CvPosAuf + i, PULS_AUF1 );
}
 
 

Deshalb kann man die Drehrichtung nicht bei den beiden Servos umabhängig ändern.
Das sollte sich aber umgehen lassen, indem man die CV's direkt von der Zentrale beschreibt oder einen FactoryReset auslöst. Bei den Daten für den Factory-Reset sind die unterschiedlichen Werte berücksichtigt.
Um zu erkennen, ob die richtigen Werte im CV stehen, könnte man in notifyDccAccState noch einen entsprechendne DB_PRINT Befehl einfügen, dann würden die CV's im Debugmode bei jedem öffnen/schliessen-Befehl ausgegeben.


Bei der Justage mit den Tastern müsste das Programm auch noch angepasst werden, da wird die aktuelle Lage noch in µs ausgelesen, Thomas hat aber eigentlich alles auf Winkel umgestellt:

1
2
3
4
5
6
7
8
9
10
11
12
13
 
              // Justageschalter wurde wieder losgelassen. Momentane Servo-Position
// als neuen Endpunkt speichern und Servo anhalten
tmp = Schranke[sn].readMicroseconds(); //<------ aendern in tmp = Schranke[sn].read();
DB_PRINT( "Schranke %d, Justage ende, Pos = %d", sn, tmp );
Schranke[sn].write( tmp );
if ( richtung == ZU ) {
positionZu[sn] = tmp;
DCC.setCV( CvPosZu + sn, tmp );
} else {
positionAuf[sn] = tmp;
DCC.setCV( CvPosAuf + sn, tmp );
}
 
 



@Marko: zur Umstellung auf Weichenadressen bei der Stepmotorversion: Dann müsstest Du auch die Justage ändern (wie im Servo-Sketch), denn die Einstellung über den Geschwindigkeitsregler geht dann natürlich nicht mehr.
P.S. deine Variante mit dem größeren Stepmotor gefällt mir auch viel besser als vorher. Mag auch mit daran liegen, dass der Messing-Schrankenbaum deutlich schwerer ist. Vielleicht reicht da auch für die Verbindung Motorhebel-Schranke ein Faden. Der ist dann automatisch durch das Gewicht vorgespannt, und Du hast auch da kein Spiel.


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: Schrankensteuerung - DCC-Ansteuerung für Betrieb und Justage

#146 von Mape71 ( gelöscht ) , 30.11.2015 19:35

Hallo zusammen,

vielen Dank für die Rückmeldungen - es funktioniert nun. Es gab wohl ein Problem mit einem Booster, nun lassen sich die CVs aber korrekt beschreiben. Ich muss nun alles mal sauber aufbauen und noch die Andreaskreuze aufstellen. Dann kann ich noch mal ein Video Posten, die alles in Aktion zeigt. Die Stepper-Version werde ich dann für den zweiten Übergang verwenden. Dabei fällt mir ein: welches Soundmodul könnt Ihr für die Glocke empfehlen? Ich habe noch ne Menge 8Ohm Lautsprecher von ESU hier liegen, wäre super, wenn das passt.

Vielen Dank und Gruß

Marko


Mape71

RE: Arduino: Schrankensteuerung - DCC-Ansteuerung für Betrieb und Justage

#147 von Mape71 ( gelöscht ) , 30.11.2015 19:54

...noch eine kleine Frage - was mache ich mit dem ACK-Signal?

Danke und Grüße

Marko


Mape71

RE: Arduino: Schrankensteuerung - DCC-Ansteuerung für Betrieb und Justage

#148 von MicroBahner , 30.11.2015 20:07

Zitat von Mape71
was mache ich mit dem ACK-Signal?

Das brauchst du wenn du CV's auslesen willst.


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: Schrankensteuerung - DCC-Ansteuerung für Betrieb und Justage

#149 von Mape71 ( gelöscht ) , 30.11.2015 20:09

...und wie wird das verschaltet? Muss ja dann irgendwie wieder zurück auf das DCC Signal - also vor den Optokoppler, oder?

Vielen Dank und Grüße

Marko


Mape71

RE: Arduino: Schrankensteuerung - DCC-Ansteuerung für Betrieb und Justage

#150 von MicroBahner , 30.11.2015 20:16

Ja, dass Ack-Signal muss den Stromverbrauch für 6ms um 60mA erhöhen - dass kann dann die Zentrale erkennen und auswerten.
Ein kurze Beschreibung findest Du in https://de.wikipedia.org/wiki/Digital_Command_Control im Abschnitt 'Auslesen von Decodern'


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


   

CAN-Stellpult oder analoges Stellpult mit LEDs für Weichen
Viessmann 5552 Umschaltrelais gehen ständig kaputt

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