Forum: Mikrocontroller und Digitale Elektronik Zeitdifferenz zwischen zwei Rechtecksignalen


von Sven P. (kiel_95)


Angehängte Dateien:

Lesenswert?

Guten Tag liebe Community,

ich habe mit Hilfe der Software Tinkercas eine Schaltung erstellt bei 
der ich mit Hilfe eines Arduino Uno die Zeitdifferenz zwischen zwei 
Rechtecksignalen messen möchte. Jedoch klappt es bei mir nicht. Ich habe 
in etlichen Foren nach Lösungen gesucht und versucht ähnliche Fälle bei 
meinem Problem anzuwenden. Jedoch ohne Erfolg. Kann mir einer sagen, was 
ich da Falsch mache ? Ich generiere mit zwei Drucktaster Signale. 
Zunächst klicke ich auf den ersten Drucktaster und danach auf den 
zweiten und möchte "einfach nur" die Zeitdifferenz messen. Ich habe auch 
nichts in Richtung Interrupt gemacht, da ich völliger Anfänger bin. Kann 
mir jemand sagen was da nicht stimmt ?

: Bearbeitet durch User
von Klaus R. (klara)


Lesenswert?

Kann es sein das Dein Loop mit Delay 10 viel zu schnell ist? Immerhin 
wird im Bildchen je Kästchen 1 s angezeigt.
mfg Klaus

von Sven P. (kiel_95)


Lesenswert?

Hallo Klaus,

danke für deine Antwort. Ich habe es geändert, jedoch funktioniert es 
trotzdem nicht. Es wird mir nur ne 0 immer angezeigt und ab und zu ne 
"4294967295".

von Uwe N. (ulegan)


Lesenswert?

Na, das erste Proramm misst ja garnichts, sondern kopiert nur den 
Zustand der Tasten an die beiden Ausgänge.
Das zweite misst durchaus den Abstand und soll ihn in Millisekunden 
anzeigen.
Wegem dem delay(100) allerdings nur mit 100ms Auflösung.
Lass das delay doch mal ganz weg.

Oh, und es sollte wohl eher
1
dauer = ende - start;
heissen. Sonst wird dauer negativ, was macht die Simulation da bei einer 
unsigned-Variablen?

von blaaaaaa (Gast)


Lesenswert?

Ende - Start

von Manfred (Gast)


Lesenswert?

Sven P. schrieb:
> Ich generiere mit zwei Drucktaster Signale
Zwei Drucktaster n , Mehrzahl!

Der angehängte Programmkot beinhaltet keinerlei Zeiten, der schaltet 
lediglich zwei LEDs und auch das erst, wenn man ihn korrigiert.

von Sven P. (kiel_95)


Lesenswert?

Vielen Danke für die Rückmeldungen,

ich habe das Delay komplett weggelassen und die Rechnung korrigiert. 
Jedoch erhalte ich andauern die Zahl "0". Also es wird keine Differenz 
angezeigt. Hier mein aktueller Code:
1
int buttonState1 = 0;
2
int buttonState2 = 0;
3
unsigned int long start;
4
unsigned int long ende;
5
unsigned int long dauer;
6
7
void setup()
8
{
9
  pinMode(2, INPUT);
10
  pinMode(13, OUTPUT);
11
  pinMode(3, INPUT);
12
  pinMode(12, OUTPUT);
13
  Serial.begin(9600);
14
 
15
}
16
17
void loop()
18
{
19
  // read the state of the pushbutton
20
  buttonState1 = digitalRead(2);
21
  buttonState2 = digitalRead(3);
22
  
23
  while(buttonState1 == HIGH);
24
  start = millis();
25
  
26
  while(buttonState2 == HIGH);
27
  ende = millis();
28
  
29
  dauer = ende - start;
30
31
  Serial.println(dauer);
32
  
33
 
34
}

von Klaus R. (klara)


Lesenswert?

Sven P. schrieb:
> while(buttonState1 == HIGH);
>   start = millis();
>
>   while(buttonState2 == HIGH);
>   ende = millis();

