Nachtriggern Zeitfunktion, serielle Kommunikation

Moin zusammen,

von einem anderen Programm aus sende ich etwas über den seriellen Port.
Wenn der Arduino etwas empfängt, soll er einen Ausgang eine definierte Zeit auf High setzen.
Sollte in der "High-Zeit" ein weiterer Char ankommen, soll die Zeit wieder neu beginnen.
Hintergund:
Eine Sondersoftware hängt gelegentlich und an eine SPS soll eine Art "Hearbeat" gesendet werden.
Die Software sendet also z.B. alle 500ms einen Buchstaben, der Arduino setzt den Ausgang für 1000ms auf High. Kommt nun innerhalb der Zeit ein weiteres Telegramm, soll der Ausgang High bleiben, aber eben NUR für z.B. 1000ms.
Mein Problem ist, wenn z.B. nach 250ms ein Signal kommt, werden erst die ersten 1000ms abgearbeitet, und DANACH nochmal 1000ms.
Wenn sich nun mehrere Telegramm unbearbeitet ansammeln, werden quasi alle Zeiten aufeinander addiert, was aber nicht sein soll.
Denn in der SPS wird z.B. alle 500ms geprüft, ob der Eingang High ist, wenn er es nicht ist, soll eine Störung ausgegeben werden, und zwar zeitnah, nicht erst wenn der "Puffer" agbearbeitet ist.
Puhhh
wenn ich das so lese, kann ich nur hoffen, dass ich micht halbwegs verständlich ausgedrückt habe.
Und ich weiss, dass Delay nicht schön ist, sobald die Grundfunktion gegeben ist, werde ich es wie in "Blink without delay" umsetzen.

Anbei der Code, er ist so komplett, kein weggelassenen Teile.
Bin froh über andere Denkansätze/Lösungsvorschläge, mir gehen im Moment die Ideen aus.

Grus aus Rade
Michael


char receivedChar;
boolean newData = false;
int LED = 7;

void setup() {
    Serial.begin(9600);
    Serial.println("<Arduino is ready>");
}

void loop() {
    recvOneChar();
    showNewData();
}

void recvOneChar() {
    if (Serial.available() > 0) {
        receivedChar = Serial.read();
        newData = true;
    }
}

void showNewData() {
    if (newData == true) {
        Serial.print("This just in ... ");
        Serial.println(receivedChar);
        newData = false;
       digitalWrite(LED, HIGH);
       delay(2000);
      digitalWrite(LED, LOW);
    }
}

Suchst Du ein retriggerbares Monoflop?

Ein retriggerbares Monoflop ist mit millis sehr leicht zu realisieren, mit delay() würde es mir schwerfallen. `vorher = millis()´ ist die Grundidee.

Hallo Agmue,

Beschreibt exakt die Funktion, die ich benötige.
Ich hatte es schon mit diversen Millis() versucht (in Anlehnung an Blink without delay), bin aber grandios gescheitert, weil durch den Aufruf im Loop immer wieder Werte überschrieben wurden.

meinst du sowas?

const byte ledPin = 7;
unsigned long chrono;
const unsigned long duration = 1000ul;
bool ledIsOn = false;

void setup() {
  pinMode(ledPin, OUTPUT);
  Serial.begin(9600); Serial.println();
  Serial.println("<Arduino is ready>");
}

void loop() {
  if (Serial.read() != -1) {

    // Wenn Sie möchten, dass die LED nur 1 Sekunde lang eingeschaltet bleibt und eingehende Zeichen ignoriert
    // Überprüfen Sie zuerst, ob die LED bereits eingeschaltet war
    if (!ledIsOn) {
      chrono = millis();
      digitalWrite(ledPin, HIGH);
      ledIsOn = true;
    }

    // Wenn Sie die Dauer jedoch trotzdem einstellen oder verlängern möchten, überprüfen Sie nicht den Status der LED
    // chrono = millis();
    // digitalWrite(ledPin, HIGH);
    // ledIsOn = true;
  }

  // timeout
  if (ledIsOn && (millis() - chrono >= duration)) {
    digitalWrite(ledPin, LOW);
    ledIsOn = false;
  }

}

Auf den würde ich verzichten und ersetzen durch digitalRead(ledPin)

es ist möglich, aber langsamer :wink:

Vermutlich möchtest Du mit einem nachtriggerbaren Monoflop einen Wachhund (watchdog) programmieren. Ist der Wachhund einmal geweckt, bellt (blinkt) er bis Reset, der Alarm rastet also ein:

const byte ledPinWachhund = 7;
const byte ledAlarm = 13;

void setup()
{
  digitalWrite(ledPinWachhund, HIGH);
  pinMode(ledPinWachhund, OUTPUT);
  pinMode(ledAlarm, OUTPUT);
  Serial.begin(115200); Serial.println();
  Serial.println(F("Arduino ist bereit."));
}

void loop()
{
  blinken(wachhund());
}

bool wachhund()
{
  unsigned long jetzt = millis();
  static unsigned long vorhin = jetzt;
  const unsigned long schlafzeit = 1000;
  static bool fehler = false;

  if (!fehler)
  {
    if (Serial.read() != -1) {
      vorhin = jetzt;  // neu triggern
      Serial.println(F("Zeichen erkannt, Monoflop nachgetriggert."));
    }
    if (jetzt - vorhin >= schlafzeit) {
      digitalWrite(ledPinWachhund, LOW);
      fehler = true;
      Serial.print(F("Fehler erkannt "));
      Serial.print(jetzt);
      Serial.println(F(" Millisekunden nach Reset."));
    }
  }
  return fehler;
}

void blinken(bool aktion)
{
  unsigned long jetzt = millis();
  static unsigned long vorhin = jetzt;
  const unsigned long blinkzeit = 100;

  if (aktion && (jetzt - vorhin >= blinkzeit)) {
    vorhin = jetzt;
    digitalWrite(ledAlarm, !digitalRead(ledAlarm));
  }
}

Kannst Du Dir aus #4 und diesem Vorschlag eine passende Lösung zusammenstellen?

Hallo Z'sammen

erstmal schönen Dank für die Ideen/Anregungen und Tips.
Ich glaube Watchdog ist klasse, passt aber nicht ganz so.
Angedachte Grundfunktion:
Sondersoftware&Arduino--> alle 500ms Signal an SPS
SPS Eingang (Barth STG-680) hat eine Abfallverzögerung und triggert (invertiert) eine Ampel (Gelb, bliken, 2Hz).
Abfallverzögerung ist auf 700ms gesetzt.
Sollte also jetzt die Sondersoftware hängen, geht nach max 1200ms die Warnlampe an.
Die bleibt an (blinkend), bis das Programm neu gestartet ist und das Signal brav wieder alle 500ms kommt.
Der Arduino bekommt alle 500ms sein Signal. Der Ausgang soll ca. 600ms High sein.
Wird also alle 500ms "nachgetriggert", und gibt brav durchgehend High aus, was die Barth dann als i.O. bewertet.
Mal schaun, aber ich denke dass 9600 schnell genug ist, aber ich könnte die serielle Kommunikation, falls zu langsam, höher setzen (Kabellänge 3m, geschirmt.), aber im Endeffekt wird nur ein einziges Zeichen gesendet, wenn's passt, überwache ich noch eine kurze Rückantwort des Arduino.

Ich werde nachher erstmal die Idee von J-M-L umsetzen und schauen, was geht.
Dann mal den Watchdog, genau hingucken, verstehen, und ggf Code-Teile übernehen.
Beim Lesen sieht es ganz gut aus, aber mal schauen ob die LED sich dann auch so verhält, wie ich es will :wink:

Soooo.... :slightly_smiling_face:

Besten Dank an alle!
Hallo J-M-L,

Deinen Code, copy... paste,
if (!ledIsOn) rausgenommen....
Macht EXAKT, was ich gesucht habe... und schon ein wenig dran verzweifelt bin.
Danke!

Eine Frage für mein Verständnis:
const unsigned long duration = 1000ul;
Ich sage ja vorne schon "unsigned long" und vermute, dass das ul hinter der 100 auch "unsigned long bedeutet?
Ist das jetzt doppelt gemoppelt, oder hat es eine andere Bedeutung?

cool :wink:

Die ul sagt tatsächlich, dass der Wert ein unsigned long ist. Es ist nicht wirklich notwendig, der Compiler generiert sowieso den richtigen Code, aber es ist eine gute Angewohnheit, besonders wenn Sie eine mathematische Formel für den Wert haben.

unsigned long zehnStunde = 1000 * 60 * 60 * 10;   // Überlauf bei UNO
unsigned long zehnStunde = 1000ul * 60 * 60 * 10; // OK bei UNO

Das unsigned long am Anfang ist der Typ des Ergebnisses der Auswertung des Ausdrucks auf der rechten Seite, aber standardmäßig wertet der Compiler Zahlen als signed int (2 Byte bei UNO) aus und stuft das Ergebnis dann in das unsigned long um.

Richtig geraten:
123UL legt fest, dass diese Zahl als unsigned long zu behandeln ist.
Hier ist es tatsächlich unnötig, da der Wert direkt in einer passenden Variablen gespeichert wird.

Interessanter wäre z.B.

unsigned long dauer = 60*1000UL;

Da würde ohne UL die Berechnung zunächst in Standard int durchgeführt, das bei 8-bit-Arduinos überläuft, bevor das falsche Ergebnis in der Variablen abgelegt wird.

Auf einem Uno/Nano liefert:

unsigned long dauer = 60*1000;
void setup() {
 Serial.begin(9600);
 Serial.println(dauer);
}
void loop() { }

die Ausgabe

4294961760

und bei genauem Hinsehen während des Kompilierens
warning: integer overflow in expression [-Woverflow]

Diese Warnung gibt's natürlich nicht, wenn es der Compiler gar nicht merkt / merken kann.
Witzigerweise ist
unsigned long dauer = 60000; // ok

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