Merkwürdiges Verhalten von Case / Switch

Hallo Kollegen,
ich bastel gerade an einem kleinen Tacho für mein Motorrad. Der grundliegende Code für den Tacho stammt nicht von mir und funktioniert auch einwandfrei. Allerdings wollte ich jetzt noch einen Taster integrieren, um die Anzeigen durchschalten zu können (Aktuelle Geschwindigkeit, Uhrzeit, Kilometerstand,....).
Und jetzt fangen die Probleme auch schon an. Ich lese den Taster ein und will dann über ein switch/case Konstrukt die verschiedenen Displayinhalte steuern.

Case 0 ist die Defaultansicht (Geschwindigkeit), die Ansichten in Case 1 und Case 2 haben derzeit nur Dummy-Inhalte.

Das dubiose ist - sobald ich in "Case 1" und "Case 2" irgendwelche Display-Anweisungen reinschreibe, ändert sich die Anzeige, die über Case 0 getriggert wird. Wenn ich die Inhalte von Case 1 und Case 2 auskommentiere, passt wieder alles.

Ich verstehe nicht, wie die Inhalte von Case1 und Case2 den Code aus Case0 beeinflussen können...
Über SerialPrint hab ich das ganze mal verfolgt - die Case-Schleifen werden korrekt abgearbeitet...

Auf dem angehängten Photo (ok.jpg) seht ihr die korrekte Anzeige. Sobald ich aber die Anweisungen in Case1 und Case2 einkommentiere, verschwindet die letzte Zeile ("Trip (km): .....")

Ich hoffe, ihr könnt mir folgen....

mfg
Basti

#include <RunningAverage.h>
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define OLED_RESET 4 // not used / nicht genutzt bei diesem Display
Adafruit_SSD1306 display(OLED_RESET);
RunningAverage myRA(100);
volatile unsigned long dauer = 0;             // microsekunden seit dem letzten Interrupt
volatile unsigned long last = 0;              // Zählerwert beim letzten Interrup
short geschwindigkeit;                         // selbstredend
short VAnzeige;
short wegstrecke;
const int buttonPin = 2;
const int reedPin = 3;
const int ledPin =  13;
int interruptCounter = 0;
int buttonState = 0;         // Tasterstatus
int anzeigeModus = 0;

static const unsigned char PROGMEM logo [] = {
};

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
  pinMode(ledPin, OUTPUT);  //interne LED an Pin13
  attachInterrupt(digitalPinToInterrupt(3), readmillis, RISING);
  myRA.clear();
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
 // display.drawBitmap(0, 0,  logo, 128, 64, 1);
  display.display();
  delay(1000);
}

void loop() {

      readButton();
      VAnzeige = myRA.getAverage(), 0;        // Mittelwert errechnen
      display.clearDisplay();                 
      display.setTextColor(WHITE);
      display.setTextSize(1);
      display.setCursor(0, 0);

switch (anzeigeModus) {
  case 0:
        display.print("Built, not bought...");
        display.setTextSize(4);
        display.setCursor(10, 12);
        display.print(VAnzeige);
        display.setTextSize(1);
        display.setCursor(10, 56);
        display.print(String("Trip (km):  ") + wegstrecke );
        myRA.clear();
  break;

  case 1:
        display.print("Anzeige 2");
  break;

    case 2:
       display.print("Anzeige 3");
    break;
}
      display.display(); 
      myRA.clear();                           // Mittelwertdaten löschen
      delay(250);                                 // Alle 1/4 Sekunde Werte aktualisieren, bis dahin über Interrupt Werte sammeln
}

void readmillis() {                           // Interrupt-Routine

  detachInterrupt(2);
  interruptCounter++;

  if (interruptCounter >537) {                //537 Radumdrehungen entsprechen einem km
    wegstrecke++;
    interruptCounter = 0;
  }

  unsigned long m = millis();                 // Microsekundenzähler auslesen
  unsigned long v = m - last;                 // Differenz zum letzten Durchlauf berechnen
  if (v > 5) {                                // ignorieren wenn <= 5ms (Kontaktpreller)
    dauer = v;                                // Wert in dauer übernehmen
    last = m;                                 // und wieder den letzten Wert merken
    geschwindigkeit = 1.86*3.6*1000/dauer;             // Geschwindigkeit: 1 Interrupt alle 1860mm (Radumfang)
    myRA.addValue(geschwindigkeit);           // Wert zur Mittelwerberechnung hinzufügen
  }
  attachInterrupt(digitalPinToInterrupt(2), readmillis, RISING);    // Interrupt wieder einschalten.
}


