Forum: Mikrocontroller und Digitale Elektronik Zugriff auf int-Variable über 8-bit Zeiger


von ThomasThiry (Gast)


Lesenswert?

Hallo!

Stellt euch bitte folgende Situation vor:

In einem IC gibt es ein 16-bit breites Konfigurationsregister, dass ich
über SPI auslesen möchte. Ich definiere mir also eine Integer-Variable,
in der ich diese Info abspeichern kann. Da ich über den SPI-Bus aber
nur 8 bit auf einmal empfangen kann, muss ich das Auslesen dieses
Registers auf 2 Anläufe staffeln.
Im ersten Anlauf lese ich z.B. das High-Byte und im zweiten das
Low-Byte. Die Frage lautet nun, wie ich die zwei gelesenen Bytes in
meine ursprünglich dafür vorgesehene Variable bekomme.

Ich habe vor kurzem ein Beispielprogramm gesehen, in dem folgendes
Konstrukt dafür verwendet wurde (auszugsweise):


int config_reg;

// Aufruf der Funktion, um das Konfigurationsregister auszulesen:
get_config_reg( (unsigned char*) &config_reg);


// Inhalt der Funktion:
void get_config_reg( (unsigned char*) &config_reg)
{
     spi_byte_1 = read_spi();    // Lies erstes Byte vom SPI-Bus
     config_reg[1] = spi_byte_1;
     spi_byte_2 = read_spi();    // Lies zweites Byte vom SPI-Bus
     config_reg[0] = spi_byte_2;
}


Mich würde jetzt interessieren, ob sowas einer "sauberen"
C-Programmierung entspricht? Mir ist schon klar, wie es funktioniert
und das es korrekt ist; ich habe so etwas in der Art aber zum ersten
Mal gesehen. Ich hätte es nämlich so gemacht:

int config_reg;

// Aufruf der Funktion, um das Konfigurationsregister auszulesen:
config_reg = get_config_reg();


// Inhalt der Funktion:
int get_config_reg()
{
     int ergebnis;

     ergebnis = read_spi();      // Lies erstes Byte vom SPI-Bus
     ergebnis = ergebnis >> 8;
     ergebnis |= read_spi();    // Lies zweites Byte vom SPI-Bus

     return ergebnis;
}


Beide Konstrukte liefern ja dasselbe Ergebnis.

Wie gesagt, würde mich aber interessieren, ob so etwas "sauber" und
gebräuchlich ist.

Vielen Dank schonmal für euere Beiträge!


Gruß
Thomas

von Ralf (Gast)


Lesenswert?

Ich halte die erste Variante für besser, da hier der Zugriff direkt
erfolgen kann, und keine Schiebe-Operationen erforderlich sind...

Ralf

von peter dannegger (Gast)


Lesenswert?

Die 1. Variante ist gefährlich, da sie einen Compiler bzw. Target mit
einer bestimmten Byteorder voraussetzt.


Die Schiebvariante ist sauber, da sie völlig unabhängig vom verwendeten
Compiler und verwendeten Target immer funktioniert.


Peter

von Thomas Thiry (Gast)


Lesenswert?

Mir gefällt die zweite Variante ehrlich gesagt auch besser, auch wenn
sie vielleicht nicht ganz so ellegant ist, wie Variante 1.

@Peter:
Was meinst du mit "einer bestimmten Byteorder" (little endian oder
big endian)?

Gruß
Thomas

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

.

Das hier geht in die Hose:

  // Inhalt der Funktion:
  int get_config_reg()
  {
     int ergebnis;

     ergebnis = read_spi();      // Lies erstes Byte vom SPI-Bus
     ergebnis = ergebnis >> 8;
     ergebnis |= read_spi();    // Lies zweites Byte vom SPI-Bus

     return ergebnis;
  }


Man beachte die Richtung des Schiebeoperators!

Obendrein ist die Funktion des Schiebeoperators bei
vorzeichenbehafteten Werten ... seltsam.

Mehr Funktionalität dürfte das hier bringen:

  unsigned int get_config_reg()
  {
     unsigned int ergebnis;

     ergebnis = read_spi();        // 1. Byte ist LSB
     ergebnis |= read_spi() << 8;  // 2. Byte ist MSB

     return ergebnis;
  }

oder, wenn die Bytes "andersrum" abgespeichert werden sollen:

  unsigned int get_config_reg()
  {
     unsigned int ergebnis;

     ergebnis = read_spi() << 8;  // 1. Byte ist MSB
     ergebnis |= read_spi();      // 2. Byte ist LSB

     return ergebnis;
  }

von Baku (Gast)


Lesenswert?

Die erste Variante ist ganz pfui, zu der Byteorder kommt noch die
Unsicherheit, ob der Compiler int mit 16 oder 32 Bit annimmt. Bei
big-endian und 32Bit kommt da ziemlich überraschendes bei raus und du
findest deine Konfigurationsbits niemals wieder...

Bei der Schiebevariante kannst du immer sicher sagen, wo jedes Bit aus
deinem Konfigurationsregister landet.

Und von wegen Eleganz:

int get_config_reg()
{
  union
  { unsigned char b[ sizeof(int) ];
    int           i;
  } tmp;

  tmp.b[0] = read_spi();    // Lies erstes Byte vom SPI-Bus
  tmp.b[1] = read_spi();    // Lies zweites Byte vom SPI-Bus

  return tmp.i;
}

Kann man auch machen, kommt aber u.U. der gleiche Murx bei raus.

Gruss,
Baku

von Baku (Gast)


Lesenswert?

Autsch, die Schieberichtung hatte ich übersehen...

von Marco S (Gast)


Lesenswert?

Hallo.

Muss es nicht ergebnis = ergebnis << 8 heissen?

Gruß Marco

von Thomas Thiry (Gast)


Lesenswert?

Ja okay, die Schieberichtung war falsch herum und auch die
Integer-Definition habe ich bei mir im konkreten Programm auf unsigned
int.

Auf jeden Fall lag ich mit meiner Meinung richtig, dass Variante 1
ziemlich unsicher ist und ich davon im Bereich
Mikrocontrollerprogrammierung wohl besser die Finger lassen werde.

Danke für eure Meinungen.

Gruß
Thomas

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.