November 23, 2024, 07:02:58 PM

News:

Be sure to checkout our Vixen interfaces in the Library forum -- if you want PC automation at near zero cost, EFX-TEK and Vixen is a great combination of tools.


Prop-1 and shift registers

Started by Jeff Haas, July 10, 2012, 01:24:17 AM

Previous topic - Next topic

Jeff Haas

Jon,

[I've started a new thread on this to keep this conversation separate.]

I found your article, Column #110 June 2004, "Drumming Up Control" and set up a shift register to connect to the Prop-1, and using a Prop-Pot and some switches, got it up and running.

However, I don't need as many options as in that article.  I'd like to connect a Prop-1 to two 74HC595 shift registers, with an "Idle" mode and a "Activated" mode toggled by the BRANCH command (since the Prop-1 is waiting for a signal from the Prop-2).  The speed of LEDs controlled by the shift registers needs to be different for each mode.

Can you please write the program for me?

Question on connections: Can the outputs to the shift registers go via the OUT headers, or are they required to go via the TTL pins?

Jeff

JonnyMac

The outputs to the 74x595 must be from the TTL headers; the OUTx terminals are open collector (floating for off, ground for on).

What are the LEDs doing in the different modes?  That will make a difference in how I construct the program. If the modes are complex I will put the patterns in tables.  One table in the Prop-1 is easy; the address for the second has to be manually calculated (which means you have to be careful with changes).
Jon McPhalen
EFX-TEK Hollywood Office

JonnyMac

Here's a place to start.  I've commented the code so you should be able to make adjustments without a lot of fuss.

' =========================================================================
'
'   File......
'   Purpose...
'   Author....
'   E-mail....
'   Started...
'   Updated... 10 JUL 2012
'
'   {$STAMP BS1}
'   {$PBASIC 1.0}
'
' =========================================================================


' -----[ Program Description ]---------------------------------------------


' -----[ Revision History ]------------------------------------------------


' -----[ I/O Definitions ]-------------------------------------------------

SYMBOL  Trigger         = PIN7                  ' SETUP = DN

SYMBOL  Latch           = 2                     ' for 74x595
SYMBOL  Clock           = 1
SYMBOL  DPin            = PIN0


' -----[ Constants ]-------------------------------------------------------

SYMBOL  YES             = 1
SYMBOL  NO              = 0

SYMBOL  S1_LENGTH       = 8                     ' 8 elements in pattern
SYMBOL  S1_TIMING       = 125                   ' ~125ms per element

SYMBOL  S2_LENGTH       = 8
SYMBOL  S2_TIMING       = 50


' -----[ Variables ]-------------------------------------------------------

SYMBOL  dOut            = B0                    ' data to 74x595
SYMBOL  dataMSB         =  BIT7

SYMBOL  bits            = B1                    ' for Shift_Out

SYMBOL  last            = B2                    ' last state of Trigger
SYMBOL  idx1            = B3                    ' index for seq 1
SYMBOL  idx2            = B4                    ' index for seq 2
SYMBOL  pntr            = B5                    ' eeprom pointer (for S2)


' -----[ Initialization ]--------------------------------------------------

Reset:
  PINS = %00000000                              ' all off
  DIRS = %00000111                              ' P2..P0 are outputs


' -----[ Program Code ]----------------------------------------------------

Main:
  BRANCH Trigger, (Run_S1, Run_S2)              ' jump to selected seq


Run_S1:
  IF last = 1 THEN Run_S1_Next                  ' running S1 last time?
    idx1 = 0                                    ' no, reset index

Run_S1_Next:
  READ idx1, dOut                               ' read outputs
  GOSUB Shift_Out                               ' send to '595
  idx1 = idx1 + 1 // S1_LENGTH                  ' update index
  PAUSE S1_TIMING                               ' hold per sequence
  last = 1                                      ' mark s1 just ran
  GOTO Main                                     ' start over


Run_S2:
  IF last = 2 THEN Run_S2_Next
    idx2 = 0

Run_S2_Next:
  pntr = idx2 + S1_LENGTH                       ' S2 table after S1
  READ pntr, dOut
  GOSUB Shift_Out
  idx2 = idx2 + 1 // S2_LENGTH
  PAUSE S2_TIMING
  last = 2
  GOTO Main


' -----[ Subroutines ]-----------------------------------------------------

' Shift bits in dOut to 74x595 shift register, MSBFIRST

Shift_Out:
  FOR bits = 7 TO 0 STEP -1                     ' send eight bits
   DPin = dataMSB                               ' move MSB to data pin
   PULSOUT Clock, 1                             ' clcok the bit
   dOut = dOut * 2                              ' dout = dout << 1
  NEXT
  PULSOUT Latch, 1                              ' latch the new outputs
  RETURN

' -----[ User Data ]-------------------------------------------------------

' Note: You must update S1_LENGTH and S2_LENGTH after making sequence
'       modifications

S1_Bits:
  EEPROM (%00000001)
  EEPROM (%00000001)
  EEPROM (%00000001)
  EEPROM (%00000001)
  EEPROM (%10000000)
  EEPROM (%10000000)
  EEPROM (%10000000)
  EEPROM (%10000000)


  ' address of S2_Bits is length of S1_Bits

S2_Bits:
  EEPROM (%00000000)
  EEPROM (%00011000)
  EEPROM (%00111100)
  EEPROM (%01111110)
  EEPROM (%11111111)
  EEPROM (%01111110)
  EEPROM (%00111100)
  EEPROM (%00011000)
Jon McPhalen
EFX-TEK Hollywood Office

Jeff Haas

Jon, this is terrific!  Thank you.  It looks really impressive.



Jeff Haas

I've had some time to work with this some more.

From what I can tell, the code is only addressing one shift register, so if you have more than one shift register chained, they all do the same thing.  Is it possible to address two or three shift registers, each with their own pattern?  Or is this getting too much for the Prop-1?

JonnyMac

It can be done -- the trick is to separate the latching from the shifting as in this [very minor] update to your program.

Keep in mind that values are pushed down the chain of shift registers, so the order that you push the bytes with the Shift_Out subroutine is important.  For example, if you're using two registers:

[ Prop-1 ] --> [ S/R #1] --> [ S/R #2 ]

...you actually have to send the bits for S/R #2 out before the bits for S/R #1.  After the first call to Shift_Out those bits will be in the S/R #1 holding register.  On the second call to Shift_Out the bits are pushed from #1 down the line to #2.  When you call Latch_Outputs the S/R holding registers are transferred to the output pins.

' =========================================================================
'
'   File......
'   Purpose...
'   Author....
'   E-mail....
'   Started...
'   Updated... 10 JUL 2012
'
'   {$STAMP BS1}
'   {$PBASIC 1.0}
'
' =========================================================================


' -----[ Program Description ]---------------------------------------------


' -----[ Revision History ]------------------------------------------------


' -----[ I/O Definitions ]-------------------------------------------------

SYMBOL  Trigger         = PIN7                  ' SETUP = DN

SYMBOL  Latch           = 2                     ' for 74x595
SYMBOL  Clock           = 1
SYMBOL  DPin            = PIN0


' -----[ Constants ]-------------------------------------------------------

SYMBOL  YES             = 1
SYMBOL  NO              = 0

SYMBOL  S1_LENGTH       = 8                     ' 8 elements in pattern
SYMBOL  S1_TIMING       = 125                   ' ~125ms per element

SYMBOL  S2_LENGTH       = 8
SYMBOL  S2_TIMING       = 50


' -----[ Variables ]-------------------------------------------------------

SYMBOL  dOut            = B0                    ' data to 74x595
SYMBOL  dataMSB         =  BIT7

SYMBOL  bits            = B1                    ' for Shift_Out

SYMBOL  last            = B2                    ' last state of Trigger
SYMBOL  idx1            = B3                    ' index for seq 1
SYMBOL  idx2            = B4                    ' index for seq 2
SYMBOL  pntr            = B5                    ' eeprom pointer (for S2)


' -----[ Initialization ]--------------------------------------------------

Reset:
  PINS = %00000000                              ' all off
  DIRS = %00000111                              ' P2..P0 are outputs


' -----[ Program Code ]----------------------------------------------------

Main:
  BRANCH Trigger, (Run_S1, Run_S2)              ' jump to selected seq


Run_S1:
  IF last = 1 THEN Run_S1_Next                  ' running S1 last time?
    idx1 = 0                                    ' no, reset index

Run_S1_Next:
  READ idx1, dOut                               ' read outputs
  GOSUB Shift_Out                               ' send to '595
  GOSUB Latch_Outputs
  idx1 = idx1 + 1 // S1_LENGTH                  ' update index
  PAUSE S1_TIMING                               ' hold per sequence
  last = 1                                      ' mark s1 just ran
  GOTO Main                                     ' start over


Run_S2:
  IF last = 2 THEN Run_S2_Next
    idx2 = 0

Run_S2_Next:
  pntr = idx2 + S1_LENGTH                       ' S2 table after S1
  READ pntr, dOut
  GOSUB Shift_Out
  GOSUB Latch_Outputs
  idx2 = idx2 + 1 // S2_LENGTH
  PAUSE S2_TIMING
  last = 2
  GOTO Main


' -----[ Subroutines ]-----------------------------------------------------

' Shift bits in dOut to 74x595 shift register, MSBFIRST

Shift_Out:
  FOR bits = 7 TO 0 STEP -1                     ' send eight bits
   DPin = dataMSB                               ' move MSB to data pin
   PULSOUT Clock, 1                             ' clcok the bit
   dOut = dOut * 2                              ' dout = dout << 1
  NEXT
  RETURN

' -------------------------------------------------------------------------

Latch_Outputs:
  PULSOUT Latch, 1                              ' latch the new outputs
  RETURN

' -----[ User Data ]-------------------------------------------------------

' Note: You must update S1_LENGTH and S2_LENGTH after making sequence
'       modifications

S1_Bits:
  EEPROM (%00000001)
  EEPROM (%00000001)
  EEPROM (%00000001)
  EEPROM (%00000001)
  EEPROM (%10000000)
  EEPROM (%10000000)
  EEPROM (%10000000)
  EEPROM (%10000000)


  ' address of S2_Bits is length of S1_Bits

S2_Bits:
  EEPROM (%00000000)
  EEPROM (%00011000)
  EEPROM (%00111100)
  EEPROM (%01111110)
  EEPROM (%11111111)
  EEPROM (%01111110)
  EEPROM (%00111100)
  EEPROM (%00011000)
Jon McPhalen
EFX-TEK Hollywood Office

Jeff Haas

Thanks again for this, Jon.  I've worked through the code a few times and tried editing it.

I'm still seeing both S/Rs do the same pattern.  I see how you shift the bits to the first register and push them down the line to the next one.  One part I don't quite get is how each register would have an independent pattern.  It seems to me that there would be a section of the eeprom sequence for S/R #1 and another for S/R #2; you load the first S/R with the bits for a pattern on S/R #2, then shift them down, load it again with a different set of bits for display on S/R #1, then latch everything to get the output.

Or do I just have to edit the sequences to add enough bits? 

JonnyMac

I would do something like this is a test program

  dOut = %11110000
  GOSUB Shift_Out
  dOut = %10101010
  GOSUB Shift_Out
  GOSUB Latch_Outputs


Do this to ensure that the outputs are working (patterns are obviously different).  If you're doing a table driven program you'll need to add a second byte to each line in the table, AND update the starting address pointer for the second table.

Jon McPhalen
EFX-TEK Hollywood Office

Jeff Haas

Thanks for the programming tips, I got this to work!  And I learned something in the process.

I added a third table to the EEPROM data.   I shiftout the pattern from the first table, then the pattern from the third table, and then latch the register.  This gives me independent patterns on each S/R, and since each one has its own table, it's easy to visualize and edit.

Then when the BRANCH happens the code acts the same as the previous versions.

Any improvements or cleanup suggestions are welcome.

Jeff

' =========================================================================
'
'   File...... ShiftBranch v2.1
'   Purpose... Two shift registers triggered by input from Prop-2
'   Author.... JonnyMac with some edits by Jeff Haas
'   E-mail....
'   Started...
'   Updated... 22 JUL 2012
'
'   {$STAMP BS1}
'   {$PBASIC 1.0}
'
' =========================================================================


' -----[ Program Description ]---------------------------------------------
' Prop-1 controls two 74HC595 shift registers, with an "Idle" mode and an
' "Activated" mode.  Flip between modes via the BRANCH command when the
' Prop-1 receives a trigger from the Prop-2.
' Prop-2 is running Embryo Chamber Halloween 2012.bs2.

' -----[ Revision History ]------------------------------------------------


' -----[ I/O Definitions ]-------------------------------------------------

SYMBOL  Trigger         = PIN7                  ' SETUP = DN

SYMBOL  Latch           = 2                     ' for 74x595
SYMBOL  Clock           = 1
SYMBOL  DPin            = PIN0


' -----[ Constants ]-------------------------------------------------------

SYMBOL  YES             = 1
SYMBOL  NO              = 0

SYMBOL  S1_LENGTH       = 8                     ' 8 elements in pattern
SYMBOL  S1_TIMING       = 125                   ' ~125ms per element

SYMBOL  S2_LENGTH       = 8
SYMBOL  S2_TIMING       = 50


' -----[ Variables ]-------------------------------------------------------

SYMBOL  dOut            = B0                    ' data to 74x595
SYMBOL  dataMSB         = BIT7

SYMBOL  bits            = B1                    ' for Shift_Out

SYMBOL  last            = B2                    ' last state of Trigger
SYMBOL  idx1            = B3                    ' index for seq 1
SYMBOL  idx2            = B4                    ' index for seq 2
SYMBOL  pntr            = B5                    ' eeprom pointer (for S2)
SYMBOL  pntr2           = B6                    ' eeprom pointer (for S3)


' -----[ Initialization ]--------------------------------------------------

Reset:
  PINS = %00000000                              ' all off
  DIRS = %00000111                              ' P2..P0 are outputs


' -----[ Program Code ]----------------------------------------------------

Main:
  BRANCH Trigger, (Run_S1, Run_S2)              ' jump to selected seq


Run_S1:
  IF last = 1 THEN Run_S1_Next                  ' running S1 last time?
    idx1 = 0                                    ' no, reset index

Run_S1_Next:
  READ idx1, dOut                               ' read outputs
  GOSUB Shift_Out                               ' send to '595

  pntr2 = idx2 + S1_LENGTH + S2_LENGTH          ' Refers to S3_Bits table, for different pattern
  READ pntr2, dOut

  GOSUB Shift_Out                               ' send to '595
  GOSUB Latch_Outputs

  idx1 = idx1 + 1 // S1_LENGTH                  ' update index
  idx2 = idx2 + 1 // S2_LENGTH

  PAUSE S1_TIMING                               ' hold per sequence
  last = 1                                      ' mark s1 just ran
  GOTO Main                                     ' start over


Run_S2:
  IF last = 2 THEN Run_S2_Next
    idx2 = 0

Run_S2_Next:
  pntr = idx2 + S1_LENGTH                       ' S2 table after S1
  READ pntr, dOut
  GOSUB Shift_Out
  GOSUB Latch_Outputs
  idx2 = idx2 + 1 // S2_LENGTH
  PAUSE S2_TIMING
  last = 2
  GOTO Main


' -----[ Subroutines ]-----------------------------------------------------

' Shift bits in dOut to 74x595 shift register, MSBFIRST

Shift_Out:
  FOR bits = 7 TO 0 STEP -1                     ' send eight bits
   DPin = dataMSB                               ' move MSB to data pin
   PULSOUT Clock, 1                             ' clock the bit
   dOut = dOut * 2                              ' dout = dout << 1
  NEXT
  RETURN


' -------------------------------------------------------------------------

Latch_Outputs:
  PULSOUT Latch, 1                              ' latch the new outputs
  RETURN

' -----[ User Data ]-------------------------------------------------------

' Note: You must update S1_LENGTH and S2_LENGTH after making sequence
'       modifications

S1_Bits:                          ' IDLE pattern for S/R #1
  EEPROM (%00000001)
  EEPROM (%00000001)
  EEPROM (%00000001)
  EEPROM (%00000001)
  EEPROM (%00100000)
  EEPROM (%00100000)
  EEPROM (%00100000)
  EEPROM (%00100000)


  ' address of S2_Bits is length of S1_Bits

S2_Bits:                         'ACTIVATED pattern for both S/Rs
  EEPROM (%00000000)
  EEPROM (%00011000)
  EEPROM (%00111100)
  EEPROM (%01111110)
  EEPROM (%11111111)
  EEPROM (%01111110)
  EEPROM (%00111100)
  EEPROM (%00011000)

  ' address of S3_Bits is length of S1_Bits + length of S2_Bits

S3_Bits:                         ' IDLE pattern for S/R #2

  EEPROM (%00011000)
  EEPROM (%00011000)
  EEPROM (%00011000)
  EEPROM (%00011000)
  EEPROM (%00000100)
  EEPROM (%00000100)
  EEPROM (%00000100)
  EEPROM (%00000100)