Are you running out of I/O on your Microcontroller? Seems like I’m always running out. There are never enough pins to attach the parallel display the 3×3 keyboard and the UART and SPI ports. Then you need another UART port and end up running a timer based port. Does this sound familier to you? But, wait theres more. Your boss comes to you and says we absolutely must know the temperature inside the box and outside and we have to keep a log of these temperatures. Now you are looking at adding an I2C bus to handle some serial flash and the temperature sensors. You go back to your boss and ask him for a bigger part to do this. But he says marketing wants to keep the COGs as low as possible. Impossible you say?
Well there are a pair of small chips that can save the day. They are very inexpensive and can be run with just 5ish I/O pins. They are the 74HCT595 and 74HCT597. These parts are serial to parallel and parallel to serial chips. You can attach a clock a data out and data in and be able to read and write 8 or 16 or 24 or even 32 I/O’s. I wouldn’t go much beyond 32 as this is a serial process anyway. These parts are easy to bit bang and are very low power.
I have used these chips more than once and they are a great way to interface to displays and keypads. Anything that runs at human speeds are good candidates to be run this way. Each chip is capable of 8 bits so to get more than 8 bits the chips have to be daisy changed. Depending on the number of chips you have daisy changed you will need to clock them that many times to get the data from or to all the chips. You could also hook up each chip separately but that would require more pins and that is exactly what we are trying to save.
It is also a good way to do conversions from 3.3 volt microcontrollers to 5 volt peripherals as you usually don’t need a level shifter going from 3.3 volt to 5 but you need it going from 5 volt to 3.3. With these chips you only need to down shift one pin. and this is easy with a voltage divider. See the schematic of the Sparkfun logic level converter .
The above schematic shows how to hook up the 74HCT595. You can see that there are only 3 pins required to attach these two chips to the MSP430. In this case the three pins on the MSP430 are 6.0, 6.1, and 6.2. The serial clock is on bit zero while the serial data is on bit 1. Bit 2 is a parallel load clock. When all the serial data has been shifted into place a pulse is put on the parallel load clock to move the serial data into latches which appear on the outputs of the chips. This is to prevent glitches on the lines as you shift the serial data into place. You wouldn’t want your logic that is attached to the 74HCT595 to change state while you are shifting things into place. It is assumed in the above schematic that pin’s 8 of both chips are tied to ground and pin’s 16 are tied to VCC which in this case is 5 volts.
#define SERCLK 1 #define SERDATA 2 #define PARCLK 4 #define NUMBITS 16 /* * Routine: serSend(unsigned int val) * * This routine takes a 16 bit value and sends it out to a * 74HCT595 which is a serial to parallel converter. There * are two such chips to give 16 bits. * * Returns: Nothing * * Globals changed: 74HCT595 output. * */ void serSend(unsigned int val) { int i; // initialize port P6OUT = 0; // we have 16 bits to shift out for (i=0; i < NUMBITS; i++) { // if the next bit starting with the most significant // digit is set then send it set // NOTE: we start with the most significant digit // (NUMBITS(16)-1) = 15 if i = 0 then we shift the // one 15 to the left which is the most significant // digit in this case. As i is incremented through // the loop we shift one less till we shift 0 at i = 15 if (val & (1 << ((NUMBITS-1)-i))) { // set next bit P6OUT = SERDATA; // clock it in P6OUT = SERDATA | SERCLK; P6OUT = SERDATA; } else { // clear next bit P6OUT = 0; // clock it in P6OUT = SERCLK; P6OUT = 0; } } // when we are done move serial bits to // parallel output port P6OUT = PARCLK; P6OUT = 0; } // end of serSend
#define SERCLK 1 #define SERDATA 2 #define PARCLK 4 #define PL 0x10 #define NUMBITS 16 /************************************************** * Function name : unsigned int serSend(unsigned int val) * returns : returns the value read from the 74HCT597. * Val : value to put into the 74HCT595. * Created by : Kim Mansfield * Date created : 8/26/2008 * Description : This routine takes a 16 bit value and sends * it out to a 74HCT595 which is a serial to * parallel converter. There are two such chips * to give 16 bits. At the same time it loads * data from 2 74HCT597 which is a parallel to * serial converter and returns the value to the * calling program. * Globals changed : Changes the output value of the 74HCT595. * Notes : restrictions, odd modes (NONE) **************************************************/ unsigned int serSend(unsigned int val) { unsigned int serinput; int i; // initialize port // and latch input to shift register P6OUT = 0; // move parallel input data over to shift register P6OUT = PARCLK; // Now allow serial shift out of 597 P6OUT = PL; serinput = 0; // we have 16 bits to shift out for (i=0; i < NUMBITS; i++) { // if the next bit starting with the most significant // digit is set then send it set // NOTE: we start with the most significant digit // (NUMBITS(16)-1) = 15 if i = 0 then we shift the // one 15 to the left which is the most significant // digit in this case. As i is incremented through // the loop we shift one less till we shift 0 at i = 15 if (val & (1 << ((NUMBITS-1)-i))) { // set next bit P6OUT |= SERDATA; // clock it in P6OUT |= SERDATA | SERCLK; // collect serial output of 597 serinput |= ((P6IN >> 3) & 1) << ((NUMBITS-1)-i); P6OUT &= ~SERCLK; } else { // clear next bit P6OUT &= ~SERDATA; // clock it in P6OUT |= SERCLK; // collect serial output of 597 serinput |= ((P6IN >> 3) & 1) << ((NUMBITS-1)-i); P6OUT &= ~SERCLK; } } // when we are done move serial bits to // parallel output port P6OUT = PARCLK; P6OUT = 0; return serinput; } // end of serSend