74HC165, parallel to serial data conversion, C Code to read & store the 8-bit Input into register

Thread Starter

rdd

Joined Nov 6, 2017
6
Hi dear friends,

Thanks for providing the opportunity to interact with you experts!

Here I want to perform parallel to serial data conversion. Therefore I am using 74HC165, 8-bit parallel-in/serial-out shift register.

I need C code to read & store the fault status into Variable( say unsigned char). I tried below C code but its not working.

Basically I have an 8 Window Annunciator product where I want to read the Eight different Fault status. These faults can be either Logic 0 or Logic 1. Now these Eight status shall be collected into a Variable(datatype: unsigned char, as value 0b00000000/ 0b11111111 is possible)

Hardware logic is illustrated as shown in fig(A):

D0 to D7 are eight fault status which can be either Logic 0 or Logic 1.

C Code to read & store the status is attached as follows:


So kindly suggest the correct C code to read & store the fault status into Variable.

Thanks!

Regards,

Santosh Bhat

Sr. Engg, Bangalore

C:
void CHK_FAULT_INPUT(void)
{
   unsigned char a=0, Val=0;

   PL_ENABLE = 1;
   SERIAL_CLK = 0;
   CHIP_ENABLE = 1;
   PL_ENABLE = 0; // PL
   asm("nop");
   asm("nop");
   CHIP_ENABLE = 0; // CE
   asm("nop");
   asm("nop");
   SERIAL_CLK = 0; // CP
   asm("nop");
   asm("nop");
   SERIAL_CLK = 1;
   asm("nop");
   asm("nop");

// FAULT_PAT: Q7
   if((FAULT_PAT & 0b00000001) == 1)
     FAULT_InP1 = 0b00000001;
   else
     FAULT_InP1 = 0b00000000;

   asm("nop");
   SERIAL_CLK = 0;
   asm("nop");
   asm("nop");
   SERIAL_CLK = 1;
   asm("nop");
   asm("nop");

   if((FAULT_PAT & 0b00000010) == 1)
     FAULT_InP2 = 0b00000010;
   else
     FAULT_InP2 = 0b00000000;

   asm("nop");
   SERIAL_CLK = 0;
   asm("nop");
   asm("nop");
   SERIAL_CLK = 1;
   asm("nop");
   asm("nop");

   if((FAULT_PAT & 0b00000100) == 1)
     FAULT_InP3 = 0b00000100;
   else
     FAULT_InP3 = 0b00000000;

   asm("nop");
   SERIAL_CLK = 0;
   asm("nop");
   asm("nop");
   SERIAL_CLK = 1;
   asm("nop");
   asm("nop");
   if((FAULT_PAT & 0b00001000) == 1)
     FAULT_InP4 = 0b00001000;
   else
     FAULT_InP4 = 0b00000000;

   asm("nop");
   SERIAL_CLK = 0;
   asm("nop");
   asm("nop");
   SERIAL_CLK = 1;
   asm("nop");
   asm("nop");
   if((FAULT_PAT & 0b00010000) == 1)
     FAULT_InP5 = 0b00010000;
   else
     FAULT_InP5 = 0b00000000;

   asm("nop");
   SERIAL_CLK = 0;
   asm("nop");
   asm("nop");
   SERIAL_CLK = 1;
   asm("nop");
   asm("nop");

   if((FAULT_PAT & 0b00100000) == 1)
     FAULT_InP6 = 0b00100000;
   else
     FAULT_InP6 = 0b00000000;

   asm("nop");
   SERIAL_CLK = 0;
   asm("nop");
   asm("nop");
   SERIAL_CLK = 1;
   asm("nop");
   asm("nop");

   if((FAULT_PAT & 0b01000000) == 1)
     FAULT_InP7 = 0b01000000;
   else
     FAULT_InP7 = 0b00000000;

   asm("nop");
   SERIAL_CLK = 0;
   asm("nop");
   asm("nop");
   SERIAL_CLK = 1;
   asm("nop");
   asm("nop");

   if((FAULT_PAT & 0b10000000) == 1)
     FAULT_InP8 = 0b10000000;
   else
     FAULT_InP8 = 0b00000000;

   asm("nop");
   FAULT_InP = FAULT_InP1 + FAULT_InP2 + FAULT_InP3 + FAULT_InP4 +
   FAULT_InP5 + FAULT_InP6 + FAULT_InP7 + FAULT_InP8;
   SERIAL_CLK = 0;
   CHIP_ENABLE = 1;
   PL_ENABLE = 1;
}
Mod edit: code tags
Note that .PDF format is difficult to work with for looking at your code.
 

