Zeit seit Statusänderung korrekt ausgeben

Hallo!

Ich versuche jetzt schon einige Zeit lang, ein - vermutlich triviales - Problem zu lösen, komme aber leider nicht weiter.

Die Aufgabe: Durch zwei bool-Variablen wird der Status erzeugt (es gibt nur drei Stati (?!?), aber für einen davon ist die Historie relevant, also sind es quasi vier). Es soll die Zeit gemessen werden, seit sich der Status geändert hat.

//// --- S E T U P ---
#define trig_A 5
#define trig_B 6

void setup() {
  Serial.begin(9600);
  pinMode(trig_A, INPUT);
  pinMode(trig_B, INPUT);
  digitalWrite(trig_A, HIGH);
  digitalWrite(trig_B, HIGH);
}
bool A_state;
bool B_state;
int state;
int state_prev;
unsigned int long state_time;

void level_state() {

  A_state = digitalRead(trig_A);   // Eingänge lesen und in Variablen schreiben
  B_state = digitalRead(trig_B);

  if (A_state == 0) {                    //Status ermitteln
    if (B_state == 0) {
      state = 2;        
    } else {
      state = 3;     
    }
  }else{
    if (B_state == 1) {
      state = 4;      
} else {
  state = 1;         
}
            
  if (state != state_prev) {    //Statusänderung prüfen, wenn ja:
    state_time = millis();      //jetzt: Startzeit
state_prev = state;             //flag ändern
  }
return;
}


void loop () {
  level_state();
  Serial.print(A_state);
  Serial.print("\t");
  Serial.print(B_state);
  Serial.print("\t");
  Serial.print(state);
  Serial.print("\t");
  Serial.print(state_prev);
  Serial.print("\t");
  Serial.print(state_time/1000);
  Serial.print("\t");
  Serial.print((millis() - state_time) / 1000);
  Serial.println("");
  delay(500);
}

Die Auswertung und Statusbestimmung klappt, die Bestimmung der Startzeit nur teilweise: Der Wechsel von oder nach Status 2 z.B. hat überhaupt keine Auswirkung, nach dem Wechsel von 3 nach 4 wird hingegen korrekt die Zeit neu gestartet. Das verwirrt mich, weil ich nicht sehe, wo der Grund dafür liegen könnte dass es mal klappt und mal nicht. Hat jemand hier einen Tipp für mich?

Hallo,

mit Verlaub, dass da oben kann noch nie funktioniert haben. Es kompiliert nicht. Ich sehe auch nicht das du dir irgendeine Zeit von einem Zustand merkst. Du merkst dir maximal den Wechsel von irgendeinem Zustand aber nicht genau von welchem zu welchem. Auch empfehle ich dir für solche Dinge switch case statt if else.

Mein Grundgerüst würde so aussehen. Die Taster entprellen musste auch noch wenn du das delay rausnimmst. In den case Vergleichen kannste dir die jeweilige Zeit merken die dich interessiert und ggf. zum nächsten wechseln. Am Ende würde ich den Zustandsmerker state und Taster states lokal machen und nicht global.

bool A_state;
bool B_state;
byte state;
byte state_prev;
unsigned long state_time;

const byte trig_A = 5;
const byte trig_B = 6;


void setup() {
  Serial.begin(9600);
  pinMode(trig_A, INPUT_PULLUP);
  pinMode(trig_B, INPUT_PULLUP);
}


void loop ()
{
  level_state();
  
  Serial.print(A_state);
  Serial.print("\t");
  Serial.print(B_state);
  Serial.print("\t");
  Serial.print(state);
  Serial.print("\t");
  Serial.print(state_prev);
  Serial.print("\t");
  Serial.print(state_time/1000);
  Serial.print("\t");
  Serial.print((millis() - state_time) / 1000);
  Serial.println("");
  
  delay(500);
}


void level_state() {

  A_state = digitalRead(trig_A);   // Eingänge lesen und in Variablen schreiben
  B_state = digitalRead(trig_B);

  // Logiktabelle
  if (!A_state & !B_state) state = 0;
  if (!A_state &  B_state) state = 1;
  if ( A_state & !B_state) state = 2;
  if ( A_state &  B_state) state = 3;

  
  switch (state) {
    case 0:
            break;
    case 1:
            break;
    case 2:
            break;
    case 3:
            break;
    default:
            break;            
  }
}

Doc_Arduino:
Hallo,

mit Verlaub, dass da oben kann noch nie funktioniert haben. Es kompiliert nicht.

Du hast Recht, entschuldige. Beim Kopieren ist eine Klammer vor loop () abhanden gekommen.

Doc_Arduino:
Ich sehe auch nicht das du dir irgendeine Zeit von einem Zustand merkst. Du merkst dir maximal den Wechsel von irgendeinem Zustand aber nicht genau von welchem zu welchem.

Der Zeitpunkt des Wechsels ist aber das, was ich haben möchte. Teilweise funktioniert es ja auch, nur eben nicht in allen Fällen.

Doc_Arduino:
Auch empfehle ich dir für solche Dinge switch case statt if else.

Vielen Dank, ich werde es morgen damit mal versuchen!

Hallo,

dann ist vielleicht die Aufgabenstellung unvollständig formuliert. Für einen bestimmten Status möchtest du die Historie haben, also die vergangene Zeit. Das klappt aber nicht wenn du deinen einen Zeitmerker mit allen Statuswechsel überschreibst. Entweder aktualisierst du diesen einen nur bei einem bestimmten Wechsel in dem entsprechenden case oder du merkst dir von allen 4 Zustandswechsel den individuellen Zeitpunkt. Wenn dich nur einer interessiert darfste nicht alle abhandeln.

Doc_Arduino:
Hallo,

dann ist vielleicht die Aufgabenstellung unvollständig formuliert. Für einen bestimmten Status möchtest du die Historie haben, also die vergangene Zeit. Das klappt aber nicht wenn du deinen einen Zeitmerker mit allen Statuswechsel überschreibst. Entweder aktualisierst du diesen einen nur bei einem bestimmten Wechsel in dem entsprechenden case oder du merkst dir von allen 4 Zustandswechsel den individuellen Zeitpunkt. Wenn dich nur einer interessiert darfste nicht alle abhandeln.

Da habe ich mich wohl wirklich falsch ausgedrückt: Es geht mir nur um den Startzeitpunkt des aktuellen Staus, also um den Zeitpunkt des letzten Statuswechsels, egal von welchem zu welchem.

Hallo,

aha, doch jeden Wechsel. Der Fehler in deinem Sketch liegt in der Statusauswertung. Das if else Konstrukt ist fehlerhaft.
Die Logiktabelle ist denke ich einfacher zuverstehen.
Nun denn, habe mir erlaubt alles umzubauen.
Wenn du die seriellen Ausgaben zum debuggen nicht mehr benötigst, dann mach bitte alle denkbaren Variablen lokal statt global. Das reduziert die Fehleranfälligkeit enorm.

// https://forum.arduino.cc/index.php?topic=570080.0

bool A_state;
bool B_state;
byte state;
byte state_prev;
unsigned long state_time;

const byte trig_A = 5;
const byte trig_B = 6;


void setup() {
  Serial.begin(9600);
  pinMode(trig_A, INPUT_PULLUP);
  pinMode(trig_B, INPUT_PULLUP);
}


void loop ()
{
  level_state();

  serieller_Monitor();
}


void level_state() {                              // Tasterauswertung

  static unsigned long last_millis = 0;
  const byte INTERVAL = 40;

  if (millis() - last_millis < INTERVAL) return;  // Zeit noch nicht erreicht, Funktion abbrechen
  last_millis += INTERVAL;
    
  A_state = digitalRead(trig_A);   // Eingänge lesen und in Variablen schreiben
  B_state = digitalRead(trig_B);

  // Logiktabelle
  if ( A_state &  B_state) state = 0;   // nichts gedrückt
  if (!A_state &  B_state) state = 1;   // A gedrückt
  if ( A_state & !B_state) state = 2;   // B gedrückt
  if (!A_state & !B_state) state = 3;   // A & B gedrückt

  if (state != state_prev) {
    state_time = millis();
    state_prev = state;
  }
}


void serieller_Monitor ()
{ 
  static unsigned long last_millis = 0;
  const unsigned int INTERVAL = 500;

  if (millis() - last_millis < INTERVAL) return;  // Zeit noch nicht erreicht, Funktion abbrechen
  last_millis += INTERVAL;
  
  Serial.print(A_state);          Serial.print('\t');
  Serial.print(B_state);          Serial.print('\t');
  Serial.print(state);            Serial.print('\t');
  Serial.print(state_prev);       Serial.print('\t');
  Serial.print(state_time/1000);  Serial.print('\t');
  Serial.print((millis() - state_time) / 1000);
  Serial.println("");
}

Hi

Die Mehrzahl von Status ist ebenfalls Status - nur, daß Das Mal gehört wurde (und oben ein/zwei Fragezeichen ersichtlich waren).

Wenn 'nur' die Zeit seit dem letzten Statuswechsel benötigt wird, reicht die eine Zeit-Variable.
Allerdings denke ich, daß die Ausgabe der ganzen Texte das Ergebnis schon verfälschen kann, da sich auch während der Ausgabe millis() verändert - mit 9600 Baud (Bits pro Sekunde) pro Zeichen ~ 1ms.
Also sollte man zumindest vor der Ausgabe eine 'Referenz-Zeit' ermitteln und damit die Berechnungen durchführen.

MfG

Doc_Arduino:
Hallo,

aha, doch jeden Wechsel. Der Fehler in deinem Sketch liegt in der Statusauswertung. Das if else Konstrukt ist fehlerhaft.
Die Logiktabelle ist denke ich einfacher zuverstehen.
Nun denn, habe mir erlaubt alles umzubauen.
Wenn du die seriellen Ausgaben zum debuggen nicht mehr benötigst, dann mach bitte alle denkbaren Variablen lokal statt global. Das reduziert die Fehleranfälligkeit enorm.

Super, vielen Dank! Da bin ich gestern echt nicht mehr drauf gekommen, obwohl es ja irgendwie offensichtlich ist, daß das das Problem war, wenn es mal funktioniert und mal nicht … Naja, wieder was gelernt. Und danke auch für den Hinweis auf die Lokalität! Das sind so Feinheiten im sauberen Programmieren die ich noch nicht drauf habe.

postmaster-ino:
Hi

Die Mehrzahl von Status ist ebenfalls Status - nur, daß Das Mal gehört wurde (und oben ein/zwei Fragezeichen ersichtlich waren).

Top, dankeschön! :slight_smile:

Allerdings denke ich, daß die Ausgabe der ganzen Texte das Ergebnis schon verfälschen kann, da sich auch während der Ausgabe millis() verändert - mit 9600 Baud (Bits pro Sekunde) pro Zeichen ~ 1ms.

Ich brauche für die Anwendung keine Genauigkeit < 1s, insofern versuche ich es erst ein Mal so und schaue dann, wie schnell das komplette Programm ist.