Ist WHILE denn hier der richtige Befehl?
Anfänglich hattest Du doch IF verwendet.

Kannst Du mit der Oberfläche nicht debuggen?
Dann geh doch mal step für step den Code durch.
mfg Klaus

von Tobias (. (Gast)


Lesenswert?

Manfred schrieb:
> Programmkot

Sollen wir das als Kritik oder Verschreiber lesen?

von GEKU (Gast)


Lesenswert?

Ich würde folgenden Code probieren:
1
void loop()
2
 {
3
    while(digitalRead(2) == HIGH); 
4
5
    start = millis(); 
6
7
    while(digitalRead(3) == HIGH);
8
9
    ende = millis(); 
10
11
    dauer = ende - start; Serial.println(dauer);
12
}

Grund:

in der While Schleife ändern sich die zuvor gelesenen Werte nicht mehr!

von Mimikri (Gast)


Lesenswert?

Sven P. schrieb:

>   while(buttonState1 == HIGH);
                               ^ Semikolon muss weg
>   start = millis();
>
>   while(buttonState2 == HIGH);
                               ^ hier ebenso
>   ende = millis();

Ich finde das mit Klammersyntax besser und eindeutiger:

while(buttonState1 == HIGH)
{
  start = millis();
}

von Manfred (Gast)


Lesenswert?

Sven P. schrieb:
> Jedoch erhalte ich andauern d die Zahl "0".

Was würde ich jetzt tun:

Ich baue serial.print(start)
und
serial.print(ende) in die Hauptschleife ein und gucke, ob die sich 
ändern.

Wenn nicht, baue ich weitere Ausgaben, ob die Taster überhaupt erkannt 
werden, z.B. auf Deine zwei LEDs.

Programmieren lebt davon, dass Du eigene Strategien entwickelt, 
Fehlfunktionen einzugrenzen.

Klaus R. schrieb:
> Ist WHILE denn hier der richtige Befehl?

Ich bezweifele es.

von Klaus R. (klara)


Lesenswert?

Sven P. schrieb:
> while(buttonState1 == HIGH);
>   start = millis();
>
>   while(buttonState2 == HIGH);
>   ende = millis();

Ich denke Du verwendest WHILE fehlerhaft.

Siehe:
https://www.arduino.cc/reference/en/language/structure/control-structure/while/

Mach es mal so.
1
while(buttonState1 == HIGH){
2
start = millis();}
3
4
while(buttonState2 == HIGH){
5
ende = millis();}

Dein Code füllt in jedem Loop die Varaiablen. Und das geht so schnell 
das sie immer den selben Wert haben.

Das IF:
1
Example Code
2
3
The brackets may be omitted after an if statement. If this is done, the next line (defined by the semicolon) becomes the only conditional statement.
4
5
if (x > 120) digitalWrite(LEDpin, HIGH);
6
7
if (x > 120)
8
digitalWrite(LEDpin, HIGH);
9
10
if (x > 120) {digitalWrite(LEDpin, HIGH);}
11
12
if (x > 120) {
13
  digitalWrite(LEDpin1, HIGH);
14
  digitalWrite(LEDpin2, HIGH);
15
}
16
// all are correct

mfg klaus

von GEKU (Gast)


Lesenswert?

GEKU schrieb:
> == HIGH

ist die Polarität der Taster richtig?  Sonst hätte er in der While 
Schleife auf Ewig hängen bleiben müssen!

Wenn nicht probiert  != HIGH  oder  == LOW

von leo (Gast)


Lesenswert?

Klaus R. schrieb:
> Dein Code füllt in jedem Loop die Varaiablen. Und das geht so schnell
> das sie immer den selben Wert haben.

Ja, es ist Freitag.
leo

von Klaus R. (klara)


Lesenswert?

GEKU schrieb:
> Sonst hätte er in der While
> Schleife auf Ewig hängen bleiben müssen!

Natürlich, also unbedingt IF verwenden, mit {}.
mfg klaus

von Manfred (Gast)


Lesenswert?

Klaus R. schrieb:
>> Sonst hätte er in der While
>> Schleife auf Ewig hängen bleiben müssen!
>
> Natürlich, also unbedingt IF verwenden, mit {}.

Wenn ich das richtig verstanden habe, bleibt while solange auf Taste1 
hängen, bis diese aktiv wird. Danach hängt while in Taste2 fest, bis 
auch diese betätigt wird.

Könnte Sinn geben, je nachdem, was man erreichen will.

Das würde man zügig heraus bekommen, wenn man Tasten und Timer serial 
ausgeben lässt, so furchtbar komplex ist das Programm ja mal nicht.

von Sven P. (kiel_95)


Angehängte Dateien:

Lesenswert?

Vielen Danke für die zahlreichen Antworten. So wie ich es nun verstanden 
habe, soll ich die while-Schleife durch eine If-Schleife ersetzten. Das 
habe ich gemacht. Sobald ich den ersten Taster (auf Pin 2) drücke 
erscheinen die Zahlen "4294967101" und anschließend habe ich 5 Sekunden 
gewartet bis ich den zweiten Taster (auf Pin 3) gedrückt habe. Ich würde 
nun erwarten, dass irgendwas im Bereich von "5000" angezeigt wird. 
Jedoch kommt ein vollkommen anderer Wert raus, wie in der Abbildung zu 
sehen.
1
int buttonState1 = 0;
2
int buttonState2 = 0;
3
unsigned int long start;
4
unsigned int long ende;
5
unsigned int long dauer;
6
7
void setup()
8
{
9
  pinMode(2, INPUT);
10
  pinMode(13, OUTPUT);
11
  pinMode(3, INPUT);
12
  pinMode(12, OUTPUT);
13
  Serial.begin(9600);
14
  Serial.println("Zeit");
15
 
16
}
17
18
void loop()
19
{
20
  if(digitalRead(2)==HIGH)
21
  {
22
      start = millis();
23
    }
24
  
25
  if(digitalRead(3)==HIGH)
26
  {
27
      ende=millis();
28
    }
29
  
30
  dauer = start - ende;
31
  
32
  Serial.println(dauer);
33
 
34
}

von GEKU (Gast)


Lesenswert?

Klaus R. schrieb:
> Ich denke Du verwendest WHILE fehlerhaft.

Die Frage ist, ob er die Arduino  Loop nutzen , oder in dieser eine 
eigene Loop verwenden will.

Im ersten Fall:
1
void loop() // rotiert ständig in loop
2
{ 
3
    if (digitalRead(2) == HIGH) // Schnappschuss wenn Taste 1 gedrückt wurde
4
         start = millis(); 
5
6
    if (digitalRead(3) == HIGH) // Schnappschuss wenn Taste 2 gedrückt wurde
7
    {
8
        ende = millis(); 
9
        dauer = ende - start; 
10
        Serial.println(dauer); 
11
     }
12
}

Im zweiten Fall:
1
void loop() 
2
{ 
3
    while (digitalRead(2) == LOW);  // wartet in der lokalen Schleife bis Taste 1 gedrückt wurde
4
    start = millis(); 
5
6
    while (digitalRead(3) == LOW); // wartet in der lokalen Schleife bis Taste 2 gedrückt wurde
7
    ende = millis(); 
8
    dauer = ende - start; 
9
    Serial.println(dauer); 
10
11
}  // loop wird fortgesetzt, nachdem Taste 1 und 2 gedrückt worden ist

von GEKU (Gast)


Lesenswert?

Sven P. schrieb:
> If-Schleife

if ist  kein Schleifenkonstrukt!

Die Schleife wird erst durch
1
void loop() { }

bewirkt!

Diese Schleife bildet das Arduino  Betriebssystem indem es loop () 
ständig aufruft.

von GEKU (Gast)


Lesenswert?

Sven P. schrieb:
> if(digitalRead(3)==HIGH)
>   {
>       ende=millis();
>     }
>
>   dauer = start - ende;
>
>   Serial.println(dauer);

Besser ist :
1
if (digitalRead(3)==HIGH)
2
{
3
        ende=millis();
4
       dauer = start - ende; 
5
       Serial.println(dauer);
6
}

dann erfolgt die Auswertung und Ausgabe nur wenn Taste 2 gedrückt wird

von Manfred (Gast)


Lesenswert?

Sven P. schrieb:
> Jedoch kommt ein vollkommen anderer Wert raus,

Dann ergreife endlich Eingeninitiative und lasse Dir alle Werte 
zeigen:
1
Serial.print("Millis: ");
2
Serial.println(millis());
3
4
Serial.print("Start: ");
5
Serial.println(start);
6
7
Serial.print("Ende: ");
8
Serial.println(ende);
9
10
Serial.print("Dauer: ");
11
Serial.println(Dauer);

von Zeno (Gast)


Lesenswert?

Sven P. schrieb:
> void loop()
> {
>   if(digitalRead(2)==HIGH)
>   {
>       start = millis();
>     }
>
>   if(digitalRead(3)==HIGH)
>   {
>       ende=millis();
>     }
>
>   dauer = start - ende;
>
>   Serial.println(dauer);
>
> }

So geht es nicht.

So sollte es gehen:
1
int Condition=0;
2
//Folgezeile Kommentar entfernen, wenn bei ungedrücktem Taster HIGH am Eingang
3
//Condition = HIGH;
4
//Folgezeile Kommentar entfernen, wenn bei ungedrücktem Taster LOW am Eingang
5
//Condition = LOW;
6
7
while (digitalRead(2)==Condition){}
8
start = millis();
9
while (digitalRead(3)==Condition){}
10
ende = millis();

Kurze Erläuterung:
Er bleibt in der 1. while Schleife hängen bis der Taster gedrückt wird. 
Drücken des Tasters unterbricht die while Schleife. Dadurch wird die 
Variable start gesetzt und er bleibt in der 2. while Schleife hängen. 
Hier gleiche Funktion wie in der 1. Schleife. Allerdings wird hier beim 
Beenden der Schleife ende gesetzt.
Anschließend käme Deine Berechnung der Differenz und Ausgabe des 
Ergebnisses. Das delay kannst Du weg lassen. Danach bleibt er dann 
wieder in der 1. Schleife hängen.

Die Variable Condition am besten global definieren und in setup() mit 
dem entsprechenden Wert belegen. Man braucht sie auch nicht wenn man den 
passenden Wert in der while-Schleife einträgt.

von Wolfgang (Gast)


Lesenswert?

Zeno schrieb:
> Die Variable Condition am besten global definieren und in setup() mit
> dem entsprechenden Wert belegen. Man braucht sie auch nicht wenn man den
> passenden Wert in der while-Schleife einträgt.

Was soll der Wert in einer Variablen, die sowieso im Programm nicht 
geändert werden kann. Ein #define für den Präprozessor ist da deutlich 
zielführender und universeller, auch wenn man den Wert in der Bedingung 
für den while-Block direkt festlegen möchte, was hier defacto der Fall 
ist.

von Zeno (Gast)


Lesenswert?

Wolfgang schrieb:
> Was soll der Wert in einer Variablen, die sowieso im Programm nicht
> geändert werden kann. Ein #define für den Präprozessor ist da deutlich
> zielführender und universeller, auch wenn man den Wert in der Bedingung
> für den while-Block direkt festlegen möchte, was hier defacto der Fall
> ist.

Es führen viele Wege nach Rom und ja man kann auch #define verwenden. 
Auch wenn Dein Post mal wieder der typische C-Zeigefinger "Das macht man 
nicht so", der von mir hin geschriebene Code wird funktionieren, sogar 
wenn man das Ganze in loop() rein schreibt, auch wenn das nicht 
sonderlich elegant wäre.

Ich habe es eigentlich nur zur Erklärung eingefügt, weil sich es sich so 
leichter schreiben ließ. Ich denke mal das es für den TO so auch 
verständlicher ist.

Das man es auch im while machen kann hatte ich ja geschrieben.

von Wolfgang (Gast)


Lesenswert?

Zeno schrieb:
> Auch wenn Dein Post mal wieder der typische C-Zeigefinger "Das macht man
> nicht so" ...
Sei beruhigt, von C habe ich nicht sonderlich viel Ahnung und enthalte 
mich gewöhnlich bei solchen Stilfragen. Aber manche Dinge fallen selbst 
mir als Quereinsteiger auf. ;-)

