int DCC_adresse_manu = 44; // DCC-weichenadresse fuer manuelles schalten, ziffer entsprechend der gewuenschten adresse anpassen. int DCC_adresse_auto = 45; // DCC-weichenadresse fuer automatisiertes abschalten, ziffer entsprechend der gewuenschten adresse anpassen. unsigned long blinkzeit_auto = 5000; // dauer in ms fuer blinkzeit beim automatischen abschalten, entsprechend des gewuenschten wertes aendern. unsigned long ruhezeit_auto = 6000; // dauer in ms fuer zeit beim automatischen abschalten, in der nach blinkzeit nicht noch mal ausgeloest werden soll. int stellwert = 1; // blinker beim einschalten an. = 0 falls blinker beim einschalten aus sein soll (analogmodus). const int maxPWM = 254; // maximale helligkeit blinkleds (constant for max). /* wechselblinker bahnuebergang fuer direkten anschluss an bahnstrom, dcc oder separater versorgung integrierter DCC-einzelweichedekoder (magnetartikeldecoder) hier vereinfacht fuer einzeldekoder mit festen (in zeile 1 & 2 vor hochladen festlegen) adressen: - DCC_adresse_manu: manuelles ein- und ausschlalten, "abzweigen" -> "aus", "gerade" -> "ein" - DCC_adresse_auto: zeitgesteuerter modus, "gerade" -> "ein", nach blinkzeit_autozeit (zeile 3) automatisches auschalten. weiteres schalten innerhalb der blinkzeit_auto + ruhezeit_auto bleibt unberuecksichtig. schalten nach blinkzeit_auto + ruhezeit_auto loest neuen vorgang aus. "abzweigen": de-/aktivierung des automatikmodus durch wiederholtes schalten. sollte aktivierung nicht direkt moeglich sein, kurz DCC-weichenadresse fuer manuelles schalten betaetigen und erneut "abzweigen" DCC-weichenadresse fuer automatisiertes abschalten druecken. deaktivierung wird durch einen kurzen doppelblitz angezeigt, aktiverung durch 3fachblitz. - zeitgesteuerter modus (https://vimeo.com/745799461) mit sensorgleis (punktmelder) oder lichtschranke (Attiny85 pin 3). A.G.-P. fading-sequenz auf basis eines sketches von mark biasotti https://forum.arduino.cc/t/fading-led-up-and-down-with-predetermined-intervals-non-blocking/559601 die benoetigte NmraDCC - bibliothek gibt es unter https://downloads.arduino.cc/libraries/github.com/mrrwa/NmraDcc-1.4.2.zip !!! WICHTIG: laeuft nur mit NmraDcc version 1.4.2 Library; ggf. in bibl.-verwaltung entsprechen einstellen! vergleiche: https://github.com/mrrwa/NmraDCC/archive/master.zip siehe auch: https://github.com/mrrwa/NmraDcc bibliothek geschreiben von Alex Shepherd, Wolfgang Kuffer, Geoff Bunza, Martin Pischky, Franz-Peter Mueller, Sven (littleyoda), Hans Tanner infos: https://www.arduino.cc/reference/en/libraries/nmradcc/ hardware: - warnbarke(n) mit LED (blinktafeln) und vorwiderstand (150Ω). spur g: z.B. tafel und andreaskreuz von Modellbau Eckstein (jecktrain) oder Modellbau Heyn, mast 4(2i)mm Messingrohr mit eingeschnittenem gewinde unten fuß Strapubox MG23 (https://vimeo.com/744793900). alternativ Busch 8626 mit passendem vorwiderstand. - Attiny85 Mini board (Digispark nachbau) mit Digistump/Digispark bootloader. fuer 2 warnblinker wird nur prinzipiell ein board (hat 3 PWM-ausgaenge, s.u.) benoetigt. achtung: je nach bootloader geht das board zunaechst in den programmiermodus (z.B. 5s), wenn es mit spannung versorgt wird. basis hardware: Karlheinz Marks http://www.robokalle.de/elektronik%20dcc-lichtsignal%20decoder.htm -- ggf. muss USB-treiber fuer betriebssystem installiert werden https://github.com/digistump/DigistumpArduino/tree/master/tools achtung: board hat keinen USB-RS232-wandler, nur virtueller USB, funktioniert nicht mit jedem host! ggf. (alten) USB2-Hub mit eigener stromversorgung verwenden https://digistump.com/wiki/digispark/tutorials/connecting MAC OSX: ~/Library/Arduino15/packages/digistump/hardware/avr/1.6.7/libraries/DigisparkKeyboard/usbconfig.h ggf. eintrag aendern: #define USB_CFG_VENDOR_ID 0xac, 0x05 vgl.: https://null-byte.wonderhowto.com/how-to/hack-macos-with-digispark-ducky-script-payloads-0198555/ -- Arduino IDE muss fuer Digistump AVR Boards (Digispark 16,5 MHz) ergaenzt werden: https://raw.githubusercontent.com/digistump/arduino-boards-index/master/package_digistump_index.json erlaeuterung: http://blog.wenzlaff.de/?p=7721 hochladen: board "Digispark (Default - 16.5mhz)"; programmer Micronucleus; OSX: keinen port waehlen; OSX, WIN, LINUX: board erst auf anforderung einstecken falls micronucleus-1.11-entry-jumper-pb0-upgrade.hex installiert (info siehe unten): P0 -> GND zum hochladen. achtung!: LED per anode an pin 0 versetzt board bei start in programmiermodus! LED per kathode an pin4 -> hochladen nicht moeglich (USB-). https://github.com/overfl0/NocInformatykaBoard/tree/master/upgrade/releases aktuelle firmware: https://github.com/micronucleus/micronucleus/tree/master/firmware version mit USB2-kontakten auf platine: auf sicheren kontakt achten -- achtung: bestimmte operationen (z.B. multiplikation) mit Attiny85 nur begrenzt moeglich. -- pin2: DCC command; -- pin-info: P0: I2C SDA, PWM, pin1: PWM, pin2: I2C SCK, analog in, pin3: analog in, USB+, pin4: PWM, analog in, USB-, pin5: analog in; Rev2 / Rev4: eingebaute LED -> pin1. Rev1: eingebaute LED -> pin0 (this board requires the trace to the LED to be cut (or the LED desoldered) if you'd like to use it with I2C devices) - alternativ(!): arduino nano. fuer mehrere warnblinker (>4) wird prinzipiell nur ein board beneotigt. PWM-pins: 3, 5, 6, 9, 10, 11. -- arduino pin 2 zwingend DCC command chinesische nachbauten je nach version mit "Old Bootloader" (ATmega328p) programmieren; programmer AVRISP mkII -- decoder kann fuer mehrere dcc-adressen erweitert werden: pin D3-D12 + A0-A7 ermoeglichen 9 magnetartikel. -- spannungsregler LM 1117 MP5,0 ggf. auf eingangsspannung (thermalabschaltung) pruefen bzw. zusätzliche spnnungsregelung vornehmen. - netzteil: einweggleichrichtung ohne puffer, ggf. hochfrequenzsiebung. alternativ: brueckengleichrichter, elko 10µF/25V, ggf. sicherung 2A, ggf. vorwiderstand Attiny85 100Ω/2W (47 - 200Ω). - vorwiderstand 22kΩ - 27kΩ fuer commandleitung. - optional vorwiderstand 22kΩ - 27kΩ und 10kΩ pulldown-widerstand fuer sensorgleiseingang. - alternative schaltung via optokoppler (6N137) fuer commandleitung -- Dave Falkenburg: https://abload.de/img/schematic1haslf.png / arcomora: https://www.arcomora.com (diode: 4004) -- Rudysmodelrailway: https://rudysarduinoprojects.files.wordpress.com/2019/04/dcc-opto.png -- Philipp Gahtow: http://pgahtow.de/wiki/index.php?title=Datei:DCC_mini_Dekoder_sch.png -- bezug fertige 24V-optokoppler boards (stand april 2021): https://de.aliexpress.com/item/32914498721.html ======================================================================================================================================================== info update bootloader Digispark Attiny85 Mini board: nach installation der micronucleus-Tools inkl. des USB-treibers und der erweiterung der Arduino-IDE finden sich die micronucleus-dateien im entsprechenden Unterordner des benutzerverzeichnis: - WIN: ...\tools\digistump - MAC: .../Applications/Arduino.app/..../packages/digistump/tools/micronucleus/2.0a4/ - Ubuntu: .../arduino15/packages/digistump/tools/micronucleus/2.0a4/ gewuenschte bootloader-datei auf host speichern: - https://github.com/overfl0/NocInformatykaBoard/tree/master/upgrade/releases - um die anfangs-5s zu eliminieren: micronucleus-1.11-entry-jumper- pb0-upgrade.hex. im terminal / bzw. in der eingabeaufforderung in das entsprechende verzeichnis wechseln und den befehl micronucleus --run micronucleus-1.11-entry-jumper-pb0-upgrade.hex ausfuehren. board auf anforderung anstecken und warten, bis upload abgeschlossen ist. besondere Vorarbeiten unter MAC OSX: - ggf. in ~/Library/Arduino15/packages/digistump/hardware/avr/1.6.7/libraries/DigisparkKeyboar d/usbconfig.h eintrag aendern: #define USB_CFG_VENDOR_ID 0xac, 0x05 - damit micronucleus ausführbar wird, folgenden Befehl eingeben: chmod +x micronucleus */ #include // nur version 1.4.2 #define DCC_DECODER_VERSION_ID 02 // versions-ID NmraDcc DCC; int ledblink1 = 1; // blinktafel 1, Attiny85: pin1 int ledblink2 = 4; // blinktafel 2 Attiny85: pin4 //int ledblink3 = 3; // blinktafel 3 //int ledblink4 = 6; // blinktafel 4 int sensor = 3; // eingang fuer optionales sensorgleis oder lichtschranke, Attiny85: pin3 int automatikanaus = HIGH; // variable um automatisiertes abschalten zu de-/aktivieren int automatikstatus = LOW; // variable fuer automatisches abschalten uint32_t previousMillis = 0; // zeitvariable fuer automatisches abschalten byte fadeIncrement = 5; // how smooth to fade? int fadeInterval = 5; // how fast to increment? // define directions for LED fade #define UP 0 #define DOWN 1 // constants for min and max PWM const int minPWM = 0; // state variable for fade direction byte fadeDirection = UP; // Global Fade Value // but be bigger than byte and signed, for rollover int fadeValue = 0; int fadeValue2; unsigned long previousFadeMillis; // millis() timing Variable, just for fading void setup() { pinMode(ledblink1, OUTPUT); pinMode(ledblink2, OUTPUT); // pinMode(ledblink3, OUTPUT); // pinMode(ledblink4, OUTPUT); pinMode(sensor, INPUT); DCC.init(MAN_ID_DIY, DCC_DECODER_VERSION_ID, FLAGS_OUTPUT_ADDRESS_MODE | FLAGS_DCC_ACCESSORY_DECODER, 0); DCC.pin(0, 2, 1); // DCC-signal an pin2 // Serial.begin(9600); } void loop() { DCC.process(); // analyse DCC-signal // Serial.println(automatikanaus); int sensorwert = digitalRead(sensor); if (sensorwert == HIGH && automatikstatus == LOW) // optionale erfassung sensorgleis oder lichtschranke { stellwert = 2; automatikstatus = !automatikstatus; previousMillis = millis(); } if (stellwert == 2 && automatikanaus == HIGH) // routine zum automatischen abschalten { if (millis() - previousMillis >= blinkzeit_auto) { digitalWrite(ledblink1, LOW); digitalWrite(ledblink2, LOW); // digitalWrite(ledblink3, LOW); // digitalWrite(ledblink4, LOW); fadeValue = 0; } if (millis() - previousMillis >= blinkzeit_auto + ruhezeit_auto) { digitalWrite(ledblink1, LOW); digitalWrite(ledblink2, LOW); // digitalWrite(ledblink3, LOW); // digitalWrite(ledblink4, LOW); fadeValue = 0; automatikstatus = LOW; } if (millis() -previousMillis < blinkzeit_auto) { warnblinker(); } } if (stellwert == 1) { warnblinker(); } } void notifyDccAccState(uint16_t Addr, uint16_t BoardAddr, uint8_t OutputAddr, uint8_t State) //wird von DCC.process() aufgerufen, wenn ein weichenstellbefehl empfangen wurde { if (Addr == DCC_adresse_manu) { if (OutputAddr & 0x1) { digitalWrite(ledblink1, LOW); digitalWrite(ledblink2, LOW); // digitalWrite(ledblink3, LOW); // digitalWrite(ledblink4, LOW); stellwert = 0; automatikstatus = LOW; } else { stellwert = 1; automatikstatus = LOW; } } if (Addr == DCC_adresse_auto && automatikstatus == LOW) { if (OutputAddr & 0x1) { automatikanaus = !automatikanaus; // automatisiertes abschalten de-/aktivieren durch weiderholtes aktiveren "abzweigung" digitalWrite(ledblink1, LOW); digitalWrite(ledblink2, LOW); // digitalWrite(ledblink3, LOW); // digitalWrite(ledblink4, LOW); stellwert = 0; automatikstatus = LOW; delay(700); // "entprellt" den schaltbefehl if (automatikanaus == HIGH) { digitalWrite(ledblink1, HIGH); digitalWrite(ledblink2, HIGH); delay(150); digitalWrite(ledblink1, LOW); digitalWrite(ledblink2, LOW); delay(150); digitalWrite(ledblink1, HIGH); digitalWrite(ledblink2, HIGH); delay(150); digitalWrite(ledblink1, LOW); digitalWrite(ledblink2, LOW); delay(150); digitalWrite(ledblink1, HIGH); digitalWrite(ledblink2, HIGH); delay(150); digitalWrite(ledblink1, LOW); digitalWrite(ledblink2, LOW); } if (automatikanaus == LOW) { digitalWrite(ledblink1, HIGH); digitalWrite(ledblink2, HIGH); delay(150); digitalWrite(ledblink1, LOW); digitalWrite(ledblink2, LOW); delay(150); digitalWrite(ledblink1, HIGH); digitalWrite(ledblink2, HIGH); delay(150); digitalWrite(ledblink1, LOW); digitalWrite(ledblink2, LOW); } } else { stellwert = 2; automatikstatus = !automatikstatus; previousMillis = millis(); } } } void warnblinker() { unsigned long startzeit = millis(); if (startzeit - previousFadeMillis > fadeInterval) { if (fadeDirection == UP) { fadeValue = fadeValue + fadeIncrement; if (fadeValue >= maxPWM) { // At max, limit and change direction fadeValue = maxPWM; delay(5); digitalWrite(ledblink1, maxPWM); digitalWrite(ledblink2, minPWM); // digitalWrite(ledblink3, maxPWM); // digitalWrite(ledblink4, minPWM); fadeDirection = DOWN; delay(300); fadeDirection = DOWN; } } else { fadeValue = fadeValue - fadeIncrement; if (fadeValue <= minPWM) { fadeValue = minPWM; delay(5); digitalWrite(ledblink1, minPWM); digitalWrite(ledblink2, maxPWM); // digitalWrite(ledblink3, minPWM); // digitalWrite(ledblink4, maxPWM); fadeDirection = UP; delay(300); } } // Only need to update when it changes analogWrite(ledblink1, fadeValue); fadeValue2 = map (fadeValue, 0, maxPWM, maxPWM, 0); analogWrite(ledblink2, fadeValue2); // reset millis for the next iteration (fade timer only) previousFadeMillis = startzeit; } }