Search code examples
cembeddedbit-manipulation

uint8 data to uint32 bits in EMBEDDED c


I am getting the input data from my microcontroller over uint8 data the are transmitted as 0xff, 0x2a.... the the two bits are subsequntly high and low values. I need to convert this to uint_32 var where i can use memcpy

example

1C 1D 1E 1F 20 21 22 23      

if this are the VALUES that are transferred how i can get them all in a single uint32 variable, with this below approach i can just get the last two bits which is just 23 and not the entire

void Func(const uint8_t * data){
    uint32_t msgh =0;
    uint32_t msgl=0;
    uint32_t datah =0;
    uint32_t datal=0;

    for(int i= 0; i<dlc;i++){
        msgh=*data >> 4;
        msgl=*data & 0x0f;
        // printf("DATA %x%x",msgh,msgl);  
        memcpy(&datah, &msgh, 4);
        memcpy(&datal, &msgl, 4);
        // printf("msgl=%x\n",msgl);           
        data++;
    }
    printf("DATA%x%x",datah,datal);
}

Solution

  • No need to memcpying all this stuff – extracting the high and low nibbles of the bytes can be done as follows:

    uint32_t high = 0;
    uint32_t low  = 0;
    unsigned int offset = 0;
    for(int i = 0; i < 8; ++i)
    {
        high |= ((uint32_t)(*data) >> 4)   << offset;
        low  |= ((uint32_t)(*data) & 0x0f) << offset;
        offset += 4;
        ++data;
    }
    

    Note how you need to shift the offsets such that the nibbles get at their right positions within their respective 32-bit values.

    Note, too that this assumes little endian byte order of transferred data (the byte order must be known and fix as part of the protocol definition for communication!).

    Big endian order slightly differs:

    uint32_t high = 0;
    uint32_t low  = 0;
    unsigned int offset = 32;
    for(int i = 0; i < 8; ++i)
    {
        offset -= 4;
        high |= (uint32_t)(*data >> 4)   << offset;
        low  |= (uint32_t)(*data & 0x0f) << offset;
        ++data;
    }
    

    (Well, could have started with 28 as well and subtracted 4 after nibble extraction, analogously to LE variant – this variant reflects my personal preference for constants of powers of two – number of operations doesn't differ anyway…).

    Finally note that you might prefer to separate conversion and outputting into separate functions to achieve better reusability, e.g. like

    void extract(uint8_t const* data, uint32_t* high, uint32_t* low)
    {
        // assign to *high and *low analogously to above
    }
    // assuming C code; if C++, prefer references:
    void extract(uint8_t const* data, uint32_t& high, uint32_t& low);
    
    
    // or alternatively:
    
    typedef struct
    {
        uint32_t high;
        uint32-t low;
    } NibblesCombined;
    
    NibblesCombined extract(uint8_t const* data)
    {
        // assign to the members of the struct analogously to above
    }
    // again assuming C; C++ could optionally return a std::pair instead!