Positive/Negative Flanke von Eingang auswerten

Hallo liebe Forenmitglieder,

Bin grad dabei, eine Tür und eine Klappe auszuwerten mit einem NodeMcu Board!

Türkontakt (Reed) 1=geschlossen 0=offen Klappe (auch Reed) 1=geschlossen 0=offen (ja ich weiß andersrum wär schlauer weil weniger Stromverbrauch, hab aber keinen NC Reed Kontakt)

Nun will ich bei den zwei Eingängen Klappe(Pin D5, GPIO 14) und Tuer(Pin D4, GPIO 02) die postive und negative Flanke auswerten und einmal beim Flankenwechsel eine Nachricht senden!

Hier mein bisheriger Code:

int Klappe_pin = 14;
int Tuer_pin = 2;

boolean LockLow_Klappe = true;
boolean TakeLowTime_Klappe; 
long unsigned int LowIn_Klappe;

boolean LockLow_Tuer = true;
boolean TakeLowTime_Tuer; 
long unsigned int LowIn_Tuer;

long unsigned int pause = 100;      //der Pin muss mindestens ...ms aktiv sein um erkannt zu werden 

void loop() {
  if(digitalRead(Klappe_pin) == HIGH) {
    if(LockLow_Klappe) {  
      LockLow_Klappe = false;            
      client.publish(outTopicKlappe, "ist geschlossen!");  
      Serial.println("Klappe ist geschlossen!");
      delay(50);
    }         
    TakeLowTime_Klappe = true;
  }
  if(digitalRead(Klappe_pin) == LOW) {       
    if(TakeLowTime_Klappe) {
      LowIn_Klappe = millis();
      TakeLowTime_Klappe = false;
    }
    if(!LockLow_Klappe && millis() - LowIn_Klappe > pause) {  
      LockLow_Klappe = true;                        
      client.publish(outTopicKlappe, "ist offen!");
      Serial.println("Klappe ist offen!");
      delay(50);
    }
  }

  //********************

  if(digitalRead(Tuer_pin) == HIGH) {
    if(LockLow_Tuer) {  
      LockLow_Tuer = false;            
      client.publish(outTopicTuer, "geschlossen");  
      Serial.println("Große Tür ist zu");
      delay(50);
    }         
    TakeLowTime_Tuer = true;
  }
  if(digitalRead(Tuer_pin) == LOW) {       
    if(TakeLowTime_Tuer) {
      LowIn_Tuer = millis(); 
      TakeLowTime_Tuer = false;
    }
    if(!LockLow_Tuer && millis() - LowIn_Tuer > pause) {  
      LockLow_Tuer = true;                        
      client.publish(outTopicTuer, "offen");
      Serial.println("Große Tür ist offen");
      delay(50);
    }
  }
}

Der Kontakt mit der Klappe funktioniert einwandfrei! Der Tuer-Pin auch, außer der Klappe-Pin ist LOW, dann bekomm ich abwechselnd sehr schnell hintereinander Meldungen mit "offen" und "geschlossen"

Wo liegt mein Fehler?

Danke schonmal für die Hilfe!

Wo liegt mein Fehler?

Kontaktprellen ? Werden wohl mechanische Kontakte sein...

Am einfachsten ohne Interrupt arbeiten und nach einem ersten Flankenwechsel einige wenige Millisekunden nichts tun ( zumindest die Kontakte ignorieren ).

Ne sind Reed Kontakte: Magnet + "Magnetschalter"

theo416: Wo liegt mein Fehler?

Klingt für mich ebenfalls nach Prellen. Warte einfach kurz und frag den Status dann nochmal ab. Nimm den Zustand erst dann als sicher an, wenn er bei der zweiten Messung gleich ausfällt.

Gruß

Gregor

theo416: Ne sind Reed Kontakte: Magnet + "Magnetschalter"

Reed Kontakte sind "mechanische" Kontakte und prellen.

theo416:
Ne sind Reed Kontakte: Magnet + “Magnetschalter”

