www.mikrocontroller.net

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


Autor: ThomasThiry (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Ralf (Gast)
Datum:

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

Ralf

Autor: peter dannegger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Thomas Thiry (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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;
  }

Autor: Baku (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Baku (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Autsch, die Schieberichtung hatte ich übersehen...

Autor: Marco S (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo.

Muss es nicht ergebnis = ergebnis << 8 heissen?

Gruß Marco

Autor: Thomas Thiry (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.