Attachments

Last edited by a moderator:

Ian Rogers

Joined Dec 12, 2012
660
What micro are you going to use.. It matters not, but if I can use the same compiler and chip as you, it will be easier to help.

That's a long winded way to clock in 8 switches...
 

djsfantasi

Joined Apr 11, 2010
5,583
Why do you need a parallel to serial conversion? With an 8 to 1 decoder, such as a 74LS138, you can address each data pin and read in its status with four pins on the MCU.
 

JohnInTX

Joined Jun 26, 2012
3,799
One problem might be this:
if((FAULT_PAT & 0b00000001) == 1) // test shift register bit on the single bit input line connected to QH
then this:
if((FAULT_PAT & 0b00000010) == 1) // this tests a different bit on the port bit

You are doing it the hard way though. Latching parallel data then reading by shifting into a single bit port can be done in a loop:
C:
// Latches the data into shift register then shifts it in a bit at a time by
// 1) clocking the shift register then
// 2) making room in the Input register by shifting
// 3) reading Qh (MSbit shifted out from latch)
// 4) setting the bit in Input reg if the shifted out bit is 1

#define FAULT_IN_FROM_SHIFT_REG_MASK 0x01  // whatever bit QH is read on

unsigned char CHK_FAULT_INPUT(void)
{
   unsigned char Input;   // accumulates image of 8 switches

   SERIAL_CLK = 1;     // make sure clock is 1
   PL_ENABLE = 0;     // latch data
   PL_ENABLE = 1;
   for(i=0;i<8; i++){   // 8 bits
     Input <<= 1;   // shift left to make room for bit, reg LSbit is 0 after shift
     if(FAULT_PAT & FAULT_IN_FROM_SHIFT_REG_MASK)
       Input |= 0x01; // if input == 1, set LSbit in Input register
     SERIAL_CLK = 0;   // shift next bit out
     SERIAL_CLK = 1;
   }
   return(Input);
}
I didn't test this but you get the idea. That's how I'd do it..

Good luck.
EDIT; Obo
 

Attachments

Last edited:

Thread Starter

rdd

Joined Nov 6, 2017
6
What micro are you going to use.. It matters not, but if I can use the same compiler and chip as you, it will be easier to help.

That's a long winded way to clock in 8 switches...


Thanks for the interest!

I am using PIC16F1938 microcontroller in which PL, CE, CP & Q7 outputs of 74HC165 are given as I/P to microcontroller. So microcontroller Port pins are configured as INPUT and other functions of the port( ANSEL, O/P, LATCH etc. are disabled)

Regards,
Santosh
 

Thread Starter

rdd

Joined Nov 6, 2017
6
Why do you need a parallel to serial conversion? With an 8 to 1 decoder, such as a 74LS138, you can address each data pin and read in its status with four pins on the MCU.
Thanks for the interest!

I dont have much idea about 74LS138, but as you rightly pointed out, I need to read 8 different Fault status and store it into any variable/register.
Can you please guide me to make use of 74LS138 with C code/Logic so that finally I shall be able to store 8 Fault status.

I am using PIC16F1938 microcontroller in which PL, CE, CP & Q7 outputs of 74HC165 are given as I/P to microcontroller. So microcontroller Port pins are configured as INPUT and other functions of the port( ANSEL, O/P, LATCH etc. are disabled)

Regards,
Santosh
 

Thread Starter

rdd

Joined Nov 6, 2017
6
One problem might be this:
if((FAULT_PAT & 0b00000001) == 1) // test shift register bit on the single bit input line connected to QH
then this:
if((FAULT_PAT & 0b00000010) == 1) // this tests a different bit on the port bit

You are doing it the hard way though. Latching parallel data then reading by shifting into a single bit port can be done in a loop:
C:
// Latches the data into shift register then shifts it in a bit at a time by
// 1) clocking the shift register then
// 2) making room in the Input register by shifting
// 3) reading Qh (MSbit shifted out from latch)
// 4) setting the bit in Input reg if the shifted out bit is 1

#define FAULT_IN_FROM_SHIFT_REG_MASK 0x01  // whatever bit QH is read on

