User Tools

Site Tools


shift_registers_and_how_to_use_them_in_smart_ways

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

shift_registers_and_how_to_use_them_in_smart_ways [2005/07/05 11:25] – created 82.96.100.100shift_registers_and_how_to_use_them_in_smart_ways [2019/08/27 20:45] (current) – external edit 127.0.0.1
Line 1: Line 1:
 +From: Thomas McGahee <tom_mcgahee@sigmais.com>
 +To: pic microcontroller discussion list <PICLIST@MITVMA.MIT.EDU>
 +Subject: Fr. Tom's Shift Register Tutorial
 +Date: Thursday, June 18, 1998 1:34 PM
  
 +Stewart,
 +I do not use Basic Stamps at all, but I do use shift registers with PICs. 
 +The info I will give is pretty much applicable to any kind of microcontroller,
 +and I have even used the techniques with IBM PC parallel ports when
 +necessary. You should be able to apply the info given to a Basic Stamp
 +without much trouble, but for the sake of helping the most PIC list
 +members as possible, I will speak in terms of the PIC, not the Basic Stamp.
 +
 +This posting will contain just the info concerning multi-bit INPUT to
 +a PIC using serial techniques. If enough members find this useful, then I 
 +might prepare a similar tutorial on multi-bit OUTPUT from a PIC using serial 
 +techniques. No sense in my wasting my time if no one is interested in this
 +stuff.
 +
 +*****
 +PARALLEL TO SERIAL INPUT TO A PIC USING A 74165
 +(Basic info will also apply to several other chips)
 +Written by Fr. Tom McGahee  tom_mcgahee@sigmais,com  copyright 1998
 +As a courtesy to the author, please include the above info if you share this
 +information with others. Permission granted for personal use.
 +
 +If you find any errors, or have any additions to be made to the text, or
 +have any comments to make about this tutorial, please notify me by e-mail:
 +tom_mcgahee@sigmais.com
 +
 +INPUT:
 +To get data INTO a PIC you can use a 74165 type parallel to serial chip.
 +These chips have:
 + 8 parallel input lines
 + A serial input line that allows you to cascade multiple chips
 + A Clock and /Clock Inhibit
 + An asynchronous Shift /Load control
 + Both a normal and inverted serial output (Q and /Q)
 +
 +Let's look at how each of these is used:
 +All lines are TTL level and will interface directly to the PIC.
 +
 +* 8 parallel input lines
 +These receive the parallel data from the 'outside' world. This can be
 +from switches, transistors, TTL or CMOS devices, etc. Note that more than
 +one 74165 can be cascaded, so that any number of parallel input lines
 +get funneled into a single bit input port. 
 +
 +* The serial input line that allows you to cascade multiple chips.
 +You only use this if you are connecting multiple 74165 chips together. If this
 +is
 +the case, then the Q output of the preceding stage connects to this line. If
 +you do not wish to use it, then tie it either to ground or +5.
 +
 +Hint: When cascading 74165 chips together, connect the Clock1 to Clock2, 
 +/Clock Inhibit1 to /Clock Inhibit2, and Shift /Load Control1 to 
 +Shift /Load Control2. That way the PIC will control both in synchronization.
 +You can cascade as many 74165s as you want.
 +
 +Sneaky Trick (1): You can use the serial input as a 9th input so long as you
 +keep
 +the following in mind: All other inputs are latched when the /Load signal is
 +pulsed low, but NOT *this* 'input'. It is effectively 'captured' as soon as you
 +perform the first shift using the clock, however.
 +
 +* The Clock and /Clock Inhibit
 +Tie the Clock Inhibit LOW to disable the inhibit permanently. The rising edge
 +of the Clock will cause the latched data present in the shift register to
 +be shifted. 
 +
 +Gotchas: Note that the rightmost bit of parallel data should be read in
 +BEFORE doing any shifting with the clock! Once you perform a shift, the data
 +moves to the right, and the rightmost digit is LOST. In other words, always
 +perform a Read *before* Shifting.
 +
 +Sneaky Trick (2A): The Clock and the /Clock Inhibit lines are inter-changeable.
 +When laying out a PC board, you may swap pins 1 and 2. Also, you can just
 +tie Clock and /Clock Inhibit together and treat them simply as a combined
 +Clock. This does increase the TTL loading, but it is not a problem.
 +
 +Sneaky Trick (2B): You can often SHARE this output with other devices.
 +If you are not running the input routine via an interrupt, then you
 +can safely share this output. You can get away with this, because you
 +will generally do a /Load just prior to assembling the data from
 +the serial port. So, if some other routine has previously used this
 +output, *who cares*? You *DO* have to make sure that the sharing is OK
 +from the other device's point of view, of course. Some outputs are sort of
 +like 'set up' bits, such as the R/W line on an LCD display. You can
 +flip 'em around all you want, as long as they are set up properly
 +JUST PRIOR to actually issuing a device command. Sharing a single
 +output line in such a case makes a lot of sense, but it is not immediately
 +evident to some people that this is allowable.
 +
 +* The asynchronous Shift /Load control
 +This line is normally held high. You pulse it low when you want to latch the
 +current state of the inputs. While this line is low, clocking is
 +automatically inhibited. 
 +
 +Sneaky Trick (3A): If you have the Shift /Load Control held low (/Load), then
 +the Q output will follow the state of the rightmost parallel input.
 +This allows you to monitor this particular line in real-time. No shifting
 +required to read it, and if attached to an input that allows interrupt
 +on change, then you can use this trick to cause the interrupt routine
 +to automatically be triggered by a pulse on the last parallel input. The
 +interrupt routine can then shift in the rest of the data. Note that if
 +you combine this trick with the sneaky trick (1), then you can get a full
 +8 'static' data bits and one 'dynamic' data bit that can initiate an
 +interrupt.
 +
 +Sneaky Trick (3B): You can often SHARE this output with other devices.
 +If you are not running the input routine via an interrupt, then you
 +can safely share this output. You can get away with this, because you
 +will generally do a /Load just prior to assembling the data from
 +the serial port. You may have problems if you try to combine sneaky
 +tricks (3A) and (3B). So, if some other routine has previously used this
 +output, *who cares*? You *DO* have to make sure that the sharing is OK
 +from the other device's point of view, of course. Some outputs are sort of
 +like 'set up' bits, such as the R/W line on an LCD display. You can
 +flip 'em around all you want, as long as they are set up properly
 +JUST PRIOR to actually issuing a device command. Sharing a single
 +output line in such a case makes a lot of sense, but it is not immediately
 +evident to some people that this is allowable.
 +
 +
 +* Normal and inverted serial output (Q and /Q)
 +Usually you just use the normal Q output. This will become our serial
 +input. As mentioned above, Q will follow the state of the rightmost 
 +bit whenever Shift /Load is low. Immediately following a /Load pulse, 
 +Q will show the latched state of the rightmost parallel input. 
 +Following each Clock pulse the data at Q will reflect the 'latched' 
 +state of the next bit.
 +
 +Sneaky Trick (4)
 +You might be wondering whether or not you can 'share' a single
 +PIC input to handle this and another device. You can, but it requires
 +some way of determining which input is 'active'. Here is where you
 +can use the same PIC output that controls Shift /Load to do double duty!
 +Whenever you are outputting a HIGH to the Shift /Load control, you could
 +use that same high to control a two-input multiplexer such that it
 +directs the Q output data into the PIC serial input port. If using 
 +trick (3B) in this context, you CANNOT also use trick (3A), since
 +activating /Load would disable the Q from getting to the PIC port. 
 +If you want to use trick (3A), you would have to control the 
 +multiplexer with some other PIC output bit.
 +
 +****
 +
 +Now that you understand the operation of the 74165, let's look at what PIC
 +resources are required to use it. Remember that you *may* be able to share the
 +PIC resources with other devices.
 +
 +PIC PORT REQUIREMENTS FOR PARALLEL to SERIAL INPUT PORT
 +
 +Two outputs, one input. (PS_IN stands for Parallel to Serial INput device)
 +Outputs: PS_IN_CLOCK and PS_IN_SHIFT_NOT_LOAD (I like descriptive names).
 +Input: PS_IN_SDATA
 +
 +SAMPLE ROUTINE TO READ 8 BITS FROM PARALLEL TO SERIAL PORT
 +Assume 74165 chip used, and allow port sharing on both outputs.
 +Assume Clock Inhibit is tied LOW.
 +
 +PS_IN_CTR equ 0x10 ;Parallel to Serial INput CouNTer
 + ; Used to keep track of current bit
 + ; Use any SRAM location desired. Sample 0x10
 + ; *** This register can be shared with other
 + ; *** routines. Local Variable.
 +PS_IN_REG equ 0x11 ;Storage for 8 bit serial input data
 + ; Use any SRAM location desired. Sample 0x11
 +PS_IN_CLOCK equ 0x01 ;Assign to PORTA, bit 1 (OUTPUT)
 +PS_IN_SHIFT_NOT_LOAD equ 0x02 ;Assign to PORTA, bit 2 (OUTPUT)
 +PS_IN_DATA equ 0x03 ;Assign to PORTA, bit 3 (INPUT)
 +
 +;Assume user has set up PIC, including PORTA I/O direction for each bit
 +
 +PS_IN: ;Entry Label for Parallel to Serial INput
 + MOVLW D'8' ;8 bits to be read
 + MOVWF PS_IN_CTR ;Save count
 + BCF PS_IN_CLOCK ;Ensure that clock is low (may be shared)
 + BCF PORTA,PS_IN_SHIFT_NOT_LOAD
 + ;That LOW latched the data for sure
 + BSF PORTA,PS_IN_SHIFT_NOT_LOAD
 + ;Now we keep it high so data doesn't change
 +PS_IN_LOOP:
 + BTFSS PORTA,PS_IN_DATA ;Read serial data from port one bit at a time
 + GOTO GOT_ZERO
 + BSF STATUS,C ;Load a 1 into carry if bit was a 1
 + GOTO SHIFT_IN
 +GOT_ZERO:
 + BCF STATUS,C ;Load a 0 into carry if bit was a 0
 +SHIFT_IN:
 + RRC PS_IN_REG ;Assemble bit into right-shifting byte
 + BSF PORTA,PS_IN_CLOCK ;Shift the data in the 74165 to get ready
 + ; to possibly read the NEXT bit...
 + BCF PORTA,PS_IN_CLOCK ;Terminate the Clock pulse!
 + DECFSZ PS_IN_CTR,F ;Update our counter
 + GOTO PS_IN_LOOP ;If not done, do next bit
 + RETURN ;Return with data in PS_IN_REG
 +
 +There, now, that wasn't so hard, was it?
 +There is more than one way to skin a cat, of course, and I am sure that 
 +there are others out there who have implemented this differently.
 +
 +*****
 +HANDLING EXTRA NINTH BIT
 +
 +With a few additions, this routine can be modified to handle ANY number of
 +inputs, though you would usually handle multiples of 8.
 +
 +To handle the '9th' bit referenced in sneaky trick (1), requires some
 +additional code. Here is the simplest way:
 +
 +Assume user has defined a register called SOME_REGISTER, and assigned
 + a bit position called PS_IN_NINTH_BIT 
 +
 +PIC PORT REQUIREMENTS FOR PARALLEL to SERIAL INPUT PORT
 +
 +Two outputs, one input. (PS_IN stands for Parallel to Serial INput device)
 +Outputs: PS_IN_CLOCK and PS_IN_SHIFT_NOT_LOAD (I like descriptive names).
 +Input: PS_IN_SDATA
 +
 +SAMPLE ROUTINE TO READ 8 BITS FROM PARALLEL TO SERIAL PORT
 +Assume 74165 chip used, and allow port sharing on both outputs.
 +Assume Clock Inhibit is tied LOW.
 +
 +PS_IN_CTR equ 0x10 ;Parallel to Serial INput CouNTer
 + ; Used to keep track of current bit
 + ; Use any SRAM location desired. Sample 0x10
 + ; *** This register can be shared with other
 + ; *** routines. Local Variable.
 +PS_IN_REG equ 0x11 ;Storage for 8 bit serial input data
 + ; Use any SRAM location desired. Sample 0x11
 +
 +SOME_REGISTER equ 0x12 ;We need one bit of this register
 +PS_IN_NINTH_BIT equ 0x07 ;Any available bit will do!
 +
 +PS_IN_CLOCK equ 0x01 ;Assign to PORTA, bit 1 (OUTPUT)
 +PS_IN_SHIFT_NOT_LOAD equ 0x02 ;Assign to PORTA, bit 2 (OUTPUT)
 +PS_IN_DATA equ 0x03 ;Assign to PORTA, bit 3 (INPUT)
 +
 +;Assume user has set up PIC, including PORTA I/O direction for each bit
 +
 +
 +PS_IN: ;Entry Label for Parallel to Serial INput
 + MOVLW D'8' ;8 bits to be read
 + MOVWF PS_IN_CTR ;Save count
 + BCF PS_IN_CLOCK ;Ensure that clock is low (may be shared)
 + BCF PORTA,PS_IN_SHIFT_NOT_LOAD
 + ;That LOW latched the data for sure
 + BSF PORTA,PS_IN_SHIFT_NOT_LOAD
 + ;Now we keep it high so data doesn't change
 +PS_IN_LOOP:
 + BTFSS PORTA,PS_IN_DATA ;Read serial data from port one bit at a time
 + GOTO GOT_ZERO
 + BSF STATUS,C ;Load a 1 into carry if bit was a 1
 + GOTO SHIFT_IN
 +GOT_ZERO:
 + BCF STATUS,C ;Load a 0 into carry if bit was a 0
 +SHIFT_IN:
 + RRC PS_IN_REG ;Assemble bit into right-shifting byte
 + BSF PORTA,PS_IN_CLOCK ;Shift the data in the 74165 to get ready
 + ; to possibly read the NEXT bit...
 + BCF PORTA,PS_IN_CLOCK ;Terminate the Clock pulse!
 + DECFSZ PS_IN_CTR,F ;Update our counter
 + GOTO PS_IN_LOOP ;If not done, do next bit
 +GET_BIT_9: ;So far all has been exactly the same
 + ; as the 8 bit example. Now we add the
 + ; extra code to handle the ninth bit.
 +
 + BCF SOME_REGISTER,PS_IN_NINTH_BIT
 + ;Assume it's a 0
 + BTFSS PORTA,PS_IN_DATA ;Get extra (for free!) ninth bit
 + GOTO PS_IN_RET ;If it was a 0, we are already done!
 + BSF SOME_REGISTER,PS_IN_NINTH_BIT
 + ;If it was a 1, make it so! 
 +PS_IN_RET:
 + RETURN ;Return with data in PS_IN_REG
 +
 +
 +*****
 +HANDLING MULTIPLES OF 8 BITS
 +
 +To handle multiples of 8 bits you would use FSR and indirect addressing
 +to load first 8 bits into one register, then the next 8 into the
 +next register, etc.  References to PS_IN_REG would be changed to references
 +to INDF. Obviously FSR would have to be initially loaded with the
 +address of the first storage register, and FSR would have to be incremented
 +after 8 bits have been loaded.
 +
 +The best way to implement that would be to have a routine that called
 +the generic 8 bit routine using INDF twice, each time with FSR containing
 +a different register address.
 +
 +PIC PORT REQUIREMENTS FOR N*8 PARALLEL to SERIAL INPUT PORT
 +
 +Two outputs, one input. (PS_IN stands for Parallel to Serial INput device)
 +Outputs: PS_IN_CLOCK and PS_IN_SHIFT_NOT_LOAD (I like descriptive names).
 +Input: PS_IN_SDATA
 +
 +SAMPLE ROUTINE TO READ MULTIPLES of 8 BITS FROM PARALLEL TO SERIAL PORT
 +Assume 74165 chips used, and allow port sharing on both outputs.
 +Assume Clock Inhibit is tied LOW.
 +
 +PS_IN_CTR equ 0x10 ;Parallel to Serial INput CouNTer
 + ; Used to keep track of current bit
 + ; Use any SRAM location desired. Sample 0x10
 + ; *** This register can be shared with other
 + ; *** routines. Local Variable.
 +PS_IN_REG1 equ 0x11 ;Storage for 8 bit serial input data
 + ; Use any SRAM location desired. Sample 0x11
 +PS_IN_REG2 equ 0x12 ;Storage for 8 bit serial input data
 + ; should be contiguous with PS_IN_REG1
 +PS_IN_CLOCK equ 0x01 ;Assign to PORTA, bit 1 (OUTPUT)
 +PS_IN_SHIFT_NOT_LOAD equ 0x02 ;Assign to PORTA, bit 2 (OUTPUT)
 +PS_IN_DATA equ 0x03 ;Assign to PORTA, bit 3 (INPUT)
 +
 +;Assume user has set up PIC, including PORTA I/O direction for each bit
 +
 +PS_IN_FSR: ;This allows multi-byte transfers.
 + MOVLW PS_IN_REG1
 + MOVWF FSR ;Point to PS_IN_REG1 for 1st byte
 + CALL PS_IN ;Do it!
 +
 + INCF FSR,F ;Point to next register, PS_IN_REG2
 + CALL PS_IN ;Do it, too!
 + RETURN ;That's all, folks!
 +
 +
 +
 +PS_IN: ;Entry Label for Parallel to Serial INput
 + MOVLW D'8' ;8 bits to be read
 + MOVWF PS_IN_CTR ;Save count
 + BCF PS_IN_CLOCK ;Ensure that clock is low (may be shared)
 + BCF PORTA,PS_IN_SHIFT_NOT_LOAD
 + ;That LOW latched the data for sure
 + BSF PORTA,PS_IN_SHIFT_NOT_LOAD
 + ;Now we keep it high so data doesn't change
 +PS_IN_LOOP:
 + BTFSS PORTA,PS_IN_DATA ;Read serial data from port one bit at a time
 + GOTO GOT_ZERO
 + BSF STATUS,C ;Load a 1 into carry if bit was a 1
 + GOTO SHIFT_IN
 +GOT_ZERO:
 + BCF STATUS,C ;Load a 0 into carry if bit was a 0
 +SHIFT_IN:
 + RRC INDF ;Assemble bit into right-shifting byte
 + ; Indirect addressing handles multi bytes
 + BSF PORTA,PS_IN_CLOCK ;Shift the data in the 74165 to get ready
 + ; to possibly read the NEXT bit...
 + BCF PORTA,PS_IN_CLOCK ;Terminate the Clock pulse!
 + DECFSZ PS_IN_CTR,F ;Update our counter
 + GOTO PS_IN_LOOP ;If not done, do next bit
 + RETURN ;Return with data in register pointed to by FSR
 +
 +
 +
 +File away for future reference.
 +
 +Hope this helps,
 +Fr. Tom McGahee
 +
 +----------
 +> From: Stewart McCallum <pdp@PC-LAND.COM>
 +> To: PICLIST@MITVMA.MIT.EDU
 +> Subject: Shift Registers & Stamps
 +> Date: Thursday, June 18, 1998 12:37 AM
 +
 +> Can anyone shed some light on using shift registers with stamps to control
 +outputs and inputs.
 +
 +> Any help would be appreciated.
 +> Stewart McCallum
 +> Vancouver, Canada