Jan282010

Arduino: figuring out shift registers

Published by paul at 10:35 AM under Arduino | LED Projects | Shift Registers

One of the parts that makes possible the scrolling message kit I built over the weekend (see Kit building: Hansen Hobbies mini-scrolling LED sign kit) is a shift register. This is a very neat device that uses at least 2 inputs to load 8 parallel outputs. The idea is to pulse a clock input for each bit of data in the 8-bit register, loading each bit in succession until all 8 bits have been loaded. The shift registers in the kit I made are 74HC164s, which means that the outputs immediately go high or low to relfect the bits as they're loaded into the shift register and shifted along into their desired positions. Many people prefer a latched shift register, where the outputs reflect a steady-state of the register until all 8 new bits have been loaded, and then the outputs change to the new bits in the register (i.e the latched register has two registers - a true shift register and a storage register).

The simple algorithm to load a latched shift-register is:

pull the latch pin low

pull the clock pin low
pull the data pin high or low to reflect bit 1
pull the clock pin high

<repeat for bits 2 through 8>

pull the latch pin high

It's up to you whether you load the 8-bit value as MSB (most-significant-bit) first or LSB (least-significant-bit) first - you'll soon work out if you've got it the wrong way around!

I'm going to use a 74HC595 shift register that can source 35mA per output - perfect for driving the LEDs in my 10-bar LED arrays.

There are two ways to implement the logic above - using the Arduino shiftOut function or writing one yourself. I played around with both to make sure I fully understood what's going on - and I like bit-twiddling in C/C++. The Arduino site has a good language reference on shiftOut (see here) and also a tutorial on using the 74HC595 (see here). I decided to figure out how to use the chip myself so I internalized how to do it in future - but I'm not trying to be a purist and re-inventing the wheel.

The circuit is pretty simple - remember to pull the OutputEnable (active low) pin low and the MemoryClear (active low) pin high.

 

And a photo (click for larger image):

 

The code I used is below, with the two different functions to push data out to the shift register. I had a problem with the code where I originally had the counter variable in the loop() function as a byte and the LEDs counted to the end and then stopped. I put in the serial output to do some testing and connected up with Windows HyperTerminal - so much easier to do it with this than when trying to debug code I'd written in the storage engine of SQL Server :-) Of course as soon as the counter value reached 256, it overflowed and was stored as 0, so no more LEDs being lit up. If you do this, don't forget to hangup before trying to upload a sketch to the Arduino otherwise it won't be able to grab the COM port.

Here's the code:

/*
  Driving a 74HC595 shift register
 
   01/27/2010
*/

// This pin gets sets low when I want the 595 to listen
const int  pinCommLatch = 2;

// This pin is used by ShiftOut to toggle to say there's another bit to shift
const int  pinClock     = 3;

// This pin is used to pass the next bit
const int  pinData    = 4;

void setup()
{
  pinMode (pinCommLatch, OUTPUT);
  pinMode (pinClock, OUTPUT);
  pinMode (pinData, OUTPUT);
 
  //Serial.begin (56600);
} // setup

// Using the builtin shiftOut function
void sendSerialData1 (
  byte  value)
{
  // Signal to the 595 to listen for data
  digitalWrite (pinCommLatch, LOW);
 
  shiftOut (pinData, pinClock, MSBFIRST, value);
 
  // Signal to the 595 that I'm done sending
  digitalWrite (pinCommLatch, HIGH);
}  // sendSerialData1

// Using my own method with as few instructions as possible
// Gotta love C/C++ for bit-twiddling!
void sendSerialData2 (
  byte  value)
{
  // Signal to the 595 to listen for data
  digitalWrite (pinCommLatch, LOW);

  for (byte bitMask = 128; bitMask > 0; bitMask >>= 1)
  {
    digitalWrite (pinClock, LOW);
 
    digitalWrite (pinData, value & bitMask ? HIGH : LOW);
     
    digitalWrite (pinClock, HIGH);
  }
 
  // Signal to the 595 that I'm done sending
  digitalWrite (pinCommLatch, HIGH);
}  // sendSerialData2
 
void loop()
{
  for (int counter = 1; counter < 256; counter++)
  {
    sendSerialData2 (counter);

    delay (75);
  }
} // loop

I recorded a quick video of the code above driving the 595 to get the LEDs to count from 1 to 255 in binary - checkout it on YouTube here.

Next up - daisy-chaining multiple shift-registers.



[KickIt] [Dzone] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

Currently rated 3.3 by 29 people

  • Currently 3.275862/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

E-mail | Permalink | Trackback | Post RSSRSS comment feed 1 Responses

Comments

Comments are closed