PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Bit in einer Variable löschen geht nicht



Mitch64
10.07.2017, 10:10
Hallo
ich habe ein kleines Problem bei einem Bit löschen in einer Bytevariable, die in einer Klasse definiert ist. Ich verwende GCC in verbindung mit Arduino.

Also ich habe eine Klasse geschrieben namens StateMachine. Diese wird im Hauptprogramm von Arduino in der Objekt-Variable Machine instanziert.
Die Klasse enthält unter anderem eine Routine setState(), in der der der Zustand der Maschine gesetzt wird. In der Routine wird zusätzlich ein Flag gesetzt, welches anzeigt, dass sich der Zustand geändert hat.
Eine Andere Routine stateChanged() liefert einen Booleanwert, ob das Flag gesetzt oder gelöscht ist. Weiterhin löscht diese Routine das Flag wieder, welches anzeigt, dass sich der Zustand geändert hat.

Das Setzen des Flags funktioniert wunderbar, das löschen jedoch nicht.

Hier die beiden Routinen:


/*
* Setzt den gewünschten Zustand der Statemaschine
* Zusätzlich wird Flag STATE_CHANGED gesetzt, um zu ermitteln, ob der Zustand sich geändert hat.
*/
void StateMachine::setState(tagStates newState)
{
currentState = newState; // Zustand setzen
mFlags |= (1<<STATE_CHANGED); // Flag setzen, dass Zustand geändert wurde
}



und die Flagabfrage


/*
* Gibt den Status des Flags STATE_CHANGED zurück und löscht das Flag
*/
boolean StateMachine::stateChanged()
{
return boolean(mFlags and STATE_CHANGED); // Flag zurück geben
mFlags &= ~(1<<STATE_CHANGED); // Flag löschen, dass Zustand geändert wurde
}



hier noch die Header-Datei:

#ifndef statemachine_h
#define statemachine_h

#include <Arduino.h>

/*
* Enumeration mit den zulässigen Maschinen-Zuständen
*/
enum tagStates // Zustände der Statemachine
{
STATE_MAIN=0,
STATE_1
};

/*
* Klasse StateMachine
*/
class StateMachine
{
public:

void setState(tagStates newState); // State setzen
enum tagStates getState(); // State abrufen
boolean stateChanged(); // State-Flag STATE_CHANGED prüfen
byte getMFlags(); // MaschineFlags abrufen

private:
enum tagStates currentState; // Variable nimmt aktuellen Maschinen-Zustand auf
byte mFlags=0; // Diverse Flags innerhalb der Zustands-Maschine
byte const STATE_CHANGED=7; // Flag-Definition (Bit-Nr)

};

#endif // statemachine_h



In der Hauptschleife habe ich im Augenblick folgenden Code:


// ------------------------------------
// Hauptschleife
// ------------------------------------
void loop() {
// put your main code here, to run repeatedly:

Serial.println(Machine.getMFlags());

switch (Machine.getState())
{
case STATE_MAIN:
if (Machine.stateChanged()!=0)
{
Serial.println("Zustand in STATE_MAIN geändert");

delay(1000);
}
else
{
Serial.println("Zustand STATE_MAIN stabil!");
delay(1000);
}
break;
}
}

Kann mir jemand sagen was ich falsch mache? Wieso kann ich das Bit STATE_CHANGED in der privaten Variable MFlags nicht löschen?
Auch wenn ich in stateChanged() MFlags=0 angebe, wird das Flag nicht gelöscht.
Stehe ich auf dem Schlauch?

Micha.

Peter(TOO)
10.07.2017, 10:30
Hallo Micha,


/*
* Gibt den Status des Flags STATE_CHANGED zurück und löscht das Flag
*/
boolean StateMachine::stateChanged()
{
return boolean(mFlags and STATE_CHANGED); // Flag zurück geben
mFlags &= ~(1<<STATE_CHANGED); // Flag löschen, dass Zustand geändert wurde
}


Tja, der Wald und die Bäume.

Die Zeile nach dem return wird nie ausgeführt!

MfG Peter(TOO)

