Gleisbesetztanzeige mit SHF309FA und SHF409

April 2020. Neue Komponenten, neues Projekt. In meiner Elektronikkiste habe ich glücklicherweise 2 Paar SHF309FA und SHF409 (IR Diode und Transistor) gefunden. Also was hält uns noch davon ab, damit eine Schaltung aufzubauen und zu testen, wie die Gleisbesetztmeldung mit diesen Komponenten funktioniert?

Nichts hält uns auf. Naja, fast nichts. Bis auf die fehlenden Werte für die Durchlaßströme der Dioden. Doch die sind ja gschwind im Internet recherchiert:

 

SHF409

UFtyp=1,3V, UFmax=5V, IFmax=100mA

 

SHF309FA

Ucemax=35V, Icmax=15mA

Das heißt für einen sicheren Betrieb nehme ich einen Vorwiderstand von 150 Ohm für die SHF409 und 2k2 für die SHF309FA, da sind wir im unteren Viertel (IF gemessen = 21mA bei der SHF409) für die Maximalwerte, also im hellgrünen Bereich.

 

Pinbelegung SHF309FA

Achtung, der SHF309FA ist ein Fototransistor, der lange Haxen ist in dem Fall der Kollektor, der Kurze der Emitter, d.h. im Gegensatz zur IR  LED SHF409 wird der kurze Haxen (Emitter) über den 2k2 Widerstand gegen Masse geschaltet.

 

 

Schaltung

 

 

 

 

Code

/*
  IR track occupancy detector - for track occupied signal for a mmodel railway
  
  provided from www.kraweuschuasta.at without any warranty or license 2020
  for personal use only

  Array based for more IR+Indicator pairs, LOW Signal = Active
  called "Sensor set" = 1x IR Receiver, 1x IR Sender, ix red LED, 1x green LED
  One Set per Track necessary (1x Analogue Input, 2x Digital Output, Sender is not connected to Arduino)
  
  Schematic (example with 2 Sensors for 2 Tracks) ========================
  SENDER
  VCC----120R----SFH409(grey)--- GND
  
  VCC----120R----SFH409(grey)--- GND


  RECEIVER (Analog input!)
  VCC----SHF309FA(black)---2k2-----GND
                     |
                     Arduino (A1)
                     
  VCC----SHF309FA(black)---2k2-----GND
                     |
                     Arduino (A3)


  INDICATOR LED
  VCC----1k----red LED-------(Arduino (2)
  VCC----1k----green LED-----(Arduino (3)

  VCC----1k----red LED-------(Arduino (4)
  VCC----1k----green LED-----(Arduino (5)
  Schematic End ===========================================================
  
*/
// ================ INIT section starts here ==========================
byte Red_Led[] = {2, 4};                           //Red indicator LEDs
byte GreenLed[] = {3, 5};                          //Green indicator LEDs
byte IR_IN_Pin[] = {A1, A3};                       //IR LED SFH309FA ANALOGUE input !!!         
int Indicator_interval[] = {1000, 1000};           //interval in milliseconds that indicator LEDs are on (can be set for each Sensor Set red/green)
long lngserial_display_interval = 500;             //interval in milliseconds for Serial Monitor output (parametizing and debugging only)
// ================ INIT section END ==================================
byte i;                                                           //Counter variable, internal
byte avg_counter;                                                 //Counter variable for average value check, internal
int intIRtotal, intIRaverage  = 0;                                //sum for average calculation for triggervalue, internal
int IR_Invalue[(sizeof(IR_IN_Pin) / sizeof(IR_IN_Pin[0]))];       //Array for Sensor values
long lastmillis4serialprintln;                                    //variable to keep timestamp for Serial monitor (delay() replacement)
long LastMillis[(sizeof(IR_IN_Pin) / sizeof(IR_IN_Pin[0]))];      //Array to keep timestamp for indicator duration (delay() replacement)
int Triggervalue[(sizeof(IR_IN_Pin) / sizeof(IR_IN_Pin[0]))];     //below this value means that IR signal is blocked, above value means nothing is between sender and receiver
void setup() {
  Serial.begin(9600);
  Serial.println("Arr_Size = " + String((sizeof(IR_IN_Pin) / sizeof(IR_IN_Pin[0]))));
  Serial.println("Setup started.");

  for (byte i = 0; i < (sizeof(IR_IN_Pin) / sizeof(IR_IN_Pin[0])); i++) { //Loop for declaring & testing indicator LEDs, every Sensor-Indicator 
                                                                          //led is switched on for approx. 300ms
    pinMode(Red_Led[i], OUTPUT);
    pinMode(GreenLed[i], OUTPUT);
    pinMode(IR_IN_Pin[i], INPUT);
    digitalWrite(Red_Led[i], LOW);
    digitalWrite(GreenLed[i], LOW);
    Serial.println("LED Test started for Led " + String(i));
    delay (300);
  }

  for (byte i = 0; i < (sizeof(IR_IN_Pin) / sizeof(IR_IN_Pin[0])); i++) {

    digitalWrite(Red_Led[i], HIGH);
    digitalWrite(GreenLed[i], HIGH);

    intIRtotal = 0;                                                                     // get average value for LDR  (100 iterations)
    for (avg_counter = 0; avg_counter <= 100; avg_counter++)  {
      IR_Invalue[i] = analogRead(IR_IN_Pin[i]);
      intIRtotal = intIRtotal + IR_Invalue[i];
      intIRaverage = (intIRtotal / avg_counter);
    }
    Serial.println("average for Sensor " + String(i) + "  " + String(intIRaverage));
    intIRaverage = intIRaverage - 10;                                                 // set Trigger value = average - 10
    Serial.println("Threshold for Sensor " + String(i) + " set to " + String(intIRaverage));

    Triggervalue[i] = intIRaverage;


    LastMillis[i] = millis();
  }

  Serial.println("Setup done.");
}

