Go Down

Topic: booleans in byte speichern (Read 488 times) previous topic - next topic

Chris72622

Nov 21, 2013, 04:34 pm Last Edit: Nov 21, 2013, 04:50 pm by Chris72622 Reason: 1
Hallo,

ich würde gerne mehrere Boolean-Variablen (?) in einem Byte speichern.

Code: [Select]
boolean t1_st;
boolean t2_st;
boolean t3_st;
boolean t4_st;
boolean t5_st;
boolean fz_st;

byte t_st = (t1_st << 0 | t2_st << 1 | t3_st << 2 | t4_st << 3 | t5_st << 4 | fz_st << 5);


In den einzelnen "Booleans" speichere ich Tastzustände.

Wenn nun Taster 2, 5 und fz gedrückt sind, soll byte t_st so lauten:

Code: [Select]
t_st == B00110010

Momentan scheint dies jedoch noch nicht zu funktionieren, weil sich der jeweilige buttonstate nicht selbständig in t_st schreibt und ich nicht weiss, wie ich dies bewerkstelligen könnte. Auszug (für eine Taste):

Code: [Select]
void t_de_st()
{
  t1_old_st = t1_st;  // 3. "neuen Status" speichern

  t1_Bouncer.update ( );  // 1. Entprellten Zustand "erfragen"

  t1_st = t1_Bouncer.read();  // 2. Tastenstatus aktualisieren

  if (t1_st != t1_old_st)                               
  {                         
    if (t1_st)                                       
    {
      Serial.println("\t\t\t\t\t\tTaste 1 wurde gedrueckt");
      t_hold_time = millis();
    }
    else if (!t1_st)
    {
      Serial.println("\t\t\t\t\t\tTaste 1 wurde losgelassen");
      t_hold_st--;
    }
  }
}


Gruß Chris
https://github.com/jeffThompson/DarkArduinoTheme

Serenifly

#1
Nov 21, 2013, 05:00 pm Last Edit: Nov 21, 2013, 09:01 pm by Serenifly Reason: 1
Funktioniert bei mir in Visual C++

Code: [Select]

bool t1_st = true;
bool t2_st = true;
bool t3_st = false;
bool t4_st = false;
bool t5_st = true;
bool fz_st = false;

unsigned char t_st = (t1_st << 0 | t2_st << 1 | t3_st << 2 | t4_st << 3 | t5_st << 4 | fz_st << 5);

cout << bitset<8>(t_st) << endl;


Ausgabe: 00010011

Ist wie gesagt C++/.NET und läuft so nicht auf dem Arduino, aber ich habe nur die Datentypen und die Ausgabe angepasst.


Was auch geht ist das:
Code: [Select]

struct bitfield
{
unsigned char t1_st : 1;
unsigned char t2_st : 1;
unsigned char t3_st : 1;
unsigned char t4_st : 1;
unsigned char t5_st : 1;
unsigned char fz_st : 1;
};

union memory
{
unsigned char asByte;
struct bitfield asBits;
};

memory bits;
bits.asByte = 0;
bits.asBits.t1_st = true;
bits.asBits.t3_st = true;


Ausgabe: 000000101

Die Union hat den Vorteil, dass wenn man auf das Bitfeld zugreift sich automatisch die Variable "asByte" ändern. Also ist eine extra Zuweisung nicht mehr nötig

Chris72622

Fehler (vermutlich) gefunden:

Die Zeile..

Code: [Select]
t_st = (t1_st << 0 | t2_st << 1 | t3_st << 2 | t4_st << 3 | t5_st << 4 | fz_st << 5);

..muss ja nach jeder Tastenabfrage erneut erfolgen. Dies hatte ich vergessen. Ich hatte nur einmalig..

Code: [Select]
byte t_st = (t1_st << 0 | t2_st << 1 | t3_st << 2 | t4_st << 3 | t5_st << 4 | fz_st << 5);

..angegeben.

Dass ich zu wenig Code gepostet hatte, damit jmd. dies hätte erkennen können, ist mir im nachhinein klar.  :smiley-zipper:

Gruß Chris
https://github.com/jeffThompson/DarkArduinoTheme

Serenifly

Ja. Du musst das immer updaten.

Daher der Vorschlag mit der Union, dann ist das nicht nötig. Bei Unions belegen alle Variablen den gleichen Speicherplatz. Ändert man eine, dann ändern sich automatisch die anderen. Und mit dem Bitfeld kann man einzelne Bits in beliebigen Datentypen speichern.

Siehe hier:
http://www.c-howto.de/tutorial-strukturierte-datentypen-bitfelder.html
http://www.c-howto.de/tutorial-strukturierte-datentypen-vereinigung-union.html