Mitch64
10.07.2017, 10:49
Ja, jetzt wo du es sagst.
Logisch!

Danke

Peter(TOO)
10.07.2017, 11:54
Grundsätzlich hat es sich bewährt den Compiler auf maximale Empfindlichkeit bei Warnungen einzustellen.
Hier hätte der Compile gewarnt, dass unerreichbarer Code existiert.

Manchmal gibt es Situationen, welche nur so gelöst werden können, dass dann der Compiler meckert.
Hier hat es sich bewährt mit "#pragma warn" vor der gewollten Stelle die spezifische Warnung aus- und danach wieder einzuschalten.
Als netter Nebeneffekt ist dann aber auch dokumentiert, dass der Programmierer dies an dieser Stelle gewollt so gemacht hat.

Vor 20-30 Jahren lieferten C-Compiler fast nur die groben Fehler. Damals hatte man ein spezielles Programm "lint", welches dann Unsauberkeiten gesucht hat. Heute ist "lint" fest im Compiler enthalten.

MfG Peter(TOO)

Holomino
10.07.2017, 12:13
Was ist denn der "and"-Ausdruck in
return boolean(mFlags and STATE_CHANGED);

Ist das 'nen Macro?
Oder eine weitere potentielle Fehlerquelle (weiter oben beim Setzen wird ja geschoben)?

Mitch64
10.07.2017, 12:27
Cooler Tip!
Habs in Ardiono gerade mal eingeschaltet und tatsächlich.

Der hat sogar gemerkt, dass ich eine Enumeration verwende mit 2 Werten, davon aber nur eine in der switch Abfrage verwendet wird.

Übrigens ich habs jetzt so gelöst:

/*
* Gibt den Status des Flags STATE_CHANGED zurück und löscht das Flag
*/
boolean StateMachine::stateChanged()
{
byte ergebnis = boolean(mFlags and STATE_CHANGED); // Flag zurück geben
mFlags &= ~(1<<STATE_CHANGED); // Flag löschen, dass Zustand geändert wurde
return ergebnis;
}



Noch ne kurze Frage wenn du schon dran bist.

In einer Klassendefinition, wo legt man da genau eine Enumerations-Struktur an, die außerhalb der Klasse auch als Rückgabewert und/oder als Übergabewert dient?

Ich habe versucht das:



/*
* Enumeration mit den zulässigen Maschinen-Zuständen
*/
enum tagStates // Zustände der Statemachine
{
STATE_MAIN=0,
STATE_1
};


im Header StateMachine.h im Bereich 'public:' anzugeben.
Beim Aufruf der Funktionen kam jedoch immer die Fehlermeldung, dass der Typ nicht bekannt sei.
Wo legt man also in einer Klasse die Enumeration an?
Vor der Klasse, so wie ich es ganz oben gezeigt habe in StateMachine.h?

Micha

- - - Aktualisiert - - -

das 'and' sollte eigentlich ein bitweiser UND-Vergleich sein. Habs in && geändert.
Ja und das mit dem Schieben, haste recht.
Als ich den Fehler suchte hab ich rumprobiert, und die Stelle vergessen zu ändern.

jetzt siehts so aus:


#include "StateMachine.h"

/*
* Setzt den gewünschten Zustand der Statemaschine
* Zusätzlich wird Flag STATE_CHANGED gesetzt, um zu ermitteln, ob der Zustand sich geändert hat.
*/
void StateMachine::setState(tagStates newState)
{
currentState = newState; // Zustand setzen
mFlags |= (1<<STATE_CHANGED); // Flag setzen, dass Zustand geändert wurde
}


/*
* Gibt den aktuellen Zustand der Statemachine zurück
*/
enum tagStates StateMachine::getState()
{
return currentState;
}

/*
* Gibt den Status des Flags STATE_CHANGED zurück und löscht das Flag
*/
boolean StateMachine::stateChanged()
{
byte ergebnis = boolean(mFlags && (1<<STATE_CHANGED)); // Flag zurück geben
mFlags &= ~(1<<STATE_CHANGED); // Flag löschen, dass Zustand geändert wurde
return ergebnis;
}