void readButton() { 
      buttonState = digitalRead(buttonPin);
      if (buttonState == LOW) { anzeigeModus++; }
      if (anzeigeModus > 2) { anzeigeModus= 0; }
  }

Du erlebst gerade, warum man keine Tastendrücke per "Interrupt" auswertet.

Und selbst, wenn das hier notwendig/sinnvoll wäre, fehlt dir offensichtlich die Übung mit "volatile" Daten, und mit dem "ATOMIC" Zugriff darauf.

So wie ich das sehe, soll der Taster gar nicht per Interrupt ausgelesen werden. Die Interruptroutine ist für die Ermittlung der Radumdrehungen/Geschwindigkeit.
Allerdings wird in der Interruptroutine der Interrupt de- und am Ende wieder aktiviert, was Unsinn ist, da während des Interrupts eh alle Interrupts gesperrt sind. Beim deaktivieren und aktivieren wird aber ein falscher Pin angegeben, nämlich der vom Taster, anstelle des reed-Schalters. Da kommen sich dann zwei Interrupts in die Quere.
Also einfach das detach und attach aus der Interruptroutine rausnehmen. Oder zumindest die richtige Pin verwenden - und zwar nicht direkt die Pinnummer, sondern den zugewiesenen Namen, also 'reedPin'. Dann fällt sowas auch eher auf, bzw. passiert erst garnicht.

P.S. das Auslesen des Tasters ist auch nicht optimal, da nicht die Flanke ausgewertet wird und der Taster nur alle 250ms abgefragt wird. Das ist etwas viel zum Entprellen. Wird der Taster zu lang oder zu kurz gedrückt, kommt es zu Fehlern. Entweder wird er gar nicht erkannt, oder als mehrfach Tastung.

P.P.S Der Inerruptroutine einen vernünftigen Namen zu geben, würde auch besser klarmachen wozu sie da ist...

BwieBertha:
Auf dem angehängten Photo (ok.jpg) seht ihr die korrekte Anzeige. Sobald ich aber die Anweisungen in Case1 und Case2 einkommentiere, verschwindet die letzte Zeile ("Trip (km): .....")

Genau diese Zeile kommt mir seltsam vor, mit der Summe aus einem String und einem short. Das würde ich jedenfalls sauberer trennen. Am besten auf String verzichten, das ist ein bekannter Stolperstein bei den kleinen Arduinos.

So wie ich das sehe, soll der Taster gar nicht per Interrupt ausgelesen werden.

Ja, das scheint mir jetzt auch so...

Beim deaktivieren und aktivieren wird aber ein falscher Pin angegeben, nämlich der vom Taster, anstelle des reed-Schalters

Das hat mich auf die falsche Fährte geschickt.

Aber auch Reed Kontakte prellen und sind damit für ISR Abhandlungen eher weniger geeignet.

Das mit "volatile" und "ATOMIC" behält natürlich seine Wichtigkeit, solange ISRs benutzt werden.

Danke für eure Antworten - sie sind alle berechtigt (werde ich heute abend gleich ändern).

Aber erklärt das das Verhalten auf dem Display / in den Switch-Case Anweisungen?

mfg
Basti

Hi

Wer löscht den Bildschirminhalt der in Case 0 gemacht wurde wenn Case 1 aufgerufen wird und setzt den Cursor an die gewünschte Position?

Du hast Recht, den Bildschirminhalt löscht derzeit noch "keiner". Allerdings tritt der Fehler auch auf, wenn der Taster noch nie gedrückt wurde / wenn "Case 0" nie verlassen wurde....
Insofern kann das eigentlich keine Rolle spielen.

Sooooo... Hab jetzt bißchen an dem Code rumgespielt, und das Ergebnis ist interessant :slight_smile:

Zuerst habe ich den kompletten Teil mit dem Interrupt testweise auskommentiert - danach hat die Anzeige funktioniert.

Anschließend hab ich den Interrupt Code wieder einkommentiert und oben den "String" aus der Display Zeile entfernt - danach hat die Anzeige auch fehlerfrei funktioniert.

Sind das evtl zwei unabhängige Fehler, die beide zum selben Symptom führen?

Bin verwirrt.... :slight_smile: