ModuleShiftReg595


A module for controlling the 74595 8bit Shift Register.

This module based on the Shift.bas module will control a max of four 74595 Shift Registers.

Basic shift register 74595 operation:

Data is written to the shift register serially, then latched onto the storage register. The storage register then controls 8 output lines.

Pin 14 (DS) is the Data pin. On some datasheets it is referred to as “SER”.

When pin 11 (SH_CP or SRCLK on some datasheets) goes from Low to High the value of DS is stored into the shift register and the existing values of the register are shifted to make room for the new bit.

Pin 12 (ST_CP or RCLK on some datasheets) is held low whilst data is being written to the shift register. When it goes High the values of the shift register are latched to the storage register which are then outputted to pins Q0-Q7.

Pin 9 (Q7) to daisy chain the shift registers together.

The module assumes that: Pin 10 (MR or SCLR on some datasheets) is tied to VCC. Pin 13 (OE or G on some datasheets) is tied to Ground.

Module Options

#option SHIFT_NUM

 The shift num, select how many 74595 shift registers are being used, max of four, By default it is set to 1.

#option SHIFT_CLOCK

 The shift clock delay, in microseconds. Can be 1 or 2 us. By default, it is set to 1 us. 

Example Code - 1 shift register:

' Options...
#option SHIFT_NUM = 1
#option SHIFT_CLOCK = 2

' Imports section...
imports ShiftReg595

Sub Main() 

   ' setup pins for output, latch and clock...
   ShiftReg595.SetOutput(D11)
   ShiftReg595.SetLatch(D10)
   ShiftReg595.SetClock(D9) 

   ' simple flash all leds On/Off...
   for y as byte = 0 to 1 
      dim myValue as Byte = &HFF
      ShiftReg595.Out(MsbFirst,myvalue)
      delayms(2000)
      ShiftReg595.Out(MsbFirst,&H00)
      delayms(2000)
   next                                     

   ' Count in Binary...
   for i as Byte = &H00 to &HFF                   
      ShiftReg595.Out(LsbFirst,i)          
      delayms(100)
      ' write data to serial port
      Console.Write(str(i),13,10)
   next

   ' prog now do nothing...
   while true
   end while
End Sub 

Example Code - 4 shift registers:

' Options...
#option SHIFT_NUM = 4
#option SHIFT_CLOCK = 2

' Imports section...
imports ShiftReg595

Sub Main() 

   ' setup pins for output, latch and clock...
   ShiftReg595.SetOutput(D11)
   ShiftReg595.SetLatch(D10)
   ShiftReg595.SetClock(D9) 

   ' simple flash all leds On/Off...
   for y as byte = 0 to 1 
      dim myValue as UInteger = &HFFFFFFFF
      ShiftReg595.Out(MsbFirst,myvalue)
      delayms(2000)
      ShiftReg595.Out(MsbFirst,&H00)
      delayms(2000)
   next          

   ' turn on each led in turn...
   for x as byte = 0 to 32   
      static shifter as UInteger = 1
      ShiftReg595.Out(LsbFirst,shifter)
      shifter = shifter << 1 
      delayms(300)   
   next                             

   ' Count in Binary on all four 74595...
   ' (4-byte) from 0 to 4,294,967,295...
   for i as UInteger = &H00 to &HFFFFFFFF                   
      ShiftReg595.Out(LsbFirst,i)          
      delayms(100)
      ' write data to serial port
      Console.Write(str(i),13,10)
   next

   ' prog now do nothing...
   while true
   end while
End Sub 

74595 module:

'*****************************************************************************
'*  Name    : ShiftReg595.BAS                                                *
'*  Author  : Gavin Wiggett                                                  *
'*  Notice  : Copyright (c) 2013 Bitfogav                                    *
'*          : All Rights Reserved                                            *
'*  Date    : 17/05/2013                                                     *
'*  Version : 1.0                                                            *
'*  Notes   : Software based shift module for 74595 Shift Register.          *
'*          : Support to control a max of four shift registers.              *
'*          :                                                                *
'*          : This module assumes that the Enable pin is tied to GND and     *
'*          : Clear reg pin is tied to VCC.                                  *
'*****************************************************************************

Module ShiftReg595

' shiftout modes...
Public Const LsbFirst = &H00     ' LSB first
Public Const MsbFirst = &H01     ' MSB first

' a pin structure...
Structure PinType
   Dim Address As UShort
   Dim Pin As ushort
   Dim PinMask As ushort
End Structure  

' local working variables...
Dim _dataOut As PinType
dim _dataLatch as PinType
Dim _dataClock As PinType 

' option to add number of 74595's to the module, Max of four 74595's.
' using less 74595's will reduce code overhead.
' the default is one 74595 shift register...
#if IsOption(SHIFT_NUM) And Not (SHIFT_NUM in (1, 2, 3, 4))
   #error SHIFT_NUM, "Invalid option. must be 1, 2, 3 or 4."
#endif
#option SHIFT_NUM = 1

' bring the number of 74595's shift registers into the module...
#if SHIFT_NUM = 1
#define NUM_BITS = 8
public Type ShiftType = Byte
#elseif SHIFT_NUM = 2
#define NUM_BITS = 16
public Type ShiftType = UShort
#elseif SHIFT_NUM = 3
#define NUM_BITS = 24
public Type ShiftType = UInteger
#else
#define NUM_BITS = 32
public Type ShiftType = UInteger
#endif

' delay speed of clock and latch pin....
#if IsOption(SHIFT_CLOCK) And Not (SHIFT_CLOCK in (1, 2))
   #error SHIFT_CLOCK, "Invalid option. CLOCK must be 1 or 2 (us)."
#endif
#option SHIFT_CLOCK = 1

'****************************************************************************
'* Name    : ToggleClock                                                    *
'* Purpose : Toggle the clock pin.                                          *
'*         : The default minimum clock width will be 1us for frequencies    *
'*         : above 4MHz. For 4Mhz and below, the minimum clock width will   *
'*         : be 2us. Using the #option SHIFT_CLOCK = 2US option will force  *
'*         : a minimum clock width of 2us for all frequencies. NOTE : These *
'*         : figures assume a perfect clock. A plus or minus variation of   *
'*         : the clock width will be observed for all real world clock      *
'*         : frequencies that deviate from the theoretical ideal.           *
'****************************************************************************
private Inline Sub ToggleClock()
   *(waddr1) = *(waddr1) Xor _dataClock.Pin
   #if (SHIFT_CLOCK = 2) Or (_clock <= 4) 
   DelayuS(2)
   #else
   DelayuS(1)
   #endif    
   *(waddr1) = *(waddr1) Xor _dataClock.Pin
End Sub 

'****************************************************************************
'* Name    : ToggleLatch                                                    *
'* Purpose : Toggle the latch pin to store the shifted data in the          *
'*         : registers.                                                     *
'*         : frequencies based the same has ToggleClock (see ToggleClock)   *
'****************************************************************************
private Inline Sub ToggleLatch()
   *(waddr1) = *(waddr1) Xor _dataLatch.Pin
   #if (SHIFT_CLOCK = 2) Or (_clock <= 4) 
   DelayuS(2)
   #else
   DelayuS(1)
   #endif    
   *(waddr1) = *(waddr1) Xor _dataLatch.Pin
End Sub 

'****************************************************************************
'* Name    : MakeOutput                                                     *
'* Purpose : Make the data pin an output. Data out address points to the    *
'*         : port latch so just offset by 4                                 *
'****************************************************************************
private Inline Sub MakeOutput()
   waddr1 = _dataOut.Address - 4 ' lat - 4 => tris
   *(waddr1) = *(waddr1) And _dataOut.PinMask
End Sub 

'****************************************************************************
'* Name    : MakeLatchOutput                                                *
'* Purpose : Make the latch pin an output. Latch out address points to the  *
'*         : port latch so just offset by 4                                 *
'****************************************************************************
private Inline Sub MakeLatchOutput()
   waddr1 = _dataLatch.Address - 4 ' lat - 4 => tris
   *(waddr1) = *(waddr1) And _dataLatch.PinMask
End Sub     

'****************************************************************************
'* Name    : LoadDataOutAndClockAddr                                        *
'* Purpose : Load the data and clock pin address into waddr(x)              *
'****************************************************************************
private Inline Sub LoadDataOutAndClockAddr()
   waddr0 = _dataOut.Address
   waddr1 = _dataClock.Address
End Sub   

'****************************************************************************
'* Name    : SetOutput                                                      *
'* Purpose : Sets the data out pin.                                         *
'****************************************************************************
Public Sub SetOutput(ByRef dataPin As Bit)
   _dataOut.Address = AddressOf(dataPin) + 2 ' port + 2 => lat
   _dataOut.Pin = BitOf(dataPin)
   _dataOut.PinMask = Not _dataOut.Pin
End Sub

'****************************************************************************
'* Name    : SetLatch                                                       *
'* Purpose : Sets the latch pin.                                            *
'****************************************************************************
Public Sub SetLatch(ByRef latchPin As Bit)
   _dataLatch.Address = AddressOf(latchPin) + 2 ' port + 2 => lat
   _dataLatch.Pin = BitOf(latchPin)
   _dataLatch.PinMask = Not _dataLatch.Pin
End Sub

'****************************************************************************
'* Name    : SetClock                                                       *
'* Purpose : Sets the clock pin. An optional idle high determines if the    *
'*         : clock pin idles high or low. The default is to idle low.       *
'*         : The clock address points to a port latch.                       *
'****************************************************************************
Public Sub SetClock(ByRef clockPin As Bit, Optional idleHigh As Boolean = False)
   _dataClock.Address = AddressOf(clockPin) + 2 ' port + 2 => lat   
   _dataClock.Pin = BitOf(clockPin)
   _dataClock.PinMask = Not _dataClock.Pin  

   ' set clock idle mode...
   waddr1 = _dataClock.Address
   If idleHigh Then
      *(waddr1) = *(waddr1) Or _dataClock.Pin
   Else
      *(waddr1) = *(waddr1) And _dataClock.PinMask   
   End If

   ' make clock pin an output...
   waddr1 = waddr1 - 4 ' lat - 4 => tris
   *(waddr1) = *(waddr1) And _dataClock.PinMask
End Sub

'****************************************************************************
'* Name    : Out                                                            *
'* Purpose : Shift out a value by number of bits.                           *
'*         :                                                                *
'* Note    : mode can be either LsbFirst or MsbFirst.                       *
'*         : data value of data to shift into registers.                    *
'*         : Optional(shiftAmount) number of bits to shift out, this is set *
'*         : by the module with NUM_BITS, depending on the number of        *
'*         : 74595's used. would leave this as is.                          *
'****************************************************************************
Public Sub Out(mode As Byte, data As ShiftType, Optional shiftAmount As Byte = NUM_BITS)

   ' set data and latch pins to outputs and load
   ' data and clock address...
   MakeOutput()
   MakeLatchOutput()
   LoadDataOutAndClockAddr()

   ' MSB first...
   If mode.0 = 1 Then
      data = Reverse(data, shiftAmount)
   End If

   ' shift out...  
   While shiftAmount > 0 
      If data.0 = 0 Then
         *(waddr0) = *(waddr0) And _dataOut.PinMask
      Else
         *(waddr0) = *(waddr0) Or _dataOut.Pin
      End If  
      ToggleClock
      data = data >> 1
      shiftAmount = shiftAmount - 1 
   End While

   ' latch data in registers...
   ToggleLatch()

   ClearWDT
End Sub

End Module