Tuesday, 15 November 2011

The Joy of Shift Registers!

The joy of Latching Shift Registers!

So...I figured tonight would be a good time to continue my new found habit of writing about technical stuff!  Carrying on from the last post where I wrote about how to connect and use a Seven Segment LED display.  The overall goal is to make a set of Chess clocks.

I have visions of my display having eight LED segments....This is so that each player has a different timer and can view how much time they have left at any point whilst playing the game.  Most Chess players I know set the game length to 20 minutes.  Therefore in order to meet those requirements we will need to have 8x LED displays, 4x for each player allowing a maximum time setting of 99:99 each.  That should be long enough!!  I also would like the user to be able to set the time for each game via a rotary encoder....next post might be on just that subject!



Players will then be able to independently set the game times and then set the clocks to run mode. The time for each turn will start and stop when a player presses the requisite button (something huge and mushroom shaped!)  I may add some pointless but amusing sound effects when the time starts approaching zero.....frivolous and unnecessary and the perfect excuse to buy an arduino wave shield!!!



For now though we need to talk about my shameless misuse of microcontroller outputs.  In my previous post I used no less than eight digital outputs to control one Seven Segment LED display.  I can already hear my boss berating me for a lack of electronic design skills!!  He moans too much but he is correct....It is shameful to waste the output pins of microcontrollers when there is a better way of going about things.  The Arduino has 18 potential output pins....For eight LED displays we will need 64 output pins!!!  The arduino just doesn't have enough digital output pins.  By the way check out the datasheet for the Atmel AVR 328P (it's the microcontroller used in the arduino)....it is useful for two purposes.  It provides all the information you need to know about the brains of an arduino and can cause narcosis in seconds!  In all seriousness though datasheets can be extremely useful and when designing electronic circuits they are a must.  Knowing what all the pins on a device does is half the battle in mastering control of the circuit....and possibly the universe*

*may or may not be true

Atmel 328P Datasheet

So we need 64 output pins just to control the LED displays....but we don't have enough pins on a single arduino...What does one do now??  Well....it is possible to daisy chain multiple arduinos together...this can be considered to be even more wasteful and getting all the arduino devices to talk to each other and stay in time with each other would be very difficult.  I'm not saying it can't be done I'm just saying that there are better easier and cheaper ways of doing things....I am a great believer in keeping things simple!

We could use a different microcontroller with more output pins.  This is a viable option but I haven't got one to hand and it is a little overkill.  An ATMEGA 2560 still doesn't have enough pins and is more way more expensive, Don't worry though I have a cunning plan!

Lets use some old fashioned digital electronics and use Shift Registers!  These are nifty logic circuits which can be used to perform several functions.  They were very popular in previous decades and are essentially a temporary data store.  Information in BITS are input or 'shifted' into the device and stored in the device memory or 'register' until required.  They are actually several J-K flip flops cascaded together in Data mode.  If requested, I can explain all about J-K flip flops in another post. (Note to self, blogging subject matter growing considerably quickly...possibly exponentially??!!)

So these shift registers can temporarily store information.....how does that help us?  Well....they can also convert serial data into parallel data....still not with me??  Ok...how about that we can use then to make three digital output pins from a microcontroller into eight. At the same time we lower the number microcontroller outputs we are using.  The device I have got hold of is the ancient but extremely useful and cheap 74LS595 from Texas Instruments.  This is an 8 bit shift register with latching functionality....The latching stuff is very cool and useful!  Check out the Datasheet!

74LS595 Shift Register Datasheet

The device can be obtained from all good electronic component vendors....Ebay is your friend!  I can't remember where I got mine from but Proto-PIC sell them online for 74 pence a go!  Proto-pic are one of many online component distributors that I favour....they give good service and reasonable value for money, worth a look!

8-bit-74HC595 Shift Registers for sale on Proto-PIC

By the way 74HC595 is the same device as the 74LS595 but it uses CMOS technology instead of TTL....Another subject for another post....the list is growing.....*sigh* always growing!

So what we are now going to do is use this device to control the Seven Segment LED display from three arduino digital output pins freeing up the other output pins for more useful purposes.  We will still need to control each of the Seven Segment LED Displays but hey....its better than a massive expensive over specified and difficult to program microcontrolller that we haven't got!!  I would like to mention at this point that there are always pros and cons in electronic design.  This is one of those moments.....the amount of physical space that this design will take up is another...(more on this subject later!!)

Lets implement the shift register into our circuit and free up some digital output pins!  I'm going to use the shift register as a serial to parallel converter and latching data store.  See the circuit below....I'm not going to talk about how to connect it all up, I am assuming if you have read this far and are still interested then you know how, By the way thanks for reading!!  I do intend getting and using Fritzing to draw diagrams but for now EagleCAD schematics will have to suffice....



The sharper eyed among you may have noticed that the Seven Segment LED Display in the schematic diagram above has different pins labelled from the one that I used in my previous post. That is because the seven segment footprint I used in EagleCAD has different pins.  I will be swapping pin 8 and 10 in my circuit because of this.  I will also need to create a new footprint in EagleCAD later.....*Sigh* More stuff to write up!!

Now then, what we need to do is write a control sketch in the arduino ide and upload it.  We can build upon the code we used in the last sketch although we now need to change things.  We are now going to output the data in a serial string and the shift register will convert it to parallel for us, we also need to create two clock signals for the shift register, one for the Shift Register Clock (SCK) and one for the Storage Register Clock (RCK).  Three output pins to control eight outputs....awesome!

Ok....So here is where we have to do some coding to ensure that we get the arduino to correctly control the Seven Segment LED Display.  You may remember the code from the previous post contained a 2 dimensional array.  This array was a convenient method of telling the microcontroller which pins to put high and low to display the required digit.  That section of code looked like this:

byte seven_seg_digits[10][8] = { 

  { 1,0,1,1,1,1,0,1 },  // = 0 
  { 1,0,0,0,0,1,0,0 },  // = 1 
  { 0,0,1,0,1,1,1,1 },  // = 2  
  { 1,0,0,0,1,1,1,1 },  // = 3 
  { 1,0,0,1,0,1,1,0 },  // = 4 
  { 1,0,0,1,1,0,1,1 },  // = 5 
  { 1,0,1,1,1,0,1,1 },  // = 6 
  { 1,0,0,0,1,1,0,0 },  // = 7 
  { 1,0,1,1,1,1,1,1 },  // = 8 
  { 1,0,0,1,1,1,1,0 },  // = 9 

};

If we look carefully we can see that the lines of 1's and zero's in the array are binary numbers.  Binary numbers are just like ordinary numbers but are written differently as they have a different 'base'.  I will go through the binary number system in another post but for now lets just re-write the above values and then convert them into decimal which is the numbering system that people with ten digits (fingers!) use.


   10111101 in binary = 189 in decimal
   10000100 in binary = 132 in decimal
   00101111 in binary = 47 in decimal
   10001111 in binary = 143 in decimal
   10010110 in binary = 150 in decimal
   10011011 in binary = 155 in decimal
   10111011 in binary = 187 in decimal
   10001100 in binary = 140 in decimal
   10111111 in binary = 191 in decimal
   10011110 in binary = 158 in decimal

Once the numbers have been converted we can then re-write the code with a 1 dimensional array which stores the values for each number in the array cells.  We can then call the array in order from right to left (least significant bit first) and send the values serially to the shift register and it will output the digits on the Seven Segment LED Display. 

Here is the arduino Sketch:


/*

 Langster's Code for driving a seven segment display via a Shift Register
 Connect Pin 3 and pin 10 on the seven segment display to 0V
 Connect all the other pins to the Shift Register digital ouputs as listed below:

 pin 1 of 74HC595 to Seven Segment LED pin 6  
 pin 2 of 74HC595 to Seven Segment LED pin 4
 pin 3 of 74HC595 to Seven Segment LED pin 2
 pin 4 of 74HC595 to Seven Segment LED pin 1
 pin 5 of 74HC595 to Seven Segment LED pin 9
 pin 6 of 74HC595 to Seven Segment LED pin 8
 pin 7 of 74HC595 to Seven Segment LED pin 5
 pin 8 of 74HC595 to 0V
 pin 9 of 74HC595 is unconnected
 pin 10 of 74HC595 to +5V
 pin 11 of 74HC595 to Arduino pin 12  
 pin 12 of 74HC595 to Arduino pin 11
 pin 13 of 74HC595 is unconnected or connected to 0V
 pin 14 of 74HC595 to Arduino pin 13
 pin 15 of 74HC595 to Seven Segment LED pin 7
 pin 16 of 74HC595 to +5V

*/

//Pin connected to ST_CP of 74HC595
int latchPin = 13;
//Pin connected to SH_CP of 74HC595
int clockPin = 12;
//Pin connected to DS of 74HC595
int dataPin = 11;


//initialise a One Dimensional integer array with the values for //0 - 9 on the Seven Segment LED Display

int seven_seg_digits[10]= {189,132,47,143,150,155,187,140,191,158};

/*
  { 1,0,1,1,1,1,0,1 },  // = 189 in decimal
  { 1,0,0,0,0,1,0,0 },  // = 132 in decimal
  { 0,0,1,0,1,1,1,1 },  // = 47 in decimal 
  { 1,0,0,0,1,1,1,1 },  // = 143 in decimal
  { 1,0,0,1,0,1,1,0 },  // = 150 in decimal
  { 1,0,0,1,1,0,1,1 },  // = 155 in decimal
  { 1,0,1,1,1,0,1,1 },  // = 187 in decimal
  { 1,0,0,0,1,1,0,0 },  // = 140 in decimal
  { 1,0,1,1,1,1,1,1 },  // = 191 in decimal
  { 1,0,0,1,1,1,1,0 },  // = 158 in decimal

//  Just for further reference here are the separate segment connections

  pin 2 = C
  pin 3 = DOT
  pin 4 = E
  pin 5 = F
  pin 6 = A
  pin 7 = B
  pin 8 = G
  pin 9 = D

*/

void setup() {
  //set the arduino pins to output so you can control the shift      // register
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
}

void loop() {
    // Start a loop from 0 to 9 and output the count to the //Seven Segment Display 
    for (int i=0; i <= 9; i++){
     //take the latch pin of the shift register low
      digitalWrite(latchPin, LOW);
      //write the binary number as a serial pulse train 
      shiftOut(dataPin, clockPin, LSBFIRST, seven_seg_digits[i]);  
      //take the latch pin high so the LEDs will light up:
      digitalWrite(latchPin, HIGH);
      // pause for a second before next value:
      delay(1000);
    }    
}



As promised here is a video of the circuit up and working!