Hi ich versteh die Welt nicht mehr. Also ich bekomme über SPI einen 16Bit Wert. Da ich das Ergebniss als 2 getrennte Bytes bekomme bastele ich mir ein double mit hilfe des 2 Byte langen Array. Und am Ende wird mit Hilfe des cast Operators aus dem Array ein double. Da das ergebniss falsch war habe ich solange rumprobiert bis es stimmt, jetzt habe ich zwar die richtige ausgabe auf dem Display aber kann das NULL nachvolziehen. Und zwar der untere Code Schnippsel funktioniert aber ich schreibe das MSB an die hinter stelle des Arrays und LSB an die vordere also eigentlich falsch rum. Meine Frage ist kann es sein das am Ende wenn mein Array zu einem double wird ein 16 Bit Pointer auf das LSB des 16 Bit werts zeigt. Danke #define u16 double #define u8 char u16 get16_pow_ic_data(u8 address) { ClrBit(SPCR,3); //TimingModus/Polarity/CPOL-Bit SetBit(SPCR,2); //TimingModus/Polarity/CPHA-Bit spi_pow_ic_on(); u8 array[2]; //Array for creating 16Bit value SPDR=address; while(!(SPSR &(1<<SPIF))); //Wait for address transmission complete u8 i; for(i=0;i<10;i++); //delay //Get FirstByte SPDR=0x00; //DummyByte for SPI-clock while(!(SPSR & (1<<SPIF))); //Wait for reception complete array[1]=SPDR; //Copy the first Byte //Get SecondByte SPDR=0x00; //DummyByte for SPI-clock while(!(SPSR & (1<<SPIF))); //Wait for reception complete array[0]=SPDR; spi_pow_ic_off(); u16 temp = *(u16*)array; //This operation uses the castOperator to //convert the 2 Byte Array in a u16 Variable return temp; }
Timur Yigit wrote: > Und zwar der untere Code Schnippsel funktioniert aber ich schreibe das > MSB an die hinter stelle des Arrays und LSB an die vordere also > eigentlich falsch rum. Wie rum richtig ist definiert die Hardware bzw. (wenns für die Hardware egal ist) der Compiler. Und da gibt es halt 2 Möglichkeiten: * little Endian. Das LSB kommt zuerst im Speicher (zb. die Intel Prozessoren benutzen das) * big Endian. Das MSB kommt zuerst im Speicher. Zb. bei Motorola Prozessoren > Meine Frage ist kann es sein das am Ende wenn mein Array zu einem double > wird ein 16 Bit Pointer auf das LSB des 16 Bit werts zeigt. Das Array wird nie zu einem int (double ist übrigens ganz was anderes). Das Array bleibt immer Array. Aber was hier ausgenutzt wird: Das Array besteht aus 2 Bytes und ein int betseht ebenfalls aus 2 Bytes. Mit dem Cast sagst du dem Compiler: Nimm die Startadresse das Arrays (also dort wo die 2 Bytes im Speicher liegen) und tu einfach so als ob an dieser Stelle im Speicher ein int liegen würde. Und dann holst du einfach den int aus den soweit maskierten Bytes heraus.
Einen 16Bit Wert nach double casten, muß immer schief gehen. Double ist mindestens 32Bit, in der Regel aber 64Bit. 16Bit float Formate sind zumindest nicht C konform (wenn es sie denn überhaupt gibt). Peter
> 16Bit float Formate sind zumindest nicht C konform Ein 32-bit-double eigentlich auch nicht. > (wenn es sie denn überhaupt gibt). Ja, gibt es. Die werden bei 3D-Beschleunigern häufig eingesetzt, z.B. für die gerade im Trend liegenden HDR-Effekte (Lichteffekte mit gegenüber erweitertem Helligkeitsbereich). 32-bit-float wäre da unnötig viel.
das kommt eben dabei raus, wenn man auf irgendwelche hochsprachen compiler angewiesen ist :-). geh den einfachen,direkten weg: assembler!
@ jens (Gast):
> geh den einfachen,direkten weg: assembler!
gute Idee: Floating-Point in Assembler emulieren ;) SCNR
Ah so ein mißt vor lauter ärger alles verwechselt also mein Problem ist das ich 2 Byte oder 4 Byte über SPI von einem LeistungmessIC über einen ATmega324P abrufe. Da diese einzelne Bytes aber nur gesplittete 16Bit oder 32Bit Werte sind muss ich aus diesen einzelnen Bytes eben den entsperechenden DatenTyp erzeugen. Ich könnte natürlich die einzelnen Bytes einlesen entsprechend oft nach links schieben und dann VERODERN das ist aber sehr unestetisch. Daher würde ich gerne die Variante mit dem Array und der Umwandlung mit dem cast Operator bevorzugen nur ist da irgendwie der Wurm drin. Ist der fehler vieleicht bei der Umwandlung.
Timur Yigit wrote: > Ich könnte natürlich die einzelnen Bytes einlesen entsprechend oft nach > links schieben und dann VERODERN das ist aber sehr unestetisch. Sei nicht so hart :-) Das ist ein durchaus gangbarer Weg. > Daher würde ich gerne die Variante mit dem Array und der Umwandlung mit > dem cast Operator bevorzugen nur ist da irgendwie der Wurm drin. Inwiefern? Das was du da oben gezeigt hast ist doch soweit in Ordnung (wenn die Bytereihenfolge beim Sender stimmt) > Ist der fehler vieleicht bei der Umwandlung. Sicher nicht. Denn da findet keine Umwandlung statt. Die Bytes bleiben so wie sie sind. Sie werden dem Compiler lediglich unter einem anderen Datentyp untergejubelt. Das ist alles. Wenn die Zahlenwerte nicht stimmen, dann kann das liegen * deine SPI Übertragung ist fehlerhaft * die Bytereihenfolge stimmt nicht
Karl heinz Buchegger wrote: > Timur Yigit wrote: >> Ich könnte natürlich die einzelnen Bytes einlesen entsprechend oft nach >> links schieben und dann VERODERN das ist aber sehr unestetisch. > > Sei nicht so hart :-) > Das ist ein durchaus gangbarer Weg. Nicht nur das, er ist auch portabel. Die Byteorder der CPU oder des Compilers spielt dann keine Rolle mehr. Sobald die Programmsicherheit darunter leidet, kannst Du Dir meinetwegen mit der Ästhetik den Hintern abwischen. Fehlervermeidung geht immer vor Schönheit. Peter
@Peter: Das mit dem double ist hier nur sehr ungünstig formuliert, da er mit dem double einen 16Bit Integer meint. double ist in C halt schon vergeben, aber per #define wirds hier überschrieben. Zur Fragestellung an sich trägt das aber hier nicht bei. Timur sollte das ding aber wirklich aml anders benennen (unsigned short, word oder was auch immer), damits halbwegs standardkonform bleibt :)
Matthias wrote: > @Peter: > Das mit dem double ist hier nur sehr ungünstig formuliert, da er mit dem > double einen 16Bit Integer meint. double ist in C halt schon vergeben, > aber per #define wirds hier überschrieben. Jetzt seh ichs erst
1 | #define u16 double
|
Das stinkt nach Ärger > Zur Fragestellung an sich > trägt das aber hier nicht bei. Doch, das tut es. Ich denke nicht, dass das so funktionieren wird. Auch wenn Rolf ein Beispiel für einen 2 Byte floating point Typ gennant hat, so ist das doch ein eher esoterisches Beispiel. In der normalen Welt hat ein double nun mal mindestens 4 Byte und nicht 2 > Timur sollte das ding aber wirklich aml anders benennen (unsigned short, > word oder was auch immer), damits halbwegs standardkonform bleibt :) Anders rum. Das hat nichts mit Benennung zu tun. Seine u16 sind double und somit Floating Point Arithmetik. Kein Wunder, dass da nichts funktioniert. Er muss sich entscheiden was er denn vom Sender bekommt: Floating Point Zahlen (dann kann das aufwendig werden) oder Ganzzahlen. Im letzteren (wahrscheinlicherem) Fall, muss er auf int oder meinetwegen unsigned int gehen, alles andere ist grundverkehrt.
furchtbar,diese substanzlosen typumwandlungsspielchen. ein typisches beispiel, wie hochsprachen simple probleme kompliziert und komplex zu lösen versuchen. einfach nur abschreckend.
jens wrote: > furchtbar,diese substanzlosen typumwandlungsspielchen. ein typisches > beispiel, wie hochsprachen simple probleme kompliziert und komplex zu > lösen versuchen. Das ist der Preis den man zahlen muss, wenn der Compiler die Datentypen für dich überwacht. Aber so schlimm wie du das jetzt hinstellst ist es normalerweise nicht. Solche cast-Orgien (so man sie macht), sind normalerweise nur bei I/O Dingen notwendig. Sobald der Datentyp dann stimmt gehts programmintern normalerweise 'sauber' weiter. Dort sind wilde casts dann eher ein Zeichen dafür, dass irgendwo die Kacke mächtig am dampfen ist. Mit etwas Disziplin und einer vernünftigen Funktionsaufteilung kann ich dafür das Ganze übersichtlich strukturieren (und hab dafür noch nicht mal 5 Minuten gebraucht)
1 | #define u16 unsigned int
|
2 | #define u8 unsigned char
|
3 | |
4 | void send_ic_address( u8 address ) |
5 | {
|
6 | SPDR = address; |
7 | while(!(SPSR &(1<<SPIF))) //Wait for address transmission complete |
8 | ;
|
9 | |
10 | u8 i; |
11 | for(i=0;i<10;i++); //delay |
12 | }
|
13 | |
14 | u8 get_ic_byte() |
15 | {
|
16 | SPDR = 0x00; //DummyByte for SPI-clock |
17 | while(!(SPSR & (1<<SPIF))) //Wait for reception complete |
18 | ;
|
19 | |
20 | return SPDR; |
21 | }
|
22 | |
23 | u16 get16_pow_ic_data(u8 address) |
24 | {
|
25 | ClrBit(SPCR,3); //TimingModus/Polarity/CPOL-Bit |
26 | SetBit(SPCR,2); //TimingModus/Polarity/CPHA-Bit |
27 | |
28 | spi_pow_ic_on(); |
29 | |
30 | send_ic_address( address ); |
31 | |
32 | u8 data[2]; //used for storing the 2 received bytes |
33 | data[1] = get_ic_byte(); |
34 | data[0] = get_ic_byte(); |
35 | |
36 | spi_pow_ic_off(); |
37 | |
38 | return *(u16*)data; //return those 2 Bytes as an unsigned int |
39 | }
|
Man kann die Meßwerte auch als String wandeln, senden und beim empfänger rückwandeln ;)
Also nach 4 Stunden Fehlersuche bin ich zum entschluss gekommen das ich die Bytes einfach schiebe und dann veroder. Weil wie ein Vorgänger bereits gesagt das völlig egal ist auf welchem Rechner das Prog läuft mit der Pointer und Array Variante ist es Glücksache ob der nächste yC die Bytes in der gleichen weise behandelt. Beim Simulieren hat sich gezeigt das der AVR das Array in eines seiner Register legt ab dann beim Übergeben an die aufrufende Funktion in von hintern wieder die RegisterWerte ausgibt. Ich könnte zwar in dem ich das Array von hinten belade das Problem lösen aber das mir echt zu gefährlich und schreit nach riesen Problemmen beim Umzug auf einen anderen Controller. Danke für die Tipps
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.