Aangespoord door de opmerking van NS264 toch maar de code herzien naar objecten. Ik werk graag met de classes in aparte files dus in mijn geval spat de sketch uiteen in drie files, de sketch en 2 ander files voor een class.In tegen stelling tot wat Meino in zijn code alvast heeft gedaan, heb ik nog niet de AKI knipper-lichten van aansturing voorzien. Dit komt wel als dit door Edsko wat duidelijker gedefinieerd is.Hieronder de nieuwe sketch:Code: [Selecteer]// 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); }}En in dezelfde directory als de sketch komen de twee volgende bestanden:Filenaam Spoor.h (definitie van de class):Code: [Selecteer]#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;};#endifFilenaam Spoor.cpp (functionaliteit van de class):Code: [Selecteer]#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);}
// 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);}
if (digitalRead(_sensorLinks) == 1)
if (digitalRead(_sensorLinks) == 0)
Nu ben ik een no-no wat betreft het programmeren van deze dingen
fase = (_memLinks ? 2 : 0); _memLinks = readLinks();fase += (_memLinks ? 1 : 0);return (_dir != 0) ;
/* NOTE BASOnderstaande macro gebruik ik om dingen met een bepaald interval te maken, het gebruik staat in de code Het is ontzettend simpel om toe te passen.*/#define REPEAT_MS(x) { \ static uint32_t previousTime ;\ uint32_t currentTime = millis() ;\ if( currentTime - previousTime >= x ) {\ previousTime = currentTime ; // code to be repeated goes between these 2 macros#define END_REPEAT } \ }// Definitie van de 4 ingangen voor de sensoren (2 per spoor)#define BB_LINKS_1 2 // BlackBox Links, Spoor 1#define BB_RECHTS_1 3 // BlackBox Rechts, Spoor 1#define BB_LINKS_2 4 // BlackBox Links, Spoor 2#define BB_RECHTS_2 5 // BlackBox Rechts, Spoor 2/* NOTE BAS:SBBLSP1 etc aangepast naar BB_LINKS_1 omdat... leesbaarheidSBBLSP1 is 'mumbo jumbo' die wij mensen niet kunnen lezen, computers wel.klein detailtje ;)*/#define BLINK_TIME 500 // BAS: knipperled toegevoegd#define SENSOR_DELAY 500 // Vertraging in milli seconde/* NOTE BAS:DELAY omgegenoemd naar SENSOR_DELAYDELAY betekent eigenlijk niks, SENSOR_DELAY verschaft iets van informatie dat het met een sensor te maken heeft*/#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(BB_LINKS_1, BB_RECHTS_1, SENSOR_DELAY); // Spoor 1 sporen[1] = Spoor(BB_LINKS_2, BB_RECHTS_2, SENSOR_DELAY); // Spoor 2 // LED uit pinMode(LED_BUILTIN, OUTPUT); digitalWrite(LED_BUILTIN, LOW); Serial.begin( 9600 ) ; /* NOTE BAS: Als je dingen naar de monitor wilt printen, moet je de seriele interface eerst opzetten, en dat doe je met bovenstaande regel. Nu kan je overal Serial.print() en Serial.println() gebruiken. */ Serial.println("hello world") ;}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 /* NOTE BAS Hier gebruik ik mijn repeat macro om de led elke 'BLINK TIME' te laten knipperen Alle code tussen REPEAT_MS en END_REPEAT wordt hier elke 'BLINK_TIME' uitgevoerd. */ REPEAT_MS( BLINK_TIME ) { digitalWrite( LED_BUILTIN, !digitalRead( LED_BUILTIN ) ; /* NOTE BAS ipv HIGH of LOW, lees ik eerst uit wat de led is met digitalRead(), het resultaat inverteer ik met ! en dat wordt de nieuwe stand van de led. Dit laat de led togglen. */ } END_REPEAT } else { // Overweg geopend digitalWrite(LED_BUILTIN, LOW); // zet de led uit. }}
#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 int8_t _dir; // NOTE BAS: dit was een 'byte' en dat was een bug. _dir kan namelijk negatief worden // maar een byte is unsigned en het bereik is 0-255. Een byte kan dus niet negatief zijn // het bereik van een int8_t is -128 tot 127 Een int8_t kan wel negatief zijn int _sensorDelay;};#endif
#include "Spoor.h"enum train_states // NOTE BAS: deze enumerator toegevoegd om verderop meer leesbaarheid te krijgen.{ geenTrein = 0, // 0: geen trein voorkantTrein, // 1: voorkant trein achterkantTrein, // 2: achterkant trein treinAanwezig, // 3: trein aanwezig} ;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(); // NOTE BAS: niet aangepast maar 'readLinks' is een *** benaming omdat 'read' Engels is en 'Links' is Nederlands // de eerste 3x las ik readLinks als 'lees verbindingen', want links is verbindingen in het Engels.... _memRechts = readRechts(); _dir = 0;}bool Spoor::readLinks(){ if (digitalRead(_sensorLinks) == 1 ) // NOTE BAS, deze omgekeerd naar een 1, omdat een sensor die geen trein ziet, een hoog signaal geeft { _timerLinks = millis() + _sensorDelay; } return (_timerLinks > millis());}bool Spoor::readRechts(){ if (digitalRead(_sensorRechts) == 0) // NOTE BAS, deze omgekeerd naar een 1, omdat een sensor die geen trein ziet, een hoog signaal geeft { _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 NOTE BAS: ik heb hiervoor een enum gemaakt hier boven in. // 1: voorkant trein // 2: achterkant trein // 3: trein aanwezig byte fase; // Links /* NOTE BAS: geen regel code met de beruchte '?' of Ternary operator is ooit leesbaar geweest.. fase = (_memLinks ? 2 : 0); _memLinks = readLinks(); fase += (_memLinks ? 1 : 0); If Condition is true ? then value X : otherwise value Y bovenstaande vervangen door: */ if( _memLinks > 0 ) { fase = achterkantTrein; } else { fase = voorkantTrein; } _memLinks = readLinks(); if( _memLinks > 0 ) { fase ++ ; } if (fase == voorkantTrein) { // Trein komt binnen if (_dir == 0) // Bij het bereiken van de andere kant alleen reageren op het verlaten { _dir++; } } if (fase == achterkantTrein) { // 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( _memRechts > 0 ) { fase = achterkantTrein; } else { fase = voorkantTrein; } _memRechts = readRechts(); if( _memLinks > 0 ) { fase ++ ; } if (fase == voorkantTrein) { // Trein komt binnen if (_dir == 0) // Bij het bereiken van de andere kant alleen reageren op het verlaten { _dir--; } } if (fase == achterkantTrein) { // Trein verlaat if (_dir > 0) // Bij het verlaten van de binnen melder niet een extra puls geven. { _dir--; } } // NOTE BAS vanwege leesbaarheid heb ik deze regel vervangen door een if else statement en een return van true of false // return (_dir != 0) ; if (dir == geenTrein) return false ; else return true ;}
#define DEBUG 1enum 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) {#if (DEBUG) if (ledOn != state) { Serial.print("[SingleLed::setOn]"); if (state) Serial.println(" aan"); else Serial.println(" uit"); }#endif 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? {#if (DEBUG) Serial.println("[SingleLed::heartBeat] led aan");#endif digitalWrite(ledPin, HIGH); // No, so switch it on lightOn = true; } else {#if (DEBUG) Serial.println("[SingleLed::heartBeat] led uit");#endif digitalWrite(ledPin, LOW); // Yes, so switch it off lightOn = false; } } } else if (lightOn) // No light, but is the led still on? {#if (DEBUG) Serial.println("[SingleLed::heartBeat] led uit");#endif 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; bool phase = 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; phase = false; pinMode(led1Pin, OUTPUT); pinMode(led2Pin, OUTPUT); lastTime = millis(); } // // Set the state of the leds (true = on, false = off) // void setOn(bool state) {#if (DEBUG) if (ledOn != state) { Serial.print("[DuoLed::setOn]"); if (state) Serial.println(" aan"); else Serial.println(" uit"); }#endif 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 { lightOn = true; unsigned long currTime = millis(); if ((currTime - lastTime) >= interval) // Has the interval passed? { lastTime = currTime; // Yes, start new interval if (!phase) // The leds alternate, are we in phase1 (led1 on, led2 off) {#if (DEBUG) Serial.println("[DuoLed::heartBeat] led1 aan, led2 uit");#endif digitalWrite(led1Pin, HIGH); // Yes, led1 on digitalWrite(led2Pin, LOW); // led2 off phase = true; // When the interval expires, switch the leds } else // We are in phase2 (led1 off, led2 on) {#if (DEBUG) Serial.println("[DuoLed::heartBeat] led1 uit, led2 aan");#endif digitalWrite(led1Pin, LOW); // Led1 off digitalWrite(led2Pin, HIGH); // Led2 on phase = false; // When the interval expires, switc the leds } } } else // The leds are not active, switch of both leds { if (lightOn) {#if (DEBUG) Serial.println("[DuoLed::heartBeat] led1 uit, led2 uit");#endif 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) {#if (DEBUG) if (state != aState) { Serial.print("[AKI::set]"); if (aState == uit) Serial.println(" uit"); else Serial.println(" aan"); }#endif state = aState; if (state == uit) { redLights->setOn(false); whiteLight->setOn(true); } else { 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.//// The Flying Fish proximity detectors, when used in reflective mode, need the "laag" setting, // when their sensors are removed and positioned opposit each other, they need the "hoog" setting//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_PULLUP); } // // Create a new instance // Sensor(int aPin, SensorTrigger aType) { sensorPin = aPin; type = aType; pinMode(sensorPin, INPUT_PULLUP); } // // 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(laag) goes off");#endif state = false; // sensor goes OFF lastTime = 0; // Reset interval timer } } } } else {#if (DEBUG) if (state != true) { Serial.println("[Sensor::heartBeat] sensor(hoog) goes on"); }#endif state = true; // Sensor goes ON lastTime = 0; // Reset interval timer } } else // sensorPin = LOW { if (type == laag) {#if (DEBUG) if (state != true) { Serial.println("[Sensor::heartBeat] sensor(laag) 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(hoog) 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)); // Sensor works reflectiveSpoorControl spoor2(new Sensor(A2, hoog), new Sensor(A3, hoog));//// Create an instance of the AKI//AKI aki(new SingleLed(2, true), new DuoLed(3, 4, 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}
Ik heb de code bekeken en ik heb zowaar een waarschijnlijke bug gevonden. Er was een byte genaamd _dir. Maar _dir moest van het programma ook -1 kunnen worden. Alleen een byte variabele die kan dat niet. Ik heb hem opgelost door er een int8_t van te maken .De sensors werden volgens mij ook verkeerdom ingelezen er stondCode: [Selecteer]if (digitalRead(_sensorLinks) == 1)En daar heb ikCode: [Selecteer]if (digitalRead(_sensorLinks) == 0)van gemaakt.Dit is wel afhankelijk van hoe je de sensor aan hebt gesloten. in 9 van de 10 keer trekt een sensor oid een input pin naar de 0V toe die anders met een pull-up weerstand op 5v wordt gehouden.
Code: [Selecteer]/* NOTE BASOnderstaande macro gebruik ik om dingen met een bepaald interval te maken, het gebruik staat in de code Het is ontzettend simpel om toe te passen.*/#define REPEAT_MS(x) { \ static uint32_t previousTime ;\ uint32_t currentTime = millis() ;\ if( currentTime - previousTime >= x ) {\ previousTime = currentTime ; // code to be repeated goes between these 2 macros#define END_REPEAT } \ }// Definitie van de 4 ingangen voor de sensoren (2 per spoor)#define BB_LINKS_1 2 // BlackBox Links, Spoor 1#define BB_RECHTS_1 3 // BlackBox Rechts, Spoor 1#define BB_LINKS_2 4 // BlackBox Links, Spoor 2#define BB_RECHTS_2 5 // BlackBox Rechts, Spoor 2/* NOTE BAS:SBBLSP1 etc aangepast naar BB_LINKS_1 omdat... leesbaarheidSBBLSP1 is 'mumbo jumbo' die wij mensen niet kunnen lezen, computers wel.klein detailtje ;)*/#define BLINK_TIME 500 // BAS: knipperled toegevoegd#define SENSOR_DELAY 500 // Vertraging in milli seconde/* NOTE BAS:DELAY omgegenoemd naar SENSOR_DELAYDELAY betekent eigenlijk niks, SENSOR_DELAY verschaft iets van informatie dat het met een sensor te maken heeft*/#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(BB_LINKS_1, BB_RECHTS_1, SENSOR_DELAY); // Spoor 1 sporen[1] = Spoor(BB_LINKS_2, BB_RECHTS_2, SENSOR_DELAY); // Spoor 2 // LED uit pinMode(LED_BUILTIN, OUTPUT); digitalWrite(LED_BUILTIN, LOW); Serial.begin( 9600 ) ; /* NOTE BAS: Als je dingen naar de monitor wilt printen, moet je de seriele interface eerst opzetten, en dat doe je met bovenstaande regel. Nu kan je overal Serial.print() en Serial.println() gebruiken. */ Serial.println("hello world") ;}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 /* NOTE BAS Hier gebruik ik mijn repeat macro om de led elke 'BLINK TIME' te laten knipperen Alle code tussen REPEAT_MS en END_REPEAT wordt hier elke 'BLINK_TIME' uitgevoerd. */ REPEAT_MS( BLINK_TIME ) { digitalWrite( LED_BUILTIN, !digitalRead( LED_BUILTIN ) ; /* NOTE BAS ipv HIGH of LOW, lees ik eerst uit wat de led is met digitalRead(), het resultaat inverteer ik met ! en dat wordt de nieuwe stand van de led. Dit laat de led togglen. */ } END_REPEAT } else { // Overweg geopend digitalWrite(LED_BUILTIN, LOW); // zet de led uit. }}
Code: [Selecteer]#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 int8_t _dir; // NOTE BAS: dit was een 'byte' en dat was een bug. _dir kan namelijk negatief worden // maar een byte is unsigned en het bereik is 0-255. Een byte kan dus niet negatief zijn // het bereik van een int8_t is -128 tot 127 Een int8_t kan wel negatief zijn int _sensorDelay;};#endif
Code: [Selecteer]#include "Spoor.h"enum train_states // NOTE BAS: deze enumerator toegevoegd om verderop meer leesbaarheid te krijgen.{ geenTrein = 0, // 0: geen trein voorkantTrein, // 1: voorkant trein achterkantTrein, // 2: achterkant trein treinAanwezig, // 3: trein aanwezig} ;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(); // NOTE BAS: niet aangepast maar 'readLinks' is een *** benaming omdat 'read' Engels is en 'Links' is Nederlands // de eerste 3x las ik readLinks als 'lees verbindingen', want links is verbindingen in het Engels.... _memRechts = readRechts(); _dir = 0;}bool Spoor::readLinks(){ if (digitalRead(_sensorLinks) == 1 ) // NOTE BAS, deze omgekeerd naar een 1, omdat een sensor die geen trein ziet, een hoog signaal geeft { _timerLinks = millis() + _sensorDelay; } return (_timerLinks > millis());}bool Spoor::readRechts(){ if (digitalRead(_sensorRechts) == 0) // NOTE BAS, deze omgekeerd naar een 1, omdat een sensor die geen trein ziet, een hoog signaal geeft { _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 NOTE BAS: ik heb hiervoor een enum gemaakt hier boven in. // 1: voorkant trein // 2: achterkant trein // 3: trein aanwezig byte fase; // Links /* NOTE BAS: geen regel code met de beruchte '?' of Ternary operator is ooit leesbaar geweest.. fase = (_memLinks ? 2 : 0); _memLinks = readLinks(); fase += (_memLinks ? 1 : 0); If Condition is true ? then value X : otherwise value Y bovenstaande vervangen door: */ if( _memLinks > 0 ) { fase = achterkantTrein; } else { fase = voorkantTrein; } _memLinks = readLinks(); if( _memLinks > 0 ) { fase ++ ; } if (fase == voorkantTrein) { // Trein komt binnen if (_dir == 0) // Bij het bereiken van de andere kant alleen reageren op het verlaten { _dir++; } } if (fase == achterkantTrein) { // 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( _memRechts > 0 ) { fase = achterkantTrein; } else { fase = voorkantTrein; } _memRechts = readRechts(); if( _memLinks > 0 ) { fase ++ ; } if (fase == voorkantTrein) { // Trein komt binnen if (_dir == 0) // Bij het bereiken van de andere kant alleen reageren op het verlaten { _dir--; } } if (fase == achterkantTrein) { // Trein verlaat if (_dir > 0) // Bij het verlaten van de binnen melder niet een extra puls geven. { _dir--; } } // NOTE BAS vanwege leesbaarheid heb ik deze regel vervangen door een if else statement en een return van true of false // return (_dir != 0) ; if (dir == geenTrein) return false ; else return true ;}
Kloppen mijn aannames mbt de benaming van de files?
en zondag ben ik vast moe en lui van vrijdag en zaterdag