Objektverhalten nicht nachvollziehbar

Hallo in die Runde,

ich habe mal eine ganz dumme und komische Frage. Dazu erstmal den Programmcode, der vielleicht einiges erklärt.

/* Das ist die Klassendefinition für die Klasse der Taster.
*/
class Taster {

    /* Hier werden die ganzen privaten Variabeln der Klasse deklariert.
    */
  private:

    /* Das ist die Variabeln für den Anschluss.
    */
    byte AnschlussTaster;

    /* Das sind die Variabel, wo der Wert für den Taster abgespeicher wird.
    */
    boolean Taster;

    /* Das sind die Variabeln, wo der Status des Eingangs abgespeichert wird, um sie dann auswerten zu können.
    */
    boolean StatusTaster;

    /* Das sind die Variabeln, die benötigt werden, den Taster zu entprellen.
        Dabei wird sich die Zeit der ersten Änderung gemerkt und sich gemerkt, dass
        da eine Änderung stattgefunden hat. Um dann 20 Millisekund, die änderungsfrei
        verlaufen müssen abzuwarten, bevor der Taster als geändert definiert wird.
    */
    unsigned long ZeitTaster;
    byte AktivTaster;

    /* Das sind die Variabeln, die benötigt werden, um ausgeben zu könne, ob eine
        Änderung der entsprechenden Teile stattgefunden hat. Dazu wird der Wert von
        der letzten Abfrage gespeichert und dann immer mit der aktuelle verglichen
        und entsprechende die Aenderungs-Variabeln angepasst.
    */
    boolean AlterTaster;
    boolean AenderungTaster;

    /* Hier werden die ganzen öffentlichen Methoden der Klasse deklariert.
        Dabei werden die ersten beiden außerhalb definiert und alle anderen
        schon hier.
    */
  public:
    Taster(byte);
    void schleife (void);

    /* Mit diesen drei Methoden fragt man den Taster ab.
        Daher wird der Merker der zu letzt abgefragten Tasterwertes
        auf die jetztigen Wert gesetzt und die Aenderung verneint.
        Danach wird das abgefragte zurückgegeben.
    */
    boolean taster(void) {
      AlterTaster = Taster;
      AenderungTaster = LOW;
      return Taster;
    };

    /* Mit diser folgenden Methode kann man abfragen, ob
        sich bei dem Taster seit der letzten Abfrage etwas geändert hat,
    */
    boolean aenderungTaster(void) {
      return AenderungTaster;
    };

};


/* Das ist die "Geburtsmethode" für die Klasse. Dabei wird der Anschluss übergeben.
*/
Taster::Taster (byte NeuerAnschlussTaster) {

  /* Hier wird überprüft, ob die Werte für den Anschluss im Wertebereich der Anschlussnummerierung liegt.
     Falls nicht, wird ein bestimmte Anschlussnummer genommen. Und anschließen als Input definiert.
  */
  if (NeuerAnschlussTaster > 20 ) {
    AnschlussTaster = 7;
  }
  else {
    AnschlussTaster = NeuerAnschlussTaster;
  }
  pinMode(AnschlussTaster, INPUT);

  /* Hier werden sämtlichen Variabeln mit Startwerten belegt, damit sie einmal
      belegt sind und die Klasse von Anfang Werte dadrin hat und damit funktioniert.
  */
  StatusTaster = LOW;
  AlterTaster = StatusTaster ;
  AenderungTaster = LOW;
  ZeitTaster = millis();
  AktivTaster = LOW;
}


/* Das ist die Methode, die in jedem Schleifendurchlauf aufgerufen werden muss!
    Sie übernimmt nämlich sämtlichen "Verwaltungsaufwand" für so einen Taster.
*/
void Taster::schleife(void) {

  /* Hier werden die der Input eingelesen und dabei negiert, da die Outputs
      des des Taster in negativer Logik aufgebaut sind. Für mich war es aber
      einfacher mit positiver Logikt umzugehen, weshalb ich die beim Einlesen
      schon negiere und damit zu positiver Logik umwandle.
  */
  StatusTaster = !digitalRead(AnschlussTaster);

  /* Hier wird geschaut, ob sich die Variabel im Vergleich zu dem Wert bei der letzten Abfrage
      geändert hat. Falls, dann wird die entsprechende AenderungsVariabel geHIGHT,
      und wenn nicht geLOWt.
  */
  if (Taster != AlterTaster) {
    AenderungTaster = HIGH;
  }
  else {
    AenderungTaster = LOW;
  }

  /* Hier passiert das Eentprellen des Tasters. Dazu wird geschaut, ob
      der Eingang des Taster anders ist als dem Taster und ob gerade noch
      nicht gewartet wird. Falls es so ist, wird die aktuelle Zeit zuzüglich
      20 Millisekunden abgespeichert und die Flag gesetzt, dass gerade gewartet wird.
      Falls gewartet wird und der Eingang und der Taster wieder gleich sind.
      wird diese Flag entfernt und damit das Warten abgebrochen. Falls gewartet wird,
      die Zeit abgelaufen ist und weiterhin der Taster ungleich dem Eingang ist, wird
      der Eingang in den Taster geschrieben und die Flag fürs Warten entfernt.
  */
  if (StatusTaster != Taster && AktivTaster == LOW) {
    AktivTaster = HIGH;
    ZeitTaster = millis() + 20;
  }
  if (AktivTaster == HIGH && StatusTaster == Taster) {
    AktivTaster = LOW;
  }
  if (AktivTaster == HIGH && StatusTaster != Taster && millis() - ZeitTaster >= 0 && millis() - ZeitTaster <= 65536) {
    AktivTaster = LOW;
    Taster = StatusTaster;
  }
}