unsigned char CHK_FAULT_INPUT(void)
{
   unsigned char Input;   // accumulates image of 8 switches

   SERIAL_CLK = 1;     // make sure clock is 1
   PL_ENABLE = 0;     // latch data
   PL_ENABLE = 1;
   for(i=0;i<7; i++){   // 8 bits needs 7 shifts
     Input <<= 1;   // shift left to make room for bit, reg LSbit is 0 after shift
     if(FAULT_PAT & FAULT_IN_FROM_SHIFT_REG_MASK)
       Input |= 0x01; // if input == 1, set LSbit in Input register
     SERIAL_CLK = 0;   // shift next bit out
     SERIAL_CLK = 1;
   }
   return(Input);
}
I didn't test this but you get the idea. That's how I'd do it..

Good luck.
Dear JohnIn Tx Sir,
Thanks for the interest!

One problem might be this:
if((FAULT_PAT & 0b00000001) == 1) // test shift register bit on the single bit input line connected to QH
then this:
if((FAULT_PAT & 0b00000010) == 1) // this tests a different bit on the port bit

:- Yes sir, I am shifting the bit to left to check the status of next fault, as I understand 74HC165 checks/sends on Q7, the individual bit after every Low to High transition of Clock, therefore I am reading First fault status after Low to High transition of Clock then shifting the bit to left to check the status of next fault by making the Clock Low to High transition again till all 8 status are checked.

I would definitely go through your suggested code to verify the same and get back to you!

Thanks!
Regards,
Santosh
 

Ian Rogers

Joined Dec 12, 2012
660
I have just done this with the SPI module....

LD high
SPI receive
LD low

Pin 9 to SDI
Pin 2 to SCK
Pin 1 to SS output
Pin 15 to ground

Works like a charm
 

JohnInTX

Joined Jun 26, 2012
3,799
One problem might be this:
if((FAULT_PAT & 0b00000001) == 1) // test shift register bit on the single bit input line connected to QH
then this:
if((FAULT_PAT & 0b00000010) == 1) // this tests a different bit on the port.

:- Yes sir, I am shifting the bit to left to check the status of next fault, as I understand 74HC165 checks/sends on Q7, the individual bit after every Low to High transition of Clock, therefore I am reading First fault status after Low to High transition of Clock then shifting the bit to left to check the status of next fault by making the Clock Low to High transition again till all 8 status are checked.
One of us is missing the point. I am assuming that FAULT_PAT is the input port with Q7 connected to one pin. As you clock the shift register, the Q value of the next flip/flop in the shift register will be output on Q7 but that doesn't change the physical bit that Q7 is connected to on the input port. The test for 1 or 0 needs to have the same mask.

It's worth noting that your original code reverses the order of the bits read i.e. the shift register outputs the MSbit first but you are storing it as the LSbit.

But now that we know that your chip has an SPI, consider using the SPI as @Ian Rogers suggests. I've also successfully used the SPI for shift registers to expand both inputs and outputs.

Good luck!
 
Last edited:

BobaMosfet

Joined Jul 1, 2009
782
Hi dear friends,

Thanks for providing the opportunity to interact with you experts!

Here I want to perform parallel to serial data conversion. Therefore I am using 74HC165, 8-bit parallel-in/serial-out shift register.

I need C code to read & store the fault status into Variable( say unsigned char). I tried below C code but its not working.

Basically I have an 8 Window Annunciator product where I want to read the Eight different Fault status. These faults can be either Logic 0 or Logic 1. Now these Eight status shall be collected into a Variable(datatype: unsigned char, as value 0b00000000/ 0b11111111 is possible)

Hardware logic is illustrated as shown in fig(A):

D0 to D7 are eight fault status which can be either Logic 0 or Logic 1.

C Code to read & store the status is attached as follows:


So kindly suggest the correct C code to read & store the fault status into Variable.

Thanks!

Regards,

Santosh Bhat

Sr. Engg, Bangalore

