Forum: Mikrocontroller und Digitale Elektronik AVR 24bit SPI signed 2er Komplement in int32_t


von Johannes (Gast)


Lesenswert?

Hallo,

ich habe mal eine Frage:

Ich habe einen HX711 Wiegesensor an einen AVR angeschlossen.

Dabei lese ich Bitweise den 24bit ADC Wert als signed 2er Komplement in 
eine int32_t Wert ein. (Jedes Bit am Eingang auf Null oder ein prüfen, 
bei 1 dann plus eins und dann immer ein Bit nach links shiften.

Jetzt habe ich Quasi in der int32_t den Wert des HX711, kann damit aber 
nicht weiterrechnen, da ja die ersten 8 Bit immer 0 sind.

Wie wandele ich nun am besten den Wert in einen "echten" int32_t um?

Würde es so evtl. funktionieren?

if (hxwert & (1<<23)) {
    hxwert |= 
(1<<31)|(1<<30)|(1<<29)|(1<<28)|(1<<27)|(1<<26)|(1<<25)|(1<<24);
  }

Oder habe ich da falsch gedacht? Weil die Werte nicht so sind, wie ich 
sie eigentlich erwartet hätte.

von Andreas R. (andreasr)


Lesenswert?

> Würde es so evtl. funktionieren?
ja
oder auch
if (hxwert & 0x800000) hxwert |= 0xff000000;

von Markus H. (traumflug)


Lesenswert?

Johannes schrieb:
> Dabei lese ich Bitweise den 24bit ADC Wert als signed 2er Komplement in
> eine int32_t Wert ein. (Jedes Bit am Eingang auf Null oder ein prüfen,
> bei 1 dann plus eins und dann immer ein Bit nach links shiften.

Klingt gut. Mit etwas Glück könnte das auch die SPI-Hardware übernehmen.

> Jetzt habe ich Quasi in der int32_t den Wert des HX711, kann damit aber
> nicht weiterrechnen, da ja die ersten 8 Bit immer 0 sind.

Wo liegt da das Problem? Es ist völlig OK, dass die oberen 8 Bit Null 
sind.

Ist es vielleicht ein Problem der Endianness, also dass höherwertige und 
niederwertige Bytes vertauscht werden? Oder ist die Variable am Anfang 
des einlesens nicht Null? Ich würde mal die erwarteten Werte mit den 
gelesenen Werten auf Bit-Ebene vergleichen.

von Walter (Gast)


Lesenswert?

Markus H. schrieb:
> Wo liegt da das Problem? Es ist völlig OK, dass die oberen 8 Bit Null
> sind.

gilt nur bei positiven Zahlen!

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Wenn es avr-gcc-ish sein darf, geht auch
1
hxwert = (__int24) hxwert;

von Ulrich P. (uprinz)


Lesenswert?

Die Frage ist ja, welcher Ausgabeart dein HX11 Wiegesensor folgt?

Signed-Magnitude:
Das oberste Bit repräsentiert das Minus-Zeichen
Das oberste Bit muss entfernt und der Wert mit -1 multipliziert werden.

1er-Complement:
http://de.wikipedia.org/wiki/Einerkomplement
Das oberste Bit muss entfernt und der Wert invertiert werden.

2er-Complement:
http://de.wikipedia.org/wiki/Zweierkomplement
Invertieren und noch einmal +1 rechnen.

Du kannst zwar die 24 bit auf 32 bit erweitern, in dem Du bit 23 
abfragst und in die Bits 24..31 "umlegst" aber eventuell musst Du noch 
+1 rechnen.

Datenblatt Seite 4:

The output 24 bits of data is in 2’s complement format. When input 
differential signal goes out of the 24 bit range, the output data will 
be saturated at 800000h (MIN) or 7FFFFFh (MAX), until the input signal 
comes back to the input range.

Alles klar?

Gruß
Ulrich

von Johannes (Gast)


Lesenswert?

Also ich lese die 24 bit manuell ohne SPI mit dem ATMEGA 8 ein.

Ich prüfe jedes Bit und shifte dann immer eins nach links.

Sodass dann in der int_32t die ersten 24 Bits befüllt sind.
Dann führe ich if (hxwert & 0x800000) hxwert |= 0xff000000; aus.

Jetzt habe ich aber das seltsame Phänomen das die Werte im Positiven und 
Negativen Bereich springen.

Es scheint so als wenn das signed Flag falsch berücksichtigt wird.

Kann es sein das da irgendwas vom C-Compiler falsch gecastet wird etc?
Ich finde den Fehler momentan einfach nicht.

Hier der CODE:

int32_t hxread()
{
  volatile int32_t hxwert;
  //volatile int32_t temp2;

  //Prüfen bzw. warten bis HX Ready ist
  while (!HX_READY);

  hxwert=0;
  for (uint8_t i=0; i<24;i++)
  {
    PORTD |= (1<<HX_SCK); //Puls an SCK Ausgeben
    _delay_us(0.5);
    if (PIND & (1<<HX_DATA))
    {
      hxwert+=1;
    }
    hxwert <<=1; //Werte um eins weiter nach links shiften
    PORTD &= ~(1<<HX_SCK); //SCK wieder auf LOW
    _delay_us(0.5);
  }
  hxwert >>=1;
  PORTD |= (1<<HX_SCK); //Puls an SCK Ausgeben
  _delay_us(0.5);
  PORTD &= ~(1<<HX_SCK); //SCK wieder auf LOW
  _delay_us(0.5);



  if (hxwert & 0x800000){hxwert |= 0xFF000000;} //in echte int32_t 
umwandeln

  //if (hxwert & (1<<23)) {
  //  hxwert |= 
(1<<31)|(1<<30)|(1<<29)|(1<<28)|(1<<27)|(1<<26)|(1<<25)|(1<<24);
  //}

  return hxwert;
}

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.