In some cases, the controller is just telling the world what to do, and does not care what may be going on in the world. But most of the time, the controller wants to check on a condition - peeking at the condition of the outside world - before doing something. In computer jargon, it is said that the computer has inputs.
We have a BASIC Stamp Input intro. This page covers advanced topics concerning input on a Basic Stamp.
Before you read this section, please:
For the sake of simplicity, we will assume that all input is positive logic. We will also assume that level shifting has already been done, so we are just dealing with "true" and "false".
For most of these issues we will simplify the input to a single trigger bit. All the controller has to do is perform an action when it sees the trigger.
With all of that simplification, one might think that input is pretty easy. You write the program to check an input bit. When it goes true, you perform the action. And such a simplistic program might even work ... mostly. But it might be a little flaky:
All of the complexities of input discussed here have a single root cause: timing. When the timing is right, it works. When the timing is off a little, the strange stuff happens.
Since timing is the problem, we will have to show you how the input changes over time.
We'll use charts something like this:
and this:
Level-Triggered Versus Edge-Triggered
This situation is most likely to happen when a trigger input lasts a long time,
you
poll
for the input trigger,
and the output action is relatively short.
Here is a code fragment that is likely to have this problem:
Main:
TryAgain:
IF Trigger = IsOff THEN TryAgain ' wait until trigger is activated
' Do your activity here!
GOTO Main ' repeat forever
Why is this a problem?
Look at the timing on a chart:
The basic problem is that the controller will act any time it sees that the input trigger is on, even if the trigger has been seen and acted on before.
In some cases, this may be desirable. But in most situations, we want the trigger pulse to cause the action to happen once and only once per pulse, even if the pulse is long.
The solution is to act not when the controller sees a true trigger, but when the controller sees the trigger go from false to true.
Here is one way to address this problem:
Main:
AwaitQuiet:
IF Trigger = IsOn THEN AwaitQuiet ' wait until trigger is NOT active
AwaitTrigger:
IF Trigger = IsOff THEN AwaitTrigger ' wait until trigger is activated
' Do your activity here!
GOTO Main ' repeat forever
Look at the timing on a chart:
When presented with this situation, the controller must "de-bounce" the input trigger signal.
There are several ways to do this, and since you may also have to deal with things like
edge-triggering,
a single, strong routine that cleans up the input signal is probably in order.
In order to show you approaches, we will just address this one problem in this code fragment:
This is the simplest approach, but it has some drawbacks:
An alternative is to wait for several consecutive good samples:
This approach has some tradeoffs:
An interrupt is when an input trigger forces the program to stop whatever it is doing
and pay attention to the input.
Let's describe this with an analogy.
Say that you are riding a train and would like to read a newspaper to pass the time.
Interrupts requires special hardware, including a CPU that is capable of handling interrupts,
and a specially written controller program that is capable of suspending the current operation,
servicing the interrupt, and resuming the previous operation after the interrupt is done.
The Prop-1 does not offer interrupts.
A "latch" is a simple piece of hardware that notices an input signal and remembers that it
happened until your controller gets around to looking for it.
After the controller sees the input signal, it resets the latch.
Some controllers have latches built in to their input pins.
Sometimes latches are built into peripheral chips to provide
Handshaking.
Bounce
It is an unfortunate fact that real-world things like switches do not produce a nice, clean trigger
pulse that a controller might like to trigger on.
In fact, many mechanical switches exhibit a behavior called "bounce",
where the switches opens and closes many times while it is making a transition.
In the real world, each time you make or break the connection,
the input signal can flap up and down dozens of times.
And don't try counting the bounces, because the number will be different each time.
Main:
TryAgain:
IF Trigger = IsOff THEN TryAgain ' wait until trigger is activated
PAUSE 1000 ' wait 1 second for bouncing to stop
' Do your activity here!
GOTO Main ' repeat forever
Main:
SawOff: ' we have seen trigger as off
SampleCount = 20 ' we want this many on triggers in a row
SampleAgain:
IF Trigger = IsOff THEN SawOff ' whenever trigger is off, we start again
SampleCount = SampleCount - 1 ' trigger is on - a good thing, count it
IF Trigger <> 0 THEN SampleAgain ' keep looking until we see enough
' Do your activity here!
GOTO Main ' repeat forever
Polling Versus Interrupts
Polling just means that your program takes a look at the input trigger,
notices that the trigger is true, and acts on it.
This is a common way to write controller programs because it requires no special hardware.
Latching Input
If an input signal is of short duration, and your controller is busy, you might miss the signal.