Question

I have declared an array of bytes:

uint8_t memory[123];

which i have filled with:

memory[0]=0xFF;
memory[1]=0x00;
memory[2]=0xFF;
memory[3]=0x00;
memory[4]=0xFF;

And now i get requests from the user to write in certain bits. For example, the user provides the starting bit (ex:10), the amount of bits (ex:9) and what bits to set. In the example I provided I would receive 2 bytes:

setbit[0]=0b11110010;
setbit[1]=0b00000001; //padded with zeros for extra bits

This will be used for Modbus which is a big-endian protocol. I have come up with the following code:

for(int j=findByteINIT;j<(findByteFINAL);j++){

   aux[0]=(unsigned char) (setbit[j]>>(startingbit-(8*findByteINIT)));
   aux[1]=(unsigned char) (setbit[j+1]<<(startingbit-(8*findByteINIT)));

   memory[j]=(unsigned char) (aux[0] & memory[j] );
   memory[j+1]=(unsigned char) (aux[1] & memory[j+1] );


   aux[0]=0x00;//clean aux
   aux[1]=0x00;

        }

which does not work but should be close to the ideal solution. Any suggestions?

Était-ce utile?

La solution

I think this should work. However I've only tested it lightly.

  int start_bit = 10; int bit_count = 9;
  uint8_t setbit[2] = { 0b11110010, 0b00000001 };

  int setbit_size = (bit_count + (CHAR_BIT - 1)) / CHAR_BIT;

  int start_byte = start_bit / CHAR_BIT;
  int shift = start_bit % CHAR_BIT;
  int modified_bytes =
      bit_count ? (bit_count + shift + (CHAR_BIT - 1)) / CHAR_BIT : 0;

  for (int i = 0; i < modified_bytes; ++i) {
    uint8_t mask = 0xFF;
    if (i == 0) {
      mask <<= shift;
    } else if (i == modified_bytes - 1) {
      mask >>= CHAR_BIT - (bit_count + shift) % CHAR_BIT;
    }

    uint8_t carried = i > 0 ? (setbit[i - 1] >> (CHAR_BIT - shift)) : 0;
    uint8_t added = i < setbit_size ? static_cast<uint8_t>(setbit[i] << shift) : 0;
    memory[start_byte + i] =
        (memory[start_byte + i] & ~mask) | ((carried | added) & mask);
  }

Autres conseils

You can use these macros.

#define ISBITARRAYSET(b,arr)      (((arr)[(b)/8]&(1<<((b)%8)))==0?FALSE:TRUE)
#define ISBITARRAYCLR(b,arr)      (((arr)[(b)/8]&(1<<((b)%8)))==0?TRUE:FALSE)
#define SETBITARRAY(b,arr)        ((arr)[(b)/8]|= (1<<((b)%8)))
#define CLRBITARRAY(b,arr)        ((arr)[(b)/8]&= ~(1<<((b)%8)))

Example:

#define BIT10 0x0A;

    if( ISBITARRAYCLR(BIT10,myarray) )
    {
        SETBITARRAY(BIT10,myarray);
    }

Regards.

Should be close to an ideal solution, but

1) Probably you meant to shift left, followed by a shift right for the remaining bits

aux[0] = setbit[j] << (startingbit-(8*findByteINIT))
aux[1] = setbit[j] >> (8 - (startingbit-(8*findByteINIT)))

if startingbit is 10, I suspect findByteINIT would become 1, so

startingbit-(8*findByteINIT)     ==  2
0b11110010 << 2    ==   0b11001000

and aux[1] :

8 - (startingbit-(8*findByteINIT))     ==  6
0b11110010 >> 6    ===  0b00000011

together with the 8 bits skipped with findByteINIT :

   aux[1]    aux[0]   skipped
0b 000000011 11001000 00000000 
                  ^  11110010 starting at bit 10 

2) the 0b prefix is not standard, it is not much portable

3) if you meant to set the bits, use or instead of and.

  memory[j]=(unsigned char) (aux[0] | memory[j] );
  // (aux[0] & memory[j] )  just clears the bits of memory[j] not set in aux[0]
  // also, shorter form:
  memory[j] |= aux[0];
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top