void loop() {

  if (lastmillis4serialprintln > millis() ) {                                     // if millis() is restarted - re-set last timestamp memory.
    lastmillis4serialprintln = millis();
    for (byte i = 0; i < (sizeof(IR_IN_Pin) / sizeof(IR_IN_Pin[0])); i++) {
      LastMillis[i] = millis();
    }
  }

  for (byte i = 0; i < (sizeof(IR_IN_Pin) / sizeof(IR_IN_Pin[0])); i++) { 

    IR_Invalue[i] = analogRead(IR_IN_Pin[i]);                                     // read values from Sensor into Array

    if (millis() - lastmillis4serialprintln >= lngserial_display_interval) {      // check duration and write Value to Serial Monitor
      Serial.println("IR " + String(i) + " Value: " + String(IR_Invalue[i]));
      lastmillis4serialprintln = millis();                                        // re-set last timestamp memory 
    }


    if (IR_Invalue[i] < Triggervalue[i] ) {                                       // IR_Led is triggered?
      Serial.println("Triggered -- Sensor " + String(i));
      digitalWrite(Red_Led[i], LOW);                                              //  Indicator RedLeds are switched on
      digitalWrite(GreenLed[i], HIGH);                                            //  Indicator GreenLeds are switched off

    } else {                                                                      //if not (no Train on Track) 
      if ((LastMillis[i] + Indicator_interval[i]) <= (millis())) {
        digitalWrite(Red_Led[i], HIGH);                                           //  Indicator RedLeds are switched off
        digitalWrite(GreenLed[i], LOW);                                           //  Indicator GreenLeds are switched on
        LastMillis[i] = millis();                                                 // re-set last timestamp memory 
      }
    }
  }
}

Einrichtung per Autokalibration

Nachdem die Autokalibrierfunktion ganz gut funktioniert, habe ich sie auch in den Infrarotlichtschranken Sketch reingebastelt.

Mit der genialen Erweiterung der Autokalibrier- Funktion wird in der Setup Routine  einfach der aktuelle IR- Seinsorwert gemessen und als Referenz- bzw. Schwellwert herangezogen.

Falls alle Strick reißen, werden Autokalibrierwert, Schwellwert und gemessene Werte im Serial Monitor ausgegeben.

 

Erweiterung Easy Cheesy

Falls ma mehr als 2 IR Sender-Empfänger Pärchen (plus AnzeigeLEDs) verwenden möchte, ist das supergenialeinfach zu erweitern, ma fummelt die Dioden einfach in die Schaltung dazu, und trägt sie in die zugehörigen Arrays ein.

Neu kompiliert, in den Arduino geschossen und Fertig.

 

Und so schauts aufgebaut aus:

 

 

kaputt?

Ups - plötzlich geht am späten Vormittag nichts mehr. Der Sensor reagiert nicht, alles bleibt grün. Hä?

Aber nein, das Steckbrett mit den Sensoren ist in direktem Sonnenlicht gelegen - das hat natürlich IR Anteil. Nachdem ich Alles aus dem direkten Sonnenlicht entfernt habe, war wieder alles gut und hat funktioniert.

 

Das Arduino Modell ist relativ blunzn, ich hab einen Nano genommen, aber auch Uno und dergleichen sind ok. Für eine Betriebsspannung von 3,3V (z.B. Due) müßt ma halt die Vorwiderstände der AnzeigeLEDs und unter Umständen für die IR Transistoren anpassen,

 

Reichweite

Ich hab ein bissl mit der Reichweite der IR Lichtschranke herumgespielt, 32cm sind kein Problem. Im Zweifelsfall bitte testen, geht ja einfach, neue Position wählen und Arduino resetten. Die entsprechenden Werte werden wieder über den Serial Monitor ausgegeben.

 

Fazit

Eigentlich eine ganz gute Lösung.

Vorteile: einfache Schaltung, kostengünstige Komponenten (je eine IR LED und ein Widerstand) , sicherer Betrieb, einfaches Einrichten.

Nachteile: empfindlich gegen direktes Sonnenlicht, es ist je Sensor ein Sender bzw. Empfänger notwendig, bei Änderung des Raumlichtes ist u.U. ein Reset des Arduinos nötig.

 

zurück zur Eisenbahnelektronik