Writing The Prop-1 Program

Since we know what the program must do (Program Design) and know how it communicates with the outside world (Input/Output Design For A Prop-1 Program), it is now time to write the actual program.

Because we did so much work up front, this will be easy.

skip list of on-page links

Sequence Of Operations

Let's start with the
final sequence of operations that the prop should perform. Then add input/output information from What The Programmer Needs To Know.

The combined list looks like this:

  1. wait for the Trick-or-Treater
    • detect the kid's presence by looking at the input from a Passive Infrared (PIR) detector
    • to be sure that the kid is really there, make sure the "kid present" input lasts for a full second before acting on it
    • Pin 7 - Passive Infrared (PIR) detector
      • 1 = trick-or-treater is present
      • 0 = no trick-or-treater
  2. pop up the monster
    • it takes 1 second for the monster to get all the way up
    • Pin 0 - monster control
      • 1 = show monster
      • 0 = hide monster
  3. after the monster is all the way up, make it roar
    • roar is played by a digital sound chip
    • Pin 2 - monster sound control
      • normally send 0
      • to trigger monster sound, pulse 0->1->0
  4. every third appearance of the monster should be accompanied by a flash of lightning
    • Pin 1 - strobe control
      • normally send 0
      • to flash strobe, pulse 0->1->0
    • also trigger thunder on a digital sound chip
    • Pin 3 - thunder sound control
      • normally send 0
      • to trigger thunder sound, pulse 0->1->0
  5. show the monster for 5 seconds
  6. hide the monster again
    • Pin 0 - monster control
      • 1 = show monster
      • 0 = hide monster
  7. do not trigger again until the current kid leaves
    • detect the kid's presence by looking at the input from a Passive Infrared (PIR) detector
    • to be sure that the kid is really gone, make sure the "nobody there" input lasts for a full 5 seconds before acting on it
    • Pin 7 - Passive Infrared (PIR) detector
      • 1 = trick-or-treater is present
      • 0 = no trick-or-treater
  8. start again at the top

Believe it or not, that's almost the program, right there!

Programming

Let's write the program, a little piece at a time...

The Beginning

I like to start programs with some comments. These are notes to myself, inside the program, that will remind me what's going on when I come back to the program later.

