Manipulating bits

Ok, I’m having a bit of trouble. I have been experimenting with using an off-board and so far everything has been going great. But now I’m having trouble fitting 10 gallons in an 8 gallon hat. My problem is that we have set up the serial link to send 8 bits at a time. Its perfect for sending joystick or pwm values back and forth but what happens when I want to send an integer that I have given an analog value? I know I can bit shift off the two right most bits and then replace them when they get to the coprocessor with zeros. That gives me the same value as when it was sent within 3. My question is, is there a way in c to take the two right-most bits of a value and put them into a byte and then fill up the rest of the byte with other right most bits of values so I don’t wast space. I know how to cut this byte back up and distribute the bits to their corresponding values (my coprocessor runs on python) but I don’t know how I would package and send something like this in C. Does anyone have a solution to this problem?

-Don

Read up on the bitwise operators:
~ (NOT)
& (AND)
^ (XOR)
| (OR)

You can use these to manipulate bits pretty easily.

OK, got it. There was a great example on wikipedia.
Thanks!

-Don

It looks like you are trying to “serialize” or “marshal” your data. Googling these terms may help.

In C, one nifty trick is to recast your data as strings.


int n=4;
char * s = (char *)&n;

Then, write a function that can push strings across.

One word of warning about the PIC, though it probably doesn’t apply in your case if you’re just using shifts for bit manipulation. Right shifts are unsigned only. So if you have a signed int that you want to divide by 4, x >> 2 only works if the value is positive. A negative value will have 0 shifted into the high order bits and will end up looking like a positive number.


144:                   var1 = var1 >> 2;
 04524    0101     MOVLB 0x1
 04526    90D8     BCF 0xfd8, 0, ACCESS                ; set Carry flag to '0'
 04528    33E7     RRCF 0xe7, F, BANKED                ; C -> var1.hi -> C
 0452A    33E6     RRCF 0xe6, F, BANKED                ; C -> var1.lo -> C
 0452C    90D8     BCF 0xfd8, 0, ACCESS                ; set C flag to '0'
 0452E    33E7     RRCF 0xe7, F, BANKED                ; shift again
 04530    33E6     RRCF 0xe6, F, BANKED

Its more accurate to say the compiler doesn’t support signed shifts. The PIC is capable of doing signed shifts if asked to. All shifts are treated as unsigned by the compiler and have the carry in flag set to zero during the rotations. The PIC is capable of shifting in a ‘1’ for negative values but the compile chooses not to – 'cause all shifting operations are unsigned. Other compilers, such as HI-TECH’s PIC C compiler chose to preserve the sign bit. This is a compiler specific implementation selection allowed by the ANSI C spec.

If you want to do signed shifts, you have to roll your own and change the instructions to:


    BTFSC 0xe7, 7, BANKED
    BRA     NEGVALUE_SHIFT
POSVALUE_SHIFT:
    BCF     0xfd8, 0, ACCESS                      ; Set CARRY (C) flag to '0'
    RRCF    0xe7, F, BANKED                       ; C -> var1.hi -> C
    RRCF    0xe6, F, BANKED                       ; C -> var1.lo -> C
    BCF     0xfd8, 0, ACCESS                      ; clear C flag for next shift op
    RRCF    0xe7, F, BANKED
    RRCF    0xe6, F, BANKED
    BRA     DONE_SHIFT
NEGVALUE_SHIFT:
    BSF     0xfd8, 0, ACCESS                      ; Set CARRY (C) flag to '1'
    RRCF    0xe7, F, BANKED                       ; C -> var1.hi -> C
    RRCF    0xe6, F, BANKED                       ; C -> var1.lo -> C
    BSF     0xfd8, 0, ACCESS                      ; set C flag for next shift op
    RRCF    0xe7, F, BANKED
    RRCF    0xe6, F, BANKED
    BRA     DONE_SHIFT
DONE_SHIFT:

alternatively, in C a little more convoluted… plus there are other methods.


    if (var1 > 0)
        var1 = (var1 >> 2);
    else
        var1 = (varl >> 2) | 0xC000;