Search code examples
cbytebitbit-shift

How do I transform column data into row data?


I'm sorry about the title, I just couldn't figure out a good one. I have a vector of 8 bytes. Each element of the vector is the column data for a 8x8 led matrix I'm using. So if the first element of the vector is "11110000", that means that the first 4 leds of the column are on, and the rest are off. I need to transform this "column data", into "row data". I'll show you what I mean, using an example:

  0     1     0     1
  1     0     0     1
  0     0     1     1
  1     1     1     1
  =     =     =     =
v1[0] v1[1] v1[2] v1[3]

I will use half bytes for this example, for simplicity (the actual vector is a vector of bytes). v1[0] is the first column .. v[3] is the last. For v1[0] = "0101", the MSB is at the top of the matirx, and LSB is at the bottom (this is how my 8x8 led matrix is organized). Now, I have to take another vector, and collect from the first vector, the rows, so the "row vector" will look like this:

v2[0] = 0101
v2[1] = 1001
v2[2] = 0011
v2[3] = 1111

This is what I've tried so far:

unsigned char vector[8] = {15, 15, 15, 15, 15, 15, 15, 15};
unsigned char x = 0;
unsigned char mask = 128;

for (int i = 0; i < 8; i++)
{
    printf("%i ", vector[i]);
}
printf("\n");

for (int i = 0; i < 8; i++)
{
    x = 0;
    for (int j = 0; j < 8; j++)
    {
        x |= vector[j] & mask;
        x >>= 1;
    }
    mask >>= 1;
    printf("%i ", x);
}
printf("\n");

So my column vector is full of 15, so "00001111". The first 4 elements of the row vector should be "00000000", and the last 4 should be "11111111". I don't use a vector for the rows is my code, for simplicity, I just make the "row", and I print it. The ideea behind this code is to use a mask = 128 ("10000000"), and iterate through the column vector, and take the first bit of every element. When I take a bit from an element, I shift "x", my row variable, to the right, in order to make room for the next bit. After I'm, done with a row, I shift the mask to the right, to take the second bit from the columns. This code should print:

15 15 15 15 15 15 15 15
0 0 0 0 255 255 255 255

But it prints:

15 15 15 15 15 15 15 15
0 0 0 0 7 3 1 0

What is wrong with the code?

Edit: Let me give you another example. If my column vector is full of 255, so that every element is "11111111", that means that my row vector should be also full of 255. My code instead of this:

255 255 255 255 255 255 255 255
255 255 255 255 255 255 255 255

Outputs this:

255 255 255 255 255 255 255 255
127 63 31 15 7 3 1 0

Solution

  • Let's take a closer look at the inner loop:

    for (int j = 0; j < 8; j++)
    {
        x |= vector[j] & mask;
        x >>= 1;
    }
    

    In this loop you need to generated a value for each bit position for x.

    The first time through this loop mask is 128 so it grabs the high order bit from each byte in the vector, putting it in the high order bit in x which is then shifted right. When you exit this loop you've shifted one time too many so you end up with an empty high bit.

    The next time through this loop mask is 64, so it isolates the second bit (from the left) and puts it in the second bit in x, then shifts it right. Note than now the high order bit of x never gets set. The same happens in later iterations of the outer loop, with more bits from x not getting touched.

    What you need to do instead after getting the isolated bit is to shift it into the correct position before placing it into x. This can be done by first applying the ! operator twice to the isolated bit to normalize it into a 1 or 0, then shifting it left based on the current value of j:

    for (int j = 0; j < 8; j++)
    {
        x |= !!(vector[j] & mask) << (7 - j);
    }