Go Down

Topic: Interrupt-Routine wird fälschlich aufgerufen (bei jedem Aufstart) (Read 635 times) previous topic - next topic

BwieBertha

Hallo Kollegen,
ich arbeite gerade an einem Motorrad-tacho, und das ist schon mein x-ter Post hier.. aber ich stoße täglich auf neue Probleme :)

ich lese einen eine Reedschalter per Interrupt ein und berechne daraus die Geschwindigkeit.

Komischerweise wird die damit verknüpfte Interrupt-Routine aber bei jedem Aufstart des Arduinos  aufgerufen (Konkret erscheint bei jedem Boot des Arduinos die Serielle Ausgabe "UmdrehungErkannt") - ohne dass der Reedschalter überhaupt betätigt wurde.

Was mache ich falsch?

Anbei mein (stark gekürzter, aber compilierender) Code:

Code: [Select]

#include <EEPROM.h>
#include <RunningAverage.h>
#include <Wire.h>
#include "OneButton.h"
#include <U8g2lib.h>
#include "RTClib.h"

U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE, /* clock=*/ 16, /* data=*/ 17);   // ESP32 Thing, HW I2C with pin remapping
RTC_DS3231 rtc;


const uint16_t Prellzeit = 100; // in ms
volatile uint32_t lastMillis = 0;
RunningAverage myRA(5);
volatile unsigned long dauer = 0;
short geschwindigkeit;                         
short VAnzeige;
const int buttonPin = 4;
const int reedPin = 3;
int screen = 0;
volatile int RotationCounter = 0;
OneButton button(buttonPin, true);
char Minute[3];
char Stunde[3];
const int RadUmfang = 1862;
// char Uhrzeit[10];
char Temperatur[15];
char Speed[10];
float dummyInterval = (RadUmfang/1000.0 * 161.0);

long GesamtMeter;
long TripMillimeter;
int GesamtMeter_ADDR = 0;
int TripMillimeter_ADDR = GesamtMeter_ADDR + 4;
char TripKm[10];
char GesamtKm[10];
int testMeter = 0;
boolean reset = false;
boolean eineUmdrehung = false;


   
void setup()   {
  Serial.begin(9600);      // open the serial port at 9600 bps:
  pinMode(reedPin, INPUT_PULLUP); // Reed-Sensor an Pin 3
  pinMode(buttonPin, INPUT_PULLUP); // Taster an Pin 2
  attachInterrupt(digitalPinToInterrupt(reedPin), readmillis, RISING);
  myRA.clear();
  delay(500); 
}

void loop() { 
  button.tick();
  if (eineUmdrehung && (millis() - lastMillis >= Prellzeit)) {      //Geschwindigkeit berechnen
       dauer = millis() - lastMillis;                                // Dauer einer Radumdrehung in ms
       lastMillis = millis();                               
       geschwindigkeit = RadUmfang*3.6/dauer;           // Geschwindigkeit: 1 Interrupt alle 1861mm (Radumfang)
       myRA.addValue(geschwindigkeit);                 // Wert zur Mittelwerberechnung hinzufügen
       TripMillimeter += RadUmfang;                    //pro Umdrehung 1861mm gefahren
       RotationCounter += 1;
       eineUmdrehung = false;
  }

  if (millis()-lastMillis >= 2000) {
    myRA.clear();                       //wenn keine Radumdrehung innerhalb von 2 Sek stattgefunden hat --> Geschwindigkeit nullen
  }       
  VAnzeige = myRA.getAverage();        // Mittelwert errechnen
}

void readmillis() {
  eineUmdrehung = true; 
  Serial.println("UmdrehungErkannt");
  }


Serenifly

Serial hat in Interrupts so oder so nichts zu suchen

Und wenn du sowieso generell mit millis() arbeitest, bräuchte man auch den Interrupt nicht unbedingt

BwieBertha

Serial.println hab ich nur eingebaut um das Problem zu verdeutlichen.

Aber wieso wird die Routine nun doppelt aufgerufen?

anwofis

@BwieBertha:

Was für ein Netzteil verwendest du? Schlechte PSUs können alle möglichen Probleme verursachen.
Vllt. musst du deinen Schalter noch entprellen?

BwieBertha

Der arduino nano wird per USB meines macbooks gespeist.
Selbst wenn garkein schalter angeschlossen ist tritt dieses Verhalten auf....

anwofis

@BwieBertha:


Hab' deinen Code (etwas geändert) auf einen Original-Uno geladen und ich kann dein Problem nicht replizieren:

Code: [Select]

#include <EEPROM.h>
#include <RunningAverage.h>
#include <Wire.h>
#include "OneButton.h"
#include <U8g2lib.h>
#include "RTClib.h"

