Shiftin Shiftout
Drago
Posts: 24
Hello there,
I need help for Shiftin and Shiftout code.
I am hardware guy and the programming is not my best side, so I need help from somebody that already have similar application or willing to help me with new one.
The application is simple and it is wired by Stampworks experiments #23 and #24
(It can be wired differently if suggested).
BS2 and 40 inputs (74HC165) and 40 outputs (74HC595).
When input #1 is triggered low the Output # 1 should be ON for two (2) seconds and reset.
Same with all 40 I/Os.
I wrote some code based on Stampworks experiments, but it doesnt work well.
Appreciate experts help!
Thank you
I need help for Shiftin and Shiftout code.
I am hardware guy and the programming is not my best side, so I need help from somebody that already have similar application or willing to help me with new one.
The application is simple and it is wired by Stampworks experiments #23 and #24
(It can be wired differently if suggested).
BS2 and 40 inputs (74HC165) and 40 outputs (74HC595).
When input #1 is triggered low the Output # 1 should be ON for two (2) seconds and reset.
Same with all 40 I/Os.
I wrote some code based on Stampworks experiments, but it doesnt work well.
Appreciate experts help!
Thank you
Comments
You have not included your code so we can see what you may be doing wrong. Also, you didn't mention if it is possible for an input to go high while one of the outputs is still being held high from a different input.
Actually I started the similar project two years ago and get help from Paal from Norway.
Anyway, he put lots of effort to help, but the code newer worked.
My programming knowledge is very low and I was able just to make just small program with BS2 I/O’s but not to include more I/O’s by Shiftin and Shiftout commands.
Due to some health circumstances I give up on project and now I would like to go again, but with different and easier configuration.
Attached is my small code and one of Paal’s applications.
Now I am not looking for complex operation as previous, but simple In/out and if that work would like to expend with more BS2’s in a chain.
Regarding the question: the Output will trigger something by short pulse 1-2 second and it may happen that another input get trigger, but not likely.
Here is Paal's code that from some reason didn't work, but now I do not need many of that actions. Just when input #1 is triggered low the Output # 1 should be ON for two (1-2) seconds and reset and the same for 40 I/O's.
' {$STAMP BS2}
' {$PBASIC 2.5}
' Author: Paal Thingbo. mailto:devfd0@msn.com
' This program controls 10 input and 10 output shift register and three Stamp pins.
' Scratchpad RAM used:
' 0-79: Stores a 1 or a 0 to indicate the timer flag for each Input#
' 80-159: Stores the elapsed 0.1 seconds for each timer
' 160 and 161: Timer for PIN 7 (Word-sized variable)
' PIN assignements
pInputIO PIN 0
pInputClock PIN 1
pInputLatch PIN 2
pOutputIO PIN 4
pOutputClock PIN 5
pOutputLatch PIN 6
' Variables
temp VAR Word
InBits VAR Byte(10)
OutBits VAR Byte(10)
counter VAR Nib
pos VAR Nib
TempInBits VAR Byte
TempOutBits VAR Byte
' Flags
IO7TimerON VAR Bit
' Program start
Init:
HIGH pInputLatch
' Reset timer flags
IO7TimerON = 0
' Rest timer flags
FOR temp = 0 TO 79 : WRITE temp, 0 : NEXT
' Reset timers
FOR temp = 80 TO 159 : WRITE temp, 0 : NEXT
Main:
DO
GOSUB ReadInputs ' Read all inputs from shift registers 165
GOSUB CheckInputs ' Check the state of the inputs
GOSUB CheckInputTimers ' Check any timers set on the inputs
GOSUB WriteOutputs ' Write outputs to shift register 595
GOSUB CheckPIN3 ' Check PIN 3
GOSUB CheckPIN7Timer ' Check pin 7 timers
PAUSE 90 ' Wait 0.1 seconds. This number should be adjusted somewhere
' between 50-100 to account for processor time.
LOOP
' Checks PIN 3
CheckPIN3:
IF IN3 = 1 THEN
DEBUG "PIN 3 triggered.", CR
PAUSE 1000
IF IN3 = 0 THEN
LOW 8
IF IN3 = 1 THEN
DEBUG "PIN 3 triggered again.", CR
HIGH 8
FOR temp = 1 TO 60
PAUSE 1000
NEXT
LOW 8
ENDIF
ENDIF
ENDIF
RETURN
' This procedure checks all 40 inputs and turns outputs high or low
CheckInputs:
'FOR counter = 0 TO 9 ' Loop through 10 shift registers
FOR counter = 0 TO 0 ' Loop through 10 shift registers
TempInBits = InBits(counter) ' Get input from ONE shift register
TempOutBits = OutBits(counter) ' Get output from ONE shift register
FOR pos = 7 TO 0 STEP 2 ' Loop through 8 inputs of ONE shift register
READ (counter * 8) + pos, temp ' Is Input in timer mode?
IF temp = 0 THEN ' No timer active for this input
IF TempInBits.BIT0(pos) = 0 THEN ' Input #1 triggered
TempOutBits.BIT0(pos) = 1 ' Activate output #1
DEBUG "Output#", DEC 8 - ((counter * 8) + pos)," - HIGH.", CR
TempOutBits.BIT0(pos - 1) = 0 ' Always close #2 if #1 goes active
GOSUB ActivateTimer7
WRITE (counter * 8) + pos, 1 ' Activate input timer flag
DEBUG "Timer on Output#", DEC 8 - ((counter * 8) + pos)," activated.", CR
WRITE 80 + (counter * 8) + pos, 0 ' Reset input timer
WRITE 80 + (counter * 8) + pos+1, 0 ' Reset input timer
ENDIF
ENDIF
' Check if timer for Input#1 is active.
' If it is, and Input#2 turn on, activate Input#2, and deactivate Input#1
READ (counter * 8) + pos, temp ' Read input timer flag
IF temp = 1 THEN ' Input#1 timer active
READ 80 + (counter * 8) + pos, temp.HIGHBYTE
READ 80 + (counter * 8) + pos + 1, temp.LOWBYTE
IF TempInBits.BIT0(pos-1) = 0 AND temp >= 100 THEN ' Check Input #2 if Input#1 is not active for more than 10 seconds
TempOutBits.BIT0(pos) = 0 ' Deactivate Input #1
DEBUG "Output#", DEC (counter * 8) + pos," LOW.", CR
WRITE (counter * 8) + pos, 0 ' Deactivate input timer on Input#1
DEBUG "Timer on Output#", DEC (counter * 8) + pos," de-activated.", CR
TempOutBits.BIT0(pos-1) = 1 ' Activate Input #2
DEBUG "Output#", DEC (counter * 8) + pos - 1," HIGH.", CR
ENDIF
ENDIF
NEXT
OutBits(counter) = TempOutBits
NEXT
RETURN
' Check the timers for all 40 inputs
CheckInputTimers:
'FOR counter = 0 TO 9 ' Loop through 10 shift registers
FOR counter = 0 TO 0 ' Loop through 10 shift registers
TempInBits = InBits(counter) ' Get input from ONE shift register
TempOutBits = OutBits(counter) ' Get output from ONE shift register
FOR pos = 7 TO 0 STEP 2 ' Loop through 8 inputs of ONE shift register
' Increment timers
READ 80 + (counter * 8) + pos, temp.HIGHBYTE
READ 80 + (counter * 8) + pos + 1, temp.LOWBYTE
temp = temp + 1
WRITE 80 + (counter * 8) + pos, temp.HIGHBYTE
WRITE 80 + (counter * 8) + pos+1, temp.LOWBYTE
' Check timer flag for #1 inputs
READ (counter * 8) + pos, temp ' Is Input#1 in timer mode?
IF temp = 1 THEN
READ 80 + (counter * 8) + pos, temp.HIGHBYTE
READ 80 + (counter * 8) + pos + 1, temp.LOWBYTE
IF temp >= 100 THEN ' 10 seconds elapsed
TempOutBits.BIT0(pos) = 0 ' Deactivate Input #1
WRITE (counter * 8) + pos, 0 ' Deactive timer on Input#1
DEBUG "Output#", DEC 8 - ((counter * 8) + pos)," de-activated (10-second timeout).", CR
ENDIF
ENDIF
NEXT
OutBits(counter) = TempOutBits
NEXT
RETURN
' This procedure checks all the timers
CheckPIN7Timer:
' Increment timers
READ 160, temp.HIGHBYTE
READ 161, temp.LOWBYTE
temp = temp + 1
WRITE 160, temp.HIGHBYTE
WRITE 161, temp.LOWBYTE
' Check PIN 7 timer
' If 5 seconds has elapsed, stop the timer.
IF IO7TimerON = 1 THEN
IF temp >= 50 THEN ' 5 seconds
IO7TimerON = 0
LOW 7
DEBUG "I/O 7 de-activated (5-second timeout).", CR
ENDIF
ENDIF
RETURN
' Activate PIN 7 timer
ActivateTimer7:
IO7TimerON = 1
WRITE 160, 0 ' Reset the timer
WRITE 161, 0 ' Reset the timer
HIGH 7
DEBUG "I/O 7 activated.", CR
RETURN
' Write all 80 bits to the output latches
WriteOutputs:
'FOR counter = 9 TO 0
FOR counter = 0 TO 0
SHIFTOUT pOutputIO, pOutputClock, MSBFIRST, [OutBits(counter)] ' Send the bits
NEXT
PULSOUT pOutputLatch, 5 ' Transfer to outputs
RETURN
' Read 80 bits from the 74HC165 shift register
ReadInputs:
PULSOUT pInputLatch, 5 ' Load switch inputs
'FOR counter = 9 TO 0
FOR counter = 0 TO 0
SHIFTIN pInputIO, pInputClock, MSBPRE, [InBits(counter)] ' Shift them in
NEXT
RETURN
Yes it is complex.
Paal wrote complex code because there was couple operations and I am not sure that it can be managed by BS2, so I simplify the operations just to IN > OUT .
My short code work, but I don’t know how to continue to 40 I/O’s.
' {$STAMP BS2}
' {$PBASIC 2.5}
DO
DEBUG ? IN5
DEBUG ? IN3
IN3 = 0
IF (IN3 = 1) THEN
HIGH 14
PAUSE 10000
LOW 14
IF IN5 = 1 THEN
HIGH 15
ELSE
IF (IN5 = 0) THEN
LOW 15
PAUSE 3000
ENDIF
ENDIF
ENDIF
LOOP
How to attach the shematic???
StampWorks Experiments #23 and #24 show pretty clearly how to add 8 or 16 outputs and 8 or 16 inputs respectively using I/O expanders. You can cascade further 74HC595s or 74HC165s the same way you add one to an existing device as shown. The Clock and Load lines are added in parallel and the Data In pin of a 74HC595 is connected to the Data Out pin of the previous 74HC595 in the cascade. The 74HC165s are handled similarly as shown. You need to add another 8-bit variable in the SHIFTOUT data list for each 74HC595 or another 16-bit variable (with the '\16') for each two 74HC595s, similarly for input expansion.
You are right, the project includes more than just IN and OUT, but I am not able to write the code.
As I mentioned I am looking for help or an experienced coder.
The entire application:
1) Receive (RS232) text command from PC program and translate to trigger a particular output,
2) Read Input status and activate the associated output (This is what I am doing now).
3) Read the Keypad and activate the outputs.
4) Network more BS2’s with associated I/O’s and direct commands to each separately.
5) Eventually connect existing .NET application and execute by BS2 instead by PIC.
I will be happy if I can move forward little bit with this IN > OUT and then learn and continue to expand the application.
I have the schematic for 74HC595 and 74HC165, but don’t know how to attach to blog.
Thank you
It is standard connection posted in Stamworks and other literature.
Also a big thank you to you two guys for fast reply.
In last 3 weeks I purchased 2 books, uploaded and tested number of samples, but still didn't move any forward.
Regards,
Drago
There are plenty of examples available for most of the pieces you're looking at. Important references include "What's a Microcontroller?" and the "Basic Stamp Syntax and Reference Manual". The "StampWorks Menu" has a lot of useful examples, like for I/O expansion. There are Nuts and Volts Columns that show how to use a keypad and how to network several Stamps together.
The schematic looks straightforward and should work like what's shown in the StampWorks Manual. The examples shown for 16 I/O pins should just work (for the 1st two 74HC595s and 1st two 74HC165s) once you change the I/O pin number definitions in the examples to what you have in your setup. To have them work for the longer cascaded strings of devices, you just have to add variables to the SHIFTOUT and SHIFTIN statements for the extra I/O pins. The descriptions of the SHIFTIN and SHIFTOUT statements in the Reference Manual should serve as examples for that.
In your initial description you said the circuit should cascade several input shift registers (74HC165) to read 32 (or more) inputs. Upon an input going high, the corresponding output on a series of cascaded output shift registers (74HC595) should also go high and remain so for 1-2 seconds.
This is easy enough to do on a BS2 as Mike pointed out, the StampWorks examples get you started and it would be a simple matter of contiuously reading the inputs until a bit goes high, then shifting the entire 32 bits (or however many) to the outputs, pause then go back to monitoring inputs. The caveat is that you would miss any inputs triggered while the output was being clocked and held.
Now, adding in the ability to read a keypad means the scanning code has to interleave cycles with a keypad scanning routine. Again, not difficult and even easier if you use a keypad decoder chip. But adding in the RS-232 input is the deal breaker. The reason is that the BS2 cannot monitor the serial port while it is doing the other things. Comands sent to the serial port would most often be missed.
Now let's add to that your existing code had timers for each output to maintain individual hold times for each output. That also could not be done due to overhead timing and more importantly 32 variables with which to hold the counts. So I am going to break my usual tradition of not recomending someone move away from the BASIC Stamp and recommend that you consider the Propeller chip for this application.
Everything you want to do could be done on a single Propeller chip and the individual sections (keypad scanning, RS-232 input, shift registers, timers) could all happen concurrently in different processors within the Propeller chip. In fact the timers would have sufficient resources in both CPU time and variable space to keep track of the delays for that many pins and then you wouldn't have to worry about multiple inputs during the timing window. With the Propeller chip you could have several inputs in a row in less than a second and the outputs could accurately maintain their output state independantly with very high resolution.
Some people who try to help me two years ago already suggested switching to Propeller.
How much the programming is different, and how much with my knowledge I would be able to work on that???
Obviously I will need help of experienced programmer, but still I wish to be able at least to make the changes, or the application maintenance by my self.
Now I am experiencing the problem because I have the application (very complex) written in .NET and I can’t fix anything without to hire the coder. Because the complexity of the application each coder take 1-2 months to learn the application, which is very expensive.
This is most reason I am trying to switch on something I can manage at least partially.
Will dig in Propeller to see how it works.
Best regards,
A flowchart would go a long way toward realizing this kind of goal. Flowcharts used to be such a great tool and it seems less and less people use them. But they really do help you hone out the flow of a complex program and help you realize potential issues before you have to think about coding around them.
And remember, it is the concurrent nature of this application that is unique and makes the BASIC Stamp modules a exception. In many similar applications you would totally be able to use a BASIC Stamp Module. I think if you could get the basic routines going and working together you could easily maintain the code in a reasonable manner. And as for your PC application, if that does what you need you can program the Propeller chip to work around its protocol for communication instead of having to rewrite the PC app for the new microcontroller.
I am back to idea to use the BS2 at this stage of the project.
This is concept proof part of the entire project and just a simple task will be OK to convince the people that the entire project works.
What I need in this stage is: to only for 3 seconds trigger the output anytime when the associated input is set LOW.
This sample code work fine (except 3 seconds timer) but cant make that more than one 74HC595 work.
Can you help please?
Stampworks: Experiment #25 Mixed IO with shift registers
' {$STAMP BS2}
' {$PBASIC 2.5}
'
[Program description]
'
' This is program that uses the 74HC596 and 74HC165 together with the fewest number of BASIC Stamp IO pins.
' This is accomplished by placing a 4.7K resistor between the data out (pin 7)of the 74HC165 and data in
' (pin 14) of the 74HC595. The serial data pin from the BASIC Stamp connects to the 74HC595.
'
[ I/O Definitions ]
Clock PIN 0 ' shift clock
SerData PIN 1 ' serial data (74HC595.14)
Latch PIN 2 ' output latch (74HC595.12)
Load PIN 3 ' input load (74HC165.1)
'
[ Constants ]
DelayTime CON 100
' ----[ Variables ]
xInputs VAR Byte ' external inputs
' ----[ Initialization ]
Reset:
LOW Latch
HIGH Load
DEBUG CLS,
"xInputs 76543210", CR,
"
", CR,
"Status ........"
' ----[ Program Code ]
Main:
DO
GOSUB get_165x1 ' get inputs
GOSUB get_165x2 ' get inputs 2 ' this im one of my try's
GOSUB Put_595x1 ' move to extended outputs
DEBUG CRSRXY, 10, 2, BIN16 xInputs ' display current status
PAUSE DelayTime ' pad the loop bit
LOOP
' ----[ Subroutines ]
Get_165x1:
PULSOUT Load, 5 ' load inputs
SHIFTIN SerData, Clock, MSBPRE, [xInputs] ' shift them in
RETURN
Get_165x2:
PULSOUT Load, 5 ' load inputs
SHIFTIN SerData, Clock, MSBPRE, [xInputs] ' shift them in
RETURN
Put_595x1:
SHIFTOUT SerData, Clock, MSBFIRST, [xInputs] ' send inputs to 595
PULSOUT Latch, 5 ' latch 595 outputs
INPUT SerData ' Float data I/O line
RETURN
Put_595x2:
SHIFTOUT SerData, Clock, MSBFIRST, [xInputs] ' send inputs to 595
PULSOUT Latch, 5 ' latch 595 outputs
INPUT SerData ' Float data I/O line
RETURN
As far I understand the inputs are "scanned" at all the times and if the status changes the data is shifted to associated output?
My biggest problem to understand how to address each output.
Many examples treat this slightly different, and so far I was able to make very different configurations (trigger I1 at 165#1 and TWO outputs #1 at 165#2&3 are ON, or some other combination. Complete mess!)
Thank you for help.
I just need help to show me the directions how to corectly do that and I will work more on expansion.
Thank you
What about this sample???
(CLICK TO ENLARGE)
Attached are two programs...the one with the _PDB is the exact code I ran on the PDB. It is slightly different from the other code which is intended for you. The buttons and DIP switches I used on the PDB are active-low and idle high. Because of this I had to add a tilde (~) to two lines to invert the variables for the buttons. If you're using a high input (active-high) then you should use the other program which has the tilde symbols removed from two lines to adjust for active-high inputs.
The attached code continuously scans the inputs looking for a non-zero value, which indicates a button has been pressed. Once that happens it copies the bit pattern to the outputs and waits three seconds. After that it clears the outputs and then goes back to scanning the buttons again. The buttons could be just any high signal on the inputs. I used 3 seconds instead of the 2 you mentioned in this thread as per your e-mail. If you have any questions please follow-up here.
I will be back in a town on Wednesday and will test it.
The chart is also looks great!
Best regards,
Miodrag
The sample of code works, but not exactly as I need.
Only the second 165 IC detecting the input and it correspond to the FIRST 595, but based on suggested code I will try to make some other combinations.
Obviously this is above of my programming capabilities and I have to find somebody to help me developing the application.
Have one more question:
In my application I will have several 74HC595s in serial, so how to send the command Hi/Low to the particular output on each 74HC595?
According to number of visitors this is very hot topic!
Best regards,
Drago
I apologize for being a bit confused about what you mean. On my demo code and board here there are 16 inputs and 16 outputs. We'll call them 0 through 15. When input 3 goes high, output 3 goes high for 3 seconds. When input 12 goes high, output 12 goes high for 3 seconds. Is this not what you asked for? This whole things can be expanded quite easily. I wonder if your hardware is not wired the same as mine?
You are right; my 595 hardware was set for mixed I/O sample from Stampworks.
Now I change the setting and it works as you suggested!
I guess for expansion only the number of IC’s need to be changed?
Can you also please suggest the example how to address the specific output (high) by command from software?
Regards,
Drago
How to change that #1 trigger #1 is that something that it can be done with MSBFIRST?
Thank you
The two ICs on the right are 74HC595 and it is important to note how they are connected...first of all these ICs are rotated 180 degrees so that the bits line up with the LEDs above them. The LSB is still on the far right and the MSB is on the far left. Data is shifted through the right IC and daisy chains into the left one. So to do this the latch and clock pins are shared on both ICs, however the serial output goes into the DS pin on the right IC and the serial out pin goes into the DS pin on the left IC. In this manner the data is coming in MSB and shifting through until the last bit (bit 0) is clocked in and then the latches are pulsed.
If you compare my code to the StampWorks code you will find an important difference...I did not set the bit count to 16. The reason is you cannot expand the chain any further using this method. Instead I broke the variables up into their high and low bytes and shifted them individually. This is important to note because in this manner you can connect more shift registers and you need only add more variable high and low byte names to the command. The latch won't be pulsed until all bytes have been clocked out. It works almost exactly the same with the inputs.
As for detecting the high input in the first place, that is done in the code where it says:
If you add more shift registers you will need to add a line to check each word variable, but that is pretty straight forward. Once a word is determined to be non-zero its contents are copied into its corresponding output variable and the whole thing is shifted out. I hope this helps. If you have any additional questions please let me know.
You actually noted the chip connections, but I didn’t compare completely with my setting.
Will play little bit with this to get the configuration that will work for my presentation and will let you know.
Best regards,
Miodrag