Also „ja“ :slight_smile: Der Magnetschalter ist Mechanik und Mechanik prellt eigentlich immer. Mir ist zumindest noch keine Ausnahme begegnet.

Gruß

Gregor

PS: Wenn Du etwas Nicht-Prellendes suchst, nimm einen Hall-Sensor

Durch deine "Flankenauswertung" steige ich nicht durch. Das sieht einfach zu verwuselt aus.

Du musst dir den aktuellen Zustand des Kontaktes merken und wenn dieser sich ändert darauf reagieren.

War er zuvor HIGH, ist es eine LOW-Flanke, war er zuvor LOW ist es eine HIG-Flanke.

Und das geht alles ohne IRQ, wie michael_x schon schreibt.

Ah oke! gut zu wissen, Lichtschranken/taster, ... sind dann optische

Es sollte hald nur sicher eine Flanke die mindestens 100ms lang gleich ist ein Auslöser sein

Wenn ich jez mach: Abfragen, warten, nochmal abfragen könnte es ja sein dass ich genau meinen Störimpuls erwische und mein Ergebniss ist wieder falsch und hab ne Pause im Programm!

theo416: Ah oke! gut zu wissen, Lichtschranken/taster, ... sind dann optische

Nee, Taster sind allgemein nicht optisch.

Ein Lichttaster ist doch optisch oder nicht?

Es sollte hald nur sicher eine Flanke die mindestens 100ms lang gleich ist ein Auslöser sein

Eine Flanke ist nicht "Lang" und schon gar nicht "lange gleich". Zumindest nicht in der Digitaltechnik, da ist sie senkrecht.

Die Lichttaster bei uns im Treppenhaus sind rein mechanisch.

theo416: Ein Lichttaster ist doch optisch oder nicht?

Kommt drauf an was du damit meinst.

Genaue Erklärung ist hier nötig.

Edit: combie hat dir die Antwort geschrieben.

Wenn du nur Prellen hast (aber keine Falschen Ereignisse), also mit ordentlichem Pullup oder Pulldown - Widerstand, und dein Signal HIGH war, sollte es in jedem Fall nach dem ersten Zucken nach kurzer Zeit (2 .. 5 ms) auf LOW sein.

Liegt also an dir, ob du überhaupt zweimal prüfst, und wenn, ob du gleich den ersten oder erst den zweiten Zustand nimmst.

Wenn relativ kurze echte Pulse (20 .. 80ms) vorkommen können, aber ignoriert werden sollen, hat das mit Prellen nichts zu tun und da musst du zusätzlich was machen.

Auch auch da erschweren dir Interrupts aber das Leben ungemein.

combie: Die Lichttaster bei uns im Treppenhaus sind rein mechanisch.

Also unbeleuchtet :-)

SCNR

Gregor

Wenn relativ kurze echte Pulse (20 … 80ms) vorkommen können, aber ignoriert werden sollen, hat das mit Prellen nichts zu tun und da musst du zusätzlich was machen.

Kann man in einem Aufwasch erschlagen.

Hier wieder mit meiner speziellen “Combie Zuweisung” :smiling_imp:

#include <CombieTimer.h>
#include <CombieTools.h>

using FE = Combie::Tools::FlankenErkennung;
using EP = Combie::Timer::EntprellTimer;

const byte aPin = 2;
const byte bPin = 4;

FE afep; // a positive Flanke
FE afen; // a negative Flanke
FE bfep; // b positive Flanke
FE bfen; // b negative Flanke

EP aep(100); // a entprellen 
EP bep(100); // b entprellen 

void setup() 
{
  Serial.begin(9600);
  Serial.println("Start");
  pinMode(aPin,INPUT_PULLUP);
  pinMode(bPin,INPUT_PULLUP);
}

void loop() 
{
  bool aEntprellt = aep = digitalRead(aPin); 
  bool bEntprellt = bep = digitalRead(bPin); 

  if(afep =  aEntprellt) Serial.println("Positive Flanke an A erkannt");
  if(afen = !aEntprellt) Serial.println("Negative Flanke an A erkannt");
  if(bfep =  bEntprellt) Serial.println("Positive Flanke an B erkannt");
  if(bfen = !bEntprellt) Serial.println("Negative Flanke an B erkannt");
}