Each comment line starts with a single apostrophe ('). After that, you can put anything.

' © Wolfstone, 2006
' =========================================================================
'
' File....... PopUpMonster.bs1
' Purpose.... Animate a pop-up monster - a learning exercise for PROP-1 programming
' Author..... Dennis Griesser
' E-mail..... wolfstone@pobox.com
'
' {$STAMP BS1}
' {$PBASIC 1.0}
'
' =========================================================================

' -----[ Program Description ]---------------------------------------------
'
' This is a PROP-1 program designed to animate a pop-up monster.
' It is a learning exercise for the Prop-1 controller.

' -----[ Revision History ]------------------------------------------------
'
' PopUpMonster_01.bs1 - 30 May 2006 - First version.
' PopUpMonster_02.bs1 - 1 June 2006 - New improved version.

None of that actually does anything. It just helps me understand which program this is, why I wrote it, and how I have changed it over time. I'll add more comments along the way.

Symbols And Constants

We could write this program using just plain numbers for the various gadgets we talk to. For example, we could look for kids (the PIR sensor) by seeing if PIN7 is 1. Such a program would work just fine. But it would be hard for us to understand later - when we have to come back and add something. It might even be hard to understand right now, when we are writing the program and trying to get it to work for the first time.

Luckily, you can assign a symbolic name to things, making then easier to understand. Let's give names to the pins for each gadget.

' -----[ I/O Definitions ]-------------------------------------------------
'
'       unused            PIN7     ' unused
SYMBOL  KidPresent      = PIN6     ' 1 = kid present; 0 = no kids
'       unused            PIN5     ' unused
'       unused            PIN4     ' unused
SYMBOL  ThunderCrash    = PIN3     ' to trigger thunder sound, pulse 0->1->0
SYMBOL  MonsterRoar     = PIN2     ' to trigger monster sound, pulse 0->1->0
SYMBOL  StrobeFlash     = PIN1     ' to flash strobe, pulse 0->1->0
SYMBOL  MonsterUp       = PIN0     ' 1 = show monster; 0 = hide monster
All of these definitions look similar. The first one, "SYMBOL KidPresent = PIN7", tells the Prop-1, "whenever you see the word KidPresent, look at input PIN7 and use whatever you see there".

See those apostrophes to the right of each SYMBOL line? More comments! They remind us how to use each gadget.

Notice that I have a line for every I/O pin on the controller, in numeric order, with unused pins being a whole-line comment. This gives me a complete checklist of what is used and what is not. Someday, if I need to add another output, I can just take a peek at this list and pick one that's not being used.

We will also define some other symbols that will make our code more readable:

' -----[ Constants ]-------------------------------------------------------
'
SYMBOL  No              = 0
SYMBOL  Yes             = 1
We will soon see how these help out.

Variables

During the execution of the program we will have to remember a few things: Here, we reserve space to hold these things:

' -----[ Variables ]-------------------------------------------------------
'
SYMBOL  KidWait         = W1
SYMBOL  MonsterCount    = W2
The Prop-1 has several storage locations where you can keep a number. They are numbered W1, W2, W3, etc. "SYMBOL MonsterCount = W2" tells the Prop-1, "Wherever the program uses the word MonsterCount, use the number stored in location W2."

THis will make the program a lot easier for us to read, because we can do things like "check the MonsterCount", which is more understandable than "check W2".

Initialization

"Initialization" is the beginning of the program where things are set up for later use. Normally, the program only executes the initialization part once - when you turn it on.

In order to prepare for input and output, you need to tell the Prop-1 which of the eight pins are used for input and which are for output. [This isn't always necessary, as the Prop-1 has certain "default" values that take effect until you decide to change them. But when I write a program, I dislike making assumptions, so I explicitly tell the Prop-1 what I want to do.] This is done by setting "DIRS" equal to some value.

Another thing that I like to do in the front of the program is to clear all output bits. You can set all the bits at once by assigning a value to PINS.

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

' Do this only once, when we first start up.
'
Reset:

  '       76543210        ' bit positions
  DIRS = %00111111        ' make P7-P6 inputs, P5-P0 outputs
  PINS = %00000000        ' all outputs off

  MonsterCount = 0        ' we never showed monster before
See that "DIRS = %00111111"? It is an "assignment" statement. It tells the Prop-1, "take the value on the right (%00111111) and stuff it into the storage location called DIRS."

We never described what DIRS and PINS are. These are special names, built in to the Prop-1 programming language. Assigning a value to DIRS indicates which of the I/O pins are used for input and which are used for output. Assigning a value to PINS sets the value of the output pins all at once.

The value that is assigned to DIRS and PINS starts with "%". This means that it is a binary value, with each digit being a "0" or "1", and corresponding to an I/O pin. When setting DIRS, "1" means the corresponding pin will be used for output and "0" means input.

The "bit positions" comment lines up with the "1"s and "0"s of DIRS and PINS, so we can see at a glance how each pin is used.

The Main Loop

Whenever programmers write a piece of program that is executed again and again, they call it a "loop".

This program has a main loop that it pretty big. It starts at the top of list of things to do and runs through the bottom where we say "start again".

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

' We start each cycle up here.
' We will come here after every show, to get ready for the next show.
Main:

' THE WHOLE "BODY" OF THE PROGRAM GOES HERE!
' LOTS OF STUFF!
' COMING SOON!

' Start again at the top
  GOTO Main
The "Main:" towards the top is a "label". It is a way to tell the Prop-1 about an important part of the program that we will refer to later.

At the bottom of the main loop it says "GOTO Main", which uses the label that we put up at the top.

When the Prop-1 "runs the program", it starts at the top, looks at each line and does that thing, and moves on to the next line.

In this case, the Prop-1 will run through the whole body of the program, hit "GOTO Main", and then go back to the "Main" label at the top.

It's like playing Monopoly: "Go directly to Jail. Do not pass GO. Do not collect $200."

Wait For A Kid

We're not supposed to start the show until we detect a kid. And not just notice one litle flicker from the detector. We have to be sure he's there.

' Wait for the Trick-or-Treater.
'
' To be sure that the kid is really there, make sure that we see
' the KidPresent several times in a row (ideally a full second)
' before actually starting.
SStartAgain:
  KidWait = 0
SLookAgain:
  IF KidPresent = No THEN SStartAgain  ' if no kid, start at the beginning
  KidWait = KidWait + 1
  IF KidWait < 20 THEN SLookAgain      ' keep looking until we see kid many times

The easy part is detecting the kid. "IF KidPresent..." does that. The rest of the lines make sure we see the kid several times before we start the show.

The line "KidWait = KidWait + 1" deserves special attention, because you would flunk math if you wrote "1 = 1 + 1". But remember that this isn't math. It is an assignment. We take the thing on the right of "=" and figure out what it means. That means we read the counter of how many times we saw a kid and add one to it. Then the result of that is placed in the location on the left of the "=". So "KidWait = KidWait + 1" just increases by one the value of KidWait.

Notice that there are two labels, SStartAgain and SLookAgain. Each time we see the kid and want to peek again, we will go to SLookAgain. If we peek and the kid is gone, we go to SStartAgain and clear the counter.

When we have seen somebody 20 times, we're happy. (The design wants us to see a kid for a whole second, but this just looks 20 times. I didn't bother measuring or calculating this, and the number of times should probably be much higher. I just threw in 20 so you could get the idea.)

Pop Up The Monster

Now it's time for the show!

' Begin the show!

' Pop up the monster
  MonsterUp = Yes

' It takes 1 second for the monster to get all the way up.
  PAUSE  1000                          ' wait 1.0 second for monster to get up

' After the monster is all the way up, make it roar
  PULSOUT MonsterRoar, 1               ' 10 µs pulse; make monster roar

Occasional Lightning

We need to simulate lightning every third time the monster pops up.

' Every third appearance of the monster should be accompanied by a flash of
' lightning.
  MonsterCount = MonsterCount + 1       ' count this appearance
  IF MonsterCount <> 3 THEN SkipFlash
  MonsterCount = 0                      ' reset the counter
  PULSOUT StrobeFlash, 1                ' 10 µs pulse; make lightning flash
  PULSOUT ThunderCrash, 1               ' 10 µs pulse; make thunder crash
SkipFlash:

Hide

Now we need to keep the monster visible for 5 seconds, and then hide him.

' Display the monster for 5 seconds
  PAUSE  5000                          ' wait 5.0 seconds

' Hide the monster again
  MonsterUp = No

' It takes 1 second for the monster to hide all the way.
  PAUSE  1000                          ' wait 1.0 second for monster to hide

Clear The Room

The show is over. But before we loop around and start again, we have to make sure all the kids are gone.

' Do not trigger again until the current kid leaves.
'
' To be sure that the kid is really gone, make sure that we see
' no KidPresent several times in a row (ideally a full 5 seconds)
' before actually starting.
FStartAgain:
  KidWait = 0
FLookAgain:
  IF KidPresent = Yes THEN FStartAgain  ' if there is kid, start at the beginning
  KidWait = KidWait + 1
  IF KidWait < 100 THEN FLookAgain      ' keep looking until we see no kid many times

This code should look mighty familiar. It works just like Wait For A Kid, except this test is waiting until everybody is gone.

The Complete Program

Here are all the pieces of the program put together and ready to run:

' © Wolfstone, 2006
' =========================================================================
'
' File....... PopUpMonster.bs1
' Purpose.... Animate a pop-up monster - a learning exercise for PROP-1 programming
' Author..... Dennis Griesser
' E-mail..... wolfstone@pobox.com
'
' {$STAMP BS1}
' {$PBASIC 1.0}
'
' =========================================================================

' -----[ Program Description ]---------------------------------------------
'
' This is a PROP-1 program designed to animate a pop-up monster.
' It is a learning exercise for the Prop-1 controller.

' -----[ Revision History ]------------------------------------------------
'
' PopUpMonster_01.bs1 - 30 May 2006 - First version.
' PopUpMonster_02.bs1 - 1 June 2006 - New improved version.

' -----[ I/O Definitions ]-------------------------------------------------
'
'       unused            PIN7     ' unused
SYMBOL  KidPresent      = PIN6     ' 1 = kid present; 0 = no kids
'       unused            PIN5     ' unused
'       unused            PIN4     ' unused
SYMBOL  ThunderCrash    = PIN3     ' to trigger thunder sound, pulse 0->1->0
SYMBOL  MonsterRoar     = PIN2     ' to trigger monster sound, pulse 0->1->0
SYMBOL  StrobeFlash     = PIN1     ' to flash strobe, pulse 0->1->0
SYMBOL  MonsterUp       = PIN0     ' 1 = show monster; 0 = hide monster

' -----[ Constants ]-------------------------------------------------------
'
SYMBOL  No              = 0
SYMBOL  Yes             = 1

' -----[ Variables ]-------------------------------------------------------
'
SYMBOL  KidWait         = W1
SYMBOL  MonsterCount    = W2

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

' Do this only once, when we first start up.
'
Reset:

  '       76543210        ' bit positions
  DIRS = %00111111        ' make P7-P6 inputs, P5-P0 outputs
  PINS = %00000000        ' all outputs off

  MonsterCount = 0        ' we never showed monster before

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

' We start each cycle up here.
' We will come here after every show, to get ready for the next show.
Main:

' Wait for the Trick-or-Treater.
'
' To be sure that the kid is really there, make sure that we see
' the KidPresent several times in a row (ideally a full second)
' before actually starting.
SStartAgain:
  KidWait = 0
SLookAgain:
  IF KidPresent = No THEN SStartAgain  ' if no kid, start at the beginning
  KidWait = KidWait + 1
  IF KidWait < 20 THEN SLookAgain      ' keep looking until we see kid many times

' Begin the show!

' Pop up the monster
  MonsterUp = Yes

' It takes 1 second for the monster to get all the way up.
  PAUSE  1000                          ' wait 1.0 second for monster to get up

' After the monster is all the way up, make it roar
  PULSOUT MonsterRoar, 1               ' 10 µs pulse; make monster roar

' Every third appearance of the monster should be accompanied by a flash of
' lightning.
  MonsterCount = MonsterCount + 1       ' count this appearance
  IF MonsterCount <> 3 THEN SkipFlash
  MonsterCount = 0                      ' reset the counter
  PULSOUT StrobeFlash, 1                ' 10 µs pulse; make lightning flash
  PULSOUT ThunderCrash, 1               ' 10 µs pulse; make thunder crash
SkipFlash:

' Display the monster for 5 seconds
  PAUSE  5000                          ' wait 5.0 seconds

' Hide the monster again
  MonsterUp = No

' It takes 1 second for the monster to hide all the way.
  PAUSE  1000                          ' wait 1.0 second for monster to hide

' Do not trigger again until the current kid leaves.
'
' To be sure that the kid is really gone, make sure that we see
' no KidPresent several times in a row (ideally a full 5 seconds)
' before actually starting.
FStartAgain:
  KidWait = 0
FLookAgain:
  IF KidPresent = Yes THEN FStartAgain  ' if there is kid, start at the beginning
  KidWait = KidWait + 1
  IF KidWait < 100 THEN FLookAgain      ' keep looking until we see no kid many times

' Start again at the top
  GOTO Main

Related Pages

Skip this list.
Our series on programming controllers:
privacy policy | write to us | tip us
©Copyright 2006 by The Wolfstone Group. All rights reserved.
You must read and abide by our terms of service.