Forum: Mikrocontroller und Digitale Elektronik AVR Pointer auf 16Bit Wert


von Timur Y. (smokingslim)


Lesenswert?

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;
}

von Karl H. (kbuchegg)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

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

von Rolf Magnus (Gast)


Lesenswert?

> 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.

von jens (Gast)


Lesenswert?

das kommt eben dabei raus, wenn man auf irgendwelche hochsprachen 
compiler angewiesen ist :-). geh den einfachen,direkten weg: assembler!

von Jörg X. (Gast)


Lesenswert?

@ jens (Gast):
> geh den einfachen,direkten weg: assembler!

gute Idee: Floating-Point in Assembler emulieren ;) SCNR

von Timur Yigit (Gast)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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


von Peter D. (peda)


Lesenswert?

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

von Matthias (Gast)


Lesenswert?

@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 :)

von Karl H. (kbuchegg)


Lesenswert?

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.


von jens (Gast)


Lesenswert?

furchtbar,diese substanzlosen typumwandlungsspielchen. ein typisches 
beispiel, wie hochsprachen simple probleme kompliziert und komplex zu 
lösen versuchen. einfach nur abschreckend.

von Karl H. (kbuchegg)


Lesenswert?

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
}

  

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Man kann die Meßwerte auch als String wandeln, senden und beim empfänger 
rückwandeln ;)

von Timur Y. (smokingslim)


Lesenswert?

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
Noch kein Account? Hier anmelden.