shift_registers_and_how_to_use_them_in_smart_ways
Differences
This shows you the differences between two versions of the page.
shift_registers_and_how_to_use_them_in_smart_ways [2005/07/05 11:25] – created 82.96.100.100 | shift_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 < | ||
+ | To: pic microcontroller discussion list < | ||
+ | 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 | ||
+ | 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 ' | ||
+ | from switches, transistors, | ||
+ | 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* ' | ||
+ | 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' | ||
+ | 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 ' | ||
+ | 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' | ||
+ | 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 ' | ||
+ | state of the next bit. | ||
+ | |||
+ | Sneaky Trick (4) | ||
+ | You might be wondering whether or not you can ' | ||
+ | PIC input to handle this and another device. You can, but it requires | ||
+ | some way of determining which input is ' | ||
+ | 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: | ||
+ | Input: | ||
+ | |||
+ | 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 ; | ||
+ | ; 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 ; | ||
+ | ; Use any SRAM location desired. Sample 0x11 | ||
+ | PS_IN_CLOCK equ 0x01 ; | ||
+ | PS_IN_SHIFT_NOT_LOAD equ 0x02 ; | ||
+ | PS_IN_DATA equ 0x03 ; | ||
+ | |||
+ | ;Assume user has set up PIC, including PORTA I/O direction for each bit | ||
+ | |||
+ | PS_IN: | ||
+ | MOVLW D' | ||
+ | MOVWF PS_IN_CTR ; | ||
+ | BCF PS_IN_CLOCK ; | ||
+ | BCF PORTA, | ||
+ | ;That LOW latched the data for sure | ||
+ | BSF PORTA, | ||
+ | ;Now we keep it high so data doesn' | ||
+ | PS_IN_LOOP: | ||
+ | BTFSS PORTA, | ||
+ | GOTO GOT_ZERO | ||
+ | BSF STATUS, | ||
+ | GOTO SHIFT_IN | ||
+ | GOT_ZERO: | ||
+ | BCF STATUS, | ||
+ | SHIFT_IN: | ||
+ | RRC PS_IN_REG ; | ||
+ | BSF PORTA, | ||
+ | ; to possibly read the NEXT bit... | ||
+ | BCF PORTA, | ||
+ | DECFSZ PS_IN_CTR, | ||
+ | GOTO PS_IN_LOOP ; | ||
+ | RETURN ; | ||
+ | |||
+ | 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 ' | ||
+ | additional code. Here is the simplest way: | ||
+ | |||
+ | Assume user has defined a register called SOME_REGISTER, | ||
+ | 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: | ||
+ | Input: | ||
+ | |||
+ | 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 ; | ||
+ | ; 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 ; | ||
+ | ; Use any SRAM location desired. Sample 0x11 | ||
+ | |||
+ | SOME_REGISTER equ 0x12 ; | ||
+ | PS_IN_NINTH_BIT equ 0x07 ; | ||
+ | |||
+ | PS_IN_CLOCK equ 0x01 ; | ||
+ | PS_IN_SHIFT_NOT_LOAD equ 0x02 ; | ||
+ | PS_IN_DATA equ 0x03 ; | ||
+ | |||
+ | ;Assume user has set up PIC, including PORTA I/O direction for each bit | ||
+ | |||
+ | |||
+ | PS_IN: | ||
+ | MOVLW D' | ||
+ | MOVWF PS_IN_CTR ; | ||
+ | BCF PS_IN_CLOCK ; | ||
+ | BCF PORTA, | ||
+ | ;That LOW latched the data for sure | ||
+ | BSF PORTA, | ||
+ | ;Now we keep it high so data doesn' | ||
+ | PS_IN_LOOP: | ||
+ | BTFSS PORTA, | ||
+ | GOTO GOT_ZERO | ||
+ | BSF STATUS, | ||
+ | GOTO SHIFT_IN | ||
+ | GOT_ZERO: | ||
+ | BCF STATUS, | ||
+ | SHIFT_IN: | ||
+ | RRC PS_IN_REG ; | ||
+ | BSF PORTA, | ||
+ | ; to possibly read the NEXT bit... | ||
+ | BCF PORTA, | ||
+ | DECFSZ PS_IN_CTR, | ||
+ | GOTO PS_IN_LOOP ; | ||
+ | GET_BIT_9: | ||
+ | ; as the 8 bit example. Now we add the | ||
+ | ; extra code to handle the ninth bit. | ||
+ | |||
+ | BCF SOME_REGISTER, | ||
+ | ; | ||
+ | BTFSS PORTA, | ||
+ | GOTO PS_IN_RET ; | ||
+ | BSF SOME_REGISTER, | ||
+ | ;If it was a 1, make it so! | ||
+ | PS_IN_RET: | ||
+ | RETURN ; | ||
+ | |||
+ | |||
+ | ***** | ||
+ | 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: | ||
+ | Input: | ||
+ | |||
+ | 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 ; | ||
+ | ; 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 ; | ||
+ | ; Use any SRAM location desired. Sample 0x11 | ||
+ | PS_IN_REG2 equ 0x12 ; | ||
+ | ; should be contiguous with PS_IN_REG1 | ||
+ | PS_IN_CLOCK equ 0x01 ; | ||
+ | PS_IN_SHIFT_NOT_LOAD equ 0x02 ; | ||
+ | PS_IN_DATA equ 0x03 ; | ||
+ | |||
+ | ;Assume user has set up PIC, including PORTA I/O direction for each bit | ||
+ | |||
+ | PS_IN_FSR: | ||
+ | MOVLW PS_IN_REG1 | ||
+ | MOVWF FSR ; | ||
+ | CALL PS_IN ; | ||
+ | |||
+ | INCF FSR, | ||
+ | CALL PS_IN ; | ||
+ | RETURN ; | ||
+ | |||
+ | |||
+ | |||
+ | PS_IN: | ||
+ | MOVLW D' | ||
+ | MOVWF PS_IN_CTR ; | ||
+ | BCF PS_IN_CLOCK ; | ||
+ | BCF PORTA, | ||
+ | ;That LOW latched the data for sure | ||
+ | BSF PORTA, | ||
+ | ;Now we keep it high so data doesn' | ||
+ | PS_IN_LOOP: | ||
+ | BTFSS PORTA, | ||
+ | GOTO GOT_ZERO | ||
+ | BSF STATUS, | ||
+ | GOTO SHIFT_IN | ||
+ | GOT_ZERO: | ||
+ | BCF STATUS, | ||
+ | SHIFT_IN: | ||
+ | RRC INDF ; | ||
+ | ; Indirect addressing handles multi bytes | ||
+ | BSF PORTA, | ||
+ | ; to possibly read the NEXT bit... | ||
+ | BCF PORTA, | ||
+ | DECFSZ PS_IN_CTR, | ||
+ | GOTO PS_IN_LOOP ; | ||
+ | RETURN ; | ||
+ | |||
+ | |||
+ | |||
+ | File away for future reference. | ||
+ | |||
+ | Hope this helps, | ||
+ | Fr. Tom McGahee | ||
+ | |||
+ | ---------- | ||
+ | > From: Stewart McCallum < | ||
+ | > 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 |
shift_registers_and_how_to_use_them_in_smart_ways.txt · Last modified: 2019/08/27 20:45 by 127.0.0.1