U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE, /* clock=*/ 16, /* data=*/ 17);   // ESP32 Thing, HW I2C with pin remapping
RTC_DS3231 rtc;


const uint16_t Prellzeit = 100; // in ms
uint32_t lastMillis = 0;
uint32_t lastMillis2 = 0;
volatile uint32_t number_of_revs =0;
RunningAverage myRA(5);
volatile unsigned long dauer = 0;
short geschwindigkeit;
short VAnzeige;
const int buttonPin = 4;
const int reedPin = 3;
int screen = 0;
volatile int RotationCounter = 0;
OneButton button(buttonPin, true);
char Minute[3];
char Stunde[3];
const int RadUmfang = 1862;
// char Uhrzeit[10];
char Temperatur[15];
char Speed[10];
float dummyInterval = (RadUmfang / 1000.0 * 161.0);

long GesamtMeter;
long TripMillimeter;
int GesamtMeter_ADDR = 0;
int TripMillimeter_ADDR = GesamtMeter_ADDR + 4;
char TripKm[10];
char GesamtKm[10];
int testMeter = 0;
boolean reset = false;
boolean eineUmdrehung = false;



void setup()   {
  Serial.begin(9600);      // open the serial port at 9600 bps:
 
  while(!Serial);
 
  pinMode(reedPin, INPUT_PULLUP); // Reed-Sensor an Pin 3
  pinMode(buttonPin, INPUT_PULLUP); // Taster an Pin 2
  attachInterrupt(digitalPinToInterrupt(reedPin), readmillis, RISING);
 
  myRA.clear();
 
  delay(500);
}

void loop() {


  button.tick();
  if (eineUmdrehung && (millis() - lastMillis >= Prellzeit)) {      //Geschwindigkeit berechnen
    dauer = millis() - lastMillis;                                // Dauer einer Radumdrehung in ms
    lastMillis = millis();
    geschwindigkeit = RadUmfang * 3.6 / dauer;       // Geschwindigkeit: 1 Interrupt alle 1861mm (Radumfang)
    myRA.addValue(geschwindigkeit);                 // Wert zur Mittelwerberechnung hinzufügen
    TripMillimeter += RadUmfang;                    //pro Umdrehung 1861mm gefahren
    RotationCounter += 1;
    eineUmdrehung = false;
    Serial.println("Umdrehung erkannt");
  }

  if (millis() - lastMillis2 >= 2000) {
    myRA.clear();                       //wenn keine Radumdrehung innerhalb von 2 Sek stattgefunden hat --> Geschwindigkeit nullen
    Serial.print(number_of_revs);
    Serial.println(" Keep alive!");
    lastMillis2 = millis();
  }
  VAnzeige = myRA.getAverage();        // Mittelwert errechnen
}

void readmillis() {
  eineUmdrehung = true;
  number_of_revs++;
}



Erst wenn ich den Pin 3 mit GND verbinde, wird eine Umdrehung erkannt. Vllt. spinnt dein Nano?

BwieBertha

Das wäre natürlich möglich, aber ist das plausibel? Bzw treten solche HW Defekte hinreichend oft auf?

Mfg!

postmaster-ino

Hi

Es ist durchaus ausreichend, wenn dieser Defekt genau 1x bei Dir austritt.

Davon abgesehen - mit 1,872m Radumfang und maximal 10 Umdrehungen die Sekunde (Entprellzeit 100ms !!) sind wir bei knapp über 60km/h - für einen Roller ausreichend, sofern es nicht steil bergab geht ;)

Wie ist das Kabel verlegt vom Reed-Schalter zum Arduino?
Hast Du diese Störung IMMER, oder nur unter bestimmten Umständen?
Alternativ ignorierst Du die ersten 3 Sekunden jede Radumdrehung - vll. nicht die eleganteste Art, dieses Problem anzugehen, aber immerhin.

MfG
anscheinend ist Es nicht erwünscht, einen Foren-internen Link als 'Homepage' einzubinden, damit JEDER nur einen Klick von combie's Liste zum Thema State-Maschine entfernt ist.
... dann eben nicht ...

BwieBertha

Der tacho ist für ein Motorrad bestimmt, also reden wir hier von maximal 220kmh.

Der Fehler tritt bei jedem aufstart auf (und auch nur da).... Auch wenn der reed Schalter nicht angeschlossen ist

anwofis

@BwieBertha:

Geht's denn auch mit meinem Code nicht?

Vllt. den Reed-Schalter durch einen Hall-Sensor ersetzen, dann müßtest du vermutlich nicht entprellen.

BwieBertha

Ja, mit deinem Code tritt das Problem auch auf (siehe Screenshot).

Ich denke nicht, dass das Entprellen mein Problem versacht / lösen würde.