Chris72622

Ich habe mal versucht, das von Dir Gepostete "arduinogerecht" aufzubereiten, aber es compiliert noch nicht.

Warum hast Du mit unsigned char gearbeitet?

Gruß Chris

Code: [Select]
struct bitfield{
unsigned char t1_st :
 1;
unsigned char t2_st :
 1;
unsigned char t3_st :
 1;
unsigned char t4_st :
 1;
unsigned char t5_st :
 1;
unsigned char fz_st :
 1;
};

void setup()
{
}

void loop()
{
}

union memory
{
 unsigned char asByte;
 struct bitfield asBits;
};

memory bits;
bits.asByte = 0;
bits.asBits.t1_st = 1;
bits.asBits.t3_st = 1;
https://github.com/jeffThompson/DarkArduinoTheme

Serenifly

#5
Nov 21, 2013, 08:34 pm Last Edit: Nov 21, 2013, 08:44 pm by Serenifly Reason: 1
Weil ich das in .NET getestet habe und es da keinen Datentyp "byte" gibt :) Byte = unsigned char. Kannst du auch auf byte ändern.

Das mit dem :1 gehört eigentlich in die gleiche Zeile. Das heißt, dass diese Variable ein Bit belegt. Macht aber funktional keinen Unterschied.

Das Problem hier ist, dass die Zuweisungen auf die Union Variablen in eine Methode müssen. Das geht irgendwie nicht global .NET meckert da auch, aber mit einem anderen Fehler. Genauso wie du nicht das global machen kannst:
Code: [Select]

int i;
i = 2;

Sowas geht immer nur einer Zeile als Initialisierung. Aber nicht als Zuweisung.

Wenn du "memory bits;" global machst kannst du dir "bits.asByte = 0;" auch sparen, da dann die Default-Initalisierung auf 0 greift. Die Zuweisungen auf die Bitfelder kommen dann sowieso irgendwo in loop.


Die Verwirrung da ist auch wieder bei copy/paste entstanden. Aus irgendeinem Grund habe ich das struct und die union innerhalb von main() deklariert. Das geht natürlich, aber eigentlich gehört es global. Dann waren die Zuweisungen auch in main() und ich habe einfach den Code kopiert, ohne den Methoden Rumpf. Dann hat es so ausgesehen als ob alles global sein sollte :(

Chris72622

Du würdest mir einen riesen Gefallen machen, wenn Du mir den Code, so wie Du ihn letztendlich für richtig hälst einfach noch einmal hochladen würdest. Ich bin Anfänger, nehme den Code mit Hilfe des Internets seit einer halben Stunde Stück für Stück auseinader und bleibe dabei leicht hängen.  :smiley-slim:

Wär echt super.

Dank Dir.

Gruß Chris
https://github.com/jeffThompson/DarkArduinoTheme

Serenifly

Einfach die Zuweisungen in loop packen, bzw. in irgendeine andere Methode:

Code: [Select]

struct bitfield
{
  byte t1_st :  1;
  byte t2_st :  1;
  byte t3_st :  1;
  byte t4_st :  1;
  byte t5_st :  1;
  byte fz_st :  1;
};

union memory
{
 byte asByte;
 struct bitfield asBits;
};

memory bits;

void setup()
{
}

void loop()
{
  bits.asBits.t1_st = 1;
  bits.asBits.t3_st = 1;

  Serial.println(bits.asByte, BIN);
}


Das ist auch nur Test Code mit dem Teil in loop(). Du fragst ja da dann irgendwo deine Taster aber und setzt die Variablen.

Chris72622

Dank Dir!

Ich wurstel dann mal weiter durch.   8)

Gruß Chris
https://github.com/jeffThompson/DarkArduinoTheme

Chris72622

Ich bekomme es (zunächst mal ohne Bitfeld) nicht hin.   :(

Nachdem alle Taster abgefragt wurden habe ich momentan diese Zeile stehen:

Code: [Select]
t_st = (t1_st << 0 | t2_st << 1 | t3_st << 2 | t4_st << 3 | t5_st << 4 | fz_st << 5);

Offensichtlich kommt da aber nur Müll dabei heraus.

Wie könnte ich denn noch die einzelnen Tastzustände in mein Byte bekommen, ohne dabei die zwei letzten Bits des Bytes zu verändern?

Gruß Chris
https://github.com/jeffThompson/DarkArduinoTheme

Serenifly

#10
Nov 24, 2013, 03:41 pm Last Edit: Nov 25, 2013, 02:54 am by Serenifly Reason: 1
http://arduino.cc/en/Reference/BitWrite

Nicht getestet:
Code: [Select]

byte writeByte(byte b1, byte b2, byte b3, byte b4, byte b5, byte b6)
{
     byte b = 0;
     bitWrite(b, 0, b1);
     bitWrite(b, 1, b2);
     bitWrite(b, 2, b3);
     bitWrite(b, 3, b4);
     bitWrite(b, 4, b5);
     bitWrite(b, 5, b6);
     return b;
}

void loop()
{
     byte t_st = writeByte(t1_st, t2_st, t3_st, t4_st, t5_st, fz_st);
}


Quote

ohne dabei die zwei letzten Bits des Bytes zu verändern?

So wie es auch bei dir steht, schreibt er immer ein komplett neues Byte.

Wenn du das auf ein bestehendes Byte anwenden willst, kann man vorher das machen:
Code: [Select]

t_st &= 0xC0;
t_st |= (t1_st << 0 | t2_st << 1 | t3_st << 2 | t4_st << 3 | t5_st << 4 | fz_st << 5);

Damit wird erst mal alles bis auf die obersten zwei Bits gelöscht. Den Rest kann man dann neu setzen

Bei dem Code oben kann man das so machen:
Code: [Select]

byte writeByte(byte data, byte b1, byte b2, byte b3, byte b4, byte b5, byte b6)
{
     byte b = data & 0xC0;
     ...
}

Also noch das Byte übergeben und die neue Version zurückgeben. Könnte man auch mit einem Pointer machen.


Chris72622

Code: [Select]

struct bitfield
{
  byte t1_st :  1;
  byte t2_st :  1;
  byte t3_st :  1;
  byte t4_st :  1;
  byte t5_st :  1;
  byte fz_st :  1;
};

union memory
{
 byte asByte;
 struct bitfield asBits;
};

memory bits;

void setup()
{
}

void loop()
{
  bits.asBits.t1_st = 1;
  bits.asBits.t3_st = 1;

  Serial.println(bits.asByte, BIN);
}


Ich habe mir jetzt diesen Code von Dir bestimmt mind. 20 Mal angeschaut, verstehe aber bis auf die Erstellung des Bitfeldes nichts.

Insbesondere die Zeilen in der es um die Erstellung einer Union geht und diese hier..

Code: [Select]
memory bits;
Code: [Select]
bits.asBits.t1_st = 1;

..verstehe ich leider gar nicht. Den Seiten, auf denen erklärt wird was eine Union ist, kann ich lediglich entnehmen, dass sich bei einer Union mehrere Variablen einen Speicherplatz teilen. Leider aber kann ich das noch immer nicht in Verbindung mit dem oben bereits von Dir geposteten Code bringen.

Vielleicht möchtest Du Dich ja nochmal erbarmen, mich mit ein paar Kommentaren (oder Links) zu erleuchten..?

Gruß Chris
https://github.com/jeffThompson/DarkArduinoTheme

Serenifly

Ein struct ist nichts anderes als eine Sammlung von einer Variablen, die man unter einem Namen ansprechen kann. Das ganze ähnelt einem Objekt (und in C++ können structs auch Funktionen und Konstruktoren enthalten). Ein Bitfeld ist eine besondere Variante davon bei der man mit ": x" angibt wie viele Bits eine Variable belegen soll.

Code: [Select]

memory bits;

Die Union heißt "memory" und wir legen einen Variable davon an die "bits" heißt. Das ist genauso wie wenn man in einer OOP Sprache ein Objekt einer Klasse instantiiert - z.B. das: LiquidCrystal lcd(...)
Statt "bits" kannst du auch einen anderen Namen wählen. Das ist nur ein Variablenname

Code: [Select]

bits.asBits.t1_st = 1;

Die Union enthält die zwei Elemente "asBits" (das Bitfeld) und "asByte" (das Byte/unsigned char). Genauso wie man bei Objekten auf die internen Methoden und Variablen zugreift, muss man hier auch auf die entsprechenden Elemente zugreifen.

Mit "bits.asBits" hat man dann das Bitfeld struct. Das enthält wiederum Elemente auf die man zugreifen kann/muss. Daher
"bits.asBits.t1_st" -> union.struct.bit


Sowas kann man sehr schön in einer IDE mit Autovervollständigung ausprobieren. Da tippt man dann den Punkt an und sieht sofort welche Elemente man danach auswählen kann. Für den Arduino gibt es da Atmel Studio. Oder eine Vollversion von Visual Studio mit dem Visual Micro Plugin (mit Visual C++ Express geht es aber nicht).

Go Up