Teile eines Array auswerten



  • Hallo

    Vielleich hat jemand von euch eine Idee oder Hinweis.

    Ich bekomme aus eine Microcontroller Datenpakete. Diese liegen zwischen 1 und 4 Bytes. Aus diesen soll ab einen Startbit (BitOffset) auf eine Länge (BitSize) Daten herausgeschnitten werden.

    Beispiel (Bytes=2, BitOffset=4,BitSize=4)
    00110010 01011011 -> 0010

    Mein bisheriger Code

    byte test01[4]={0x30,0x33,0x22,0x11};
    Serial.println(ByteToLong(test01,1,8),BIN);
    
    unsigned long ByteToLong( byte const *bp, byte BitOffset, byte BitSize)
    {
    
      //**** Ermittelt Anzahl der Byte auf Basis des Startbits und der Laenge der Bitstring
      byte c=((BitOffset+BitSize)/8);
      (c) - (int)(c) > 0.0 ? (int)(c) + 1 : c;
    
      //**** Init Long
      unsigned long value = 0;   
    
      //**** Kopiert Byts in Long 
      memcpy( &value, bp, c );
    
      //**** Bitverschiebung
      value<<=32-(BitOffset+BitSize);
      value>>=32-BitSize;
    
      return(value);
    }
    

    1. Ein Array wird an *bp übergeben.
    2. Aus BitOffset und BitSize die notwendige Länge der Bytes welche verwendet wird (BUG)
    3. memcpy kopiert alles in eine ulong
    4. Bitverschiebung mit Basis 32 da es sich um eine Long handelt.

    Das ganze klappt so nicht, wer hat eine Tipp für mich wie es richtig funktioniert (oder eine Quellcode) - vielleicht denke ich zu umständlich.

    vielen Dank im Voraus.



  • Der Thread ist nun einige Stunden unbeantwortet, einige dutzend (wahrscheinlich teilweise sehr gute) Programmierer haben drüber geschaut und es gibt (noch) keine Lösung. Vielleicht solltest du deinen Lösungsansatz überdenken.

    Du weißt hoffentlich selber am besten, auf wieviele Bytes der Pointer zeigt, den Offset würde ich von "hinten" angeben:

    11100011 : bytes 1, offset 6, size 3
    -> 100
    

    Ein erster zweifelsohne dikussionswürdiger Schnellschuss:

    uint32_t UI8PtrToUI32(const uint8_t* val, uint8_t bytes)
    {
        uint32_t ret = 0;
        int i;
        for(i=0;i<bytes;++i)
        {
            ret <<= 8;
            ret |= val[i];
        }
        return ret;
    }
    
    uint32_t SolveIt(const uint8_t* val, uint8_t bytes, uint8_t offset, uint8_t size)
    {
        assert(offset && size);
        uint32_t ret = UI8PtrToUI32(val, bytes);
        ret >>= (offset-size);
        return ret & ((1<<size)-1);
    }
    


  • So etwas habe ich hier noch rumfliegen, hilft dir das?

    unsigned int ex(unsigned int val, unsigned int start, unsigned int len)
    {
      int t = 1 << ((sizeof(int) * CHAR_BIT) - 1);
      t >>= start - 1;
      val &= ~t;
      t ^= t >> len;
      return t & val;
    }
    


  • kuckuck!
    guckst du hier:

    c = ( BitOffset + BitSize ) / 8;
    	c * 8 == BitOffset + BitSize ? 0 : c++;
      memcpy ( &value, bp, c );
    	value <<= ( sizeof ( value ) - c ) * 8 + BitOffset;
    	value >>= ( sizeof ( value ) - c ) * 8 + BitOffset;
    


  • Erstmal vielen Dank für euer Unterstützung.

    Leider gibts noch ein Problem. Ich habe den Code von Big Brother (01) und Hmmh (02) in ein komplettes Beispiel eingearbeitet.
    Bei cooky451 bekomme ich die Daten nicht aus einen Array, tu mir etwas schwer.

    Der C Code läuft auf einen ATMEL Mikrokontroller:

    /**
    * ATMEL - MC Bitextraction
    * V0.1
    */
    
    //byte test01[]={33};
    byte test01[4]={0x22,0x11};
    //byte test01[4]={0x33,0x22,0x11};
    //byte test01[4]={0x00,0x33,0x22,0x11};
    
    void setup()
    {  
      Serial.begin(9600);
    
      Serial.print(test01[0],BIN);Serial.print("-");
      Serial.print(test01[1],BIN);Serial.print("-");
      Serial.print(test01[2],BIN);Serial.print("-");
      Serial.println(test01[3],BIN);
    
      Serial.println("Ergebnis(BitOffset=3,BitSize=7): ");
    
      Serial.println(ByteToLong01(test01,3,6),BIN);
      Serial.println(ByteToLong02(test01,2,3,6),BIN);
    
    }
    
    void loop()
    {}
    
    /** 
    * Version 01 - Big Brother
    */
    unsigned long ByteToLong01( byte const *bp, byte BitOffset, byte BitSize)
    { 
      unsigned long value=0;
      byte c = ( BitOffset + BitSize ) / 8;
      c * 8 == BitOffset + BitSize ? 0 : c++;
    
      memcpy ( &value, bp, c );
      value <<= ( sizeof ( value ) - c ) * 8 + BitOffset;
      value >>= ( sizeof ( value ) - c ) * 8 + BitOffset;
    
      return(value);
    }
    
    /** 
    * Version 02 - Hmmh
    */
    unsigned long ByteToLong02(const byte *val, byte bytes, byte offset, byte BitSize)
    {
        assert(offset && BitSize);
        unsigned long ret = UI8PtrToUI32(val, bytes);
        ret >>= (offset-BitSize);
        return ret & ((1<<BitSize)-1);
    }
    
    unsigned long UI8PtrToUI32(const byte* val, byte bytes)
    {
        unsigned long ret = 0;
        int i;
        for(i=0;i<bytes;++i)
        {
            ret <<= 8;
            ret |= val[i];
        }
        return ret;
    }
    

    Version 01:
    value <<= ( sizeof ( value ) - c ) * 8 + BitOffset;
    value >>= ( sizeof ( value ) - c ) * 8 + BitOffset;

    verstehe ich nicht!

    Version 02:
    Habe ich für ATMEL umgearbeitet.
    Leider gibts keinen assert.h für meinen compiler - was macht dieser Befehl genau - was kann man da machen?

    Danke im Voraus



  • wo ist bei dir das höchste byte,

    byte test01[4]={0x30,0x33,0x22,0x11};

    ist das die zahl 0x30332211 oder ist es die zahl 0x11223330 ?



  • 0x30332211 währe die Basis

    in der Bitfolge liegen die eigentlichen Daten verborgen.
    zb ab Bit 5 auf eine Länge von 8 Bit = Temperaturwert des Sensors

    etwas mühselig jedoch geizt der Hersteller mit jeden Bit 🙂



  • value <<= ( sizeof ( value ) - c ) * 8 + BitOffset;
      value >>= ( sizeof ( value ) - c ) * 8 + BitOffset;
    verstehe ich nicht!
    

    wassn nicht? der shift nach links und nach rechts macht alle bits, die vorm
    offset sind platt, also zu null.
    beim zurückshiften habe ich die unteren bits vergessen rauszuwerfen, also die bits, die nach offset + bitsize kommen, sorry, so sollte das funzen:

    value <<= ( sizeof ( value ) - c ) * 8 + BitOffset;
    value >>= ( sizeof ( value ) - c ) * 8 + BitOffset + c * 8 - ( BitOffset + BitSize );
    

    das ist die anschauliche version. dabei lässt sich die untere zeile vereinfachen, sodass sich zwei summenglieder aufheben zu

    value <<= ( sizeof ( value ) - c ) * 8 + BitOffset;
    value >>= 8 * sizeof ( value ) - BitSize;
    

    also im prinzip ist das die zeile, die du sie schon hattest.

    bedenke auch die byte order ( big endian, little endian ).
    gruß,
    B.B.



  • Vielen Dank für deine Hilfe, jetzt klappts

    Die Lösung (Zusammenfassung):

    USE CAse:
    Aus einen Array von 1-4 Bytes werden Abschnitte mit Startbit (BitOffset)
    und Länge (BitSize) herrausgeschnitten. Der Wert wird als uL ausgegeben.

    Die Minimalcode Variation:

    /**
    * Wandel Array zwischen 1-4 Bytes in Long und schneidet Bits Abschnitte von diesen heraus
    * @V0.3      2011.09.20
    */
    unsigned long ByteToLong( byte const *bp, byte BitOffset, byte BitSize)
    { 
      unsigned long value=0;
      byte c = ( BitOffset + BitSize ) / 8;
      c * 8 == BitOffset + BitSize ? 0 : c++;
    
      memcpy ( &value, bp, c );
    
      value <<= ( sizeof ( value ) - c ) * 8 + BitOffset;
      value >>= 8 * sizeof ( value ) - BitSize;
    
      return value;
    }
    

Anmelden zum Antworten