Unterscheidung Dauer- und Rechtecksignal

Servus Forum.

Ich möchte an einem digitalen Eingang unterscheiden, ob das Signal einer Ampel dauerhaft an ist oder blinkt.

Mit folgendem Sketch hab ich bereits versucht, eine Ausschaltverzögerung zu realisieren.
Damit halte ich die LED an Pin 12 am Leuchten, wenn innerhalb von immer 2 Sekunden ein Impuls auf Pin 13 ankommt.

Halte ich aber den Simulationstaster an PIN 13 gedrückt, kommt ja dann alle 0,2 Sekunden ein Impuls.

Der gewünschte Zustand wäre, dass die LED an PIN 12 nur leuchtet, wenn am PIN 13 ein Rechtecksignal anliegt.
Wenn PIN 13 auf dauer-HIGH ist, soll nur LED an PIN 11 leuchten.

Könnt ihr mir da bitte auf die Sprünge helfen?

const int ledPin = 12; // Soll leuchten, wenn Eingang blinkt
const int leddau = 11; // Soll leuchten, wenn Eingang DAUER-an ist
const int button = 13; // Simulationstaster

int counta = 0;
long myTimer = 0;
long myTimeout = 2000;

void setup() {
  pinMode(ledPin, OUTPUT);
  pinMode(leddau, OUTPUT);
  pinMode(button, INPUT);
  Serial.begin(115200);
}

void loop() {
  if (digitalRead(button) == true) {
    counta ++;
    Serial.println(counta);
    delay(200);
    myTimer = millis();
  }

  if (millis() > myTimeout + myTimer) {
    myTimer = millis();
    counta = 0;
    Serial.println("counta reset");
  }

  if (counta >= 2) {
    digitalWrite(ledPin, HIGH);
   }
  else {
    digitalWrite(ledPin, LOW);
   }
}

Hallo lebon1089

Herzlich Willkommen im weltbesten Arduino Forum.

Schaue mal ob dir das in deinem Projekt weiterhilft:

Ich wünsche einen geschmeidigen Tag und viel Spass beim Programmieren in C++.

Schau Dir das StateChangeDetection Beispiel in der IDE an.

Du möchtest ein retriggerbares Monoflop implementieren, falls Dir das bei der Suche weiterhilft.

