bit-manipulationbitwise-operatorspicpic18mplab-c18

PIC C18: Reading bits from a byte


I have a very elementary question. However, what ever I tried, I couldn't successfully implement this.

I have a shift register (74LS164) connected to PIC18F2550 with the following hardware configuration:

// Data pin
#define SCLCD_DATA          LATBbits.LATB7
#define SCLCD_DATA_TRIS     TRISBbits.TRISB7

// Clock pin
#define SCLCD_CLOCK         LATBbits.LATB6
#define SCLCD_CLOCK_TRIS    TRISBbits.TRISB6

LEDs are connected to the output pins of 74LS164 to view its status. I have an 8-bit variable declared as unsigned char. I want to send the bits of this variable to the shift register. The shift register has internal flip-flops whose outputs are named as Q0-Q7. The first sent bit loads into Q0, when you send a second bit, previous Q0 shifts to Q1 and the newly sent bit comes to Q0, and this goes so on as you send succeeding bits. When the sending is completed, LSB of the variable is supposed to be on the Q0 of the shift register, and MSB will be on Q7.

My code is like this (Language is C18):

void SCLCD_SendSerialBits(unsigned char unRegister)
{
    // ucRegister is always passed as 0b10101010 for test
    for (i=0; i<8; i++)
    {
        SCLCD_CLOCK = 0;
        SCLCD_DATA = ((ucRegister & 0b10000000) == 0b10000000) ? 1 : 0;
        ucRegister = ucRegister << 1;
        SCLCD_CLOCK = 1;
    }
}

The code above doesn't run as I want to. When I run it, all the LEDs light on, as if I had loaded 0b11111111 into the ucRegister variable.

However, the following one works very well:

void SCLCD_SendSerialBits(void)
{
    SCLCD_CLOCK = 0;    SCLCD_DATA = 1;     SCLCD_CLOCK = 1;
    SCLCD_CLOCK = 0;    SCLCD_DATA = 0;     SCLCD_CLOCK = 1;
    SCLCD_CLOCK = 0;    SCLCD_DATA = 1;     SCLCD_CLOCK = 1;
    SCLCD_CLOCK = 0;    SCLCD_DATA = 0;     SCLCD_CLOCK = 1;
    SCLCD_CLOCK = 0;    SCLCD_DATA = 1;     SCLCD_CLOCK = 1;
    SCLCD_CLOCK = 0;    SCLCD_DATA = 0;     SCLCD_CLOCK = 1;
    SCLCD_CLOCK = 0;    SCLCD_DATA = 1;     SCLCD_CLOCK = 1;
    SCLCD_CLOCK = 0;    SCLCD_DATA = 0;     SCLCD_CLOCK = 1;
}

What is wrong with my code? I thing the error is most likely to be on the line SCLCD_DATA = ((ucRegister & 0b10000000) == 0b10000000) ? 1 : 0;, but no matter how much I look at it, it looks perfectly OK to me. What is wrong with my code?

Any help will be appreciated.


Solution

  • Your code looks like it should work. I would write it like this to be more readable and efficient (assuming your system has a barrel shifter):

    for (i=7; i>=0; i--)
    {
        SCLCD_CLOCK = 0;
        SCLCD_DATA = ((ucRegister >> i) & 1);
        SCLCD_CLOCK = 1;
    }
    

    For systems without a barrel shifter, a variation of your code

    unsigned char ucMask = 0x80;
    
        for (i=0; i<8; i++)
        {
            SCLCD_CLOCK = 0;
            SCLCD_DATA = (ucRegister & ucMask) ? 1:0;
            ucMask >>= 1;
            SCLCD_CLOCK = 1;
        }
    

    If my first or second examples work, then it sounds like the compiler is not handling the constant values or compares correctly in your original code.