Im Grunde genommen hab ich zur Laufzeit auch kein Problem - mir ist nur schleierhaft, wieso die ISR zu Programmstart einmal aufgerufen wird...

Edit:
Selbst dieser Minimal-Sketch triggert die ISR "ohne Grund".
Vermutlich muss ichmir doch mal einen austausch-Nano organisieren.. .dazu komme ich aber erst nächste Woche :(
Code: [Select]

const int reedPin = 3;
boolean eineUmdrehung = false;

void setup()   {
  Serial.begin(9600);      // open the serial port at 9600 bps:
  while(!Serial);
 
  pinMode(reedPin, INPUT_PULLUP); // Reed-Sensor an Pin 3
  attachInterrupt(digitalPinToInterrupt(reedPin), readmillis, RISING);
}

void loop() {
}

void readmillis() {
    Serial.println("Umdrehung erkannt");
}

postmaster-ino

Hi

Wirkt irgend etwas an dem Reed-Schalter als Kondensator, was sich erst aufladen muß?
Wenn Du den Arduino im Sekundentakt resettest (also immer, wenn Er gerade angesprungen ist) - wird JEDES Mal diese Erkennung gezeigt?
Wie gesagt, das Serial.print in der ISR ist - äh - unglücklich.
Es würde reichen, wenn Du in der loop() darauf reagierst (wird keine ms später der Fall sein).
Davon abgesehen - mit der ganzen Prellerei werden Dir die Interrupts nur so um die Ohren pfeifen - da bleibt kaum noch Zeit für die Display-Ausgabe.
Du musst Dir ja in der ISR 'merken', daß Du gerade den Reed gelesen hast.
Während Deiner Prellzeit werden wohl weitere Aufrufe ignoriert (Prellzeit auf max 25ms, sonst kommst Du nicht auf Deine 220km/h).
Ich würde Dir aber ebenfalls zu einem Hall-Sensor raten - Der prellt nicht, gibt Dir also ein sauberes 'Magnet da' oder 'Magnet nicht da' zurück - gibt's als Bi-polar mit Latch, Den kannst Du mit einer Magnetseite 'Setzen' und mit der Anderen 'Rücksetzen' - vll. zwei Magnete ans Vorderrad und mit super sauberen Halbumdrehungen rechnen.
Diese müsstest Du auch fast pollen können - 12ms bei Maximal-Geschwindigkeit für den Wechsel High-Low oder umgekehrt.

MfG
anscheinend ist Es nicht erwünscht, einen Foren-internen Link als 'Homepage' einzubinden, damit JEDER nur einen Klick von combie's Liste zum Thema State-Maschine entfernt ist.
... dann eben nicht ...

BwieBertha

Danke für die Tips - ich lass das mal sacken.

Bzgl. Kondensator etc: Der nano zeigt dieses Verhalten auch ohne jegliche Peripherie - also nur Nano mit USB-Kabel.. .

Vermutlich hat der echt ne Macke :(

postmaster-ino

Hi

Wenn Du den Sensor an einen anderen Pin packst?
Man muß ja nicht jeden defekten Pin benutzen ;)
(oder zur Not eine Blink-LED als Heart-Beat anbrömmeln - INTERVALL.h einbinden - lässt sich hier irgendwo im Forum finden)

PCINT-fähig sind mehrere Pins, auf eine geforderte Flanke sind's glaube nur 2 und 3 - wäre hier die alternativ-Auswahl dann die 3.

Wie geschrieben, würde ich Das wohl pollen, gerade bei der Prellerei wird der µC so laufend in die ISR springen (deshalb MUSS Diese auch so kurz wie möglich sein!!).
Variablen, Die auch in der ISR verändert (oder gar auch bei Verwendung ?? Bitte Erleuchtung hierzu) werden, als VOLATILE deklarieren - sonst bekommst die loop() davon nicht viel mit.

MfG
anscheinend ist Es nicht erwünscht, einen Foren-internen Link als 'Homepage' einzubinden, damit JEDER nur einen Klick von combie's Liste zum Thema State-Maschine entfernt ist.
... dann eben nicht ...

BwieBertha

Ich hab den Interrupt-Pin auch schon von 3 auf 2 geändert (komplett ohne jegliche angeschlossene Peripherie), aber das Verhalten ist dasselbe. Mittlerweile kann ich mir das auch nur noch durch eine HW-Macke erklären.

Mein Reed-Sensor hat laut Datenblatt eine maximale Prellzeit von 5ms - das sollte also nicht in eine endlose "Prellerei" ausarten. Nichtsdestotrotz werde ich mir die Variante mit Hall-Sensor mal anschauen (obwohl die Bauform hier vermutlich deutlich unattraktiver ist als bei einem Reedswitch).

mfg

Go Up