Dauer von High- und Low-Signalen messen und aufzeichnen

Hallo,

Ich habe ein LED-Blinklicht das unregelmäßig schnell blinkt (Die Bandbreite der Frequenz liegt zwischen wenigen Millisekunden bis ca. 1 Sekunde (z. B. 80millis EIN, 100ms AUS, 14ms EIN, 60ms AUS, etc…).

Wie kann ich die unterschiedlichen Frequenzen messen und in eine tabellarische Liste übertragen?

ZIEL: Eine Liste die so aussieht:

200ms EIN
100ms AUS
140ms EIN
70ms AUS
90ms AUS
100ms EIN
Etc...

Hardware:
Ich dachte an eine Photodiode die ich an der LED anbringe um die Lichtsignale in elektrische Single umzuwandeln um diese dann an einen Arduino UNO weiterzuleiten.

Software:
Dabei bräuchte ich eure Hilfe:

Ich habe einen Thread gefunden der in etwa das beschreiben was ich brauche. Aber ich komme alleine nicht weiter. Könnte mir jemand einen Tipp geben was ich diesen Code ändern muss um ihn an mein Projekt anzu passen?

https://forum.arduino.cc/t/time-between-high-signal-low-signal-during-high-signal/495999

Hier habe ich noch weitere Threads gefunden die ähnliche Themen behandeln, falls hilfreich.

https://forum.arduino.cc/t/zeitdauer-eines-high-signals-ermitteln/616561

https://forum.arduino.cc/t/zeitmessung-wie-lange-ein-bestimmter-zustand-wahr-ist/327817

https://forum.arduino.cc/t/zeit-zwischen-2-aktionen-messen/194706

Danke.

Wie lang wird die Liste? Wie soll die Liste ausgegeben werden? Sollen die Liste auch gespeichert werden, oder nur ausgegeben?

Was ist das für eine LED dessen Licht du einlesen willst?

Meine Frage: willst Du copy/paste oder selbst was machen?
Im letzten Fall: fang mal an mit dem Einlesen eines Pins und bei Pegeländerung schiebst Du den neuen Status und die Millis auf den seriellen Monitor. Vielleicht reicht das schon, Auswertung kann ja extern erfolgen - ist ja nur ne einfache Arithmetik.

Die Liste wird in etwa 40.000 Werte haben (20.000 ON und 20.000 OFF).
Sind so viele Werte ein Problem?

Die Liste kann gerne nur im seriellen Monitor ausgegeben werden, ich kann sie ja danach ins Excel kopieren und auswerten. Der 1. Wert den ich berkomme müsste ja ein ON-Wert sein (wenn das LED zum 1. Mal aufleuchtet).

In diesem Fall bevorzuge ich copy/paste, weil ich gerne so effizent wie möglich mit meinem Projekt (einen Prototyp bauen) vorankommen möchte.

Dann las Dir den Zahn ziehen.
Der SerMon ist dafür nicht gedacht und macht das nicht mit. - Wenn unten neue Daten kommen, gehen oben welche ins Nirwana.

Du könntest ein Terminalprogramm nutzen und den gesamten Ausgabeteil von dort aus in eine Text-/.csv -datei schreiben.
Dann einfach nur auswerten, ob die Zeile zu Deiner Anforderung passt und schon ist schick.

Vieleicht magst ja etwas genauer beschreiben - das was bisher da ist, ist wage, das passt in ein paar Zeilen Code.

const byte inputPin = 3;
bool lastOnOff = false;
unsigned long lastmillis;

void setup()
{
  Serial.begin(115200);
  Serial.println(F("Start...."));
  pinMode(inputPin, INPUT_PULLUP);
  lastmillis = millis();
}

void loop()
{
  if (digitalRead(inputPin) != lastOnOff)
  {
    Serial.print(millis() - lastmillis);
    lastmillis = millis();
    Serial.print("\t");
    Serial.println(!lastOnOff);
    lastOnOff = !lastOnOff;
  }
}

wäre ne idee....

Vielen Dank für den Code!!!

Ich habe mir einen Photoransistor besorgt. %product-title% kaufen
Den Plus-Pol des Transistors hab ich an den Pin 3 angeschlossen und den Minus-Pol am GND.

Es werden Daten ausgegeben! :slightly_smiling_face:
Mit Tageslicht und mit einer herkömmlichen Glühbirne funiktioniert es richtig, ABER mit der Lichtquelle die ich messen will (ein LED-Licht) funktioniert es noch nicht richtig.

Die Zeit von LIcht AUS bis Licht EIN wird richtig gemessen.
ABER, Wenn dich Lichtquelle ein LED-Licht ist, dann bekomme ich (Wenn das Licht an ist) andauernd Werte übertragen, so als würde das Licht andauern blinken.

||0|
|3790|0|   --> die Zeit in der das Licht AUS war wird richtig gemessen
|1|1|
|3|0|
|2|1|
|7|0|
|2|1|
|2739|0|   --> die Zeit in der das Licht AUS war wird richtig gemessen
|2|1|
|2|0|
|3|1|
|2|0|
|3|1|
|2|0|
|4|1|
|1|0|
|4529|0|   --> die Zeit in der das Licht aus war wird richtig gemessen
|3|1|
|1|0|
|5|1|
...

| ... |0| = die Zeitdauer in der das Licht AUS war
| ... |1| = die Zeitdauer in der das Licht AN war

Ich nehme an der Grund dafür ist der, dass das LED-Licht tatsächlich ständig hochfrequent blinkt.

Fällt euch eine Lösung ein wie man das programmiertechnisch korrigieren könnte?
Die Blinkfrequenz ist immer < 10ms.

Keine Ahnung, ob das geht:

void loop()
{
  if (digitalRead(inputPin)!= lastOnOff)
  {
    if (millis() - lastmillis > 10)
    {
      Serial.print(millis() - lastmillis);
      lastmillis = millis();
      Serial.print("\t");
      Serial.println(!lastOnOff);
      lastOnOff = !lastOnOff;
    }
  }
}

Es geht natürlich auch aufwendiger mit mehreren Zeiten merken etc...

Das is die normale Methode, bei einer LED die Helligkeit einzustellen.

Ja, ab 100 Hz sieht ein Mensch kein Flackern mehr. Wenn die Zeiten, die du messen willst, wesentlich größer sind, gilt eben jede Pause unter 10 als immer noch AN, und die "echte" Startzeit musst du dir zusätzlich merken.

@my_xy_projekt 's Schnellschuß wird leider nicht gehen, weil der nach insgesamt 10 ms einen Wechsel erkennt.

Stimmt, so wie es aussieht, blinkt das ding mit 2,5ms.
Also doch Zeit merken.

Ach ja, daran hatte ich nicht gedacht. Also wenn man die LED-Helligkeit auf 100% stellen kann, dann löst sich das Problem auf, richtig?
Ich kann erst morgen überprüfen, ob das in meinem Fall möglich ist.

Bis dahin hat @my_xy_projekt schon längst was fertig :smiley:

1 Like

Dein Vertrauen in mich ehrt...

const byte inputPin = 3;
bool lastOnOff = false;
unsigned long lastmillis;
unsigned long bouncemillis = 0;
bool bouncemerker = false;
void setup()
{
  Serial.begin(115200);
  Serial.println(F("Start...."));
  pinMode(inputPin, INPUT_PULLUP);
  lastmillis = millis();
}

void loop()
{
  if (digitalRead(inputPin))  // PIN ist HIGH wenn LED leuchtet
  {
      bouncemerker = false;
    if (!lastOnOff)           // War vorher LOW
    {
      serielleAusgabe();
    }
  }
  else                        // PIN ist LOW - der muss 10ms LOW sein
  {
    if (!bouncemerker)        // wird beim ersten Erkennen von LOW gesetzt
    {
      bouncemerker = true;
      bouncemillis = millis();
    }
    if (millis() - bouncemillis > 10 && bouncemerker && lastOnOff)
    {
      serielleAusgabe();
    }
  }
}

void serielleAusgabe()
{
  Serial.print(millis() - lastmillis);
  lastmillis = millis();
  Serial.print("\t");
  Serial.println(!lastOnOff);
  lastOnOff = !lastOnOff;
}

zum Testen - kompiliert fehlerfrei.
Ich gehe davon aus, das der Eingang HIGH geht, wenn die LED leuchet.

Das umschalten von LOW nach HIGH merkt er sofort , das umschalten von HIGH nach LOW muss 10ms laufen.
Musst sehen, ob das geht.
[Das edit oben im Code war das verschieben des Merkers zum löschen]

Hallo,

kann man an der Led die Spannung als Signal abgreifen? Sind das 5V? Man sollte möglichst beim rein digitalen Signal bleiben und das verarbeiten. Phototransistor würde ich vermeiden. Notfalls Pegelwandler.

Ach wach geworden :wink:

An der Stelle würde ich das nicht abgreifen wollen, wenn nicht klar ist, was da für ein Potential drauf ist.
Notfalls vielleicht mit OK - Ich hatte gestern eine Schaltung, da war an der LED gut zwirbeln....

Irgendwo gab es hier mal jemanden, der diese komischen Platinen mit LED und OK als 240V-Detektor verteidigte .. :frowning:

Ungeachtet dessen, ist der Abgriff mit einem Fototransi garnicht mal schlecht um dem PWM-Signal hardwareseitig entgegen treten zu können. Nen kleiner Konni..

Hallo,

bin schon eine Weile wach, gehe gleich in Bett. :wink:

Gehts hier wirklich um 230V Led Lampen oder um eine Led auf einem Steckbrett o.ä.?
Oder soll ein Stromzähler ausgelesen werden? Beim Phototransistor habe ich bedenken, wie hier schon angedeutet wurde, dass bei Dimmung die Signalspannung verfälscht wird.

Das ist die Frage derer. Nen Zähler definitiv nicht, die LED's werden nicht mit PWM angefahren.

Schaun wa mal heute, was noch kommt....
@scharfet: Was liest Du da aus?

Hallo,

für den Fall das ein geeignetes Signal vorhanden ist habe ich folgendes.
messung() erfasst abwechselnd den Zeitpunkt vom Pegelwechsel.
auswertung() berechnet die Dauer vom vorherigen Signalpegel.
seriellerMonitor() gibt die Signaldauer aus wenn sich etwas geändert hat.

/*
 * Doc_Arduino - german Arduino Forum
 * IDE 1.8.16
 * Arduino Mega2560
 * 30.09.2021
 * https://forum.arduino.cc/t/dauer-von-high-und-low-signalen-messen-und-aufzeichnen/909684
 */

#include <Streaming.h>

struct Daten
{
  const byte pin {3};
  unsigned long timeStampLow {0};
  unsigned long timeStampHigh {0};
  unsigned long oldTimeStampLow {0};
  unsigned long oldTimeStampHigh {0};
  unsigned long timeDurationLow {0};
  unsigned long timeDurationHigh {0};
  unsigned long oldTimeDurationLow {0};
  unsigned long oldTimeDurationHigh {0};
};
Daten led;

void setup(void)
{  
  Serial.begin(250000);
  Serial.println(F("\nµC Reset ### ###"));
  pinMode (led.pin, INPUT_PULLUP);
}

void loop(void)
{
   messung();
   auswertung();
   seriellerMonitor(Serial);
}  

/* *** Funktionen *** */
void seriellerMonitor (Stream &out)
{
  if (led.oldTimeDurationHigh != led.timeDurationHigh)
  {
    out << "HIGH " << led.timeDurationHigh << endl;
    led.oldTimeDurationHigh = led.timeDurationHigh;
  }
  
  if (led.oldTimeDurationLow != led.timeDurationLow)
  {
    out << "LOW  " << led.timeDurationLow << endl;
    led.oldTimeDurationLow = led.timeDurationLow;
  }
}

void auswertung (void)
{
  if (led.oldTimeStampHigh != led.timeStampHigh)
  {
    led.timeDurationLow = led.timeStampHigh - led.timeStampLow;
    led.oldTimeStampHigh = led.timeStampHigh;
  }
   
  if (led.oldTimeStampLow != led.timeStampLow)
  {
    led.timeDurationHigh = led.timeStampLow - led.timeStampHigh;
    led.oldTimeStampLow = led.timeStampLow;
  }
}

void messung (void)
{
  enum class Phase : byte {ONE, TWO};
  static Phase phase = Phase::TWO;
 
  switch (phase)
  {
    case Phase::ONE:  // HIGH
              if ( digitalRead(led.pin) )      
              {
                led.timeStampHigh = millis();          
                phase = Phase::TWO;
              }
              break;

    case Phase::TWO:  // LOW
              if ( !digitalRead(led.pin) )       
              {
                led.timeStampLow = millis();          
                phase = Phase::ONE;
              }  
              break;
  }              
}

:slight_smile: In welcher Zeitzone bist Du?
Aber das ist schon starker Tobak...
Ok.
Ich geh auf meine andere Baustelle....

Das ist meine private Zeitzone. :wink: Ist nur das Datum der ersten Sketcherstellung.
Durch die Vergleiche ob ein neuer Wert vorhanden ist sieht es ehrlich gesagt schlimmer aus als es ist. Damit wird trotz ungebremsten maximalen Speed der serielle Monitor nicht zugemüllt. Man kann damit sogar Kontaktpreller erfassen wenn man Glück hat.