CombieLib.zip (31.3 KB)

theo416: Es sollte hald nur sicher eine Flanke die mindestens 100ms lang gleich ist ein Auslöser sein

Für Reed-Kontakte finde ich 100 ms etwas lang, 30 ms sollten reichen. Kannst Du aber bei Bedarf ändern.

Getestet mit UNO (andere Pins):

const byte Klappe_pin = 3;
const byte Tuer_pin = 2;

boolean aktKlappe, altKlappe, aktTuer, altTuer;
const uint32_t prellIntervall = 30;
uint32_t aktMillis, prellMillis;

void setup() {
  Serial.begin(9600);
  Serial.println("Anfang");
  pinMode(Klappe_pin, INPUT_PULLUP);
  pinMode(Tuer_pin, INPUT_PULLUP);
}

void loop() {
  aktMillis = millis();
  altKlappe = aktKlappe;
  altTuer = aktTuer;
  if (aktMillis - prellMillis >= prellIntervall)
  {
    prellMillis = aktMillis;
    aktKlappe = digitalRead(Klappe_pin);
    aktTuer = digitalRead(Tuer_pin);
  }

  if (altKlappe != aktKlappe) {
    if (aktKlappe) {
      Serial.println("Klappe ist geschlossen!");
    }
    else
    {
      Serial.println("Klappe ist offen!");
    }
  }

  if (altTuer != aktTuer) {
    if (aktTuer) {
      Serial.println("Tuer ist geschlossen!");
    }
    else
    {
      Serial.println("Tuer ist offen!");
    }
  }
}

So bin wieder da!

Mit Lichttaster meinte ich einen "Industrielichttaster" (optische Erkennung eines Gegenstands). Hab ich nicht genau genug geschrieben.

Der Reed Kontakt wird mit 10K(weil meistens 1 Signal=weniger mA Verbrauch, ansonsten 1K) auf GND gezogen!

Danke an combie und agmue für die Codes! Bei beiden Codes muss ich in meinem Fall(weil 10K auf GND) bei pinMode INPUT_PULLUP weglassen richtig? Ich werde morgen gleich mal beide Codes ausprobieren und euch dann berichten!

theo416:
Bei beiden Codes muss ich in meinem Fall(weil 10K auf GND) bei pinMode INPUT_PULLUP weglassen richtig?

“PULLUP” weglassen, ja, also nur “INPUT”.

So habs jez mal getestet,

Hab jez den Code von agmue im Einsatz und er funktioniert perfekt! Danke!

Beim Code+Lib von combie hab ich aber noch eine frage! Und zwar irritieren mich die Zeilen:

const byte aPin = 2;
const byte bPin = 4;

FE afep; // a positive Flanke
FE afen; // a negative Flanke
FE bfep; // b positive Flanke
FE bfen; // b negative Flanke

EP aep(100); // a entprellen
EP bep(100); // b entprellen

die beiden Pins heißen ja aPin und bPin, und in den Zeilen darunter finde ich nurnoch die Buchstaben a und b?! muss der Pin zwingend aPin, bPin, cPin, ... heißen oder wie müsste ich die Zeilen ändern damit ich den Pin z.B. Klappe_pin nennen kann?

Hier sind die drei Zeilen, wo aPin verwendet wird. Diese müsstest du beim Umtaufen anpassen.

const byte aPin = 2;

//---

pinMode(aPin,INPUT_PULLUP);

// ---

bool aEntprellt = aep = digitalRead(aPin);

Die anderen a und b dienen nur dazu, damit Mensch es leichter zuordnen kann. Genau wie die p und n für positiv und negativ.

Du kannst auch die anderen Kürzel umtaufen. Es gelten die üblichen C++ Regeln. In dem Punkt backe ich keine Extrawürste