von Sven P. (kiel_95)


Lesenswert?

Danke für eure Hilfe, der Code funktioniert nun und es zähl fleißig die 
Differenz. Jedoch zählt es sie falsch. Nach 10 sek. ist die Anzeige 
gerade mal bei "2100 ms". Kann mir einer sagen woran das liegt ? wenn 
"millis()" Millisekunden entsprechen, so müsste es ja bei "10000" sein.

von Wolfgang (Gast)


Lesenswert?

Sven P. schrieb:
> Danke für eure Hilfe, der Code funktioniert nun und es zähl fleißig die
> Differenz. Jedoch zählt es sie falsch.

Das Programm zählt nicht die Differenz, sondern es holt sich bei den 
Tastenereignissen als Timestamp den Zählerstand vom 
Millisekunden-Systemtimer. Die Dauer wird erst später ausgerechnet.

Prüfe also erstmal die Timestamps unter Berücksichtigung der Tatsache, 
dass der Zähler auch mal überlaufen kann.

von Sven P. (kiel_95)


Lesenswert?

Danke für die Antwort, aber leider verstehe ich nicht was du meinst :(

von Kai D. (robokai)


Lesenswert?

Zeno schrieb:
> Es führen viele Wege nach Rom

Bei dem Vorgehen, landet er aber nicht in Rom, sondern kommt nur bis 
Castrop-Rauxel, weil er in einer Schleife überlaufende Werte erwischt. 
Damit wird er zwangsläufig auch negative Zeiten heraus bekommen.

Dann kommt die Frage hoch, ob da die Relativitätstheorie zugeschlagen 
hat!

von Wolfgang (Gast)


Lesenswert?

Kai D. schrieb:
> Damit wird er zwangsläufig auch negative Zeiten heraus bekommen.

Wie sollen bei Verrechnung von unsigned Variablen negative Zahlen heraus 
kommen?

von Wolfgang (Gast)


Lesenswert?

Sven P. schrieb:
> Danke für die Antwort, aber leider verstehe ich nicht was du meinst :(

Gehe Stück für Stück bei der Fehlersuche vor:
Prüfe erstmal die Werte für start und ende auf Plausibilität

von Zeno (Gast)


Lesenswert?

Kai D. schrieb:
> Bei dem Vorgehen, landet er aber nicht in Rom, sondern kommt nur bis
> Castrop-Rauxel, weil er in einer Schleife überlaufende Werte erwischt.
> Damit wird er zwangsläufig auch negative Zeiten heraus bekommen.
>
> Dann kommt die Frage hoch, ob da die Relativitätstheorie zugeschlagen
> hat!

Nö er muß nur die Variablen start und ende passend definieren. Die 
Funktion millis() liefert unsigned long zurück, d.h. es kommt erst nach 
1193 Stunden bzw. 49 Tagen zum Überlauf. Innerhalb dieser Zeit wird er 
wohl beide Taster gedrückt haben.
Also die Variablen auf unsigned long setzen.

Den Überlauf kann relativ einfach abfangen, wenn man prüft ob start > 
ende ist. Wenn dem so ist, dann muß etwas anders die Differenz 
berechnen. Die Differenz wäre nach einem Überlauf 4294967296-start+ende.

von Wolfgang (Gast)


Lesenswert?

Zeno schrieb:
> Also die Variablen auf unsigned long setzen.

Was meinst du wohl, was hier passiert:

Sven P. schrieb:
> unsigned int long start;
> unsigned int long ende;
> unsigned int long dauer;

Zeno schrieb:
> Den Überlauf kann relativ einfach abfangen, wenn man prüft ob start >
> ende ist.

Warum willst du beim Überlauf des millis()-Timers irgendetwas abfangen?
Mir scheint, da fehlen ein paar Grundlagen.

Rechne mal mit unsigned long Arithmetik aus, was bei der Rechnung
1
unsigned long int t_start;
2
unsigned long int t_end;
3
unsigned long int t_delta;
4
...
5
t_start = 4294967286;      //    0xffffffF6
6
t_end   = 4;               //    0x00000004
7
t_delta = t_end - t_start; // -> 0x0000000E
heraus kommt.
Die Differenz wird richtig als 14 berechnet.

von Conrad (Gast)


Lesenswert?

Tja,

heißt es nun

Ende-Start

oder

Start-Ende

... genau hinschauen hilft hier ziemlich weiter.

von Zeno (Gast)


Lesenswert?

Wolfgang schrieb:
> Was meinst du wohl, was hier passiert:
>
> Sven P. schrieb:
>> unsigned int long start;
>> unsigned int long ende;
>> unsigned int long dauer;

Hatte ich übersehen - wirgendwie nur auf long.

Wolfgang schrieb:
> Mir scheint, da fehlen ein paar Grundlagen.

Mir schein Du bist ein biss'l arrogant. Ein einfacher Hinweis das es 
auch so funktioniert wäre völlig ausreichend gewesen.

Rein mathematisch würde das nicht funktionieren. Von einer natürlichen 
Zahl kannst Du keine größere natürliche Zahl abziehen, das wäre ja 
negativ und das kennt dieser Zahlenbereich nicht. Bei ganzen Zahlen 
ginge es zwar aber es käme das falsche heraus und dazu noch negativ. 
Allerdings gibt es in der Mathematik auch keine Begrenzung des 
Zahlenbereiches.
Das das hier richtig umgesetzt wird war mir bisher nicht bewußt. Ich 
habe es bisher immer so gemacht wie beschrieben. Funktioniert auch ist 
halt nur etwas umständlicher.

von Wolfgang (Gast)


Lesenswert?

Zeno schrieb:
> Rein mathematisch würde das nicht funktionieren.

Natürlich funktioniert das auch mathematisch. Man muss nur die 
Rechenregeln beachten. Beim Datentyp unsigned long gilt
1
4294967296 = 0

von c-hater (Gast)


Lesenswert?

Zeno schrieb:

> Rein mathematisch würde das nicht funktionieren.

Doch.

> Von einer natürlichen
> Zahl kannst Du keine größere natürliche Zahl abziehen, das wäre ja
> negativ

Das ist korrekt. Nur leider völlig am Problem vorbei. Computer rechnen 
nämlich nicht mit natürlichen Zahlen (dazu müssten sie unendlich breite 
Register haben), sondern in einem zyklischen Zahlenraum, der eine 
Teilmenge entweder der natürlichen oder der ganzen Zahlen umfaßt.

Und in solchen zyklischen Zahlenräumen gelten andere Rechenregeln. Jeder 
Programmierer sollte diese aus dem Effeff beherrschen, sonst fällt er 
früher oder später auf die Schnauze.

von Kai D. (robokai)


Lesenswert?

Wolfgang schrieb:
> Wie sollen bei Verrechnung von unsigned Variablen negative Zahlen heraus
> kommen?

Na, so:

Zeno schrieb:
> Rein mathematisch würde das nicht funktionieren. Von einer natürlichen
> Zahl kannst Du keine größere natürliche Zahl abziehen, das wäre ja
> negativ und das kennt dieser Zahlenbereich nicht.
Doch kann man, wie die Antwort zeigte:

Wolfgang schrieb:
> Natürlich funktioniert das auch mathematisch. Man muss nur die
> Rechenregeln beachten
Wobei:

Zeno schrieb:
> Den Überlauf kann relativ einfach abfangen
Muss aber auch erst einmal getan werden. Erst mal gibt es einen 
Unterlauf.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.