Forum: Mikrocontroller und Digitale Elektronik Array into int und dann Bit Verschiebung


von Spezi (Gast)


Lesenswert?

Guten Morgen,

vermutlich sehr einfache Frage.
Ich habe folgendes Array:

unsigned char Array[3];

Jetzt möchte ich gerne das letzte Bit rausschieben.
Array = Array >> 1 funktioniert natürlich nicht.

Am allerliebsten würde ich die drei Array Elemente als eine Zahl in 
einem int abspeicher, also Array[0] = High Byte, Array[1] = MittelByte, 
Array[2] = Low Byte,

Dann könnte ich das letzte Bit auch einfach rausscheiben.

Wie macht man sowas?

von Karl H. (kbuchegg)


Lesenswert?

Spezi schrieb:
> Guten Morgen,
>
> vermutlich sehr einfache Frage.
> Ich habe folgendes Array:
>
> unsigned char Array[3];
>
> Jetzt möchte ich gerne das letzte Bit rausschieben.
> Array = Array >> 1 funktioniert natürlich nicht.
>
> Am allerliebsten würde ich die drei Array Elemente als eine Zahl in
> einem int abspeicher, also Array[0] = High Byte, Array[1] = MittelByte,
> Array[2] = Low Byte,
>
> Dann könnte ich das letzte Bit auch einfach rausscheiben.
>
> Wie macht man sowas?

Entweder in dem man im Array schiebt
1
uint8_t Carry1, Carry2;
2
3
   Carry1 = Array[2] & 0x01;
4
   Array[2] >>= 1;
5
6
   Carry2 = Array[1] & 0x01;
7
   Array[1] >>= 1
8
   if( Carry1 )
9
     Array[2] |= 0x80
10
11
   Array[0] >>= 1;
12
   if( Carry1 )
13
     Array[0] |= 0x80;

oder den Compiler machen lassen, so wie du das vorgeschlagen hast.
1
  union convert
2
  {
3
    uint8_t  Bytes[4];
4
    uint32_t Value;
5
  } convertVar;
6
7
  convertVar.Bytes[0] = Array[0];
8
  convertVar.Bytes[1] = Array[1];
9
  convertVar.Bytes[2] = Array[2];
10
  convertVar.Bytes[3] = 0;
11
12
  covertVar.Value >>= 1;
13
14
  Array[0] = convertVar.Bytes[0];
15
  ....

eine andere Möglichkeit, bei der man nicht umkopiert
1
  uint32_t * pValue;
2
3
  pValue = (uint32_t*)Array;
4
  *pValue >>= 1;

bei der Union Lösung hat man den Vorteil, dass man während des 
Umkopierens gleich die Bytereihenfolge für einen unsigned long 
entsprechend den Vorstellungen des COmpilers und/oder Systems anpassen 
kann, falls das notwendig ist. Bei der Pointer Variante muss man mit dem 
leben, wie sich der Compiler die Anordnung eines 32 Bit Wertes im 
Speicher so vorstellt.

Oder aber: man findet einen Weg, wie man sich das ganze Bitgeschubse 
sparen kann. Normalerweise ist das der beste Ansatz.

von Daniel V. (danvet)


Lesenswert?

Du könntest eine union verwenden:
1
typedef union _Zahl_def{
2
 UCHAR  Array[4];
3
 UINT32 Wert;
4
} Zahl_def;
5
6
Zahl_def Zahl;
7
8
Zahl.Array[0] = LowByte;
9
Zahl.Array[1] = MittelByte;
10
Zahl.Array[2] = HighByte;
11
Zahl.Array[3] = 0;
12
13
Zahl.Wert = Zahl.Wert >> 1;

Das ist jetzt aber ungeprüft.

Edit: Da war einer schneller...

von Spezi (Gast)


Lesenswert?

Vielen Dank schon einmal für die ausführlichen freundlichen Antworten:
DIe Union Methode würde mich am Meisten interessieren:

Bis
convertVar.Bytes[0] = Array[0];
convertVar.Bytes[1] = Array[1];
convertVar.Bytes[2] = Array[2];
convertVar.Bytes[3] = 0;

ist auch alles klar.

Was genau macht er jetzt bei covertVar.Value >>= 1; ??? Klar shiftet er 
hier das Bit.
In meiner Anwendung soll in Value doch nur 24 Bit stehen.
Es müßte also in etwa wie folgt aussehen:
1
 union convert
2
  {
3
    uint8_t  Bytes[3];
4
    uint32_t Value;
5
  } convertVar;
6
7
  convertVar.Bytes[0] = Array[0];
8
  convertVar.Bytes[1] = Array[1];
9
  convertVar.Bytes[2] = Array[2];
10
11
  covertVar.Value >>= 1;

In Value stehen jetzt leider (verständlicherweise) nicht wie gewünscht 
die 24 Bit.

von Spezi (Gast)


Lesenswert?

OK ich muss einfach die 8 Nullen nochmal rausshiften

von Karl H. (kbuchegg)


Lesenswert?

Spezi schrieb:
> OK ich muss einfach die 8 Nullen nochmal rausshiften

?
Du musst da nichts rausshiften.
Du schreibst 3 Bytes in die union (und initialisierst das 4.te mit 0) 
und holst dir 3 Bytes aus der union.

Das in der union das Array 4 Bytes gross ist, hängt damit zusammen, dass 
auch ein uint32_t 4 Bytes gross ist und wir auch die Kontrolle über 
dieses 4.te Byte haben wollen. Und sei es nur, um es 0 zu setzen.

Was natürlich sein kann: dass die Bytereihenfolge des Arrays nicht mit 
der in einem uint32_t übereinstimmt. Das muss man dann eben 
ausprobieren, wie rum ein uint32_t im Speicher angeordnet ist.

von Karl H. (kbuchegg)


Lesenswert?

Karl Heinz schrieb:

> eine andere Möglichkeit, bei der man nicht umkopiert
>
1
>   uint32_t * pValue;
2
> 
3
>   pValue = (uint32_t*)Array;
4
>   *pValue >>= 1;
5
>

Das da noch keiner drauf angesprungen ist :-)

Das ist natürlich so erst mal ungeheurer Blödsinn, solange das Array nur 
3 Bytes gross ist.

von Karl H. (kbuchegg)


Lesenswert?

Spezi schrieb:

> In meiner Anwendung soll in Value doch nur 24 Bit stehen.

Es gibt aber auf dem AVR keinen Standard Datentyp mit 24 Bit. Der nächst 
größere hat 32 Bit. Wenn du also dem Compiler die Arbeit aufbürden 
willst, das byteübergreifende Schieben für dich zu erledigen, dann wirst 
du dich wohl oder übel nach dem richten müssen, was du hast. Und nicht 
nach dem, was du gerne hättest.

> Es müßte also in etwa wie folgt aussehen:
>
>
1
>  union convert
2
>   {
3
>     uint8_t  Bytes[3];
4
>     uint32_t Value;
5
>   } convertVar;
6
> 
7
>   convertVar.Bytes[0] = Array[0];
8
>   convertVar.Bytes[1] = Array[1];
9
>   convertVar.Bytes[2] = Array[2];
10
> 
11
>   covertVar.Value >>= 1;
12
>

Frage: welchen Wert hat das Bit, welches von links (von seiten des MSB) 
reinkommt?

Eben. Du hast da erst mal keine Kontrolle drüber.
Daher: das Array 4 Bytes gross machen und dieses 4.te Byte (aus dem das 
1 Bit nachgeschoben wird) auf 0 setzen.

von Peter D. (peda)


Lesenswert?

Man kann auch 3 * 8 Bit schieben:
1
void out24bit( uint8_t *array )
2
{
3
  for( uint8_t i = 3; i; i-- ){
4
    uint8_t val = *array++;
5
    for( uint8_t j = 8; j; j-- ){
6
      if( val & 1 ){
7
        mache_irgendwas();
8
      }
9
      val >>= 1;
10
    }
11
  }
12
}

von Spezi (Gast)


Lesenswert?

Vielen Dank nochmal,

es gilt also einfach die Reihenfolge zu überprüfen.
Ich habe es jetzt fälschlicherweise wie folgt angeordnet:

HB | MB | LB | 0

habe dann 1 Bit geshiftet und dann nochmal 8 Bit für die 0, was 
natürlich quatsch ist , wenn ich von Anfang an wie folgt anordne: 0 | HB 
| MB | LB

Danke nochmals für die Hilfe.

Was mich mal interessieren würde Herr Buchegg, machen Sie das ganze hier 
eientlich "vollberuflich"?

von Daniel V. (danvet)


Lesenswert?

Spezi schrieb:
> Was mich mal interessieren würde Herr Buchegg, machen Sie das ganze hier
> eientlich "vollberuflich"?

Manchmal kommt einem das so vor, gell?

von Karl H. (kbuchegg)


Lesenswert?

Spezi schrieb:

> Was mich mal interessieren würde Herr Buchegg, machen Sie das ganze hier
> eientlich "vollberuflich"?

Nein.
Nebenbei, zwischen Compilerläufen.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.