Taster Taste(3);


void setup() {
  Serial.begin(9600);
}

void loop() {
  Taste.schleife();
  if (Taste.aenderungTaster() and Taste.taster()) {
    Serial.println("Endlich!");
  }
  if ( Taste.taster()) {
    Serial.println("Schaue!");
  }
  delay(500);
}

Jetzt kommt die Sache das Problem zu erklären… Ich habe mir eine Klasse der Taster geschaffen. Innerhalb dieser Klasse gibt es für das Problem drei entscheidene Methoden und eine private Variable. Mit Hilfe der schleife() Methode, die regelmäßig aufgerufen werden muss(, damit es funktioniert), wir ein Taster “eingelesen” und entprellt. Mit der Methode taster() kann geschaut werden, welchen Status der Taster jetzt hat. Dabei wir dieser Status in die interne Variable AlterTaster abgespeichert. Mit Hilfe dieser Variable kann die Methode aenderungTaster() ausgeben ob sich der Status des Tasters seit der letzten Abfrage geändert hat. Dazu wird in der schleife() geschaut ob der aktuelle Status sich von AlterTaster unterscheidet, wenn ja, wird die interne Variable AenderungTaster HIGH gesetzt, sonst auf LOW. Die Methode taster() setzt diese Variable auch auch LOW. Das sollte als Einführung hoffentlich reichen. Jetzt kommt das komische Verhalten.
Wenn ich die loop() wie oben mache, dann ist es so, dass die Variable AlterTaster sofort den Wert des jetztigen Status des Tasters annimmt, obwohl das eigentlich nur mit Hilfe der Methode taster() passieren kann. Das führt dazu, dass die erste if() nach der schleife() niemals nach einem Tastendruck aktiv wird, da der Taster wenn er aus der schleife() rauskommt und in der schleife() der Tastendruck stattgefunden hat, “denkt”, dass keine Änderung stattgefunden hat.
Wenn ich jetzt die letzte if() weglasse, dann ändert sich die Variable AlterTaster erst durch den Aufruf taster() und damit klappt wieder der if() direkt nach der Schleife.
Meine Frage ist jetzt natürlich, warum die Methode taster() ohne das sie aufgerufen wird innerhalb der Methode schleife() die Variable AlterTaster ändert und wie man das verhindern kann.

Vielen Dank für die Hilfe!

Viele Grüße
HerrLixe

P.S.: Läuft bei mir auf einem Arduino Nano.

Hallo,

bevor du dich in der Klasse verzettelst, schreibe erstmal eine ganz normale Funktion für eine Tasterentprellung mittels millis. Wenn das klappt, schreibst dir eine Klasse. Deine Variablen zum Zeiten merken stimmen leider vorn und hinten nicht. Also die Art und Weise wie man einen Zeitenvergleich macht und sich die nächste Abfragezeit berechnet. Ohne Klammersetzung warnt auch der Compiler, weil er die Logik nicht aufdrösseln kann.

In der IDE alle Ausgaben einschalten.
Datei > Voreinstellungen >

  • Ausführliche Ausgabe während > beide Haken rein
  • Compilerwarnungen > "ALLE"
    Zeilennummern und Codefaltung sind auch hilfreich.
    Speichern beim Überprüfen und Hochladen würde ich abschalten.

Theseus erklärt millis()

GuntherB - BlinkwithoutDelay - Die Nachtwächtererklärung

Denke dabei einfach an deine Armbanduhr oder deine Smartphoneuhr die auch ewig läuft und aller 24h überläuft und man dennoch täglich irgendwelche Differenz Wartezeiten hinbekommt. Mag jetzt ein wenig hart klingen, aber ich schick dich erstmal zurück ans kleinere Reißbrett. :slight_smile: Da muss jeder Neuling durch der ohne delay auskommen möchte.

Ich stimme dem Doc_Arduino in weiten Teilen zu....

Habe allerdings große Schwierigkeiten deinen Code zu lesen.

Vorschlag:
Nenne alle Variablen, Methoden und Objekteigenschaften mit einem Kleinbuchstaben am Anfang.
Ausnahme, Konstruktor und Destruktor.

Zudem sind die Bedingungen arg viele und zu kompliziert für mich.
Da plädiere ich für eine Reduktion

Aber was solls.... alles nur subjektiv.

Klar, könnte ich dir auch meinen Entpreller zeigen...
Aber ob dir das aufs Pferd hilft?

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.