micros(), unsigned long - Differenz wird sporadisch falsch berechnet

Hallo zusammen,
ich habe zwei Lichtschranken an meinem Arduino Nano.
Wenn die erste durchbrochen wird, wird micros() in Z1 geschrieben, wird die zweite durchbrochen wird micros() in Z2 geschrieben. Die Differenz wird in Z geschrieben. Um die Differenz möglichst exakt berechnen zu können benutze ich Interrupts um die einzelnen Zeiten festzustellen.

Das funktioniert auch recht gut, nur manchmal wird die Differenz falsch berechnet und ich weis nicht warum, wahrscheinlich gibt es ein Overflow der Variablen oder ähnliches.

z.B.:
Z2 - Z1 = Z_Differenz
11053704 - 11033340 = 4294944004

Arduino Code:

unsigned long Z1;
unsigned long Z2;
unsigned long Z_Differenz;

byte PinO;
byte PinU;

void setup() {

PinO = 3;
PinU = 2;

pinMode(PinO, INPUT);
pinMode(PinU, INPUT);
Serial.begin(9600);
Z1 = 0;
Z2 = 0;
Z_Differenz = 0;
attachInterrupt(digitalPinToInterrupt(PinO), Oben, FALLING);
attachInterrupt(digitalPinToInterrupt(PinU), Unten, FALLING);

}

void loop() {
if (Z2 != 0 && Z1 != 0){

Z_Differenz = Z2 - Z1;

Serial.print("Z1: ");
Serial.println(Z1);
Serial.print("Z2: ");
Serial.println(Z2);
Serial.print("Z_Differenz: ");
Serial.println(Z_Differenz);
Serial.println("");

Z2 = 0;
Z1 = 0;
}
}

void Oben() { //Wird ausgeloest wenn der die obere Photodiode auf Low faellt
Z1 = micros();
}

void Unten() { //Wird ausgeloest wenn der die untere Photodiode auf Low faellt
Z2 = micros();
}

Auszug, Serieller Monitor:

Z1: 10771912
Z2: 10788092
Z_Differenz: 16180

Z1: 11033340
Z2: 11053704
Z_Differenz: 4294944004

Z1: 11303000
Z2: 11320560
Z_Differenz: 4294936488

Z1: 11592064
Z2: 11612988
Z_Differenz: 20864

Während du in loop auf Z1 und Z2 zugreifst, müssen die Interrupte zu sein!

Ausserdem sollten diese als volatile deklariert sein.

void loop() {
  unsigned long _z1;  // lokale Kopien
  unsigned long _z2;

  noInterrupts();
     _z1 = Z1;
     _z2 = Z2;
     Z1 = 0;
     Z2 = 0;
  interrupts();
  if (_z2 != 0 && _z1 != 0){  // ? warum nicht ein oder ?
    unsigned long Z_Differenz = _z2 - _z1;  // braucht nicht global zu sein
    Serial.print("Z1: ");
    Serial.print(_z1);
    Serial.print("  Z2: ");
    Serial.print(_z2);
    Serial.print("   Z_Differenz: ");
    Serial.println(Z_Differenz);
  }
}

Falsche Verwendung von Interrupts

1.) Variablen die innerhalb und außerhalb von ISRs verwendet werden müssen als volatile deklariert sein
2.) Auf Multi-Byte Variablen muss man außerhalb von ISRs atomar (d.h. bei abgeschalteten Interrupts) zugreifen. Sonst können sie mittendrin verändert werden

Danke für die schnellen Antworten.
Jetzt tut es wie es soll :slight_smile: