Hallo, ich habe leider einen kleinen Knoten im Hirn. Bei der ADC-Abfrage (18bit) per SPI mit dem STM32F429 habe ich etwas Probleme. Die Daten werden wie angehängt gesendet. Ich rufe die Daten per SPI_I2S_ReceiveData(SPI5) (von der STD-Lib) 8-bitweise ab. Im ersten Byte habe ich dann D17-D10, im zweiten D9-D2 und im dritten Byte habe ich dann D1-D0. Die Byte sind alle uint8_t Es gibt doch bestimmt eine einfache Variante die jetzt in eine int32_t Variable zu speichern, und dabei das Vorzeichen nicht zu verlieren, oder? Mir fällt da nur eine Variante mit viel schieben und ifs ein. Kann mir da bitte jemand auf die Sprünge helfen?
Was spricht gegen das Schieben? Sind 3 Zeile. Geht schneller als ein Post hier.
ja ok, meine Version ist gerade folgende:
1 | int32_t value; |
2 | uint8_t bytes[3]; |
3 | uint8_t i; |
4 | for(i=0;i<3;i++){ |
5 | bytes[i]=GG_SPI5_SendByte(0x00); |
6 | }
|
7 | if (0x80 & bytes[0]){ |
8 | value =~(0x3FFFF-((bytes[0]<<10) | (bytes[1]<<2)| (bytes[2]>>6))); |
9 | }
|
10 | else
|
11 | value = (bytes[0]<<10) | (bytes[1]<<2)| (bytes[2]>>6); |
Dachte vielleicht gibt es etwas schöneres. edit: So muss es sein
So, neue Möglichkeit:
1 | int32_t value; |
2 | uint8_t bytes[3]; |
3 | uint8_t i; |
4 | for(i=0;i<3;i++){ |
5 | bytes[i]=SPI5_SendByte(0x00); |
6 | }
|
7 | value = (((bytes[0]<<24) | (bytes[1]<<16)| (bytes[2]<<8))>>14); |
Voraussetzung hierfür ist allerdings dass negative signed Integer beim GCC Compiler beim rechtsshiften mit Einsen aufgefüllt werden und positive mit Nullen. Wahrscheinlich muss ich in der zweiten Zeile:
1 | value = (int32_t)(((bytes[0]<<24) | (bytes[1]<<16)| (bytes[2]<<8))>>14); |
casten.
Gerald G. schrieb: > So, neue Möglichkeit: >
1 | > int32_t value; |
2 | > uint8_t bytes[3]; |
3 | > uint8_t i; |
4 | > for(i=0;i<3;i++){ |
5 | > bytes[i]=SPI5_SendByte(0x00); |
6 | > } |
7 | > value = (((bytes[0]<<24) | (bytes[1]<<16)| (bytes[2]<<8))>>14); |
8 | >
|
> Voraussetzung hierfür ist allerdings dass negative signed Integer beim > GCC Compiler beim rechtsshiften mit Einsen aufgefüllt werden und > positive mit Nullen. Nicht nur. bytes[0]<<24 geht schon mal schief. > Wahrscheinlich muss ich in der zweiten Zeile: >
1 | > value = (int32_t)(((bytes[0]<<24) | (bytes[1]<<16)| (bytes[2]<<8))>>14); |
2 | >
|
> casten.
Das ist zu spät gecastet. Wenn du das komplette 16 Bit Ergebnis von 16
Bit auf 32 Bit hochcastest, dann ist das zwar nett von dir für die
Zuweisung, ändert abder nichts daran, dass das Ergebnis der ganzen
Schiebeorgie erst mal 16 Bit war.
In jeder arithmetischen Operation gilt in C die Regel, dass die
IMplementierung der Operation ausschliesslich von den Datentypen der
Operanden abhängt. In1 | c = a + b |
bestimmen die Datentypen von a und b, wie die Addition durchgeführt wird. Der Datentyp von c ist dazu völlig uninteressant. Bei den Schiebeoperationen
1 | c = a << b |
ist es sogar nur der Datentyp von a, welcher darüber entscheidet, welche Operation da zum Einsatz kommt. Weiters gilt die Regel: gerechnet wird immer im größten Datentyp der in einer (Teil-)Operation vorkommt. Aber nicht kleiner als int. Und int ist nun mal auf deinem µC 16 Bit.
Karl Heinz schrieb: > Das ist zu prät gecastet. Wenn du das komplette 16 Bit Ergebnis von 16 > Bit auf 32 Bit hochcastest, dann ist das zwar nett von dir für die > Zuweisung, ändert abder nichts daran, dass das Ergebnis der ganzen > Schiebeorgie erst mal 16 Bit war. Also so:
1 | value = (((int32_t)(bytes[0]<<24) | (int32_t)(bytes[1]<<16)| (int32_t)(bytes[2]<<8))>>14); |
Oder reicht es nach der ersten Klammer zu casten? Also bezieht sich das dann auf jede Variable in der Klammer. Also:
1 | value = ((int32_t)((bytes[0]<<24) | (bytes[1]<<16)| (bytes[2]<<8))>>14); |
edit: hoppl,a hast ja deinen Beitrag editiert, ich lese schnell.
Gerald G. schrieb: > Also so: >
1 | > value = (((int32_t)(bytes[0]<<24) | (int32_t)(bytes[1]<<16)| |
2 | > (int32_t)(bytes[2]<<8))>>14); |
3 | >
|
Immer noch falsch. in
1 | uint8_t i = 5; |
2 | uint64_t c; |
3 | |
4 | c = i << 5; |
bestimmt der Datentyp von i, wie die Schiebeoperation aufgefasst wird. i ist ein uint8_t und damit 'kleiner' als ein int. Ergo ist das eine int Operation. i wird implizit zu einem int hochgecastet, ist damit 16 Bit breit und die Schiebeoperation wird als 16 Bit Schiebeoperation implementiert. Ein nachträglicher Cast
1 | uint8_t i = 5; |
2 | uint64_t c; |
3 | |
4 | c = (uint64_t)(i << 5); |
ändert daran nicht das geringste. Wenn du den Compiler dazu zwingen willst, die Schiebeoperation als 64 Bit Operation zu implementieren, dann musst du VOR dem Verschieben i auf 64 Bit hochcasten. Nicht hinterher.
1 | uint8_t i = 5; |
2 | uint64_t c; |
3 | |
4 | c = ((uint64_t)i) << 5); |
Jetzt wird zuerst i auf 64 Bit hochgehoben, damit hat das a in
1 | c = a << b |
einen 64 Bit Datentyp und damit wird auch die Verschiebeoperation als 64 Bit Operation implementiert.
Karl Heinz schrieb: > einen 64 Bit Datentyp und damit wird auch die Verschiebeoperation als 64 > Bit Operation implementiert. Und immer schön darauf achten welche Signedness deine Zwischenergebnisse haben. Dann ganz zum SChluss willst du aus dem unsigned ja einen signed machen, damit dir das rechts schieben um 14 Positionen das Vorzeichenbit entsprechend aufzieht. Na, wäre eine Abfrage des MSB des 24 Bit Ergebnisses und je nachdem wird das höchstwertige Byte auf entweder 0x00 oder 0xFF gesetzt nicht doch einfacher gewesen?
So, hatt schon meinen ersten Beitrag editiert, aber durfte nicht mehr absenden. Also werde ich die "bytes[]" als 32bit initialisieren. Nur die Frage wegen dem cast von uint in int, welcher entweder beim auslesen passiert oder beim zuweisen an den Wert. In jedem Fall wird eine Art "signed overflow" geschehen, da bei einem negativen Wert am ADC das Masterbit gesetzt ist, der Wert für den µC größer als für einen int-Typ zulässig ist. Am liebsten würde ich gerne Bitweise kopieren, unabhängig vom Typ. Ich glaube es läuft auf eine eigene "SPI5_SendByte()" Funktion hinaus, die gleich einen signed int8 ausgibt. edit: Karl Heinz schrieb: > Na, wäre eine Abfrage des MSB des 24 Bit Ergebnisses und je nachdem wird > das höchstwertige Byte auf entweder 0x00 oder 0xFF gesetzt nicht doch > einfacher gewesen? Das war ja mein erster Vorschlag oben, der mir so nicht gefällt, mir jedoch immer sympathischer wird :D Das Castingproblem werde ich dort natürlich korrigieren.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.