Richtig wäre
if (millis() - myTimer > myTimeout) {
sonst bekommst Du Probleme mit Überäufen.
Diese Abfrage muß noch irgendwie mit dem Button in Verbindung gebracht werden.

retriggerbares Monoflop, genau!
So hab ich's in der Siemens LOGO implementiert.
Jedoch bekomm ich aus der LOGO kein MQTT raus, daher muss die Sache in einen Arduino rein.

Ich schau mir die Sache mit StateChangeDetection mal an!

Pin 13 am UNO ist unglücklich, ist an der eingebauten LED angeschlossen, daher habe ich die Pins anders belegt. Außerdem nutze ich den eingebauten PullUp-Widerstand, weshalb der Taster nach GND schalten muß. Zeiten sind unsigned long und das Intervall ist konstant.

const uint8_t ledBlinkt = 13; // Soll leuchten, wenn Eingang blinkt
const uint8_t ledDauer = 12;  // Soll leuchten, wenn Eingang DAUER-an ist
const uint8_t taster = 11;    // Simulationstaster

uint32_t myTimer = 0;
const uint32_t myTimeout = 2000;
bool blinkt = false;

void setup() {
  pinMode(ledBlinkt, OUTPUT);
  pinMode(ledDauer, OUTPUT);
  pinMode(taster, INPUT_PULLUP);  // Taster schaltet nach GND
}

void loop() {
  if ( !digitalRead(taster) ) {
    myTimer = millis();
    blinkt = true;
  }

  if (millis() - myTimer >= myTimeout) {
    blinkt = false;
  }

  digitalWrite(ledBlinkt, blinkt);
  digitalWrite(ledDauer, !blinkt);
}

Sehr durchsichtig :slight_smile:

Mich stört nur etwas, daß blinkt auch dann True ist, wenn Dein Taster ständig gedrückt bleibt. Aber wenn das der Aufgabenstellung genügt...

Da der Taster kein Taster ist, sondern ein "Signal", wäre das zu ergründen. Aber dazu kann sich der TO ja zu äußern :slightly_smiling_face:

Die Änderung zu erfassen, ist natürlich auch möglich:

const uint8_t ledBlinkt = 13; // Soll leuchten, wenn Eingang blinkt
const uint8_t ledDauer = 12;  // Soll leuchten, wenn Eingang DAUER-an ist
const uint8_t taster = 11;    // Simulationstaster

uint32_t myTimer = 0;
const uint32_t myTimeout = 2000;
bool tasterStatusAlt, tasterStatusAkt, blinkt = false;

void setup() {
  pinMode(ledBlinkt, OUTPUT);
  pinMode(ledDauer, OUTPUT);
  pinMode(taster, INPUT_PULLUP);  // Taster schaltet nach GND
  tasterStatusAkt = digitalRead(taster);
  tasterStatusAlt = tasterStatusAkt;
}

void loop() {
  tasterStatusAkt = digitalRead(taster);
  if ( tasterStatusAlt != tasterStatusAkt ) 
  {
    tasterStatusAlt = tasterStatusAkt;
    myTimer = millis();
    blinkt = true;
  }

  if (millis() - myTimer >= myTimeout) {
    blinkt = false;
  }

  digitalWrite(ledBlinkt, blinkt);
  digitalWrite(ledDauer, !blinkt);
}
#include <CombieTimer.h>
#include <CombiePin.h>
#include <CombieTypeMangling.h>

using namespace Combie::Millis;


Combie::Pin::InvInputPin<2>     button; // taster gegen GND
Combie::Pin::OutputPin<13>      ledDauer;
Combie::Pin::OutputPin<12>      ledBlinkt;
Combie::Timer::RisingEdgeTimer  ton {2_Sekunden};  // steigende Flanke wird verzoegert


void setup() 
{

 button.initPullup();
 ledBlinkt.init();
 ledDauer.init();
}

void loop() 
{
 ledBlinkt = !(ledDauer = ton = button);
}

Erst wenn der Button am Pin 2 2sec gedrückt wird leuchtet die LED an Pin 13.
Sonst die LED an Pin 12

Der gewünschte Zustand wäre, dass die LED an PIN 12 nur leuchtet, wenn am PIN 13 ein Rechtecksignal anliegt.
Wenn PIN 13 auf dauer-HIGH ist, soll nur LED an PIN 11 leuchten.

Habe mal unter den o.a. Anforderungen einen Sketch geschrieben:

/*
  Forum: https://forum.arduino.cc/t/unterscheidung-dauer-und-rechtecksignal/1157204
  Wokwi: https://wokwi.com/projects/373346939661441025

*/

constexpr int ledPin = 12; // Soll leuchten, wenn Eingang blinkt
constexpr int leddau = 11; // Soll leuchten, wenn Eingang DAUER-an ist
constexpr int button = 13; // Simulationstaster
constexpr int signalOut = 8;  //

int mode = 0;
bool doReset = true;

void setup() {
  pinMode(ledPin, OUTPUT);
  pinMode(leddau, OUTPUT);
  pinMode(button, INPUT_PULLUP);
  pinMode(signalOut, OUTPUT);
  Serial.begin(115200);
  Serial.println("Eingabe: ");
  Serial.println("0 für LOW Signal  an Pin 13 ");
  Serial.println("1 für HIGH Signal an Pin 13 ");
  Serial.println("2 für Rechteck    an Pin 13 ");

}

void loop() {
  handleSerial();
  createSignal();
  if (signalIstRechteck(400)) {
    rechteckErkannt();
  } else {
    keinRechteckErkannt();
  }
}

void handleSerial(){
  if (Serial.available()) {
    char c = Serial.read();
    switch (c) {
      case '0' : mode = 0;
                 doReset = true;
        break;
      case '1' : mode = 1;
                 doReset = true;
        break;
      case '2' : mode = 2;
                 doReset = true;
        break;
    }
  }
}

void createSignal(){
  switch (mode) {
    case 0 : digitalWrite(signalOut, LOW);
      break;
    case 1 : digitalWrite(signalOut, HIGH);
      break;
    case 2 : signalRechteck(400);
      break;
  }

}

void rechteckErkannt() {
  digitalWrite(ledPin, HIGH);
  digitalWrite(leddau, LOW);
}

void keinRechteckErkannt() {
  digitalWrite(ledPin, LOW);
  byte buttonState = digitalRead(button);
  digitalWrite(leddau, buttonState);
}

//  Erzeugt Rechtecksignale, die interval [ms] Periodendauer aufweisen
void signalRechteck(unsigned long interval) {
  static unsigned long lastChange;
  if (millis() - lastChange >= interval) {
    lastChange = millis();
    byte sig = digitalRead(signalOut);
    digitalWrite(signalOut, !sig);
  }
}

// Erkennt Rechtecksignale, die maximal Dauer [ms] Periodendauer aufweisen
boolean signalIstRechteck(unsigned long Dauer) {
  static unsigned long lastSignalChange;
  static byte lastValue;
  boolean static istRechteck = false;
  unsigned long diff;
  byte actValue = digitalRead(button);
  if (doReset) {
    doReset = false;
    lastValue = actValue;
    istRechteck = false;
  }
  if (actValue != lastValue) {
    diff = millis() - lastSignalChange;
    lastSignalChange = millis();
    lastValue = actValue;
    if (diff <= Dauer) {
      istRechteck = true;
    } else {
      istRechteck = false;
    }
  }
  return istRechteck;
}

image

Zum Ausprobieren: https://wokwi.com/projects/373346939661441025

Die Funktion void signalRechteck(unsigned long interval) erzeugt ein simples Rechtecksignal auf Pin 8, das auf Pin 13 durchgeschleift wird und eine Periodendauer von interval ms hat.

Der Zustand des Signals wird von der blauen Led angezeigt.
Die rote Led entspricht "Rechteck erkannt".
Die grüne Led leuchtet, wenn kein Rechteck erkannt, das Signal aber auf HIGH ist.

Beim Umschalten auf Rechteck leuchtet die grüne Led zunächst auf, bis das Rechteck-Signal erkannt wird.

Zwischen Signal LOW, Signal HIGH und Signal Rechteck lässt sich per serieller Eingabe von 0,1 oder 2 im Betrieb umschalten.

Die Funktion boolean signalIstRechteck(unsigned long Dauer) liest den Pin button aus und prüft bei einem Wechsel des Pegels, ob die Zeit kürzer oder gleich der Dauer [ms] war. Der Wert "Dauer" erlaubt das Eingeben einer maximal gewünschten Rechteckdauer, die noch zu einer Erkennung führen soll. Alles was dann länger dauert, wird nicht mehr als Rechteckfunktion bewertet.

Viel Erfolg!

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.