C:
void CHK_FAULT_INPUT(void)
{
   unsigned char a=0, Val=0;

   PL_ENABLE = 1;
   SERIAL_CLK = 0;
   CHIP_ENABLE = 1;
   PL_ENABLE = 0; // PL
   asm("nop");
   asm("nop");
   CHIP_ENABLE = 0; // CE
   asm("nop");
   asm("nop");
   SERIAL_CLK = 0; // CP
   asm("nop");
   asm("nop");
   SERIAL_CLK = 1;
   asm("nop");
   asm("nop");

// FAULT_PAT: Q7
   if((FAULT_PAT & 0b00000001) == 1)
     FAULT_InP1 = 0b00000001;
   else
     FAULT_InP1 = 0b00000000;

   asm("nop");
   SERIAL_CLK = 0;
   asm("nop");
   asm("nop");
   SERIAL_CLK = 1;
   asm("nop");
   asm("nop");

   if((FAULT_PAT & 0b00000010) == 1)
     FAULT_InP2 = 0b00000010;
   else
     FAULT_InP2 = 0b00000000;

   asm("nop");
   SERIAL_CLK = 0;
   asm("nop");
   asm("nop");
   SERIAL_CLK = 1;
   asm("nop");
   asm("nop");

   if((FAULT_PAT & 0b00000100) == 1)
     FAULT_InP3 = 0b00000100;
   else
     FAULT_InP3 = 0b00000000;

   asm("nop");
   SERIAL_CLK = 0;
   asm("nop");
   asm("nop");
   SERIAL_CLK = 1;
   asm("nop");
   asm("nop");
   if((FAULT_PAT & 0b00001000) == 1)
     FAULT_InP4 = 0b00001000;
   else
     FAULT_InP4 = 0b00000000;

   asm("nop");
   SERIAL_CLK = 0;
   asm("nop");
   asm("nop");
   SERIAL_CLK = 1;
   asm("nop");
   asm("nop");
   if((FAULT_PAT & 0b00010000) == 1)
     FAULT_InP5 = 0b00010000;
   else
     FAULT_InP5 = 0b00000000;

   asm("nop");
   SERIAL_CLK = 0;
   asm("nop");
   asm("nop");
   SERIAL_CLK = 1;
   asm("nop");
   asm("nop");

   if((FAULT_PAT & 0b00100000) == 1)
     FAULT_InP6 = 0b00100000;
   else
     FAULT_InP6 = 0b00000000;

   asm("nop");
   SERIAL_CLK = 0;
   asm("nop");
   asm("nop");
   SERIAL_CLK = 1;
   asm("nop");
   asm("nop");

   if((FAULT_PAT & 0b01000000) == 1)
     FAULT_InP7 = 0b01000000;
   else
     FAULT_InP7 = 0b00000000;

   asm("nop");
   SERIAL_CLK = 0;
   asm("nop");
   asm("nop");
   SERIAL_CLK = 1;
   asm("nop");
   asm("nop");

   if((FAULT_PAT & 0b10000000) == 1)
     FAULT_InP8 = 0b10000000;
   else
     FAULT_InP8 = 0b00000000;

   asm("nop");
   FAULT_InP = FAULT_InP1 + FAULT_InP2 + FAULT_InP3 + FAULT_InP4 +
   FAULT_InP5 + FAULT_InP6 + FAULT_InP7 + FAULT_InP8;
   SERIAL_CLK = 0;
   CHIP_ENABLE = 1;
   PL_ENABLE = 1;
}
Mod edit: code tags
Note that .PDF format is difficult to work with for looking at your code.

I recognize the efficiency of using assembly language in terms of space-saving-- that doesn't have to change. but the way you are doing it makes me think you're not fully understanding the relationship between CP and CE.

Without going the SPI method, the proper way to do this starts with understanding the entire operation of the serial side of this chip hinges on CP and CE. That's your heartbeat. CP = Clock Pulse, and CE = Clock Enable.

Essentially, you set up a clock at a speed you want to run at, that generates continuous pulses on the CP pin. The only time the 74HC165 will pay attention to that clock is when you toggle it to do so with CE. At which time it will start pulsing the data out of itself towards Q7. Your start of sequence begins with toggling PL. That locks the parallel side, and then you toggle CE, and start reading input from Q7.

Now, the easiest way to do this, is make your clock routine, that generates continuous pulses on CP, check the state of your flag that sets CE. If CE AND CP (logically AND them together) are both high, then you are taking input from the 74HC165, and you branch and read pin Q7 input into an 8-bit register, shifted to the proper position to account for MSB .v. LSB orientation, and exit your clock routine.

Once you've read 8-bits, you toggle CE to disable clocked transfer, handle the information you've received to deal with your alarms, and then repeat the cycle.

Everything is clocked. In order to reliably read Q7 inputs, you have to read them in time with your CP signal. Otherwise the values you get could be either 0 or 1, incorrectly based on lack of sync with CP. The beauty of this method is that you can either drive CP with an interrupt, or not. It isn't the frequency or even regularity of a clock that makes a simple protocol like this work- it's simply utilizing a clock pulse to determine when to pay attention to Q7, and when not.

Hope that helps.
 
Last edited:
Top