Dieses Modul des RailFX-Systems steuert einen Arduino Bahnhof für die Modellbahn. Zu den Funktionen zählten:
- OLED-Abfahrtsanzeiger mit wechselnden Inhalten
- Zufalls- oder sensorgesteuerte Umschaltung des Displays
- Sound-Modul mit Ansagen der »Blechelse«
- Bahnhofsbeleuchtung mit Leuchtstoffröhren-Einschalteffekt
Schaltplan
- D2, D3: DFPlayer MP3 Modul
- D4 – D12: LEDs als Leuchtstoffröhren
- A0 (D14) und A1 (D15) Lichtschranken für Zugdetektion
- A3: Anschluss des Zeitsignals des Conrol-Moduls
- A4, A5: I2C Verbindung zum OLED-Display
Achtung: Am Pin A3 (normalerweise A4, aber hier A3) wird das Control-Signal des RailFX Control-Moduls angelegt. Es steuert die Tageszeit und ist zwingend erforderlich.
Bauteile Arduino Bahnhof
- 1x LED-Set
- 1x OLED-Display
- 1x Elektrolytkondensator (100 – 470µF)
- DFPlayer Mini MP3 Player Modul (Bitte nicht das ähnlich aussehende MP3-TP-16P Modul kaufen)
- MicroSD-Karte
- Lautsprecher
- 2x TCRT5000 Lichtschranken
- 1x 1kOhm Widerstand
Einstellungen im Code
Auch dieses Modul bietet eine Reihe von Einstellmöglichkeiten. Die Beleuchtung des Bahnhofes kann beim Einschalten wie Leuchtstoffröhren flackern. Die Zeit, die alle Lampen zum Einschalten kann man mit der Variable flackerzeitLeuchten einstellen. Je höher der Wert ist, desto länger flackern die Leuchten. Wie heftig sie flackern lässt sich mit der Variable flackerGeschwindigkeit einstellen.
Die Anzeigen auf dem OLED-Display wechseln sich entweder per Zufall oder per Lichtschranken, je nachdem, ob man die Methode anzeigeTafelAutomatisch() oder anzeigeTafelSensor() im Loop anspricht. Im Lichtschranken-Modus wechselt sich die Anzeigt, sobald beide Sensoren freigegeben werden, also, wenn sich kein Zug mehr auf dem Gleis befindet.
Im automatischen Modus kann man die folgenden Einstellungen vornehmen: Die minimale Dauer pro Anzeige lässt sich mit der Variable anzeigenWechselMin einstellen. Zu ihr wird per Zufall eine Zeit zwischen 0 und dem in der Variable anzeigenwechselVariableZeit festgelegten Wert addiert.
Die Texte auf dem Display werden im Array textSegments festgelegt. Es lässt sich durch weitere Texte erweitern. Dafür müssen die Dimensionen im Array und die Variable anzeigeAnzahl angepasst werden.
Das Display zeigt automatisch beim Umschalten die aktuelle Modellbahnzeit an. Die Folgezüge werden im 30-Minuten-Takt angezeigt. Ist die aktuelle Zeit also 17:21, werden die Abfahrtszeiten der Folgezüge 17:51 und 18:21 angezeigt.
Per Zufall zeigt das Display auch einen Hinweis an. Den Text kann man in der Variable hinweis anpassen.
Für die Tonausgabe wird der DFPlayer Mini verwendet. Er spielt MP3- und WAV-Dateien von einer SD-Karte ab. Für die Nutzung muss die DFPlayer Mini Bibliothek eingebunden werden. Klicke dafür im Arduino-Menü auf Sketch>Bibliotheken einbinden>Bibliotheken verwalten und gib im Suchfeld »dfplayer mini« ein. Installiere die Bibliothek DFPlayer Mini MP3 by Makuna in der aktuellen Version.
Die SD-Karte muss im FAT16 oder FAT32-Dateisystem formatiert sein. Darüber hinaus müssen sich die Dateien im Ordner »01« befinden und die Dateinamen müssen aufeinander folgend 001.mp3, 002.mp3, 003.mp3 usw. benannt sein. Wie erwähnt, dürfen auch WAV-Dateien verwendet werden: 001.mp3, 002.wav, 003.mp3 …
Beispiel-Dateien können hier heruntergeladen werden:
/* ***** ***** Einstellungen ***** ***** */ int flackerzeitLeuchten = 1000; // Je höher der Wert, desto mehr flackern die Leuchtstoffröhren beim Einschalten int flackerGeschwindigkeit = 100; // Flackergeschwindigkeit der Leuchtstoffröhren int anzeigenWechselMin = 2000; // Anzeigewechsel alle x Millisekunden int anzeigenwechselVariabeleZeit = 3000; // Um diesen Wert (Millisekunden) variiert der Anzeigewechsel int mp3Anzahl = 10; // Menge der MP3 Dateien auf der SD-Karte int mp3Dauer[] = {16,16,15,17,17,18,19,18,19,9}; // Dauer der MP3 Dateien in Sekunden int mp3Wahrscheinlichkeit = 20; // Wahrscheinlichkeit, mit der MP3s abgespielt werden, 10 oft, 100 selten int lautstaerke = 10; // Lautstärke des DFPlayers (0 – 30); /* Anzeigen */ int anzeigeAnzahl = 6; // Muss so groß sein, wie die Anzahl der angezeigten Texte aus dem Array textSegments const char* textSegments[6][9] = { {"12", "", "Zugdurchfahrt", "17:08", "17:44", "RB31", "RB31", "Elsterw-Biehal", "von Coswig (b. Dresde"}, {"12", "Leipzig Hbf - Halle (Saale)", "Hannover Hbf", "17:08", "17:44", "RB31", "RB31", "Elsterw-Biehal", "von Coswig (b. Dresde"}, {"12", "Leipzig Hbf - Halle (Saale)", "Berlin Hbf", "17:08", "17:44", "RB31", "RB31", "Elsterw-Biehal", "von Coswig (b. Dresde"}, {"12", "Leipzig Hbf - Halle (Saale)", "Dresden Hbf", "17:08", "17:44", "RB31", "RB31", "Elsterw-Biehal", "von Coswig (b. Dresde"}, {"12", "Leipzig Hbf - Halle (Saale)", "Leipzig Hbf", "17:08", "17:44", "RB31", "RB31", "Elsterw-Biehal", "von Coswig (b. Dresde"}, {"12", "Leipzig Hbf - Halle (Saale)", "Hamburg Hbf", "17:08", "17:44", "RB31", "RB31", "Elsterw-Biehal", "von Coswig (b. Dresde"} }; const char* hinweis[] = { "Aufgrund einer Signalstorung ", "hat der ICE100 heute leider ca. 25 Minuten Verspatung. ", "Wir bitten um Ihr Verstandnis." };
Code für das Modul: RailFX-Bahnhof
Libraries
Für dieses Projekt wird dieSSD1306Ascii Bibliothek von Bill Greiman benötigt. Man kann sie hinzufügen, indem man im Arduino Menü > Sketch > Bilbiothek hinzufügen > Bibliotheken verwalten nach »SSD1306Ascii« sucht und die aktuelle Version installiert.
Darüber hinaus wird die Bibliothek DFRobotDFPlayerMini von DFRobot verwendet. Auch diese installiert man über Bibliotheken verwalten. Hier kann man einfach nach dfplayer suchen.
Beim Upload muss man darauf achten, dass das richtige Board im Arduino-Menü ausgewählt ist. Dazu muss ebenfalls im Werkzeuge-Menü im Unterpunkt Prozessor »ATmega328P (Old Bootlaoder)« ausgewählt sein. Ansonsten kann man den folgenden Programmcode mit den oben erwähnten Änderungen einfach kopiert und auf das Arduino-Nano laden.
#include <Wire.h> #include "SSD1306Ascii.h" #include "SSD1306AsciiWire.h" #include "SoftwareSerial.h" // Wird für den DFPlayer benötigt #include "DFRobotDFPlayerMini.h" // Wird für den DFPlayer benötigt /* Rail-FX Bahnhof StartHardware.org */ /* ***** ***** Einstellungen ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** */ int flackerzeitLeuchten = 1000; // Je höher der Wert, desto mehr flackern die Leuchtstoffröhren beim Einschalten int flackerGeschwindigkeit = 100; // Flackergeschwindigkeit der Leuchtstoffröhren int anzeigenWechselMin = 2000; // Anzeigewechsel alle x Millisekunden int anzeigenwechselVariabeleZeit = 3000; // Um diesen Wert (Millisekunden) variiert der Anzeigewechsel int mp3Anzahl = 6; // Menge der MP3 Dateien auf der SD-Karte int mp3Dauer[] = {13, 16, 16, 10, 9, 9}; // Dauer der MP3 Dateien in Sekunden int mp3Wahrscheinlichkeit = 10; // Wahrscheinlichkeit, mit der MP3s abgespielt werden, 10 oft, 100 selten int lautstaerke = 10; // Lautstärke des DFPlayers (0 – 30); int empfangsPuffer = 55; // Ändern der Anzeige kann das Empfangen des Zeitsignals verhindern. Deshalb werden ab dieser Modellbahn-Minute keine Displayänderungen ausgeführt (muss kleiner als 59 sein) /* Anzeigen */ int anzeigeAnzahl = 6; // Muss so groß sein, wie die Anzahl der angezeigten Texte aus dem Array textSegments const char* textSegments[6][7] = { {"12", "", "Zugdurchfahrt", "RB31", "RB31", "Elsterw-Biehal", "von Coswig (b. Dresde"}, {"12", "Leipzig Hbf - Halle (Saale)", "Hannover Hbf", "RB31", "RB31", "Elsterw-Biehal", "von Coswig (b. Dresde"}, {"12", "Leipzig Hbf - Halle (Saale)", "Berlin Hbf", "RB31", "RB31", "Elsterw-Biehal", "von Coswig (b. Dresde"}, {"12", "Leipzig Hbf - Halle (Saale)", "Dresden Hbf", "RB31", "RB31", "Elsterw-Biehal", "von Coswig (b. Dresde"}, {"12", "Leipzig Hbf - Halle (Saale)", "Leipzig Hbf", "RB31", "RB31", "Elsterw-Biehal", "von Coswig (b. Dresde"}, {"12", "Leipzig Hbf - Halle (Saale)", "Hamburg Hbf", "RB31", "RB31", "Elsterw-Biehal", "von Coswig (b. Dresde"} }; const char* hinweis[] = { "Auf Grund einer Signalstorung ", "hat der ICE100 heute leider ca. 25 Minuten Verspatung. ", "Wir bitten um Ihr Verstandnis." }; /* ***** ***** Ab hier beginnt der Programmcode, der nicht angepasst werden muss ***** ***** ***** ***** */ // 0X3C+SA0 - 0x3C or 0x3D #define I2C_ADDRESS 0x3C uint32_t tickTime = 0; int tickerPosition = 0; #define RTN_CHECK 1 int leuchtstoffroehrenPins[9] = {4, 5, 6, 7, 8, 9, 10, 11, 12}; int sensorPin1 = 15; // an diesem Pin ist ein Abstandssensor angeschlossen (15 = A1) int sensorPin2 = 16; // an diesem Pin ist ein Abstandssensor angeschlossen (16 = A2) int sensor1Zustand = 0; // speichert den aktuellen Zustand des Sensors int sensor1ZustandAlt = 0; // macht den Zustand des Sensors nach dem Neueinlesen verfügbar int sensor2Zustand = 0; // speichert den aktuellen Zustand des Sensors int sensor2ZustandAlt = 0; // macht den Zustand des Sensors nach dem Neueinlesen verfügbar /* Speicher Variablen */ int leuchtstoffroehrenZustand[9] = {1, 1, 1, 1, 1, 1, 1, 1, 1}; TickerState state; // Speichert den aktuellen Text-Pointer des OLED-Tickers int verspaetung = 0; // wird per Zufall ermittelt; 1=Verspätung, 0=keine Verspätung int anzeigenwechselVariabeleZeitHilfsvariable = 0; /* Timer Variablen */ long leuchtstoffroehrenTimer[9]; long anzeigeTimer; /* Variablen für das OLED */ SSD1306AsciiWire oled; /* Variablen für den MP3 Player*/ long soundTimer = 0; // Timer des DFPlayers long soundTimeout = 0; // Speichert die Abspieldauer des aktuellen MP3 int soundState = 0; // Status des DFPlayers int soundRandom; int theSound; int soundPlaying = false; SoftwareSerial mySoftwareSerial(3, 2); // RX, TX für den DFPlayer DFRobotDFPlayerMini myDFPlayer; // DFPlayer Objekt /* Variablen vom Controlmodul um die Uhrzeit festzustellen*/ boolean receive = false; boolean receiveStarted = false; int receiveTimeout = 10; long receiveTimer = 0; int receivedTime = 0; int receivePulse = 0; int lastReceivePulse = 0; int receivePin = 17; int myTime = 8; int myMinutes = 0; long lastTimeSignal; int timeToHour; #define PAYLOAD_SIZE 2 // nötig für die Kommunikation zum Master int uhrzeit = 0; // speichert die uhrzeit vom Master-Modul (0 und 255) byte nodePayload[PAYLOAD_SIZE]; // speichert die Daten vom Master-Modul zwischen void setup() { Serial.begin(115200); // started die serielle Kommunikation pinMode(receivePin, INPUT); // Empfangspin vom Control-Modul Wire.begin(); // I2C Verbindung zum OLED Wire.setClock(400000L); // I2C Verbindung zum OLED mySoftwareSerial.begin(9600); // started die serielle Kommunikation für den DFPlayer oled.begin(&Adafruit128x64, I2C_ADDRESS); // Start des OLEDs for (int i = 0; i < 9; i++) { pinMode(leuchtstoffroehrenPins[i], OUTPUT); digitalWrite(leuchtstoffroehrenPins[i], HIGH); } randomSeed(A2); oled.tickerInit(&state, Adafruit5x7, 0, false, 27, 100); // Ticker für die Anzeigetafel drawInfo(1); /* DFPlayer Setup */ Serial.println(F("Initializing DFPlayer ... ")); if (!myDFPlayer.begin(mySoftwareSerial, false)) { // nutze softwareSerial um mit dem DFPlayer zu sprechen Serial.println(F("Fehler: Prüfe Verbindung zum DFPlayer und SD-Karte")); /*while (true) { delay(0); // Code to compatible with ESP8266 watch dog. }*/ } Serial.println(F("DFPlayer Mini online.")); myDFPlayer.volume(lautstaerke); // Lautstärke wird zugewiesen delay(1000); pinMode(sensorPin1, INPUT_PULLUP); pinMode(sensorPin2, INPUT_PULLUP); } void loop() { receiveFunction(); // Führe Anweisungen für Empfang aus if (receiveStarted == false) { // Falls gerade keine Daten empfangen werden: if (myTime > 22) { // ***** Später Abend ***** leuchtstoffroehrenEin(); // Leuchtstoffröhren einschalten soundAn(); // Sound An } else if (myTime > 18) { // ***** Abend ***** leuchtstoffroehrenEin(); // Leuchtstoffröhren einschalten soundAn(); // Sound An } else if (myTime > 12) { // ***** Nachmittag ***** leuchtstoffroehrenAus(); // Leuchtstoffröhren ausschalten soundAn(); // Sound An } else if (myTime > 9) { // ***** Vormittag ***** leuchtstoffroehrenAus(); // Leuchtstoffröhren ausschalten soundAn(); // Sound An } else if (myTime > 7) { // ***** Morgen ***** leuchtstoffroehrenAus(); // Leuchtstoffröhren einschalten soundAn(); // Sound An } else if (myTime > 0) { // ***** Nacht ***** leuchtstoffroehrenEin(); // Leuchtstoffröhren einschalten soundAus(); // Sound Aus } if (myMinutes < empfangsPuffer) { anzeigeTafelSensor(); // Anzeigetafel schaltet per Sensor um // anzeigeTafelAutomatisch(); // Anzeigetafel schaltet per Zufall um } } } void anzeigeTafelSensor() { sensor1Zustand = digitalRead(sensorPin1); sensor2Zustand = digitalRead(sensorPin2); //Serial.print("Sensor 1: ");Serial.print(sensor1Zustand);Serial.print("\t Sensor 2: ");Serial.println(sensor2Zustand); int i; if ((sensor1Zustand == 1) && (sensor2Zustand == 1)) { // Gleis leer if ((sensor1ZustandAlt == 0) || (sensor2ZustandAlt == 0)) { // Vorher Gleis besetzt i = random(anzeigeAnzahl); drawInfo(i); verspaetung = random(2); } } if ((verspaetung > 0) && (i != 0)) { if (tickTime <= millis()) { tickTime = millis() + 30; oled.setInvertMode(1); int8_t rtn = oled.tickerTick(&state); if (rtn <= RTN_CHECK) { oled.tickerText(&state, hinweis[(tickerPosition++) % 3]); } } } sensor1ZustandAlt = sensor1Zustand; sensor2ZustandAlt = sensor2Zustand; } void anzeigeTafelAutomatisch() { int i; if (anzeigeTimer + anzeigenWechselMin + anzeigenwechselVariabeleZeitHilfsvariable < millis()) { // der zweite Teil verhindert, dass ein Anzeigewechsel dem Empfang des Zeitsignals blockiert anzeigeTimer = millis(); i = random(anzeigeAnzahl); drawInfo(i); verspaetung = random(2); anzeigenwechselVariabeleZeitHilfsvariable = random(anzeigenwechselVariabeleZeit); } if ((verspaetung > 0) && (i != 0)) { if (tickTime <= millis()) { tickTime = millis() + 30; oled.setInvertMode(1); int8_t rtn = oled.tickerTick(&state); if (rtn <= RTN_CHECK) { oled.tickerText(&state, hinweis[(tickerPosition++) % 3]); } } } } void drawInfo(int i) { // OLED Ausgabe oled.clear(); oled.setInvertMode(0); oled.setCursor(0 , 0); oled.setFont(Callibri15); oled.println(textSegments[i][0]); oled.clearToEOL(); oled.setCursor(104 , 0); oled.setFont(Callibri10); oled.println(makeTime()); oled.clearToEOL(); oled.setFont(Callibri10); oled.setCursor(27 , 1); oled.println(textSegments[i][1]); oled.setFont(Callibri14); oled.setCursor(27 , 2); oled.println(textSegments[i][2]); oled.setFont(Callibri10); oled.setCursor(0 , 5); oled.println(makeTime1()); oled.setCursor(0 , 6); oled.println(makeTime2()); oled.setCursor(27 , 5); oled.println(textSegments[i][3]); oled.setCursor(27 , 6); oled.println(textSegments[i][4]); oled.setCursor(54 , 5); oled.println(textSegments[i][5]); oled.setCursor(54 , 6); oled.println(textSegments[i][6]); } String makeTime() { String myTimeString = ""; int myHoursSub = myTime; int myMinutesSub = myMinutes; if (myHoursSub < 10) myTimeString = " " + String(myHoursSub); else myTimeString = String(myHoursSub); if (myMinutesSub < 10) myTimeString += ":0" + String(myMinutesSub); else myTimeString += ":" + String(myMinutesSub); return myTimeString; } String makeTime1() { // Nächster Zug String myTimeString = ""; int myHoursSub = myTime; int myMinutesSub = myMinutes; //int myMinutesSub1=random(30); if (myMinutesSub > 29) { if (myHoursSub > 22) myHoursSub = 0; else myHoursSub++; } else { myMinutesSub += 30; } if (myHoursSub < 10) myTimeString = " " + String(myHoursSub); else myTimeString = String(myHoursSub); if (myMinutesSub < 10) myTimeString += ":0" + String(myMinutesSub); else myTimeString += ":" + String(myMinutesSub); return myTimeString; } String makeTime2() { // Übernächster Zug String myTimeString = ""; int myHoursSub = myTime; int myMinutesSub = myMinutes; if (myHoursSub >= 23) myHoursSub = 0; else myHoursSub++; if (myHoursSub < 10) myTimeString = " " + String(myHoursSub); else myTimeString = String(myHoursSub); if (myMinutesSub < 10) myTimeString += ":0" + String(myMinutesSub); else myTimeString += ":" + String(myMinutesSub); return myTimeString; } void leuchtstoffroehrenEin() { for (int i = 0; i < 9; i++) { if (random(flackerzeitLeuchten) == 0) leuchtstoffroehrenZustand[i] = 0; if (leuchtstoffroehrenZustand[i] != 0) { // wenn die Röhre nicht eingeschaltet ist if (leuchtstoffroehrenZustand[i] + leuchtstoffroehrenTimer[i] < millis()) { leuchtstoffroehrenZustand[i] = random(flackerGeschwindigkeit) + 20; // erzeugt eine Timeout-Variable leuchtstoffroehrenTimer[i] = millis(); int myOutput = random(2); digitalWrite(leuchtstoffroehrenPins[i], myOutput); } } else { digitalWrite(leuchtstoffroehrenPins[i], 0); } } } void leuchtstoffroehrenAus() { for (int i = 0; i < 9; i++) { leuchtstoffroehrenZustand[i] = 1; digitalWrite(leuchtstoffroehrenPins[i], HIGH); } /*if (random(ausschaltWahrscheinlichkeit) == 1) { // Einschalten der Leuchtstoffröhren per Zufall int thePin = random(10); digitalWrite(leuchtstoffroehrenPins[thePin], HIGH); leuchtstoffroehrenZustand[thePin] = 0; }*/ } void soundAn() { switch (soundState) { case 0: Serial.println("soundTimer 0"); soundRandom = random(mp3Wahrscheinlichkeit); if (soundRandom < 1) { soundState = 1; theSound = random(mp3Anzahl) + 1; soundTimer = millis(); soundTimeout = mp3Dauer[theSound - 1] * 1000; Serial.print("Playsound: \t\t\t"); Serial.print(theSound); Serial.print("\t\t\t"); Serial.println(soundTimeout); myDFPlayer.playFolder(1, theSound); //play specific mp3 in SD:/15/004.mp3; Folder Name(1~99); File Name(1~255) soundPlaying = true; } else { soundTimer = millis(); soundTimeout = 500; soundState = 1; } break; case 1: if (soundTimer + soundTimeout < millis()) { soundPlaying = false; soundState = 0; } break; } } void soundAus() { if (soundPlaying == true) { Serial.println(soundPlaying); myDFPlayer.pause(); soundPlaying = false; } } void receiveFunction() { // Empfängt die Uhrzeit vom Control-Modul receivePulse = digitalRead(receivePin); // Lies den Empfangspin aus if ((receiveTimer + receiveTimeout < millis()) && (receiveStarted == true)) { // Bei Timeout und aktivem Empfang receiveStarted = false; // beende aktiven Empfang myTime = receivedTime - 1; // speichere die empfangene Zeit receivedTime = 0; // setze die Hilfsvariable zum Zeitempfang zurück timeToHour = millis() - lastTimeSignal; lastTimeSignal = millis(); } // falls ein Puls am Empfangspin erfasst wird, der vorher nicht da war if ((receivePulse == 0) && (lastReceivePulse == 1)) { receiveTimer = millis(); // starte Timer neu if (receiveStarted == false) receiveStarted = true; // starte aktiven Empfang, wenn noch nicht geschehen receivedTime++; // es gab einen Puls, also erhöhe die Hilfsvariable zum Zeitempfang } lastReceivePulse = receivePulse; // aktuellen Zustand am Pin für nächsten Durchlauf merken if (receiveStarted == false) { if (millis() % 100 < 2) { int myNewMinutes = map(millis() - lastTimeSignal, 0, timeToHour, 0, 59); myNewMinutes = constrain(myNewMinutes, 0, 59); if (myNewMinutes != myMinutes) { Serial.print(myTime); Serial.print(":"); Serial.print(myMinutes); Serial.print("\t"); Serial.println(myTime); } myMinutes = myNewMinutes; } } }
Wenn dir das Projekt gefallen hat und du von weiteren interessanten Projekten inspiriert werden willst, sieh dir doch mal mein neues E-Book »Arduino Projekte Volume 1« an!
- Die beliebtesten Arduino-Projekte von StartHardware
- Inklusive Schaltplan, Beschreibung und Code
- Arduino-Schnellstart-Kapitel
- Kompakter Programmierkurs
Hallo Stefan,
erst mal ein großes Lob und ein herzliches Dankeschön für Deine RailFX-Projekte.
Ich habe schon einige nachgebaut und bin voll begeistert.
Bin gerade dabei einen Bahnsteig mit Aufzug zu bauen, der mit einem als Motor umgebauten SG90 Servo angetrieben wird und über H-Brücke und 2 Micro-Endschalter jeweils in der oberen und unteren Position die Richtung wechselt. Leider bekomme ich es in meinem Sketch nicht hin, in den jeweiligen Endpostionen eine einstellbare Zeit zu warten. Kannst Du mir helfen wie der Sketch aussehen müsste, damit das funktioniert?
#include
#define DIRECTION_CCW -1
#define DIRECTION_CW 1
#define ENA_PIN 7 // The Arduino pin connected to the EN1 pin L298N
#define IN1_PIN 6 // The Arduino pin connected to the IN1 pin L298N
#define IN2_PIN 5 // The Arduino pin connected to the IN2 pin L298N
ezButton limitSwitch_1(A0); // create ezButton object that attach to pin A0
ezButton limitSwitch_2(A1); // create ezButton object that attach to pin A1
int direction = DIRECTION_CW;
int prev_direction = DIRECTION_CW;
void setup() {
Serial.begin(9600);
limitSwitch_1.setDebounceTime(50); // set debounce time to 50 milliseconds
limitSwitch_2.setDebounceTime(50); // set debounce time to 50 milliseconds
// initialize digital pins as outputs.
pinMode(ENA_PIN, OUTPUT);
pinMode(IN1_PIN, OUTPUT);
pinMode(IN2_PIN, OUTPUT);
digitalWrite(ENA_PIN, HIGH); // max speed
digitalWrite(IN1_PIN, HIGH); // control motor A spins clockwise
digitalWrite(IN2_PIN, LOW); // control motor A spins clockwise
}
void loop() {
limitSwitch_1.loop(); // MUST call the loop() function first
limitSwitch_2.loop(); // MUST call the loop() function first
if (limitSwitch_1.isPressed()) {
direction *= -1; // change direction
Serial.println(F(“The limit switch 1: TOUCHED”));
}
if (limitSwitch_2.isPressed()) {
direction *= -1; // change direction
Serial.println(F(“The limit switch 2: TOUCHED”));
}
if (prev_direction != direction) {
Serial.print(F(“The direction -> “));
if (direction == DIRECTION_CW) {
Serial.println(F(“CLOCKWISE”));
digitalWrite(IN1_PIN, HIGH); // control motor A spins clockwise
digitalWrite(IN2_PIN, LOW); // control motor A spins clockwise
} else {
Serial.println(F(“ANTI-CLOCKWISE”));
digitalWrite(IN1_PIN, LOW); // control motor A spins anti-clockwise
digitalWrite(IN2_PIN, HIGH); // control motor A spins anti-clockwise
}
prev_direction = direction;
}
}
Noch schöner wäre es, wenn man die Funktion in Dein Projekt “Bahnhof” integrieren könnte und der Aufzug zufällig ev. mit der Anzeige oder der Soundausgabe ablaufen würde.
Viele Grüße und ein schönes Wochenende in Erwartung Deiner Antwort
Manfred Knöfel
Hallo zusammen
Echt Klasse. Habe jetzt das Modul fertig nachgebaut und funktioniert auch. Nur ein Problem.
Die Flackerleuchten gehen bei 20 Uhr aus, sollten aber angehen und gehen um 8 Uhr an und sollten aber ausgehen, Die Schaltbefehle sind gerade falsch herum. Was muss ich ändern?
Hallo Stefan
Wollte mich nur mal für das RailFX System bedanken,
bis jetzt hat das meiste auf Anhieb Funktioniet, alles ist gut beschieben,
das es auch ein anfänger wie ich es kapiert.
LG Berthold
Vielen Dank für den Kommentar und weiterhin viel Spaß mit dem System :-)
Hallo zusammen
Echt Klasse. Habe jetzt das Modul fertig nachgebaut und funktioniert auch. Nur ein Problem.
Die Flackerleuchten gehen bei 20 Uhr aus, sollten aber angehen und gehen um 8 Uhr an und sollten aber ausgehen, Die Schaltbefehle sind gerade falsch herum. Was muss ich ändern?
Hallo Stefan.
Ich bin dabei das Modul zu bauen. Bin da allerdings auf ein Problem gestoßen. Ich will mit 12 Volt led schalten.
Habe mir dazu Mosfet Module gekauft. Doch die wollen das Pwm Signal von vcc. Und bei dir wird ja mit GND geschaltet. Kann man das umstellen im Sketch geht sowas? Das ich das pwm + habe und nicht wie jetzt pwm-?
Hallo,
kurze Nachfrage, bin in der Welt von Adruino und Programmieren noch ein Anfänger, aber besteht die Möglichkeit den freien A ( 0 ) oder A ( 2 ) für einen Taster oder Schalter zu verwenden? Und mit dieser Option Lichtschranke und Taster oder Schalter einen bestimmten Sound abzuspielen?
Mit freundlichen Grüßen
Martin
Hi Martin, ja klar, das geht schon. Die analogen Inputs kann man auch als digitale Pins verwenden. A0 wäre dann Pin 14, A1 wäre Pin 15 usw. Liebe Grüße Stefan
Hallo Stefan,
danke für die Info, dann wäre ja somit eine “kleine Personalisierung ” für eine Gleis 1 oder X möglich, mit einem Sound-File.
Denn ich habe bei meinem Eigenbau Bremsmodulen noch einen Schaltkontakt (Schließer) frei, und wenn der aktive wäre könnte der Sound X abgespielt wären.
Gruß
Martin
Hallo Stefan,
kurzer Nachtrag, Ihre “Sound Machine mit Arduino” wäre eigentlich schon die Lösung, man müsste nur die Eingänge vom Taster gegen ein Schalter Signal ändern?
Gruß
Martin
Moin Stefan, habe das Rail fx system schon auf der neuen spur z platte in Angriff genommen, meine Frage kann man die lichtschranken vom bahnhofsmodul an 2 arduino anschließen wollte noch eine Geschwindigkeitmessstrecke im Tunnel verbauen und etwas Material einsparen Grüße Michel
Hi Michel, das weiß ich nicht genau. Solange du alle GNDs verbindest, könnte es klappen. Wäre es aber nicht einfacher, die Geschwindigkeitsmessung zum RailFX Modul hinzuzufügen? Liebe Grüße Stefan
Beim Bahnhofs-Modul gibt es eine Möglichkeit die Anzeige und Ansage den Zügen zu zuteilen. Also Personalieren.
Ist leider nicht implementiert, aber wäre schon spannend.
Hallo Hartmut,
vielen Dank für die Nachricht! Zum Glück wissen wir jetzt, woran es lag. Die Module sehen ja fast gleich aus. Ich hab jetzt auch beide da und das MP3-TP-16P macht auch bei mir Probleme. Ich hab keien Ahnung, woran das liegt. Ich hab jetzt aber einen Hinweis zu allen RailFX-Modulen mit MP3-Player hinzugefügt. Dann viel Spaß mit dem System und ich will Fotos sehen ;-)
Liebe Grüße
Stefan
Hallo Stefan,
ich habe noch einmal ein DFPlayer Mini Modul bestellt und es ist heute angekommen.
Alles funktioniert wunderbar. Warum das andere Modul nicht funktioniert würde mich aber doch interessieren.
Ich danke dir für deine Mühe, du hast hier ein super Projekt begonnen.
Gruß Hartmut
Hallo Stefan,
Bestellt war der dfp aber bekommen habe ich den MP3-TP-16P. Mir ist noch aufgefallen das er auf die Lautstärkeeinstellung nicht reagiert.
Vielen Dank für deine Mühe.
Gruß Hartmut
Hallo Stefan,
dein Projekt ist super, großen Respekt für deine Arbeit. Ich habe mich mit dem Bahnhofsmodul beschäftigt aber an der Tonausgabe scheiter ich.
Es kommt kein Sound aus dem Lautsprecher. Danach habe ich das MP3 Modul separat nach der Anleitung (https://starthardware.org/dfplayer-mini-mp3-player-fuer-arduino/) aufgebaut. Alles in Ordnung.
Vielleicht hast du eine Idee für mich.
Viele Grüße!
Hi Hartmut, betreibst du das Bahnhofsmodul mit dem Control-Modul? Was steht im Seriellen Monitor der Arduino-Software? Liebe Grüße Stefan
Ja das Control-Modul läuft einwandfrei und steuert die Funktionen im Bahnhofsmodul. Im seriellen Monitor steht:
21:56:22.547 -> 6:55 6
21:56:22.750 -> 6:56 6
21:56:22.852 -> 6:57 6
21:56:22.953 -> 7:58 7
21:56:23.055 -> 7:0 7
21:56:23.259 -> 7:1 7
21:58:30.586 -> 23:45 23
21:58:30.688 -> 23:46 23
21:58:30.756 -> Playsound: 2 16000
21:58:30.857 -> 23:47 23
21:58:30.959 -> 23:48 23
21:58:31.061 -> 23:49 23
21:58:31.264 -> 23:50 23
Gruß Hartmut
Hi Hartmut,
hm, das sieht alles gut aus. Steht auf dem DFPlayer MP3-TP-16P oder DFPlayer Mini?
Liebe Grüße
Stefan
Hallo Stefan,
danke für Deine Antwort! Ich antworte mal hier, da es so alle sehen können.
Hab die Speicherkarte gewechselt, einmal Fat16 einmal Fat32 formatiert. Das mit beiden Karten abwechselnd. Die Dateien und Ordner sind korrekt drauf. Ergebnis: Knacken bleibt, auch mit Labornetzteil 10A. Festgestellt habe ich, dass man die mp3 manuell beim Player starten kann, also die Karten funktionieren Beide. Die Ansagen sind echt cool!
Vermutlich liegt es am DFP-Player, habe 2 Stück probiert, beide gehen nicht mit dem Code. Aber beide sind auch nicht von DFRobot sondern FN-M16P! Das wird das Problem sein. Habe direkt über die Links bei am*z*n bestellt, da bekommt man eben diese. Bei den Bewertungen hat “Gartenfreund” schön etwas beschrieben. Womöglich muss der Code auf diese Player angepasst werden. Hab aber noch keine Lösung gefunden…
Viele Grüße!
Hi Nochimmeranonym,
da bin ich echt gespannt, ob es an den Playern liegt. Ich freue mich auf das Update :-) Und vielen Dank, dass du der Sache auf den Grund gehst!
Ob das Tauschen der RX und TX-Verbindungen hilft, kann ich mir kaum vorstellen, ist den Versuch aber wert. Danke Marcus für die Idee.
Liebe Grüße
Stefan
Hallo Stefan,
habe mich Deinem Projekt gewidmet, da ich es einfach klasse finde!
Darum großen Dank!
Ich bekomme noch keinen Ton aus dem Lautsprecher. Er knackt beim Spannung einschalten und rauscht sehr leise. Die Ansagen werden mit kleinem Knack womöglich begonnen, aber nichts weiter. Was kann noch der Fehler sein?
Hi bleibnochmalanonym,
das könnte an der SD-Karte liegen. Kannst du mal prüfen, ob sie richtig formatiert ist (https://starthardware.org/dfplayer-mini-mp3-player-fuer-arduino/) und ob die Dateien im Richtigen Ordner abgelegt sind? Das Knacken beim Einschalten ist normal.
Es könnte aber auch an einer zu klein dimensionierten Stromversorgung liegen. Probier das mal aus, ansonsten schreib mir noch mal eine Email: hello@starthardware.org
Liebe Grüße
Stefan
Tausche mal am MP3 Player die Leitung Tx und Rx, dann sollte das Problem beseitigt sein.
Erst einmal vielen Dank für das tolle Projekt. Ich bin zwar kein Modelleisenbahnbauer, suchte aber ein Geburtstagsgeschenk für einen Freund und wurde hier fündig.
Ich glaube, dass sich bei der Erweiterung für die Lichtschranken im Fritzing ein Fehler eingeschlichen hat.
Für mich sieht es so aus, als ob die Lichtschranken an A2 und A1 angeschlossen sind.
Im Code werden die Pins A1 und A0 verwendet.
Hi Ralf, vielen Dank für den Hinweis! Da war tatsächlich noch ein Fehler drin. Ich hab es im Code geändert :-) Jetzt sollte es funktionieren.
Liebe Grüße
Stefan
Halo Stefan, kannst Du mir eine Bezugsquelle für Modellbahnsounds in de Qualität wie Du sie hier zum Download bereitstellt nennen? Auch für die Deine Einsatzstelle finde ich nur Blechdosensounds. Bin auch gern bereits dafür zu bezahlen.
Hi Volker, die Datei SSD1306AsciiWire.h ist eine Bibliothek, die eingebunden werden muss. Oben unter dem Punkt Libraries hab ich beschrieben, wie das geht. Hast du das schon probiert? Das mit dem Kontakt ist eine gute Idee. Ich würde das mit den Sensoren aus dem Bahnübergangsmodul machen: https://starthardware.org/railfx-bahnuebergang/ Ich werd die Tage mal eine Version damit entwickeln. Danke für die Anregung.
Liebe Grüße Stefan
Ich bin gespannt auf die Neuerung. Der Sensor ist perfekt!!
Das habe ich gemacht, aber ich finde die Bibliothek nicht, alle anderen sind da. Es geht trotzdem, finde ich nur komisch.
Gruß Volker
Ich habe noch einen Nachtrag, vielleicht kann mit einem zweiten Sensor noch bei der Einfahrt ertönen lassen “Bitte zurücktreten von der Bahnsteigkante, Achtung bei Einfahrt des Zuges” oder so.
Gruß Volker
Hallo Stefan, ich bin jetzt bei dem Bahnhof bei und finde die Datei “SSD1306AsciiWire.h” nicht. Kannst Du mir sagen wo ich die finde?
Eine Frage zur Schaltung, ist es nicht möglich die Anzeige über einen externen Kontakt weiter zu schalten? Immer wenn ein Zug den Bahnhof verlässt, schaltet er einen weiter? Kannst Du mir da einen Tipp geben?