Zeitdifferenz zwischen zwei Rechtecksignalen

OP #5883035
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 ?
Angehängte Dateien:
#5883068
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?
OP #5883112
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
}
Gast #5883127
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!
Gast #5883135
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.
#5883138
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
Gast #5883160
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.
OP #5883165
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
}
Angehängte Dateien:
Gast #5883166
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
Gast #5883178
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
Gast #5883187
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);
Gast #5883191
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.
Gast #5883542
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.
Gast #5883571
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.
Gast #5883580
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. ;-)
OP #5883885
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.
Gast #5883889
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.
(Firma: CAD- und CAE-Konstruktion) #5883929
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!
Gast #5884013
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.
Gast #5884037
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.
Gast #5884567
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.
Gast #5884729
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.
(Firma: CAD- und CAE-Konstruktion) #7246113
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren