// Definitie van de 4 ingangen voor de sensoren#define SBBLSP1 3 // BlackBox Links, Spoor 1#define SBBLSP2 4 // BlackBox Links, Spoor 2#define SBBRSP1 5 // BlackBox Rechts, Spoor 1#define SBBRSP2 6 // BlackBox REchts, Spoor 2#define DELAY 500 // Vertraging in milli seconde// Laatste stand van de melderbool MBBLSP1;bool MBBLSP2;bool MBBRSP1;bool MBBRSP2;// Timers om het vrijgeven te vertragenunsigned long TSBBLSP1;unsigned long TSBBLSP2;unsigned long TSBBRSP1;unsigned long TSBBRSP2;// Variabelen die richting in de sporen bij houden// < 0: trein rijdt van rechts naar links// 0: geen trein// > 0: trein rijdt van links naar rechtsbyte DIRSP1;byte DIRSP2;// Functies om de melders te lezen (true = bezet)bool readBBLSP1() { // if (digitalRead(SBBLSP1) > 0) { if (digitalRead(SBBLSP1) == 0) { TSBBLSP1 = millis() + DELAY; } return (TSBBLSP1 > millis());}bool readBBLSP2() { // if (digitalRead(SBBLSP2) > 0) { if (digitalRead(SBBLSP2) == 0) { TSBBLSP2 = millis() + DELAY; } return (TSBBLSP2 > millis());}bool readBBRSP1() { // if (digitalRead(SBBRSP1) > 0) { if (digitalRead(SBBRSP1) == 0) { TSBBRSP1 = millis() + DELAY; } return (TSBBRSP1 > millis());}bool readBBRSP2() { // if (digitalRead(SBBRSP2) > 0) { if (digitalRead(SBBRSP2) == 0) { TSBBRSP2 = millis() + DELAY; } return (TSBBRSP2 > millis());}// Initialialatie van de Arduinovoid setup() { // put your setup code here, to run once: // Maak de inputs met extra pullups pinMode(SBBLSP1, INPUT_PULLUP); pinMode(SBBLSP2, INPUT_PULLUP); pinMode(SBBRSP1, INPUT_PULLUP); pinMode(SBBRSP2, INPUT_PULLUP); // Zet de interne LED output pinMode(LED_BUILTIN, OUTPUT); // Initialiseer de laatste waarde MBBLSP1 = readBBLSP1(); MBBLSP2 = readBBLSP2(); MBBRSP1 = readBBRSP1(); MBBRSP2 = readBBRSP2(); // Initialiseer de timers TSBBLSP1 = millis(); TSBBLSP2 = millis(); TSBBRSP1 = millis(); TSBBRSP2 = millis(); // Meld geen trein (waarde 0) DIRSP1 = 0; DIRSP2 = 0; // LED uit digitalWrite(LED_BUILTIN, LOW);}void loop() { // put your main code here, to run repeatedly: // fase: toestand nu en de vorige keer van de melder // volgorde: // 0: geen trein // 1: trein komt binnen // 2: trein verlaat // 3: trein aanwezig byte fase; // Spoor 1 (links) fase = (MBBLSP1 ? 2 : 0); MBBLSP1 = readBBLSP1(); fase += (MBBLSP1 ? 1 : 0); if (fase == 1) { // Trein komt binnen if (DIRSP1 == 0) { // Bij het bereiken van de andere kant alleen reageren op het verlaten DIRSP1++; } } if (fase == 2) { // Trein verlaat if (DIRSP1 < 0) { // Bij het verlaten van de binnen melder niet een extra puls geven. DIRSP1++; } } // Spoor 1 (rechts) fase = (MBBRSP1 ? 2 : 0); MBBRSP1 = readBBRSP1(); fase += (MBBRSP1 ? 1 : 0); if (fase == 1) { // Trein komt binnen if (DIRSP1 == 0) { // Bij het bereiken van de andere kant alleen reageren op het verlaten DIRSP1--; } } if (fase == 2) { // Trein verlaat if (DIRSP1 > 0) { // Bij het verlaten van de binnen melder niet een extra puls geven. DIRSP1--; } } // Spoor 2 (links) fase = (MBBLSP2 ? 2 : 0); MBBLSP2 = readBBLSP2(); fase += (MBBLSP2 ? 1 : 0); if (fase == 1) { // Trein komt binnen if (DIRSP2 == 0) { // Bij het bereiken van de andere kant alleen reageren op het verlaten DIRSP2++; } } if (fase == 2) { // Trein verlaat if (DIRSP2 < 0) { // Bij het verlaten van de binnen melder niet een extra puls geven. DIRSP2++; } } // Spoor 2 (rechts) fase = (MBBRSP2 ? 2 : 0); MBBRSP2 = readBBRSP2(); fase += (MBBRSP2 ? 1 : 0); if (fase == 1) { // Trein komt binnen if (DIRSP2 == 0) { // Bij het bereiken van de andere kant alleen reageren op het verlaten DIRSP2--; } } if (fase == 2) { // Trein verlaat if (DIRSP2 > 0) { // Bij het verlaten van de binnen melder niet een extra puls geven. DIRSP2--; } } // Aansturen van de AKI / AHOB (overweg) if ((DIRSP1 == 0) && (DIRSP2 == 0)) { // Overweg geopend digitalWrite(LED_BUILTIN, LOW); } else { // Overweg gesloten digitalWrite(LED_BUILTIN, HIGH); }}
Oke,Alles even samenvatten:Eisen/Wensen:Aansturing van een AKI door een trein. Aan de trein mogen geen aanpassingen gedaan worden. De AKI is dubbelsporig en moet van beide zijde op hetzelfde spoor aangestuurd worden. Gekozen is voor aansturing via "lichtsluizen" en een Arduino.Eventuele knippenringen door de lichtsluizen worden door een schuine opstelling verminderd, geheel voorkomen kan niet. Dit wordt niet door extra hardware opgelost.
@C goeroes:Het programma roept om optimalisatie. Ik weet dat dit mogelijk is, maar moet te veel research op het internet doen om het in C voor elkaar te krijgen.Help mij en Edsko door met voorbeelden te komen hoe stukken code geoptimaliseerd kunnen worden. Zie het als een een simpele wedstrijd zoals Meino aangaf.
Zo ik ga met vakantie en zal alleen via mijn mobiel meelezen en reageren. Dus verwacht de komende dagen geen lappen tekst meer.
Met interesse kijk ik mee:Ik heb een leuke voor jullie.Zelfde situatie, alleen driesporig. - knipperleds(oranje)- stepper controller voor 2 servos voor slaghekwerk.- fotocellen als lichtsluis.
#define DEBUG 0enum SpoorState {leeg, sensor1komend, sensor2komend, sensor1gaand, sensor2gaand };// // Class for a single (white) led which flickers 50 times per // minute when on// class SingleLed{ private: int ledPin; bool ledOn = true; int interval = 600; // *** 50 keer per minuut bool lightOn = false; unsigned long lastTime; public: // // Create a new instance of a (white) led, connect it to the specified // digital pin and put it in the specified state (true = on, false = off) // SingleLed(int aPin, bool state) { ledPin = aPin; ledOn = state; lightOn = false; pinMode(ledPin, OUTPUT); lastTime = millis(); } // // Set the state of the led (true = on, false = off) // void setOn(bool state) { ledOn = state; } // // If the state is on, put power on the pin of the led, using timers // to make the flicker work. // If the led is off, remove the power from the pin of the led. // void heartBeat() { if (ledOn) // Do we need to light the led? { unsigned long currTime = millis(); if ((currTime - lastTime) >= interval) // Has the interval time passed? { lastTime = currTime; // Start new interval if (!lightOn) // Was the led lighted? { digitalWrite(ledPin, HIGH); // No, so switch it on lightOn = true; } else { digitalWrite(ledPin, LOW); // Yes, so switch it off lightOn = false; } } } else if (lightOn) // No light, but is the led still on? { digitalWrite(ledPin, LOW); // Switch ir off lightOn = false; } }};// // Class for a set of two (red) leds which alternate(flicker) 50 times per // minute when on//class DuoLed{ private: int led1Pin; int led2Pin; bool ledOn = true; int interval = 600; // *** 50 keer per minuut bool lightOn = false; unsigned long lastTime; public: // // Create a new instance, connect it to the specified // digital pins and put it in the specified state (true = on, false = off) // DuoLed(int aPin1, int aPin2, bool state) { led1Pin = aPin1; led2Pin = aPin2; ledOn = state; lightOn = false; pinMode(led1Pin, OUTPUT); pinMode(led2Pin, OUTPUT); lastTime = millis(); } // // Set the state of the leds (true = on, false = off) // void setOn(bool state) { ledOn = state; } // // If the state is on, put power on the pins of the leds, using timers // to make the alternating flicker work. // If the led is off, remove the power from the pins of the leds. // void heartBeat() { if (ledOn) // Are the leds activated { unsigned long currTime = millis(); if ((currTime - lastTime) >= interval) // Has the interval passed? { lastTime = currTime; // Yes, start new interval if (!lightOn) // The leds alternate, are we in phase1 (led1 on, led2 off) { digitalWrite(led1Pin, HIGH); // Yes, led1 on digitalWrite(led2Pin, LOW); // led2 off lightOn = true; // When the interval expires, switch the leds } else // We are in phase2 (led1 off, led2 on) { digitalWrite(led1Pin, LOW); // Led1 off digitalWrite(led2Pin, HIGH); // Led2 on lightOn = false; // When the interval expires, switc the leds } } } else // The leds are not active, switch of both leds { digitalWrite(led1Pin, LOW); digitalWrite(led2Pin, LOW); lightOn = false; } }};enum AkiStaat {aan, uit};//// A simple class that represents a complet AKI with all its leds//// TBD, the sound of the bells//class AKI{ private: SingleLed *whiteLight; DuoLed *redLights; AkiStaat state = uit; public: // // Create an instance of the AKI, using the specified Led objects // AKI(SingleLed *aWhiteLed, DuoLed *aRedLed) { whiteLight = aWhiteLed; redLights = aRedLed; state = uit; } // // Activate the connected leds. TBD: the sound // void heartBeat() { redLights->heartBeat(); whiteLight->heartBeat(); } void set(AkiStaat aState) { state = aState; if (state == uit) {#if (DEBUG) Serial.println("[AKI::set] AKI uit");#endif redLights->setOn(false); whiteLight->setOn(true); } else {#if (DEBUG) Serial.println("[AKI::set] AKI aan");#endif redLights->setOn(true); whiteLight->setOn(false); } }};//// Some sensors use a digital signal and keep it high when not active and drop the signal// when the sensor trips, use in that case the laag setting. Others use a digital signal // and are low when not active and make the signal high when the sensor trips, use in that case// the hoog setting.// if the sensor doesn't generate a digital signal, you have to use a pullup resistor (or INPUT_PULLUP) // and in that case specify hoog.//enum SensorTrigger {laag, hoog};//// A simple class which represents the state of a single sensor//class Sensor{ private: int sensorPin; SensorTrigger type = hoog; bool state = false; // true = on, false = off unsigned long lastTime = 0; // Timer to ignore short interrupts #define JITTER_TIME 1000 // wait a second before the sensor goes off public: // // Create a new instance // Sensor(int aPin) { sensorPin = aPin; pinMode(sensorPin, INPUT); } // // Create a new instance // Sensor(int aPin, SensorTrigger aType) { sensorPin = aPin; type = aType; pinMode(sensorPin, INPUT); } // // Return the current logical state of the sensor // bool getState() { return state; } // // Monitor the physical sensor and update the state accordingly // void heartBeat() { if (digitalRead(sensorPin) == HIGH) { if (type == laag) // For sensors type laag an high signal means they are in the off state { if (state != false) // Process this signal only when the current state is ON { if (lastTime == 0) { lastTime = millis(); // start Interval } else { unsigned long currTime = millis(); if ((currTime-lastTime) >= JITTER_TIME) {#if (DEBUG) Serial.println("[Sensor::heartBeat] sensor goes off");#endif state = false; // sensor goes OFF lastTime = 0; // Reset interval timer } } } } else {#if (DEBUG) Serial.println("[Sensor::heartBeat] sensor goes on");#endif state = true; // Sensor goes ON lastTime = 0; // Reset interval timer } } else // sensorPin = LOW { if (type == laag) {#if (DEBUG) Serial.println("[Sensor::heartBeat] sensor goes on");#endif state == true; // Sensor goes ON lastTime = 0; // Reset interval timer; } else { if (state != false) // Process this signal only when the current state is ON { if (lastTime == 0) { lastTime = millis(); // start Interval } else { unsigned long currTime = millis(); if ((currTime-lastTime) >= JITTER_TIME) {#if (DEBUG) Serial.println("[Sensor::heartBeat] sensor goes off");#endif state = false; // sensor goes OFF lastTime = 0; // Reset interval timer } } } } } } };//// A finite state machine that guards a occupance of a single track//class SpoorControl{ private: Sensor *sensor1; Sensor *sensor2; SpoorState state = leeg; // // Based on the state of sensor 1 and the current state of the FSM, a new state // is calculated. // void handleSensor1(bool trigger) { if (trigger) // Sensor 1 is ON { if (state == leeg) // If the state is "leeg" it means that a train enters the section {#if (DEBUG) Serial.println("[SpoorControl::handleSensor1] state is sensor1komend");#endif state = sensor1komend; // so set it to state komend } else if (state == sensor2komend) // if the other sensor tripped first {#if (DEBUG) Serial.println("[SpoorControl::handleSensor1] state is sensor1gaand");#endif state = sensor1gaand; // The train is starting to leave the section } } else { // Sensor went OFF if (state == sensor1gaand) // If the train started to leave via sensor 1 {#if (DEBUG) Serial.println("[SpoorControl::handleSensor1] state is leeg");#endif state = leeg; // the section is "leeg" } } } // // Based on the state of sensor 2 and the current state of the FSM, a new state // is calculated. // void handleSensor2(bool trigger) { if (trigger) // Sensor 2 is ON { if (state == leeg) // Is the section "leeg"? {#if (DEBUG) Serial.println("[SpoorControl::handleSensor2] state is sensor2komend");#endif state = sensor2komend; // A Train entered the section via sensor 2 } else if (state == sensor1komend) // No a train entered the section via the other sensor {#if (DEBUG) Serial.println("[SpoorControl::handleSensor2] state is sensor2gaand");#endif state = sensor2gaand; // Start the leaving process } } else { if (state == sensor2gaand) // A train is in the process of leaving {#if (DEBUG) Serial.println("[SpoorControl::handleSensor2] state is leeg");#endif state = leeg; // Section is empty again } } } public: // // Create an instance with two sensors // SpoorControl(Sensor *aSensor1, Sensor *aSensor2) { sensor1 = aSensor1; sensor2 = aSensor2; } // // Get give the sensors a kick and check their state so we can update our own // state. // void heartBeat() { sensor1->heartBeat(); sensor2->heartBeat(); handleSensor1(sensor1->getState()); handleSensor2(sensor2->getState()); } // // Return the current state of the section // SpoorState getState() { return state; }};//// Create 2 FSM controling two track sections//SpoorControl spoor1(new Sensor(A0, hoog), new Sensor(A1, hoog));SpoorControl spoor2(new Sensor(A2, hoog), new Sensor(A3, hoog));//// Create an instance of the AKI//AKI aki(new SingleLed(A4, true), new DuoLed(A5, A6, false));void setup() {#if (DEBUG) //Serial.begin(9600); Serial.begin(115200); while (!Serial); Serial.println("Starting"); Serial.flush();#endif //DEBUG }void loop() { spoor1.heartBeat(); // These object must monitor their sensors spoor2.heartBeat(); // so they can update their states if ((spoor1.getState() == leeg) && (spoor2.getState() == leeg)) { aki.set(uit); // Stop sound and flashing red lights } else { aki.set(aan); // Start flashing red lights and sound } aki.heartBeat(); // Let the AKI update it's connected bells and leds}
//class SpoorControl//// Create 2 FSM controling two track sections//SpoorControl spoor1(new Sensor(A0, hoog), new Sensor(A1, hoog));SpoorControl spoor2(new Sensor(A2, hoog), new Sensor(A3, hoog));
// Definitie van de 4 ingangen voor de sensoren (2 per spoor)#define SBBLSP1 2 // BlackBox Links, Spoor 1#define SBBRSP1 3 // BlackBox Rechts, Spoor 1#define SBBLSP2 4 // BlackBox Links, Spoor 2#define SBBRSP2 5 // BlackBox Rechts, Spoor 2#define DELAY 500 // Vertraging in milli seconde#define NUMSPOREN 2 // Aantal sporen#include "Spoor.h"Spoor sporen[NUMSPOREN];// Initialialatie van de Arduinovoid setup() { // put your setup code here, to run once: // Define sporen sporen[0] = Spoor(SBBLSP1, SBBRSP1, DELAY); // Spoor 1 sporen[1] = Spoor(SBBLSP2, SBBRSP2, DELAY); // Spoor 2 // LED uit pinMode(LED_BUILTIN, OUTPUT); digitalWrite(LED_BUILTIN, LOW);}void loop() { // put your main code here, to run repeatedly: bool bezet = false; for(int i = 0; i < NUMSPOREN; i++) { bezet |= sporen[i].calcBezet(); } // Aansturen van de AKI / AHOB (overweg) if (bezet) { // Overweg gesloten digitalWrite(LED_BUILTIN, HIGH); } else { // Overweg geopend digitalWrite(LED_BUILTIN, LOW); }}
#ifndef Spoor_h#define Spoor_h#include "Arduino.h"class Spoor {public: Spoor(); // for array Spoor(byte sensorLinks, byte sensorRechts, int sensorDelay); bool calcBezet();private: bool readLinks(); bool readRechts(); byte _sensorLinks; byte _sensorRechts; bool _memLinks; bool _memRechts; unsigned long _timerLinks; unsigned long _timerRechts;// < 0: trein rijdt van rechts naar links// 0: geen trein// > 0: trein rijdt van links naar rechts byte _dir; int _sensorDelay;};#endif
#include "Spoor.h"Spoor::Spoor() { // Empty constructor, don't use (for array)}Spoor::Spoor(byte sensorLinks, byte sensorRechts, int sensorDelay) { // Variabelen met externe waardes _sensorLinks = sensorLinks; _sensorRechts = sensorRechts; _sensorDelay = sensorDelay; // Maak de inputs met extra pullups pinMode(_sensorLinks, INPUT_PULLUP); pinMode(_sensorRechts, INPUT_PULLUP); // Voorzie overige variabelen van een default value _timerLinks = millis(); _timerRechts = millis(); _memLinks = readLinks(); _memRechts = readRechts(); _dir = 0;}bool Spoor::readLinks() { // if (digitalRead(_sensorLinks) > 0) { if (digitalRead(_sensorLinks) == 0) { _timerLinks = millis() + _sensorDelay; } return (_timerLinks > millis());}bool Spoor::readRechts() { // if (digitalRead(_sensorRechts) > 0) { if (digitalRead(_sensorRechts) == 0) { _timerRechts = millis() + _sensorDelay; } return (_timerRechts > millis());}// return true als bezetbool Spoor::calcBezet() { // fase: toestand nu en de vorige keer van de melder // volgorde: // 0: geen trein // 1: voorkant trein // 2: achterkant trein // 3: trein aanwezig byte fase; // Links fase = (_memLinks ? 2 : 0); _memLinks = readLinks(); fase += (_memLinks ? 1 : 0); if (fase == 1) { // Trein komt binnen if (_dir == 0) { // Bij het bereiken van de andere kant alleen reageren op het verlaten _dir++; } } if (fase == 2) { // Trein verlaat if (_dir < 0) { // Bij het verlaten van de binnen melder niet een extra puls geven. _dir++; } } // Rechts fase = (_memRechts ? 2 : 0); _memRechts = readRechts(); fase += (_memRechts ? 1 : 0); if (fase == 1) { // Trein komt binnen if (_dir == 0) { // Bij het bereiken van de andere kant alleen reageren op het verlaten _dir--; } } if (fase == 2) { // Trein verlaat if (_dir > 0) { // Bij het verlaten van de binnen melder niet een extra puls geven. _dir--; } } return (_dir != 0);}
Ik heb een kleine opmerking over de code van Gerard. Ik zie dat hij de sensor pins initialiseer met INPUT_PULLUP, ik denk dat dat niet goed gaat werken, omdat deze bordjes zelf een goede 5v of een goede gnd maken. Ik initialiseer de pinnen dus met INPUT. Verder als de IR receiver geen IR ziet, dan zet hij het signaal hoog (5v), op het moment dat hij IR ziet, gaat het signaal naar low (0v). Dat betekend dat als de detector gemodificeerd wordt om als lichtsluis te werken, een HIGH signaal betekend dat de IR is onderbroken en een LOW signaal betekend dat IR niet onderbroken is.Tenminste dat is de situatie met de benadering detectors die ik heb van het merk "Flying fish", die het zelfde zijn als die Edsko heeft aangeschaft.
Toch vraag ik me af of je met twee sluizen over 2 of meer sporen, niet beter af bent dan met 2 sluizen per spoor.
Even in "Grasland" gekeken voor de juiste opstelling. De overweg bevind zich links op de module. Dus er is een ongelijke tijd voor het aanrijden van de AKI. Is in dit geval niet storend, daar de korte aanrijtijd door de BBL (blackbox links) gecamoufleerd wordt. De rode lijnen zijn de 4 sensoren voor de AKI aansturing.