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
Ich halte die erste Variante für besser, da hier der Zugriff direkt erfolgen kann, und keine Schiebe-Operationen erforderlich sind... Ralf
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
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
.
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;
}
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
Hallo. Muss es nicht ergebnis = ergebnis << 8 heissen? Gruß Marco
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.