BASIC Stamp® PBASIC&tm; Online Help

BASIC Stamp® PBASIC Online Help

533 Menlo Drive, Suite 100
Rocklin, CA 95765

916-624-8333
916-624-8003 (FAX)

Sales: 888-512-1024 (US only)
Support: 888-99-STAMP (US only)

www.parallax.com 		Copyright © 2000-2005 Parallax, Inc.
All Rights Reserved

Issued: 16 JUN 2005


 Copyrights and Trademarks

Copyright © 2000-2005 by Parallax, Inc. All rights reserved.

  • PBASIC is a trademark and BASIC Stamp is a registered trademark of Parallax, Inc.
  • PIC is a registered trademark of Microchip Technology, Inc.
  • Windows is a registered trademark of Microsoft Corporation.
  • I2C is a registered trademark of Philips Corporation.
  • 1-Wire is a registered trademark of Maxim/Dallas Semiconductor.

    • Other brand and product names are trademarks or registered trademarks of their respective holders.


 Disclaimer of Liability

Parallax, Inc. is not responsible for special, incidental, or consequential damages resulting from any breach of warranty, or under any legal theory, including lost profits, downtime, goodwill, damage to or replacement of equipment or property, and any costs of recovering, reprogramming, or reproducing any data stored in or used with Parallax products.

This command reference is valid with the following BASIC Stamp firmware versions:

Version 1.4
Version 1.0
Version 1.1
Version 1.1
Version 1.4
Version 1.1
Version 1.0


 Internet Access

We maintain Internet systems for your convenience. These may be used to obtain software, communicate with members of Parallax and communicate with other customers. Access information is shown below:

Home Page: | http://www.parallax.com
Web Forums: | http://forums.parallax.com
General E-Mail: | info@parallax.com
Technical E-Mail: | support@parallax.com


Internet Discussion List

 BASIC Stamp Support Forums

Parallax maintains several BASIC Stamp related discussion forums for people interested in BASIC Stamps, SX micros, and their applications. Many people subscribe to the forums, and all questions and answers to them are available to all subscribers. It's a fun, fast, and free way to discuss BASIC Stamp and their uses. To subscribe to the Parallax forums visit the Tech Support section of the Parallax web site.

Direct Link:

  • http://forums.parallax.com/forums/


 PBASIC Command Reference

2 | Note: For BS1/BS2-compatible commands, syntax shown below is in BS2 format. Some commands may use slightly different formatting with the BS1.
2.5 | Note: Requires {$PBASIC 2.5} directive.
† | Note: Compound, multi-line command; syntax not shown.

• AUXIO | AUXIO
• BRANCH 2 | BRANCH Offset, [Address1, Address2, ...AddressN]
• BUTTON | BUTTON Pin, DownState, Delay, Rate, Workspace, TargetState, Address
• COMPARE | COMPARE Mode, Result
• CONFIGPIN | CONFIGPIN Mode, PinMask
• COUNT | COUNT Pin, Duration, Variable
• DATA | {Symbol } DATA DataItem {, DataItem, ...}
• DEBUG | DEBUG OutputData {, OutputData }
• DEBUGIN 2.5 | DEBUGIN InputData
• DO...LOOP 2.5 | DO {WHILE | UNTIL Condition(s) } ... LOOP {UNTIL | WHILE Condition(s) }
• DTMFOUT | DTMFOUT Pin, {OnTime, OffTime, } [Tone {, Tone, ...}]
• EEPROM | EEPROM {Location,} (DataItem {, DataItem, ...})
• END | END
• EXIT 2.5 | EXIT
• FOR...NEXT | FOR Counter = StartValue TO EndValue {STEP StepValue} ... NEXT
• FREQOUT | FREQOUT Pin, Duration, Freq1 {, Freq2 }
• GET | GET Location, {Word 2.5} Variable {, ...} 2.5
• GOSUB | GOSUB Address
• GOTO | GOTO Address
• HIGH | HIGH Pin
• I2CIN | I2CIN Pin, SlaveID, {Address{\LowAddress },} [InputData]
• I2COUT | I2COUT Pin, SlaveID, {Address{\LowAddress},} [OutputData]
• IF...THEN | IF Condition THEN Address
• IF...THEN...ELSE 2.5, † |
• INPUT | INPUT Pin
• IOTERM | IOTERM Port
• LCDCMD | LCDCMD Pin, Command
• LCDIN | LCDIN Pin, Command, [InputData]
• LCDOUT | LCDOUT Pin, Command, [OutputData]
• LOOKDOWN 2 | LOOKDOWN Target, {ComparisonOp } [Value0, Value1, ...ValueN], Variable
• LOOKUP 2 | LOOKUP Index, [Value0, Value1, ...ValueN], Variable
• LOW | LOW Pin
• MAINIO | MAINIO
• NAP | NAP Duration
• ON...GOSUB 2.5 | ON Offset GOSUB Address1, Address2, ...AddressN
• ON...GOTO 2.5 | ON Offset GOTO Address1, Address2, ...AddressN
• OUTPUT | OUTPUT Pin
• OWIN | OWIN Pin, Mode, [InputData]
• OWOUT | OWOUT Pin, Mode, [OutputData]
• PAUSE | PAUSE Duration
• POLLIN | POLLIN Pin, State
• POLLMODE | POLLMODE Mode
• POLLOUT | POLLOUT Pin, State
• POLLRUN | POLLRUN ProgramSlot
• POLLWAIT | POLLWAIT Duration
• POT | POT Pin, Scale, Variable
• PULSIN | PULSIN Pin, State, Variable
• PULSOUT | PULSOUT Pin, Duration
• PUT | PUT Location, {Word 2.5} Variable {, ...} 2.5
• PWM | PWM Pin, Duty, Duration
• RANDOM | RANDOM Variable
• RCTIME | RCTIME Pin, State, Variable
• READ | READ Location, {Word 2.5} Variable {, ...} 2.5
• RETURN | RETURN
• REVERSE | REVERSE Pin
• RUN | RUN ProgramSlot
• SELECT...CASE 2.5, † |
• SERIN 2 | SERIN Rpin {\Fpin}, Baudmode, {Plabel,} {Timeout, Tlabel, } [InputData]
• SEROUT 2 | SEROUT Tpin {\Fpin}, Baudmode, {Pace,} {Timeout, Tlabel,} [OutputData]
• SHIFTIN | SHIFTIN Dpin, Cpin, Mode, [Variable{\Bits} {, Variable{\Bits}...}]
• SHIFTOUT | SHIFTOUT Dpin, Cpin, Mode, [OutputData{\Bits} {, OutputData{\Bits}...}]
• SLEEP | SLEEP Duration
• SOUND | SOUND Pin, (Note, Duration {, Note, Duration...})
• STOP | STOP
• STORE | STORE ProgramSlot
• TOGGLE | TOGGLE Pin
• WRITE | WRITE Location, {Word 2.5} Variable {, ...} 2.5
• XOUT | XOUT Mpin, Zpin, [House\Command {\Cycles} {, House\Command {\Cycles}...}]


 Memory Organization and Variables

The BASIC Stamp has two kinds of memory; RAM (for variables used by your program) and EEPROM (for storing the program itself). EEPROM may also be used to store long-term data in much the same way that desktop computers use a hard drive to hold both programs and files.

An important distinction between RAM and EEPROM is this:

  • RAM loses its contents when the BASIC Stamp loses power; when power returns, all RAM locations are cleared to 0s.
  • EEPROM retains the contents of memory, with or without power, until it is overwritten (such as during the program-downloading process or with a WRITE instruction.)

BASIC Stamp 1 RAM Organization

The BS1 has 16 bytes (8 words) of RAM space arranged as shown in the table below. The first word, called PORT, is used for I/O pin control. It consists of two bytes, PINS and DIRS. The bits within PINS correspond to each of the eight I/O pins on the BS1. Reading PINS effectively reads the I/O pins directly, returning an 8-bit set of 1's and 0's corresponding to the high and low state of the respective I/O pin at that moment. Writing to PINS will store a high or low value on the respective I/O pins (though only on pins that are set to outputs).

Word Name | Byte Names | Bit Name | Special Notes
PORT | PINS DIRS | PIN0 - PIN7 DIR0 - DIR7 | I/O pins; bit addressable I/O pins directions; bit addressable
W0 | B0 B1 | BIT0 - BIT7 BIT8 - BIT15 | Bit addressable Bit addressable
W1 | B2 B3 |  |
W2 | B4 B5 |  |
W3 | B6 B7 |  |
W4 | B8 B9 |  |
W5 | B10 B11 |  |
W6 | B12 B13 |  | Used by GOSUB instruction Used by GOSUB instruction

The second byte of PORT, DIRS, controls the direction of the I/O pins. Each bit within DIRS corresponds to an I/O pin's direction. A high bit (1) sets the corresponding I/O pin to an output direction and a low bit (0) sets the corresponding I/O pin to an input direction.

The remaining words (W0 – W6) are available for general-purpose use. Each word consists of separately addressable bytes and the first two bytes (B0 and B1) are bit addressable as well. You may assign other names (symbols) to these RAM registers as shown in section "Defining and Using Variables", below.

When the BS1 is powered up, or reset, all memory locations are cleared to 0, so all pins are inputs (DIRS = %00000000). Also, if the PBASIC program sets all the I/O pins to outputs (DIRS = %11111111), then they will initially output low, since the output latch (PINS) is cleared to all zeros upon power-up or reset, as well.

BASIC Stamp 2 Series RAM Organization

The BS2, BS2e, BS2sx and BS2p have 32 bytes of Variable RAM space arranged as shown in the table below. Of these, the first six bytes are reserved for input, output, and direction control of the I/O pins. The remaining 26 bytes are available for general-purpose use as variables.

Note: There are 16 words, consisting of two bytes each for a total of 32 bytes. All bits are individually addressable through modifiers and the bits within the upper three words are also individually addressable though the pre-defined names shown.

Word Name | Byte Names | Nibble Names | Bit Name | Special Notes
INS | INL INH | INA, INB INC, IND | IN0 - IN7 IN8 - IN15 | Input pins
OUTS | OUTL OUTH | OUTA, OUTB OUTC, OUTD | OUT0 - OUT7 OUT8 - OUT15 | Output pins
DIRS | DIRL DIRH | DIRA, DIRB DIRC, DIRD | DIR0 - DIR7 DIR8 - DIR15 | I/O pin direction control
W0 | B0 B1 |  |  |
W1 | B2 B3 |  |  |
W2 | B4 B5 |  |  |
W3 | B6 B7 |  |  |
W4 | B8 B9 |  |  |
W5 | B10 B11 |  |  |
W6 | B12 B13 |  |  |
W7 | B14 B15 |  |  |
W8 | B16 B17 |  |  |
W9 | B18 B19 |  |  |
W10 | B20 B21 |  |  |
W11 | B22 B23 |  |  |
W12 | B24 B25 |  |  |

The INS variable always shows the state of the I/O pins themselves, regardless of the direction of each I/O pin. We call this, "reading the pins." If a pin was set to an input mode (within DIRS) and an external circuit connected the I/O pin to ground, the corresponding bit of INS would be zero. If a pin was set to be an output and the pin's state was set to a high level (within OUTS), the corresponding bit of INS would be high. If, however, that same pin was externally connected directly to ground, the corresponding bit of INS would be low; since we're reading the state of the pin itself and the BASIC Stamp cannot override a pin that is driven to ground or 5 volts externally. Note: The final example is an error; it will cause a direct short and can cause damage to the BASIC Stamp! Do not intentionally connect output pins directly to Vss (Ground) or Vdd (positive supply) or you risk destroying your BASIC Stamp module.

To summarize: DIRS determines whether a pin's state is set by external circuitry (input, 0) or by the state of OUTS (output, 1). INS always matches the actual states of the I/O pins, whether they are inputs or outputs. OUTS holds bits that will only appear on pins whose DIRS bits are set to output.

In programming the BASIC Stamp, it's often more convenient to deal with individual bytes, nibbles or bits of INS, OUTS and DIRS rather than the entire 16-bit words. PBASIC has built-in names for these elements, shown in table above.

Here's an example of what is described in the table above. The INS register is 16-bits (corresponding to I/O pins 0 though 15). The INS register consists of two bytes, called INL (the Low byte) and INH (the High byte). INL corresponds to I/O pins 0 through 7 and INH corresponds to I/O pins 8 though 15. INS can also be though of as containing four nibbles, INA, INB, INC and IND. INA is I/O pins 0 though 3, INB is I/O pins 4 though 7, etc. In addition, each of the bits of INS can be accessed directly using the names IN0, IN1, IN2... IN15.

The same naming scheme holds true for the OUTS and DIRS variables as well.

As the table shows, the BASIC Stamp's memory is organized into 16 words of 16 bits each. The first three words are used for I/O. The remaining 13 words are available for use as general-purpose variables.

Just like the I/O variables, the general-purpose variables have predefined names: W0 through W12 and B0 through B25. B0 is the low byte of W0; B1 is the high byte of W0; and so on through W12 (B24=low byte, B25=high byte). Unlike I/O variables, there's no reason that your program variables have to be stuck in a specific position in the BASIC Stamp's physical memory. A byte is a byte regardless of its location. And if a program uses a mixture of variables of different sizes, it can be a pain in the neck to logically dole them out or allocate storage.

More importantly, mixing fixed variables with automatically allocated variables (discussed in the next section) is an invitation to bugs. A fixed variable can overlap an allocated variable, causing data meant for one variable to show up in another! The fixed variable names (of the general-purpose variables) are only provided for power users who require absolute access to a specific location in RAM.

We recommend that you avoid using the fixed variables in most situations. Instead, let PBASIC allocate variables as described in the next section. The editor software will organize your storage requirements to make optimal use of the available memory.

Defining and Using Variables

Before you can use a variable in a PBASIC program you must declare it. "Declare" means letting the BASIC Stamp know that you plan to use a variable, what you want to call it, and how big it is. Although PBASIC does have predefined variables that you can use without declaring them first (see previous sections), the preferred way to set up variables is to use the directive SYMBOL (for the BS1) or VAR (for all other BASIC Stamps). Here is the syntax for a variable declaration:

SYMBOL  name    = RegisterName

name    VAR     VarType

where name is the name by which you will refer to the variable, RegisterName is the "fixed" name for the register and VarType indicates the type (Bit, Nib, Byte, or Word) of storage for the variable. NOTE: The top example is for the BS1 and the bottom example is for BS2-series Stamps.

The Rules of Symbol Names

There are certain rules regarding symbol names. Symbols must start with a letter, can contain a mixture of letters, numbers, and underscore (_) characters, and must not be the same as PBASIC keywords or labels used in your program. Additionally, symbols can be up to 32 characters long. See the Command Reference for a list of PBASIC keywords. PBASIC does not distinguish between upper and lower case, so the names MYVARIABLE, myVariable, and MyVaRiAbLe are all equivalent.

Refer to "The Elements of PBASIC Style" for suggested guidelines on naming variables.

For the BS1, the RegisterName is one of the predefined "fixed" variable names, such as W0, W1, B0, B1, etc. Here are a few examples of variable declarations on the BS1:

SYMBOL  temp    = W0                    ' value can be 0 to 65535
SYMBOL  cntr    = B1                    ' value can be 0 to 255
SYMBOL  result  = B2                    ' value can be 0 to 255

The above example will create a variable called temp whose contents will be stored in the RAM location called W0. Also, the variable cntr will be located at RAM location B1 and result at location B2. Note that temp is a word-sized variable (because that's what size W0 is) while the other two are both byte-sized variables. Throughout the rest of the program, we can use the names temp, cntr, and result instead of W0, B1 and B2, respectively. This makes the code much more readable; it's easier to determine what cntr is used for than it would be to figure out what the name B1 means. Please note, that cntr resides at location B1, and B1 happens to be the high byte of W0. This means than changing cntr will also change temp since they overlap. A situation like this usually is a mistake and results in strange behavior, but is also a powerful feature if used carefully.

For the BS2-family, the Size argument has four choices: 1) Bit (1 bit), 2) Nib (nibble; 4 bits), 3) Byte (8 bits), and 4) Word (16 bits). Here are some examples of variable declarations on the BS2-family:

mouse   VAR     Bit                     ' Value can be 0 or 1
cat     VAR     Nib                     ' Value can be 0 to 15
dog     VAR     Byte                    ' Value can be 0 to 255
rhino   VAR     Word                    ' Value can be 0 to 65535

The example above will create a bit-sized variable called mouse, and nibble-sized variable called cat, a byte-size variable called dog and a word-sized variable called rhino. Unlike in the BS1, these variable declarations don't point to a specific location in RAM. Instead, we only specified the desired size for each variable; the BASIC Stamp will arrange them in RAM as it sees fit. Throughout the rest of the program, we can use the names mouse, cat, dog and rhino to set or retrieve the contents of these variables.

A variable should be given the smallest size that will hold the largest value that will ever be stored in it. If you need a variable to hold the on/off status (1 or 0) of switch, use a bit. If you need a counter for a FOR...NEXT loop that will count from 1 to 100, use a byte. And so on.

If you assign a value to a variable that exceeds its size, the excess bits will be lost. For example, suppose you use the nibble variable cat, from the example above, and write cat = 260 (%100000100 binary). What will cat contain? It will hold only the lowest 4 bits of 260: %0100 (4 decimal).

On the BS2-family, you can also define multipart variables called arrays. An array is a group of variables of the same size, and sharing a single name, but broken up into numbered cells, called elements. You can define an array using the following syntax:

name    VAR     Size(n)

where name and Size are the same as described earlier. The new argument, (n), tells PBASIC how many elements you want the array to have. For example:

myList  VAR     Byte(10)                ' Create a 10-byte array

Once an array is defined, you can access its elements by number. Numbering starts at 0 and ends at n–1. For example:

  myList(3) = 57
  DEBUG ? myList(3)

This code will display "myList(3) = 57" on the PC screen. The real power of arrays is that the index value can be a variable itself. For example:

myBytes VAR     Byte(10)                ' Define 10-byte array
index   VAR     Nib                     ' Define normal nibble variable

Main:
  FOR index = 0 TO 9                    ' Repeat with index= 0, 1, 2...9
    myBytes(index) = index * 13         ' Write index*13 to each cell of array
  NEXT

  FOR index = 0 TO 9                    ' Repeat with index= 0, 1, 2...9
    DEBUG ? myBytes(index)              ' Show contents of each cell
  NEXT
  STOP

If you run this program, DEBUG will display each of the 10 values stored in the elements of the array: myBytes(0) = 0 * 13 = 0, myBytes(0) = 1 * 13 = 13, myBytes(2) = 2 * 13 = 26 ... myBytes(9) = 9 * 13 = 117.

A word of caution about arrays: If you're familiar with other BASICs and have used their arrays, you have probably run into the "subscript out of range" error. Subscript is another term for the index value. It is out-of-range when it exceeds the maximum value for the size of the array. For instance, in the example above, myBytes is a 10-cell array. Allowable index numbers are 0 through 9. If your program exceeds this range, PBASIC will not respond with an error message. Instead, it will access the next RAM location past the end of the array. If you are not careful about this, it can cause all sorts of bugs.

If accessing an out-of-range location is bad, why does PBASIC allow it? Unlike a desktop computer, the BASIC Stamp doesn't always have a display device connected to it for displaying error messages. So it just continues the best way it knows how. It's up to the programmer (you!) to prevent bugs.

Another unique property of PBASIC arrays is this: You can refer to the 0th (first) cell of the array by using just the array's name without an index value. For example:

myBytes VAR     Byte(10)                ' Define 10-byte array

Main:
  myBytes(0) = 17                       ' Store 17 to 0th (first) cell
  DEBUG ? myBytes(0)                    ' Display contents of 0th cell
  DEBUG ? myBytes                       ' Also displays contents of 0th cell

This feature is how the "string" capabilities of the DEBUG and SEROUT command expect to work, that is, referencing the variable name only and not a specific element. A string is simply a byte array used to store text. See the "Displaying Strings (Byte Arrays)" section in the DEBUG command description for more information.

An alias is an alternative name for an existing variable. For example:

SYMBOL  cat     = B0                    ' Create a byte-sized variable
SYMBOL  tabby   = cat                   ' Create alias for cat

cat     VAR     Byte                    ' Create a byte-sized variable
tabby   VAR     cat                     ' Create alias for cat

In this example, tabby is an alias to the variable cat. Anything stored in cat shows up in tabby and vice versa. Both names refer to the same physical piece of RAM. This kind of alias can be useful when you want to reuse a temporary variable in different places in your program, but also want the variable's name to reflect its function in each place. Use caution, because it is easy to forget about the aliases; during debugging, you might end up asking 'How did that value get here?!' The answer is that it was stored in the variable's alias.

On the BS2-family an alias can also serve as a window into a portion of another variable. This is done using "modifiers." Here the alias is assigned with a modifier that specifies what part:

rhino   VAR     Word                    ' A 16-bit variable
head    VAR     rhino.HIGHBYTE          ' Highest 8 bits of rhino
tail    VAR     rhino.LOWBYTE           ' Lowest 8 bits of rhino

Given that example, if you write the value %1011000011111101 to rhino, then head would contain %10110000 and tail would contain %11111101.

The table below lists all the variable modifiers. PBASIC2 lets you apply these modifiers to any variable name and to combine them in any fashion that makes sense. For example, it will allow:

rhino   VAR     Word                            ' A 16-bit variable
eye     VAR     rhino.HIGHBYTE.LOWNIB.BIT1      ' A bit

Symbol | Definitions
LOWBYTE | Low byte of a word
HIGHBYTE | High byte of a word
BYTE0 | Low byte of a word
BYTE1 | High byte of a word
LOWNIB | Low nibble of a word or byte
HIGHNIB | High nibble of a word or byte
NIB0 | Nibble 0 of a word or byte
NIB1 | Nibble 1 of a word or byte
NIB2 | Nibble 2 of a word
NIB3 | Nibble 3 of a word
LOWBIT | Low bit (LSB) of a word, byte, or nibble
HIGHBIT | High bit (MSB) of a word, byte, or nibble
BIT0 | Bit 0 (LSB) of a word, byte, or nibble
BIT1 | Bit 1 of a word, byte, or nibble
BIT2 | Bit 2 of a word, byte, or nibble
BIT3 | Bit 3 of a word, byte, or nibble
BIT4 ... BIT7 | Bits 4 through 7 of a word or byte
BIT8 ... BIT15 | Bits 8 through 15 of a word

The commonsense rule for combining modifiers is that they must get progressively smaller from left to right. It would make no sense to specify, for instance, the low byte of a nibble, because a nibble is smaller than a byte! And just because you can stack up modifiers doesn't mean that you should unless it is the clearest way to express the location of the part you want get at. The example above might be improved:

rhino   VAR     Word                    ' A 16-bit variable
eye     VAR     rhino.BIT9              ' A bit

Although we've only discussed variable modifiers in terms of creating alias variables, you can also use them within program instructions:

rhino   VAR Word                        ' A 16-bit variable
head    VAR rhino.HIGHBYTE              ' Highest 8 bits of rhino

Main:
  rhino = 13567
  DEBUG ? head                          ' Show the value of alias variable head
  DEBUG ? rhino.HIGHBYTE                ' rhino.HIGHBYTE works too
  STOP

Modifiers also work with arrays. For example:

myBytes VAR     Byte(10)                ' Define 10-byte array

Main:
  myBytes(0) = $AB                      ' Hex $AB into 0th byte
  DEBUG HEX ? myBytes.LOWNIB(0)         ' Show low nib ($B)
  DEBUG HEX ? myBytes.LOWNIB(1)         ' Show high nib ($A)

If you looked closely at that example, you probably thought it was a misprint. Shouldn't myBytes.LowNib(1) give you the low nibble of byte 1 of the array rather than the high nibble of byte 0? Well, it doesn't. The modifier changes the meaning of the index value to match its own size. In the example above, when myBytes() is addressed as a byte array, it has 10 byte-sized cells numbered 0 through 9. When it is addressed as a nibble array, using myBytes.LowNib(), it has 20 nibble-sized cells numbered 0 through 19. You could also address it as individual bits using myBytes.LowBit(), in which case it would have 80 bit-sized cells numbered 0 through 79.

What if you use something other than a “low” modifier, say myBytes.HighNib()? That will work, but its effect will be to start the nibble array with the high nibble of myBytes(0). The nibbles you address with this nib array will all be contiguous, one right after the other, as in the previous example.

myBytes VAR Byte(10)                    ' Define 10-byte array

Main:
  myBytes(0) = $AB                      ' Hex $AB into 0th byte
  myBytes(1) = $CD                      ' Hex $CD into next byte
  DEBUG HEX ? myBytes.HIGHNIB(0)        ' Show high nib of cell 0 ($A)
  DEBUG HEX ? myBytes.HIGHNIB(1)        ' Show next nib ($D)

This property of modified arrays makes the names a little confusing. If you prefer, you can use the less-descriptive versions of the modifier names; Bit0 instead of LowBit, Nib0 instead of LowNib, and Byte0 instead of LowByte. These have exactly the same effect, but may be less likely to be misconstrued.

You may also use modifiers with the 0th cell of an array by referring to just the array name without the index value in parentheses. It's fair game for aliases and modifiers, both in VAR directives and in instructions.

Scratchpad RAM

The BS2e, BS2sx, BS2p, BS2pe, and BS2px have some additional RAM called Scratchpad RAM. The BS2e and BS2sx have are 64 bytes of Scratchpad RAM (0 – 63), and the BS2p, BS2pe, and BS2px have 128 bytes of Scratchpad RAM (0 – 127). Scratchpad RAM can only be accessed with the GET and PUT commands (see the GET and PUT command descriptions for more information) and cannot have variable names assigned to it.

The highest location in Scratchpad RAM (location 63 on the BS2e and BS2sx, location 127 on the BS2p, BS2pe, and BS2px) is read-only, and always contains the number of the currently running program slot. This can be handy for programs that need to know which program slot they exist in.


 Constants

Suppose you’re working on a program called "Three Cheers" that flashes LEDs, makes hooting sounds, and activates a motor that crashes cymbals together, all in sets of three. A portion of your PBASIC program might contain something like:

  FOR counter = 1 TO 3
    GOSUB Make_Cheers
  NEXT

  FOR counter = 1 TO 3
    GOSUB Blink_LEDs
  NEXT

  FOR counter = 1 TO 3
    GOSUB Crash_Cymbals
  NEXT

The numbers 1 and 3 in the code above are called constants. They are constants because, while the program is running, nothing can happen to change those numbers. This distinguishes constants from variables, which can change while the program is running.

PBASIC allows you to use several numbering systems. By default, it assumes that numbers are in decimal (base 10), our everyday system of numbers. But you can also use binary and hexadecimal (hex) numbers by identifying them with prefixes. And PBASIC will automatically convert quoted text into the corresponding ASCII code(s). For example:

99 | decimal
%1010 | binary
$FE | hex
"A" | ASCII code for A (65)

You can assign names to constants in a similar fashion to how variables are declared. On a BS1, it is identical to variable declarations and on the other BASIC Stamps you use the CON directive. Here is the syntax:

SYMBOL  Name    = ConstantValue

Name    CON     ConstantValue

Once created, named constants may be used in place of the numbers they represent. For example:

SYMBOL  Cheers  = 3

SYMBOL  idx     = B2

Main:
  FOR idx = 1 TO Cheers
    GOSUB Make_Cheers
  NEXT

Cheers  CON     3

idx     VAR     Nib

Main:
  FOR idx = 1 TO Cheers
    GOSUB Make_Cheers
  NEXT

That code would work exactly the same as the previous FOR...NEXT loops. The editor software would substitute the number 3 for the constant named Cheers throughout your program. Like variable names, labels and instructions, constant names are not case sensitive; CHEERS, and ChEErs would all be processed as identical to Cheers.

Refer to "The Elements of PBASIC Style" for suggested guidelines on naming constant values.

Using named constants does not increase the amount of code downloaded to the BASIC Stamp, and it often improves the clarity of the program. Weeks after a program is written, you may not remember what a particular number was supposed to represent—using a name may jog your memory (or simplify the detective work needed to figure it out).

Named constants also have another benefit. Suppose the "Three Cheers" program had to be upgraded to "Five Cheers." In the original example you would have to change all of the 3s to 5s. Search and replace would help, but you might accidentally change some 3s that weren't numbers of cheers, too. However, if you made smart use of a named constant, all you would have to do is change 3 to 5 in one place, the constant's declaration:

SYMBOL  Cheers  = 5

Cheers  CON     5

Now, assuming that you used the constant cheers wherever your program needed 'the number of cheers,' your upgrade would be done.

On the BS2-family you can take this idea a step further by defining constants with expressions; groups of math and/or logic operations that the editor software solves (evaluates) at compile time (the time right after you start the download and before the BASIC Stamp starts running your program). For example, suppose the "Cheers" program also controls a pump to fill glasses with champagne. Perhaps the number of glasses to fill is always twice the number of cheers, minus 1 (another constant):

Cheers  CON     5                       ' # of cheers
Glasses CON     Cheers * 2 - 1          ' # of glasses

As you can see, one constant can be defined in terms of another. That is, the number glasses depends on the number cheers.


 Pins

{$PBASIC 2.5}

With the introduction of PBASIC 2.5 syntax comes the PIN declaration. The purpose of the PIN declaration is to give an alias to an IO Pin and let the compiler determine whether a given line of code requires a numeric value for the pin, the output bit for that pin, or the input bit for that pin. Using the PIN declaration simplifies IO pin aliasing in sophisticated programs.

Using the PIN declaration is similar to CON:

' {$PBASIC 2.5}

RedLED  PIN     0                               ' red LED is connected to pin 0

IsOn    CON     1                               ' LED is active high
IsOff   CON     0

Setup:
  OUTPUT RedLED                                 ' same as OUTPUT 0

Main:
  DO
    RedLED = IsOn                               ' same as Out0 = 1
    PAUSE 1000
    RedLED = IsOff                              ' same as Out0 = 0
    PAUSE 1000
  LOOP

Most programs will work like the example above where a given IO pin will either be an input or an output. There are times, however, when a change in function is required mid program. Prior to PBASIC 2.5, programmers wishing to use named constants were forced to create redundant definitions or complicated modifiers. For example:

' {$PBASIC 2.0}

SDA     CON     8                               ' I2C data I/O
SCL     CON     9                               ' I2C clock output

...

I2C_Start:
  INPUT SDA
  INPUT SCL
  LOW SDA

Clock_Hold:                                     ' monitor device clock hold
  IF (INS.LOWBIT(SCL) = 0) THEN Clock_Hold      ' <-- tricky modifiers
  RETURN

With PBASIC 2.5 the tricky modifiers can be eliminated:

' {$PBASIC 2.5}

SDA     PIN     8                               ' I2C data I/O
SCL     PIN     9                               ' I2C clock output

...

I2C_Start:
  INPUT SDA
  INPUT SCL
  LOW SDA

Clock_Hold:                                     ' monitor device clock hold
  DO : LOOP WHILE (SCL = 0)                     ' easier, same as "IN9 = 0"
  RETURN

The compiler is "smart" and knows how to replace a PIN declaration with a constant value, an INS register bit or and OUTS register bit. Note that as in the example above, the programmer is still responsible for setting the DIRS bit of the IO pin as required by the program.


 Compiler Directives

$STAMP

The $STAMP directive is a special compiler command that must be included (usually near the top) in a program to indicate the model of BASIC Stamp targeted. The line below is an example of the $STAMP directive (in this case, it indicates that the program is intended for a BASIC Stamp 2):

' {$STAMP BS2}

This line should be entered into your code, usually near the top, on a line by itself. Note that the directive appears on a comment line (the apostrophe (') indicates this) for compatibility with the DOS versions of the editor.

The 'BS2' in the example above should be changed to indicate the appropriate model of the BASIC Stamp you are using. For example, to use another BASIC Stamp module, enter one (just one) of the following lines into program:

' {$STAMP BS1}
' {$STAMP BS2}
' {$STAMP BS2e}
' {$STAMP BS2sx}
' {$STAMP BS2p}
' {$STAMP BS2pe}
' {$STAMP BS2px}

The directive itself must be enclosed in braces, {...}. There should not be any spaces between the dollar sign, $, and the word STAMP, however, the directive may contain additional spaces in certain other areas. Buttons on the editor tool bar simplify adding or changing the $STAMP directive.

The $STAMP directive is read and acted upon by the BASIC Stamp Windows Editor any time a source code file is loaded, tokenized, downloaded (run), or viewed in the Memory Map.

For BS2e, BS2sx, BS2p, BS2pe, and BS2px programs, each editor page can be a separate project, or part of a single project. A project is a set of up to eight files that should all be downloaded to the BASIC Stamp for a single application. Each of the files within the project is downloaded into a separate "program slot". Only the BASIC Stamp 2e, 2sx, 2p, 2pe, and 2px modules support projects (multiple program slots).

For BASIC Stamp projects (consisting of multiple programs), the $STAMP directive has an option to specify additional filenames. The syntax below demonstrates this form of the $STAMP directive:

' {$STAMP BS2e, file2, file3, ..., file8}

Use this form of the $STAMP directive if a project, consisting of multiple files, is desired. This directive must be entered into the first program (to be downloaded into program slot 0) and not in any of the other files in the project. The file2, file3, etc. items should be the actual name (and optionally the path) of the other files in the project. File2 refers to the program that should be downloaded into program slot 1, file3 is the program that should be downloaded into program slot 2, etc. If no path is given, the path of program 0 (the program in which the $STAMP directive is entered) is used.

Up to seven filenames can be included, bringing the total to eight files in the project all together. Upon tokenizing, running or viewing program 0 in the Memory Map, the editor will read the $STAMP directive, determine if the indicated files exist, will load them if necessary and change their captions to indicate the project they belong to and their associated program number. After the directive is tokenized properly, and all associated files are labeled properly, tokenizing, running or viewing any program in the Memory Map will result in that program’s entire project being tokenized, downloaded or viewed.

$PBASIC

The $PBASIC directive allows the programmer to specify the syntax level for the compiler to use. Example:

' {$PBASIC 1.0}                         ' use version 1.0 syntax (BS1 only)
' {$PBASIC 2.0}                         ' use version 2.0 syntax
' {$PBASIC 2.5}                         ' use version 2.5 syntax

Note that while the $PBASIC directive is optional, only version 1.0 syntax is allowed when using a BS1 module. If an attempt is made to select an incompatible syntax for the specified $STAMP directive, the editor will generate a warning. Buttons on the editor tool bar simplify adding or modifying the $PBASIC directive.

$PORT

The purpose of the $PORT directive is to select a specific serial port for programming the BASIC Stamp. Both standard serial and USB ports (with proper adapter circuitry) may be used. The syntax is as follows:

' {$PORT COM#}

where # is a valid port number. When any PBASIC program containing this directive is downloaded, all other ports will be ignored. This directive is especially important if using two of the same BASIC Stamp models (such as two BS2 modules) on two COM ports and you have two different PBASIC programs to download (one for each BS2). Without this directive, developing and downloading in this case would be a tedious task of always answering the "which Stamp?" prompt. The $PORT directive can be automatically inserted or modified by selecting the appropriate port from the Directive -> Port menu. The COM ports listed in the Directive -> Port menu are automatically updated any time a change is made to the exiting computer hardware or to the available ports list (in preferences).


PBASIC Command Reference

 PBASIC Operators

Operator Precedence
The BASIC Stamp solves math problems in the order they are written; from left to right. The result of each operation is fed into the next operation. So to compute

12 + 3 * 2 / 4

...the BASIC Stamp goes through a sequence like this:

12 + 3 = 15
15 * 2 = 30
30 / 4 = 7

Note that since the BASIC Stamp performs integer math (whole numbers only) 30 / 4 results in 7, not 7.5.

Some other dialects of BASIC would compute that same expression based on their precedence of operators, which requires that multiplication and division be done before addition. So the result would be:

3 * 2 = 6
6 / 4 = 1
12 + 1 = 13

Once again, because of integer math, the fractional portion of 6 / 4 is dropped, so we get 1 instead of 1.5.

The BS1 does not allow parenthesis in expressions. Unfortunately, all expressions have to be written so that they evaluate as intended strictly from left to right.

The BS2 family modules, however, allow parenthesis to be used to change the order of evaluation. Enclosing a math operation in parentheses gives it priority over other operations. To make the BASIC Stamp compute the previous expression in the conventional way, you would write it as 12 + (3 * 2 / 4). Within the parentheses, the BASIC Stamp works from left to right. If you wanted to be even more specific, you could write 12 + ((3 * 2) / 4). When there are parentheses within parentheses, the BASIC Stamp works from the innermost parentheses outward. Parentheses placed within parentheses are called nested parentheses.

Binary Operators
 | • + | Addition
 | • - | Subtraction
 | • * | Multiplication
 | • ** | Multiply High (Returns Upper 16 Bits)
 | • */ | Multiply Middle (Returns Middle 16 Bits)
 | • / | Division
 | • // | Modulus (Remainder of Division)
 | • MIN | Limits a Value to Specified Low
 | • MAX | Limits a Value to Specified High
 | • DIG | Returns Specified Digit of Number
 | • REV | Reverse Specified Number of Bits
 | • << | Shift Bits Left by Specified Amount
 | • >> | Shift Bits Right by Specified Amount
 | • & | Bitwise AND
 | • | | Bitwise OR
 | • ^ | Bitwise XOR
 | • &/ | Bitwise AND NOT
 | • |/ | Bitwise OR NOT
 | • ^/ | Bitwise XOR NOT
 | • AND | Logical AND
 | • OR | Logical OR
 | • XOR | Logical XOR
 | • ATN | Returns ArcTangent of Vector
 | • HYP | Returns Hypotenuse
Unary Operators
 | • ABS | Returns Absolute Value
 | • - | Negate
 | • ~ | Bitwise Inverse
 | • DCD | 2n-power Decoder
 | • NCD | Priority Encoder of 16-bit Value
 | • SIN | Returns (signed) Sine Value of Angle
 | • COS | Returns (signed) Cosine Value of Angle
 | • SQR | Returns Square Root of value
 | • NOT | Logical NOT


 PBASIC Command Reference

2 | Note: For BS1/BS2-compatible commands, syntax shown below is in BS2 format. Some commands may use slightly different formatting with the BS1.
2.5 | Note: Requires {$PBASIC 2.5} directive.
† | Note: Compound, multi-line command; syntax not shown.

BRANCHING / PROGRAM CONTROL
 | • GOTO | GOTO Address
 | • IF...THEN | IF Condition THEN Address
 | • BRANCH 2 | BRANCH Offset, [Address1, Address2, ...AddressN]
 | • ON...GOTO 2.5 | ON expression GOTO Address1, Address2, ...AddressN
 | • GOSUB | GOSUB Address
 | • ON...GOSUB 2.5 | ON expression GOSUB Address1, Address2, ...AddressN
 | • RETURN | RETURN
 | • RUN | RUN ProgramSlot
 | • POLLRUN | POLLRUN ProgramSlot
 | • IF...THEN...ELSE 2.5, † |
 | • SELECT...CASE 2.5, † |
 | • STOP | STOP
LOOPING
 | • DO...LOOP 2.5 | DO {WHILE | UNTIL Condition(s) } ... LOOP {UNTIL | WHILE Condition(s) }
 | • FOR...NEXT | FOR Counter = StartValue TO EndValue {STEP StepValue} ... NEXT
 | • EXIT 2.5 | EXIT
EEPROM ACCESS
 | • EEPROM | EEPROM {Location,} (DataItem {, DataItem, ...})
 | • DATA | {Symbol } DATA DataItem {, DataItem, ...}
 | • READ | READ Location, {Word 2.5} Variable {, ...} 2.5
 | • WRITE | WRITE Location, {Word 2.5} Variable {, ...} 2.5
 | • STORE | STORE ProgramSlot
RAM ACCESS
 | • GET | GET Location, {Word 2.5} Variable {, ...} 2.5
 | • PUT | PUT Location, {Word 2.5} Variable {, ...} 2.5
NUMERICS
 | • LOOKUP 2 | LOOKUP Index, [Value0, Value1, ...ValueN], Variable
 | • LOOKDOWN 2 | LOOKDOWN Target, {ComparisonOp } [Value0, Value1, ...ValueN], Variable
 | • RANDOM | RANDOM Variable
DIGITAL I/O
 | • CONFIGPIN | CONFIGPIN Mode, PinMask
 | • INPUT | INPUT Pin
 | • OUTPUT | OUTPUT Pin
 | • REVERSE | REVERSE Pin
 | • LOW | LOW Pin
 | • HIGH | HIGH Pin
 | • TOGGLE | TOGGLE Pin
 | • PULSIN | PULSIN Pin, State, Variable
 | • PULSOUT | PULSOUT Pin, Duration
 | • BUTTON | BUTTON Pin, DownState, Delay, Rate, Workspace, TargetState, Address
 | • COUNT | COUNT Pin, Duration, Variable
 | • XOUT | XOUT Mpin, Zpin, [House\Command {\Cycles} {, House\Command {\Cycles}...}]
 | • AUXIO | AUXIO
 | • MAINIO | MAINIO
 | • IOTERM | IOTERM Port
 | • POLLIN | POLLIN Pin, State
 | • POLLOUT | POLLOUT Pin, State
 | • POLLMODE | POLLMODE Mode
ASYNCHRONOUS I/0
 | • SERIN 2 | SERIN Rpin {\Fpin}, Baudmode, {Plabel,} {Timeout, Tlabel, } [InputData]
 | • SEROUT 2 | SEROUT Tpin {\Fpin}, Baudmode, {Pace,} {Timeout, Tlabel,} [OutputData]
 | • OWIN | OWIN Pin, Mode, [InputData]
 | • OWOUT | OWOUT Pin, Mode, [OutputData]
SYNCHRONOUS SERIAL I/O
 | • SHIFTIN | SHIFTIN Dpin, Cpin, Mode, [Variable{\Bits} {, Variable{\Bits}...}]
 | • SHIFTOUT | SHIFTOUT Dpin, Cpin, Mode, [OutputData{\Bits} {, OutputData{\Bits}...}]
 | • I2CIN | I2CIN Pin, SlaveID, {Address{\LowAddress },} [InputData]
 | • I2COUT | I2COUT Pin, SlaveID, {Address{\LowAddress},} [OutputData]
PARALLEL I/O
 | • LCDCMD | LCDCMD Pin, Command
 | • LCDIN | LCDIN Pin, Command, [InputData]
 | • LCDOUT | LCDOUT Pin, Command, [OutputData]
ANALOG I/O
 | • COMPARE | COMPARE Mode, Result
 | • POT | POT Pin, Scale, Variable
 | • PWM | PWM Pin, Duty, Duration
 | • RCTIME | RCTIME Pin, State, Variable
TIME
 | • PAUSE | PAUSE Duration
 | • POLLWAIT | POLLWAIT Duration
SOUND
 | • SOUND | SOUND Pin, (Note, Duration {, Note, Duration...})
 | • FREQOUT | FREQOUT Pin, Duration, Freq1 {, Freq2 }
 | • DTMFOUT | DTMFOUT Pin, {OnTime, OffTime, } [Tone {, Tone, ...}]
POWER CONTROL
 | • NAP | NAP Duration
 | • SLEEP | SLEEP Duration
 | • END | END
PROGRAM DEBUGGING
 | • DEBUG | DEBUG OutputData {, OutputData }
 | • DEBUGIN 2.5 | DEBUGIN InputData


Conditional Compilation

 Conditional Compilation Directives

{$PBASIC 2.5}

In order to facilitate the creation of programs that can be compiled for and downloaded to the connected BASIC Stamp, several conditional compilation directives have been added to PBASIC 2.5. Conditional compilation directives are evaluated before the program is compiled, so variables and named constants cannot be referenced within a conditional compilation definition.

#DEFINE

Syntax: #DEFINE Symbol {= Value}

#DEFINE allows the programmer to create custom symbols for use within conditional compilation control structures.

  • Symbol is a string (up to 32 characters).
  • Value is an optional constant/expression specifying the value of the defined symbol. If the value parameter is omitted, Symbol is defined as True.

Example:

#DEFINE DebugMode = 1

In the example above, the "= 1" is optional. Note that when the compiler encounters an undefined symbol it will evaluate that symbol as False (0). You can define a symbol as False by removing the definition with a comment character ( ' ) or change its value to zero (recommended)

#IF...#THEN...#ELSE

Syntax:

#IF Condition #THEN
Statement(s)
{ #ELSE
Statement(s) }
#ENDIF

Function
Evaluate Condition and, if it is True, compile the statement(s) following #THEN, otherwise compile the statements following #ELSE.

  • Condition is a statement, such that can be evaluated as True or False.
  • Statement is any valid PBASIC statement.

Example:

' set Baud for 9600-N81
#IF ($STAMP = BS2sx) OR ($STAMP = BS2p) #THEN
  Baud  CON  240
#ELSE
  Baud  CON  84
#ENDIF

In this example, the constant Baud is set to match the connected BASIC Stamp. This code will work with the BS2, BS2e, BS2sx, BS2p and BS2pe.

#SELECT...#CASE

Syntax:

#SELECT Expression
#CASE Condition(s)
Statement(s)
{ #CASE Condition(s)
Statement(s)
#CASE #ELSE
Statement(s) }
#ENDSELECT

Function
Evaluate Expression and then conditionally compile a block of code based on comparison to Condition(s). If no conditions are found True and a #CASE ELSE block is included, the #CASE #ELSE code statements will compiled.

  • Expression is a variable, a constant or an expression.
  • Condition is a statement, that can be evaluated as True or False. Multiple conditions within the same CASE can be separated by commas ( , ).
  • Statement(s) is any valid PBASIC statement or statements.

Example:

#SELECT $STAMP
  #CASE BS2, BS2e, BS2sx
    GOSUB LCD_Write
  #CASE #ELSE
    LCDOUT LCDpin, cmd, [char]
#ENDSELECT

#ERROR

Syntax: #ERROR Message

#ERROR allows the programmer to create custom a custom error dialog.

  • Message is the error message string.

Example:

#DEFINE I2CReady = (($STAMP = BS2p) OR ($STAMP = BS2pe))

#IF NOT I2CReady #THEN
  #ERROR "BS2p or BS2pe is required for this program."
#ENDIF

The example above will halt the program and display the dialog below if you attempt to compile the program and run it on a Stamp other than the BS2p or BS2pe:


PBASIC Style

 The Elements of PBASIC Style

INTRODUCTION

Like most versions of the BASIC programming language, PBASIC is very forgiving and the compiler enforces no particular formatting style. As long as the source code is syntactically correct, it will compile and download to the BASIC Stamp without trouble.

Why, then, would one suggest a specific style for PBASIC? Consider this: Over three million BASIC Stamp modules have been sold and there are several thousand members that participate in the Parallax online forums. This makes it highly likely that you'll be sharing your PBASIC code with someone, if not co-developing a BASIC Stamp project. Writing code in an organized, predictable manner will save you -- and your potential colleagues -- a lot of time; in analysis, in troubleshooting and especially when you return to a project after a long break.

The style guidelines presented here are just that: guidelines. They have been developed from style guidelines used by professional programmers using other high-level languages such as Visual Basic®, C/C++, and Java™. Use these guidelines as-is, or modify them to suit your individual needs. The key is selecting a style the works well for you or your organization, and then sticking to it.

PBASIC Style Guidelines

1. Do It Right The First Time
Many programmers, especially new ones, fall into the "I'll knock it out now and fix it later." trap. Invariably, the "fix it later" part never happens and sloppy code makes its way into production projects. If you don't have time to do it right, when will you find time to do it again?

Start clean and you'll be less likely to introduce errors in your code. And if errors do pop up, clean and organized formatting will make them easier to find and fix.

2. Be Organized and Consistent
Using a blank program template will help you organize your programs and establish a consistent presentation.

3. Use Meaningful Names
Be verbose when naming constants, variables and program labels. The compiler will allow names up to 32 characters long. Using meaningful names will reduce the number of comments and make your programs easier to read, debug and maintain.

4. Naming IO Pins
BASIC Stamp IO pins are a special case as various elements of the PBASIC language require a pin to be constant value, an input variable or an output variable. To prevent redundant definitions, use the PIN type.

HeaterCtrl      PIN         15

Since connections don't change during the program run, IO pins are named like constants (#5) using mixed-case, beginning with an uppercase letter.

5. Naming Constants
Begin constant names with an uppercase letter and use mixed case, using uppercase letters at the beginning of new words within the name.

SYMBOL          AlarmCode   = 25

AlarmCode       CON         25

6. Naming Variables
Begin variable names with a lowercase letter and use mixed case, using uppercase letters at the beginning of new words within the name.

BS1: Avoid using W0 (B0 and B1) so that bit variables (Bit0..Bit15) are available for use in your programs. Bit variables 0..15 overlay W0, so the use of W0 may cause undesired effects.

SYMBOL          waterLevel  = W1

BS2: Avoid the use of internal variable names (such as B0 or W1) in your programs. Allow the compiler to automatically assign RAM space by declaring a variable of specific type.

waterLevel      VAR         Word

7. Variable Type Declarations
When using the BS1, variable type is declared by aliasing the SYMBOL name to an internal variable of a specific size.

SYMBOL          status      = Bit0
SYMBOL          ovenTmp     = B2
SYMBOL          rndVal      = W2

For the BS2, variable types should be in mixed-case and start with an uppercase letter.

status          VAR         Bit
counter         VAR         Nib
ovenTmp         VAR         Byte
rndVal          VAR         Word

Conserve BASIC Stamp user RAM by declaring the variable type required to hold the expected values of the variable.

SYMBOL          bitVal      = BIT0              ' 0 - 1
SYMBOL          byteVal     = B2                ' 0 - 255
SYMBOL          wordVal     = W2                ' 0 - 65535

bitValue        VAR         Bit                 ' 0 - 1
nibValue        VAR         Nib                 ' 0 - 15
byteValue       VAR         Byte                ' 0 - 255
wordValue       VAR         Word                ' 0 - 65535

8. Program Labels
Begin program labels with an uppercase letter, used mixed case, separate words within the label with an underscore character and begin new words with a number or uppercase letter. Labels should be preceded by at least one blank line, begin in column 1 and must be terminated with a colon (except after GOTO and THEN [in classic PBASIC] where they appear at the end of the line and without a colon).

Print_String:
  READ eeAddr, char
  IF char = 0 THEN Print_Done
  DEBUG char
  eeAddr = eeAddr + 1
  GOTO Print_String

Print_Done:
  RETURN

9. PBASIC Keywords
All PBASIC language keywords, including SYMBOL, CON, VAR, PIN and serial/debugging format modifiers (DEC, HEX, BIN) and constants (CR, LF) should be uppercase.

Main:
  DEBUG "BASIC Stamp", CR
  END

10. Indent Nested Code
Nesting blocks of code improves readability and helps reduce the introduction of errors. Indenting each level with two spaces is recommended to make the code readable without taking up too much space.

Note: The dots are used to illustrate the level of nesting and are not a part of the code.

Main:
..FOR testLoop = 1 TO 10
....IF checkLevel >= Threshold THEN LED_Okay
....lowLevel = lowLevel + 1
....GOTO Loop_Delay

LED_Okay:
....LEDokay = IsOn

Loop_Delay:
....PAUSE 100
..NEXT
..IF testMode = Yes THEN Main

Main:
..DO
....FOR testLoop = 1 TO 10
......IF (checkLevel < Threshold) THEN
........lowLevel = lowLevel + 1
......ELSE
........LEDokay = IsOn
......ENDIF
......PAUSE 100
....NEXT
..LOOP WHILE (testMode = Yes)

11. Condition Statements
Enclose condition statements in parenthesis for clarity (BS2 only - parenthesis are not allowed when using the BS1).

Check_Temp:
  IF (indoorTemp >= setPoint) THEN
    AcCtrl = IsOn
  ELSE
    lowLevel = lowLevel + 1
  ENDIF

Fill_Water_Tank:
  DO WHILE (waterLevel = IsLow)
    TankFill = IsOn
    PAUSE 250
  LOOP

Get_Delay:
  DO
    DEBUG HOME, "Enter time (5 - 30)... ", CLREOL
    DEBUGIN DEC2 tmDelay
  LOOP UNTIL ((tmDelay >= 5) AND (tmDelay =< 30))

12. Be Generous With White Space
White space (spaces and blank lines) does not affect compiler performance or BASIC Stamp execution speed, so be generous with it to make listings easier to read. As suggested in #8 above, allow at least one blank line before program labels (two blanks lines before a subroutine label is recommended). Separate items in a parameter list with a space.

Main:
  DO
    ON task GOSUB Update_Motors, Scan_IR, Close_Gripper
  LOOP

Update_Motors:
  PULSOUT MtrLeft, leftSpeed
  PULSOUT MtrRight, rightSpeed
  PAUSE 20
  task = (task + 1) // NumTasks
  RETURN

An exception to this guideline is with the bits parameter used with SHIFTIN and SHIFTOUT, the REP modifier for DEBUG and SEROUT, and the byte count and terminating byte value for SERIN. In these cases, format without spaces.

  SHIFTIN A2Ddata, A2Dclock, MSBPost, [result\9]
  DEBUG REP "*"\25, CR
  SERIN IRbSIO, IRbBaud, [buffer\8\255]


BS1 Serial Adapter Circuit

 BASIC Stamp 1 Serial Adapter

Starting with Version 2.1, the BASIC Stamp Editor/Compiler supports programming BASIC Stamp 1 modules through a standard serial connection. Programming BS1 modules via the serial connection requires an adapter to handle the voltage level and mechanical requirements of the BS1. For convenience, Parallax manufactures an adapter that plugs into the end of a serial cable and connects to the programming header of the BS1.

BS1 Serial Programming Adapter (Part #27111)

For those that would like to make their own adapter, the schematic is shown below.


 AUXIO

Example

Syntax: AUXIO

Function
Switch from control of main I/O pins to auxiliary I/O pins (on the BS2p40 only).

Quick Facts
 | BS2p, BS2pe, and BS2px
I/O Pin IDs | 0 - 15 (just like main I/O, but after AUXIO command, all references affect physical pins 21 - 36).
Special Notes | The BS2p, BS2pe, and BS2px modules accept this command, however, only the BS2p40 gives access to the auxiliary I/O pins.

Explanation
The BS2p, BS2pe, and BS2px is available as a 24-pin module that is pin-compatible with the BS2, BS2e, and BS2sx. Also availabe is a 40-pin module called the BS2p40 with an additional 16 I/O pins (for a total of 32). The BS2p40's extra, or auxiliary, I/O pins can be accessed in the same manner as the main I/O pins (by using the IDs 0 to 15) but only after issuing an AUXIO or IOTERM 1 command. . The AUXIO command causes the BASIC Stamp to affect the auxiliary I/O pins instead of the main I/O pins in all further code until the MAINIO or IOTERM 0 command is reached, or the BASIC Stamp is reset or power-cycled. AUXIO is also used when setting the DIRS register for auxiliary IO pins on the BS2p40.

The following example illustrates this:

Main:
  HIGH 0
  AUXIO
  LOW 0
The first line of the above example will set I/O pin 0 of the main I/O pins (physical pin 5) high. Afterward, the AUXIO command tells the BASIC Stamp that all commands following it should affect the auxiliary I/O pins. The following LOW command will set I/O pin 0 of the auxiliary I/O pins (physical pin 21) low.

Note that the main I/O and auxiliary I/O pins are independent of each other; the states of the main I/O pins remain unchanged while the program affects the auxiliary I/O pins, and vice versa.

Note on reducing power consumption.

When the BASIC Stamp is reset all RAM variables, including DIRS and OUTS are cleared to zero. This goes for main and auxiliary pins. On the BS2p24, BS2pe, and BS2px the auxiliary pins from the interpreter chip are not connected to physical IO pins on the BASIC Stamp. While not connected to anything, these pins do have pull-ups activated, effectively connecting them to Vdd. After reset, reading the auxiliary pins from a BS2p24, BS2pe, or BS2px will return all 1s. For lowest possible current consumption where required, you may set the BS2p24, BS2pe, and BS2px auxiliary pins as output low.
Setup:
  AUXIO                                 ' select AUXIO pins
  OUTS = $0000                          ' force outputs low
  DIRS = $FFFF                          ' make (unconnected) pins outputs
  MAINIO                                ' back to MAINIO group

Other commands that affect I/O group access are MAINIO and IOTERM.

Related commands: MAINIO and IOTERM


 AUXIO / MAINIO / IOTERM Example

Note: This program was written for the BS2p but can also run on the BS2pe or BS2px with a change of the $STAMP directive, however, its effects can only be seen on the BS2p40.

' AUX_MAIN_TERM.BSP
' This program demonstrates the use of the AUXIO, MAINIO AND IOTERM
' commands to affect I/O pins in the auxiliary and main I/O groups.

' {$STAMP BS2p}
' {$PBASIC 2.5}

#SELECT $STAMP
  #CASE BS2, BS2E, BS2SX
    #ERROR "Program requires BS2p40"
  #CASE BS2P, BS2PE, BS2PX
    DEBUG "Note: This program designed for the BS2p40", CR
#ENDSELECT

port            VAR     Bit

Main:
  DO
    MAINIO                              ' Switch to main I/O pins
    TOGGLE 0                            ' Toggle state of I/O pin P0
    PWM 1, 100, 40                      ' Generate PWM on I/O pin P1

    AUXIO                               ' Switch to auxiliary I/O pins
    TOGGLE 0                            ' Toggle state of I/O pin P0
    PULSOUT 1, 1000                     ' Generate a pulse on I/O pin P1
    PWM 2, 100, 40                      ' Generate PWM on I/O pin P2

    IOTERM port                         ' Switch to main or aux I/Os
                                        ' -- depending on port
    TOGGLE 3                            ' Toggle state of I/O pin P3
                                        ' -- on main and aux, alternately
    port = ~port                        ' Invert port
    PAUSE 1000                          ' 1 second delay
  LOOP
  END


 BRANCH

Examples

Syntax [image]: BRANCH Offset, (Address1, Address2, ...AddressN)
Syntax [image]: BRANCH Offset, [Address1, Address2, ...AddressN]

Function
Go to the address specified by offset (if in range).

  • Offset is a variable/constant/expression* (0 - 255) that specifies the index of the address, in the list, to branch to (0 - N).
  • Addresses are labels that specify where to go. BRANCH will ignore any list entries beyond offset 255.

* Note: Expressions are not allowed as arguments on the BS1.

Quick Facts
 | BS1 | BS2 Family
Limit of Address entries | Limited only by memory | 256

Explanation
The BRANCH instruction is useful when you want to write something like this:

Test_Value:
  IF value = 0 THEN Case_0              ' if value is 0, jump to Case_0
  IF value = 1 THEN Case_1              ' if value is 1, jump to Case_1
  IF value = 2 THEN Case_2              ' if value is 2, jump to Case_2
You can use BRANCH to organize this into a single statement:

  BRANCH value, (Case_0, Case_1, Case_2)

  BRANCH value, [Case_0, Case_1, Case_2]
This works exactly the same as the previous IF...THEN example. If the value isn’t in range (in this case if value is greater than 2), BRANCH does nothing and the program continues with the next instruction after BRANCH.

Related commands: IF...THEN, ON...GOTO ( [image] ) and ON...GOSUB ( [image] )


 BRANCH Examples

Syntax
' BRANCH.BS1
' This program shows how the value of idx controls the destination of the
' BRANCH instruction.

' {$STAMP BS1}
' {$PBASIC 1.0}

SYMBOL  idx             = B2

Main:
  DEBUG "idx: ", #idx, " "
  BRANCH idx, (Task_0, Task_1, Task_2)  ' branch to task
  DEBUG "BRANCH target error..."        ' ... unless out of range
  DEUBG CR, CR

Next_Task:
  idx = idx + 1 // 4                    ' force idx to be 0..3
  GOTO Main

Task_0:
  DEBUG "BRANCHed to Task_0", CR
  GOTO Next_Task

Task_1:
  DEBUG "BRANCHed to Task_1", CR
  GOTO Next_Task

Task_2:
  DEBUG "BRANCHed to Task_2", CR
  GOTO Next_Task

NOTE: This is written for the BS2 and will run on any of the BS2-family modules. Modify the $STAMP directive (as required) before downloading to the BS2e, BS2sx, BS2p, BS2pe, or BS2px.

' BRANCH.BS2
' This program shows how the value of idx controls the destination of the
' BRANCH instruction.

' {$STAMP BS2}
' {$PBASIC 2.5}

idx             VAR     Nib

Main:
  DEBUG "idx: ", DEC1 idx, " "
  BRANCH idx, [Task_0, Task_1, Task_2]  ' branch to task
  DEBUG "BRANCH target error...",       ' ... unless out of range
        CR, CR

Next_Task:
  idx = idx + 1 // 4                    ' force idx to be 0..3
  PAUSE 250
  GOTO Main

Task_0:
  DEBUG "BRANCHed to Task_0", CR
  GOTO Next_Task

Task_1:
  DEBUG "BRANCHed to Task_1", CR
  GOTO Next_Task

Task_2:
  DEBUG "BRANCHed to Task_2", CR
  GOTO Next_Task


 BUTTON

Example

Syntax: BUTTON Pin, DownState, Delay, Rate, Workspace, TargetState, Address

Function
Monitor and process a pushbutton input, perform auto-repeat, and branch to address if button is in target state. Button circuits may be active-low or active-high.

  • Pin is a variable/constant/expression* (0 - 15) that specifies the I/O pin to use. This pin will be set to input mode.
  • DownState is a variable/constant/expression* (0 or 1) that specifies which logical state occurs when the button is pressed.
  • Delay is a variable/constant/expression* (0 - 255) that specifies how long the button must be pressed before auto-repeat starts. The delay is measured in cycles of the BUTTON routine. Delay has two special settings: 0 and 255. If Delay is 0, BUTTON performs no debounce or auto-repeat. If Delay is 255, Button performs debounce, but no auto-repeat.
  • Rate is a variable/constant/expression* (0 - 255) that specifies the number of cycles between auto-repeats. The rate is expressed in cycles of the BUTTON routine.
  • Workspace is a byte variable used by BUTTON for workspace. It must be cleared to 0 before being used by BUTTON for the first time and should not be adjusted outside of the BUTTON instruction. NOTE: All RAM is cleared to 0 by default upon power-up or reset of the BASIC Stamp.
  • TargetState is a variable/constant/expression* (0 or 1) that specifies which state the button should be in for a branch to occur (0=not pressed, 1=pressed).
  • Address is a label that specifies where to branch if the button is in the target state.

* Note: Expressions are not allowed as arguments on the BS1. The range of the Pin argument on the BS1 is 0 - 7.

Explanation
When you press a button or flip a switch, the contacts make or break a connection. A brief (1 to 20-ms) burst of noise occurs as the contacts scrape and bounce against each other. By scanning an input within a loop to ensure that the contact remains in a specified state for a minimum duration, spurious multiple inputs caused by contact noise can be eliminated. The BUTTON instruction helps prevent this noise from being interpreted as more than one switch action; this is the function of the Delay parameter. (For a demonstration of switch bounce, see the demo program for the COUNT instruction.) Delay, combined with the Rate parameter, allows the programmer to control the rate at which multiple inputs are accepted by the BASIC Stamp.

BUTTON also lets PBASIC react to a button press the way your computer keyboard does to a key press. When you press a key, a character immediately appears on the screen. If you hold the key down, there's a delay, then a rapid-fire stream of characters appears on the screen. BUTTON's auto-repeat function can be set up to work much the same way.

BUTTON is designed for use inside a program loop. Each time through the loop, BUTTON checks the state of the specified pin. When it first matches DownState, BUTTON begins the Delay countdown for auto-repeat. Then, in accordance with TargetState, it either branches to address (TargetState = 1) or doesn't (TargetState = 0).

If the switch stays in DownState, BUTTON counts the number of program loops that execute. When this count equals Delay, BUTTON once again triggers the action specified by TargetState and address. Hereafter, if the switch remains in DownState, BUTTON waits Rate number of cycles between actions. The Workspace variable is used by BUTTON to keep track of how many cycles have occurred since the pin switched to TargetState or since the last auto-repeat.

BUTTON does not stop program execution. In order for its delay and auto repeat functions to work properly, BUTTON must be executed from within a program loop.


BUTTON Examples

Syntax
' BUTTON.BS1
' Connect an active-low circuit to pin P0 of the BS1. When you press the
' button, the DEBUG screen will display an asterisk (*). The program, as
' shown below, will print an asterisk at the first button press, then
' delay approximately one second (200 x 5 ms PAUSE) before auto-repeating
' at a rate of approximately 100 ms (5 x 20 ms).  Feel free to modify the
' program to see the effects of your changes on the way BUTTON responds.

' {$STAMP BS1}
' {$PBASIC 1.0}

SYMBOL  Btn             = 0

SYMBOL  btnWrk          = B2

Main:
  ' Try changing the Delay value (255) in BUTTON to see the effect of
  ' its modes: 0 = no delay; 1-254 = varying delays before auto-repeat;
  ' 255 = no auto-repeat (only one action per button press)
  '
  ' The BUTTON instruction will cause the program to branch to
  ' No_Press unless P0 = 0

  PAUSE 5
  BUTTON Btn, 0, 200, 20, btnWrk, 0, No_Press
  DEBUG "*"

No_Press:
  GOTO Main

NOTE: This is written for the BS2 and will run on any of the BS2-family modules. Modify the $STAMP directive (as required) before downloading to the BS2e, BS2sx, BS2p, BS2pe, or BS2px.

' BUTTON.BS2
' Connect an active-low circuit to pin P0 of the BS2. When you press the
' button, the DEBUG screen will display an asterisk (*). The program, as
' shown below, will print an asterisk at the first button press, then
' delay approximately one second (200 x 5 ms PAUSE) before auto-repeating
' at a rate of approximately 100 ms (5 x 20 ms).  Feel free to modify the
' program to see the effects of your changes on the way BUTTON responds.

' {$STAMP BS2}
' {$PBASIC 2.5}

Btn             PIN     0

btnWrk          VAR     Byte

Main:
  ' Try changing the Delay value (255) in BUTTON to see the effect of
  ' its modes: 0 = no delay; 1-254 = varying delays before auto-repeat;
  ' 255 = no auto-repeat (only one action per button press)
  '
  ' The BUTTON instruction will cause the program to branch to
  ' No_Press unless P0 = 0

  PAUSE 5
  BUTTON Btn, 0, 200, 20, btnWrk, 0, No_Press
  DEBUG "*"

No_Press:
  GOTO Main


 COMPARE

Example

Syntax: COMPARE Mode, Result

Function
Enable or disable comparator, compare voltages on P1 and P2 and retrieve comparison result to store in Result.

  • Mode is a variable/constant/expression (0 – 2) that enables or disables the comparator (input pins P1 and P2) and determines if the optional comparator output pin (pin P0) is enabled or not. See the table below for an explanation of the Mode values.
  • Result is a variable (usually a bit) in which the comparison result is stored.

Quick Facts
 | BS2px
Mode Values | 0: Disables comparator.
 | 1: Enables comparator with P0 as Result output.
 | 2: Enables comparator without P0 as Result output.
Result Values | 0: Voltage P1 > P2; P0 optionally outputs 0.
 | 1: Voltage P1 < P2; P0 optionally outputs 1.

Explanation
The COMPARE command enables or disables the built-in comparator hardware on the BS2px's I/O pins P0, P1, and P2. I/O pins P1 and P2 are the comparator inputs and P0 is optionally the comparator result output pin.

By default, the comparator feature is disabled. Using the COMPARE command with a Mode argument of 1 or 2 enables the comparator feature (using input pins P1 and P2) and returns the result of the comparison in Result. If Mode is 1, the result of the comparison is also output on I/O pin P0. The following is an example of the COMPARE command:

result  VAR     Bit

Main:
  COMPARE 1, result

This example enables the comparator (setting P0 to output the result, with P1 and P2 as the comparator inputs) and writes the result of the comparison into result. Both result and the output pin P0 will be 0 if the input voltage on P1 was greater than that of P2. Result and the output pin P0 will be 1 if the input voltage on P1 was less than that of P2.

Note that the comparator hardware operates independently of the execution speed of the BS2px and will continue to run and update P0 if Mode = 1, even during sleep mode (execution of END, NAP, POLLWAIT 8, or SLEEP commands). To avoid spurious current draw during sleep mode, disable the comparator first.


RUN Example

COMPARE Example

Syntax
' COMPARE.BPX
' This example demonstrates the use of the COMPARE command.
' Connect two variable voltage sources (0 to 5 volts) on I/O pins
' P1 and P2 (or a button on each pin connected to ground). Run the
' program and watch the Debug Terminal display as you adjust the
' variable voltage or press the buttons.

' {$STAMP BS2px}
' {$PBASIC 2.5}

#IF $STAMP <> BS2PX #THEN
  #ERROR "This program requires a BS2px."
#ENDIF

result  VAR Bit

Setup:
  ' P0 = output, all others = input
  CONFIGPIN DIRECTION, %0000000000000001
  ' Enable pull-ups on P1 and P2
  CONFIGPIN PULLUP, %0000000000000110

  DEBUG CLS,
        "BS2px Comparator Demonstration", CR,
        "==============================", CR,
        CR,
        "Input Voltage: P1 > P2", CR,
        "Output State: P0 = 0"

Main:
  DO                                            ' Display P1/P2 comparison
    COMPARE 1, result
    IF (result = 0) THEN
      DEBUG CRSRXY, 18, 3, ">"
    ELSE
      DEBUG CRSRXY, 18, 3, "<"
    ENDIF
    DEBUG CRSRXY, 19, 4, BIN1 result
  LOOP


 CONFIGPIN

Example

Syntax: CONFIGPIN Mode, PinMask

Function
Configure special properties of I/O pins.

  • Mode is a variable/constant/expression (0 – 3), or one of four predefined symbols, that specifies the I/O pin property to configure: Schmitt Trigger, Logic Threshold, Pull-up Resistor or Output Direction. See table below for an explanation of Mode values.
  • PinMask is a variable/constant/expression (1 – 65535) that indicates how Mode is applied to I/O pins. Each bit of PinMask corresponds to an individual I/O pin. A high bit (1) enables the Mode and a low bit (0) disables the Mode on the corresponding I/O pin.

Quick Facts
 | BS2px
Mode Values | 0 (or SCHMITT): Schmitt Trigger
 | 1 (or THRESHOLD): Logic Threshold
 | 2 (or PULLUP): Pull-up Resistor
 | 3 (or DIRECTION): Output Direction

Explanation
The CONFIGPIN command enables or disables special I/O pin properties on all 16 I/O pins at once. There are four properties, or modes, available: Schmitt Trigger, Logic Threshold, Pull-up Resistor, and Output Direction. Each I/O pin on the BS2px contains special hardware dedicated to each of these properties.

By default, all BASIC Stamp I/O pins are set to inputs. Enabling the Output Direction mode sets an I/O pin’s direction to output. Disabling the Output Direction mode sets an I/O pin’s direction to input. This has the same effect as using the OUTPUT or INPUT commands, or the DIRx = # assignment statement to configure I/O pin directions. The following is an example of the CONFIGPIN command using the Output Direction mode:

  CONFIGPIN DIRECTION, %0000000100010011

Every high bit (1) in the PinMask argument enables the output direction for the corresponding I/O pin while every low bit (0) disables the output direction. In the above example, I/O pins 8, 4, 1, and 0 are set to the output direction and all other I/O pins are set to the input direction. This is similar to the following statement:

  DIRS = %0000000100010011

Pull-up resistors are commonly used in circuitry where a component, such as a button, provides an open/drain signal; the signal is either floating (open) or is driven to ground (drain). Since the BASIC Stamp input pins must always be connected to either 5 volts or ground (0 volts) in order to read a reliable logic state with them, a pull-up resistor is required on circuitry, such as the button circuit mentioned above, so that the signal is never left floating (electrically disconnected).

The following example enables internal pull-up resistors on I/O pins 15, 12, 6, and 3, and disables internal pull-up resistors on all other I/O pins:

  CONFIGPIN PULLUP, %1001000001001000

Note that the internal pull-up resistors are intentionally weak, about 20 kΩ. Additionally, the internal pull-up resistors can be activated for all pins, regardless of pin direction, but really matter only when the associated pin is set to input mode.

An input pin’s logic threshold determines the voltage levels that are interpreted as logic high (1) and logic low (0). Most microcontrollers, and other integrated circuits use one of two types of logic threshold: TTL Level or CMOS Level. The BASIC Stamp I/O pins are, by default, configured for TTL level logic thresholds. The figure below is an illustration of the difference between TTL and CMOS logic levels.

TTL Logic Level | CMOS Logic Level

The logic threshold for TTL is 1.4 volts; a voltage below 1.4 is considered to be a logic 0 while a voltage above 1.4 is considered to be a logic 1. The logic threshold for CMOS is 50% of Vdd; a voltage below ½ Vdd is considered a logic 0 while a voltage above ½ Vdd is considered a logic 1.

For the CONFIGPIN command's THRESHOLD mode, a high bit (1) in the PinMask argument sets the corresponding I/O pin to CMOS threshold level, and a low bit sets it to a TTL threshold level. The following example sets CMOS threshold level on I/O pins 3, 2, 1, and 0, and TTL threshold level on all other I/O pins.

  CONFIGPIN THRESHOLD, %0000000000001111

The threshold level can be set for all pins, regardless of pin direction, but really matters only when the associated pin is set to input mode.

Normally, if a signal on an input pin is somewhat noisy (the voltage level randomly rises and falls beyond the logic threshold boundary) then reading that pin’s input value will result in spurious highs and lows (1s and 0s). Schmitt Triggers are circuits that make inputs more steady and reliable by adding a region of hysteresis around the logic threshold that the signal must completely traverse before the logic level is interpreted as being changed. By default BASIC Stamp I/O pins are set to normal input mode, but the BS2px can be configured for Schmitt Trigger mode as well. The figure below illustrates Schmitt Trigger characteristics.

In Schmitt Trigger mode, the threshold for a logic 0 is approximately 15% of Vdd and the threshold for a logic 1 is approximately 85% of Vdd. The input pin defaults to an unknown state until the initial voltage crosses a logic 0 or logic 1 boundary. Thereafter, the voltage must cross above 85% of Vdd to be interpreted as a logic 1 and must cross below 15% of Vdd to be interpreted as a logic 0. If the voltage transitions somewhere between the two thresholds, the interpreted logic state remains the same as the previous state.

For the CONFIGPIN command’s SCHMITT mode, a high bit (1) in the PinMask argument enables the Schmitt Trigger on the corresponding I/O pin and a low bit (0) disables the Schmitt Trigger. The following example sets Schmitt Triggers on I/O pins 7, 6, 5, and 4, and sets all other I/O pins to normal mode.

  CONFIGPIN SCHMITT, %0000000011110000

Schmitt Trigger mode can be activated for all pins, regardless of pin direction, but really matters only when the associated pin is set to input mode.

Related commands (for DIRECTION mode) : INPUT and OUTPUT


CONFIGPIN Example

Syntax
' CONFIGPIN.BPX
' This example demonstrates the use of the CONFIGPIN command.
' All I/O pins are set to inputs with various combinations of
' Pull-Up Resistor, Logic Threshold and Schmitt-Trigger properties.
' While running, this program will constantly display the state of all
' input pins along with an indication of the configuration for each group
' of pins. Try connecting different input signals to the I/O pins (such as
' buttons, a function generator with a slowing sweeping signal (0 to 5
' VDC)) or simply running your fingers across the I/O pins and note how
' they react based upon their configured property.

' {$STAMP BS2px}
' {$PBASIC 2.5}

#IF $STAMP <> BS2PX #THEN
  #ERROR "This program requires a BS2px."
#ENDIF

Setup:
  CONFIGPIN DIRECTION, %0000000000000000        ' Set all I/O pins to inputs
  CONFIGPIN PULLUP, %1111111111110000           ' Enable pull-ups on pins 4 - 15
  CONFIGPIN THRESHOLD, %0000111100000000        ' Set P8-P11 to CMOS, others TTL
  CONFIGPIN SCHMITT, %1111000000000000          ' Enable Schmitt-Triggers P12-P15

  DEBUG CLS,
        " BS2px INPUT PIN CONFIGURATION TEST", CR,
        "=========================================================", CR,
        "     P15-P12: Pull-Up Resistors, TTL & Schmitt-Triggers  ", CR,
        "    /                                                    ", CR,
        "   /     P11-P8: Pull-Up Resistors & CMOS                ", CR,
        "  /     /                                                ", CR,
        "  |    /     P7-P4: Pull-Up Resistors & TTL              ", CR,
        "  |    |    /                                            ", CR,
        "  |    |    |     P3-P0: Normal                          ", CR,
        "  |    |    |    /                                       ", CR,
        "  |    |    |    |                                       ", CR,
        "---- ---- ---- ----                                      "
Main:
  DO
    ' Display input pin states
    DEBUG CRSRXY, 0, 12 ,
          BIN4 IND, " ", BIN4 INC, " ", BIN4 INB, " ", BIN4 INA
  LOOP


 COUNT

Example

Syntax: COUNT Pin, Duration, Variable

Function
Count the number of cycles (0-1-0 or 1-0-1) on the specified pin during the Duration time frame and store that number in Variable.

  • Pin is a variable/constant/expression (0 – 15) that specifies the I/O pin to use. This pin will be set to input mode.
  • Duration is a variable/constant/expression (1 – 65535) specifying the time during which to count. The unit of time for Duration is described below.
  • Variable is a variable (usually a Word) in which the count will be stored.

Quick Facts
 | BS2 / BS2e | BS2sx | BS2p | BS2pe | BS2px
Units in Duration | 1 ms | 400 µs | 287 µs | 720 µs | 287 µs
Duration range | 1 ms to 65.535 s | 400 µs to 26.214 s | 287 µs to 18.809 s | 720 µs to 47.180 s | 287 µs to 18.809 s
Minimum pulse width | 4.16 µs | 1.66 µs | 1.20 µs | 3.00 µs | 1.20 µs
Maximum frequency (square wave) | 120,000 Hz | 300,000 Hz | 416,700 Hz | 166,667 Hz | 416,700 Hz

Explanation
The COUNT instruction makes the Pin an input, then for the specified duration, counts cycles on that pin and stores the total in a variable. A cycle is a change in state from 1 to 0 to 1, or from 0 to 1 to 0.

According to table above, COUNT on the BS2 can respond to transitions (pulse widths) as small as 4.16 microseconds (µs). A cycle consists of two transitions (e.g., 0 to 1, then 1 to 0), so COUNT (on the BS2) can respond to square waves with periods as short as 8.32 µs; up to 120 kilohertz (kHz) in frequency. For non-square waves (those whose high time and low time are unequal), the shorter of the high and low times must be at least 4.16 µs in width (on the BS2). Refer to the table for data on other BASIC Stamp modules.

If you use COUNT on slowly changing analog waveforms like sine waves, you may find that the value returned is higher than expected. This is because the waveform may pass through the BASIC Stamp’s 1.4-volt logic threshold slowly enough that noise causes false counts. You can fix this by passing the signal through a Schmitt Trigger, like one of the inverters of a 74HCT14. Or, you may use the BS2px’s built-in Schmitt-Trigger pin property; see CONFIGPIN for details.”

Related command: PULSIN


COUNT Example

Syntax

NOTE: This is written for the BS2 and will run on any of the BS2-family modules. Modify the $STAMP directive (as required) before downloading to the BS2e, BS2sx, BS2p, BS2pe, or BS2px.

' COUNT.BS2
' Connect an active-low button circuit shown to pin P0 of the BS2. The
' DEBUG screen will prompt you to press the button as quickly as possible
' for a 1-second count.  When the count is done, the screen will display
' your "score," the total number of cycles registered by COUNT.  Note that
' this score will almost always be greater than the actual number of presses
' because of switch contact bounce.

' {$STAMP BS2}
' {$PBASIC 2.5}

PushBtn         PIN     0               ' pushbutton on P0

#SELECT $STAMP
  #CASE BS2, BS2E
    DurAdj      CON     $100            ' / 1
  #CASE BS2SX
    DurAdj      CON     $280            ' / 0.400
  #CASE BS2P, BS2PX
    OneSec      CON     $37B            ' / 0.287
  #CASE BS2PE
    OneSec      CON     $163            ' / 0.720
#ENDSELECT

Capture         CON     1000            ' 1 second

cycles          VAR     Word            ' counted cycles

Main:
  DO
    DEBUG CLS,
          "How many times can you press the button in 1 second?", CR
    PAUSE 1000
    DEBUG "Ready, set... "
    PAUSE 500
    DEBUG "GO!", CR
    COUNT PushBtn, (Capture */ DurAdj), cycles
    DEBUG CR, "Your score: ", DEC cycles, CR
    PAUSE 3000
    DEBUG "Press button to go again."
    DO : LOOP UNTIL (PushBtn = 0)       ' wait for button press
  LOOP
  END


 DATA

Example

Syntax: {Symbol} DATA {@Address,} {Word} DataItem {, DataItem ...}

Function
Write user data to the EEPROM location(s) during program download.

  • Symbol is an optional, unique symbol name that will be automatically defined as a constant equal to the location number of the first data item.
  • Address is an optional starting location for subsequent DataItems
  • DataItem is a constant/expression (0 - 65535) indicating a value or how to store a value.

Explanation
When you download a program into the BASIC Stamp, it is stored in the EEPROM starting at the highest address (2047) and working towards the lowest address. Most programs don't use the entire EEPROM, so the lower portion is available for other uses. The DATA directive allows you to define a set of data to store in the available EEPROM locations. It is called a "directive" rather than a "command" because it performs an activity at compile-time rather than at run-time (i.e.: the DATA directive is not downloaded to the BASIC Stamp, but the data it contains is downloaded).

The simplest form of the DATA directive is something like the following:

  DATA          100, 200, 52, 45

This example, when downloaded, will cause the values 100, 200, 52 and 45 to be written to EEPROM locations 0, 1, 2 and 3, respectively. You can then use the READ and WRITE commands in your code to access these locations and the data you've stored there.

DATA uses a counter, called a pointer, to keep track of available EEPROM addresses. The value of the pointer is initially 0. When a program is downloaded, the DATA directive stores the first byte value at the current pointer address, then increments (adds 1 to) the pointer. If the program contains more than one DATA directive, subsequent DATAs start with the pointer value left by the previous DATA. For example, if the program contains:

  DATA          72, 69, 76, 76, 79
  DATA          104, 101, 108, 108, 111

The first DATA directive will start at location 0 and increment the pointer for each data value it stores (1, 2, 3, 4, and 5). The second DATA directive will start with the pointer value of 5 and work upward from there. As a result, the first 10 bytes of EEPROM will look like the following:

 | EEPROM Location (address)
 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
Contents | 72 | 69 | 76 | 76 | 79 | 104 | 101 | 108 | 108 | 111

What if you don't want to store values starting at location 0? Fortunately, the DATA directive has an option to specify the next location to use. You can specify the next location number (to set the pointer to) by inserting a DataItem in the form @x ;where x is the location number. The following code writes the same data in the table above to locations 100 through 109:

  DATA          @100, 72, 69, 76, 76, 79, 104, 101, 108, 108, 111

In this example, the first DataItem is @100. This tells the DATA directive to store the following DataItem(s) starting at location 100. All the DataItems to the right of the @100 are stored in their respective locations (100, 101, 102... 109).

In addition, the DATA directive allows you to specify new starting locations at any time within the DataItem list. If, for example, you wanted to store 56 at location 100 and 47 at location 150 (while leaving every other location intact), you could type the following:

  DATA          @100, 56, @150, 47

If you have multiple DATA directives in your program, it may be difficult to remember exactly what locations contain the desired data. For this reason, the DATA directive can optionally be prefixed with a unique symbol name. This symbol becomes a constant that is set equal to the location number of the first byte of data within the directive. For example,

MyNumbers       DATA    @100, 72, 73

This would store the values 72 and 73 starting with location 100 and will create a constant, called MyNumbers, which is set equal to 100. Your program can then use the MyNumbers constant as a reference to the start of the data within a READ or WRITE command. Each DATA directive can have a unique symbol preceding it, allowing you to reference the data defined at different locations.

There may be a time when you wish to reserve a section of EEPROM for use by your BASIC code, but not necessarily store data there to begin with. To do this, simply specify a DataItem within parentheses, as in:

  DATA          @100, (20)

The above DATA directive will reserve 20 bytes of EEPROM, starting with location 100. It doesn't store any values there, rather it simply leaves the data as it is and increments DATA's location pointer by 20. A good reason to do this is when you have a program already downloaded into the BASIC Stamp that has created or manipulated some data in EEPROM. To protect that section of EEPROM from being overwritten by your next program (perhaps a new version of the same program) you can reserve the space as shown above. The EEPROM's contents from locations 100 to 119 will remain intact. NOTE: This only "reserves" the space for the program you are currently downloading; the BASIC Stamp does not know to "reserve" the space for future programs. In other words, make sure use this feature of the DATA directive in every program you download if you don't want to risk overwriting valuable EEPROM data.

It is important to realize that EEPROM is not overwritten during programming unless it is needed for program storage, or is filled by a DATA directive specifying data to be written. During downloading, EEPROM is always written in 16-byte sections if, and only if, any location within that section needs writing.

DATA can also store the same number in a block of consecutive locations. This is similar to reserving a block of EEPROM, above, but with a value added before the first parenthesis. For example,

  DATA          @100, 0 (20)

This statement writes the value 0 in all the EEPROM locations from 100 to 119.

A common use for DATA is to store strings; sequences of bytes representing text. PBASIC converts quoted text like "A" into the corresponding ASCII character code (65 in this case). To make data entry easier, you can place quotes around a whole chunk of text used in a DATA directive, and PBASIC will understand it to mean a series of bytes (see the last line of code below). The following three DATA directives are equivalent:

  DATA          72, 69, 76, 76, 79
  DATA          "H", "E", "L", "L", "O"
  DATA          "HELLO"

All three lines of code, above, will result in the numbers 72, 69, 76, 76, and 79 being stored into EEPROM upon downloading. These numbers are simply the ASCII character codes for "H", "E", "L", "L", and "O", respectively. See the example program for a demonstration of storing and reading multiple text strings.

The EEPROM is organized as a sequential set of byte-sized memory locations. By default, the DATA directive stores bytes into EEPROM. If you try to store a word-size value (ex: DATA 1125) only the lower byte of the value will be stored. This does not mean that you can't store word-sized values, however. A word consists of two bytes, called a low-byte and a high-byte. If you wanted to store the value 1125 using the DATA directive, simply insert the prefix "Word" before the number, as in:

  DATA          Word 1125

The directive above will automatically break the word-size value into two bytes and store them into two sequential EEPROM locations (the low-byte first, followed by the high-byte, or "Little Endian"). In this case, the low-byte is 101 and the high byte is 4 and they will be stored in locations 0 and 1, respectively. If you have multiple word-size values, you must prefix each value with "Word", as in:

  DATA          Word 1125, Word 2000

To retrieve a word-size value, you'll need to use the Word modifier with READ (only available in PBASIC 2.5 syntax). For example,

' {$PBASIC 2.5}

result          VAR     Word

Storage:
  DATA          Word 1125

Main:
  READ 0, Word result
  DEBUG DEC result
  END

This code would write the low-byte and high-byte of the number 1125 into locations 0 and 1 during download. When the program runs, the READ function (with the Word modifier) will retrieve the value out of EEPROM and then display the value on the screen. See the READ and WRITE commands for more information.

Finally, a DataItem may be defined using a simple expression with the binary operators as shown below:

MinLvl          CON     10

myLvl           VAR     Byte

Level1          DATA    MinLvl + 10
Level2          DATA    MinLvl * 5 + 21

Main:
  READ Level2, myLvl                    ' read EE location Level2
  DEBUG DEC myLvl                       ' show value of myLvl (71)
  END

Related commands: READ, WRITE and EEPROM ( [image] )


DATA Example

Syntax

NOTE: This is written for the BS2 and will run on any of the BS2-family modules. Modify the $STAMP directive (as required) before downloading to the BS2e, BS2sx, BS2p, BS2pe, or BS2px.

' DATA.BS2
' This program stores a number of large text strings into EEPROM with the
' DATA directive and then sends them, one character at a time via the DEBUG
' command.  This is a good demonstration of how to save program space by
' storing large amounts of data in EEPROM directly, rather than embedding
' the data into DEBUG commands.

' {$STAMP BS2}
' {$PBASIC 2.5}

idx             VAR     Word            ' current location number
phrase          VAR     Nib             ' current phrase number
char            VAR     Byte            ' character to print

' ----- Define all text phrases (out of order, just for fun!) -----
'
Text1           DATA    "Here is the first part of a large chunk of textual "
                DATA    "data ", CR, "that needs to be transmitted.  There's "
                DATA    "a 5 second delay", CR, "between text paragraphs. ", CR
                DATA    CR, 0

Text3           DATA    "The alternative (having multiple DEBUGs or SEROUTs, "
                DATA    "each ", CR, "with their own line of text) consumes "
                DATA    "MUCH more EEPROM ", CR, "(program) space. ", CR
                DATA    CR, 0

Text6           DATA    "The 255 is used by this program to indicate we've "
                DATA    "reached the ", CR, "End of Text.  The Main routine "
                DATA    "pauses in between each block of ", CR, "text, and then "
                DATA    "uses a LOOKUP command TO retrieve the location ", CR
                DATA    "of the next desired block of text to print. ", 0

Text4           DATA    CLS, "This program also demonstrates retrieving data "
                DATA    "out of order ", CR, "in relation TO the way it is "
                DATA    "stored in EEPROM.  Additionally, ", CR, "control codes "
                DATA    "(like carriage-returns, clear-screens, etc) can ", CR
                DATA    "be embedded right in the data, as it is here. ", CR
                DATA    CR, 0

Text2           DATA    "This is an example of a good way to save space in "
                DATA    "your ", CR, "BASIC Stamp's program by storing data "
                DATA    "into EEPROM and ", CR, "retrieving it, one byte at a "
                DATA    "time, and transmitting it ", CR, "with just a single "
                DATA    "DEBUG (or SEROUT) command.", CR, CR, 0

Text5           DATA    "The Print_It routine simply takes the Index variable, "
                DATA    "retrieves ", CR, "the character at the EEPROM location "
                DATA    "pointed to by it, and ", CR, "prints it to the screen "
                DATA    "unti it finds a byte with a value of 255.", CR, CR, 0

Main:
  DEBUG CLS                             ' Clear DEBUG window
  FOR phrase = 1 TO 6                   ' Print blocks one by one
    LOOKUP (phrase - 1),
           [Text1, Text2, Text3, Text4, Text5, Text6], idx
    GOSUB Print_It
    PAUSE 5000                          ' Pause for 5 seconds
  NEXT
  END

Print_It:
  DO
    READ idx, char                      ' Get next character
    idx = idx + 1                       ' Point to next location
    IF (char = 0) THEN EXIT             ' If 0, we're done with block
    DEBUG char                          ' Otherwise, transmit it
  LOOP
  RETURN                                ' Return to the main routine


 DEBUG

Examples

Syntax: DEBUG OutputData {,OutputData}

Function
Display information on the PC screen within the BASIC Stamp editor program. This command can be used to display text or numbers in various formats on the PC screen in order to follow program flow (called debugging) or as part of the functionality of the BASIC Stamp application.

  • OutputData is a variable/constant/expression* (0 - 65535) that specifies the information to output. Valid data can be ASCII characters (text strings and control characters), decimal numbers (0 - 65535), hexadecimal numbers ($0000 - $FFFF) or binary numbers (up to %1111111111111111). Data can be modified with special formatters as explained below.

* NOTE: Expressions are not allowed as arguments on the BS1. The only constant allowed for the BS1 DEBUG command is a text string.

Quick Facts
 | BS1 | BS2, BS2e, BS2sx, BS2p, and BS2pe | BS2px
Serial Protocol | Asychronous 4800 baud, N, 8, 1 Inverted polarity, Raw Data Custom packetized format | Asychronous 9600 baud, N, 8, 1 Inverted polarity, Raw Data | Asychronous 19.2 kBaud, N, 8, 1 Inverted polarity, Raw Data

Explanation
DEBUG provides a convenient way for your BASIC Stamp to send messages to the PC screen while running. The name "debug" suggests its most popular use; debugging programs by showing you the value of a variable or expression, or by indicating what portion of a program is currently executing. DEBUG is also a great way to rehearse programming techniques. Throughout this manual, we use DEBUG to give you immediate feedback on the effects of instructions. The following example demonstrates using the DEBUG command to send the text string message "Hello World!".

  DEBUG "Hello, World!"                         ' test Message

After you download this one-line program, the BASIC Stamp Editor will open a Debug terminal on your PC screen and wait for a response from the BASIC Stamp. A moment later, the phrase "Hello World!" will appear. Note that if you close the Debug terminal, your program keeps executing, but you can't see the DEBUG data anymore.

Multiple pieces of data can be sent with one DEBUG command by separating the data with commas (,). The following example produces exactly the same results as the example above.

  DEBUG "Hello, ", "World!"                     ' test Message

DEBUG can also print and format numbers (values) from both constants and variables. Please note that formatting the DEBUG output with the BS1 differs significantly from formatting the DEBUG output with the BS2 family. Please read the appropriate sections that follow carefully.

BASIC Stamp 1 Formatting

On the BS1, the DEBUG command, by default, displays numbers in the format "symbol = value" (followed by a carriage return), using the decimal number system. For example,

SYMBOL  x       = B2

Init:
  x = 75

Main:
  DEBUG x
  END

displays "x = 75" on the screen. To display the value, in decimal, without the "x =" text, use the decimal formatter (#) before the variable name. For example, the following code displays "75" on the screen.

SYMBOL  x       = B2

Init:
  x = 75

Main:
  DEBUG #x
  END

To display numbers in hexadecimal or binary form, use the $ or % formatter, respectively. The code below displays the same number in its hexadecimal and binary forms.

SYMBOL  x       = B2

Init:
  x = 75

Main:
  DEBUG $x, %x
  END

After running the above code, "X = $4B" and "X = %01001011" should appear on the screen. To display hexadecimal ($) or binary (%) values without the "symbol = " preface, use the # modifier as shown below:

SYMBOL  x       = B2

  x = 75
  DEBUG #x, "as HEX is ", #$x           ' displays "75 as HEX is $4B"

To display a number as its ASCII character equivalent, use the ASCII formatter (@). Typing DEBUG @x (in place of the DEBUG statement in the code above) would display "x = 'K'" on the screen.

Two pre-defined symbols, CR and CLS, can be used to send a carriage-return or clear-screen command to the Debug Terminal. The CR symbol will cause the Debug Terminal to start a new line and the CLS symbol will cause the Debug Terminal to clear itself and place the cursor at the top-left corner of the screen. The following code demonstrates this.

  DEBUG  "You can not see this.", CLS, "Here is line 1", CR, "Here is line 2"

When the above is run, the final result is "Here is line 1" on the first line of the screen and "Here is line 2" on the second line. You may or may not have seen "You can not see this." appear first. This is because it was immediately followed by a clear-screen symbol, CLS, which caused the display to clear the screen before displaying the rest of the information.

NOTE: The rest of this discussion does not apply to the BASIC Stamp 1.

BASIC Stamp 2 Series Formatting

On the all BASIC Stamps except the BS1, the DEBUG command, by default, displays everything as ASCII characters. What if you want to display a number? You might think the following example would do this:

x       VAR     Byte

Init:
  x = 65

Main:
  DEBUG x                               ' show value of x
  END

Since we set x equal to 65 (in line 2), you might expect the DEBUG line to display "65" on the screen. Instead of "65", however, you'll see the letter "A" if you run this example. The problem is that we never told the BASIC Stamp how to output x, and it defaults to ASCII (the ASCII character at position 65 is "A"). Instead, we need to tell it to display the "decimal form" of the number in X. We can do this by using the decimal formatter (DEC) before the variable. The example below will display "65" on the screen.

x       VAR     Byte

Init:
  x = 65

Main:
  DEBUG DEC x                           ' show decimal value of x
  END

In addition to decimal (DEC), DEBUG can display numbers in hexadecimal (HEX) and binary (BIN). See the table below for a complete list of formatters.

Expressions are allowed within the DEBUG command arguments as well. In the above code, DEBUG DEC x+25 would yield "95" and DEBUG DEC x*10/2-3 would yield "322".

Formatter | Description
? | Displays "symbol = x' + carriage return; where x is a number. Default format is decimal, but may be combined with conversion formatters (ex: BIN ? x to display "x = binary_number").
ASC ? | Displays "symbol = 'x'" + carriage return; where x is an ASCII character.
DEC{1..5} | Decimal, optionally fixed to 1 - 5 digits
SDEC{1..5} | Signed decimal, optionally fixed to 1 - 5 digits
HEX{1..4} | Hexadecimal, optionally fixed to 1 - 4 digits
SHEX{1..4} | Signed hexadecimal, optionally fixed to 1 - 4 digits
IHEX{1..4} | Indicated hexadecimal, optionally fixed to 1 - 4 digits
ISHEX{1..4} | Signed, indicated hexadecimal, optionally fixed to 1 - 4 digits ($ prefix)
BIN{1..16} | Binary, optionally fixed to 1 - 16 digits
SBIN{1..16} | Signed binary, optionally fixed to 1 - 16 digits
IBIN{1..16} | Indicated binary, optionally fixed to 1 - 16 digits
ISBIN{1..16} | Signed, indicated binary, optionally fixed to 1 - 16 digits
STR ByteArray | ASCII string from bytearray until byte = 0.
STR ByteArray {\L} | ASCII string consisting of n bytes from bytearray.
REP Byte\L | Display ASCII character n times.

As seen above, special versions of the DEC, HEX and BIN formatters allow for the display of indicated, signed and fixed-width numbers. The term "indicated" simply means that a special symbol is displayed, before the number, indicating what number system it belongs to. For example,

x       VAR     Byte

Init:
  x = 65

Main:
  DEBUG HEX x                           ' show hexadecimal value of x
  END

displays "41" (65, in decimal, is 41, in hexadecimal). You might see a problem here... unless you knew the number was supposed to be hexadecimal, you might think it was 41, in decimal... a totally different number. To help avoid this, use the IHEX formatter (the "I" stands for indicated). Changing the DEBUG line to read: DEBUG IHEX x would print "$41" on the screen. A similar formatter for binary also exists, IBIN, which prints a "%" before the number.

Signed numbers are preceded with a space ( ) or a minus sign (-) to indicate a positive or negative number, respectively. Normally, any number displayed by the BASIC Stamp is shown in its unsigned (positive) form without any indicator. The signed formatters allow you to display the number as a signed (rather than unsigned) value. NOTE: Only Word-sized variables can be used for signed number display. The code below demonstrates the difference in all three numbering schemes.

x       VAR     Word

Init:
  x = -65

Main:
  DEBUG "Signed:   ", SDEC  x, "  ", ISHEX x, "  ", ISBIN x, CR
  DEBUG "Unsigned: ", DEC  x, "  ", IHEX x, "  ", IBIN x
  END

This code will generate the display shown below:

Signed: -65 -$41 -%1000001
Unsigned: 65471 $FFBF %1111111110111111

The signed form of the number -65 is shown in decimal, hexadecimal and then in binary on the top line. The unsigned form, in all three number systems, is shown on the bottom line. If the unsigned form looks strange to you, it's because negative numbers are stored in twos-compliment format within the BASIC Stamp.

Suppose that your program contained several DEBUG instructions showing the contents of different variables. You would want some way to tell them apart. One possible way is to do the following:

x       VAR     Byte
y       VAR     Byte

Init:
  x = 100
  y = 250

Main:
  DEBUG "X = ", DEC x, CR               ' show decimal value of x
  DEBUG "Y = ", DEC y, CR               ' show decimal value of y
  END

but typing the name of the variables in quotes (for the display) can get a little tedious. A special formatter, the question mark (?), can save you a lot of time. The code below does exactly the same thing (with less typing):

x       VAR     Byte
y       VAR     Byte

Init:
  x = 100
  y = 250

Main:
  DEBUG DEC ? x                         ' show decimal value of x
  DEBUG DEC ? y                         ' show decimal value of y
  END

The display would look something like this:

x = 100
y = 250

The ? formatter always displays data in the form "symbol = value" (followed by a carriage return). In addition, it defaults to displaying in decimal, so we really only needed to type: DEBUG ? x for the above code. You can, of course, use any of the three number systems. For example: DEBUG HEX ? x or DEBUG BIN ? y.

It's important to note that the "symbol" it displays is taken directly from what appears to the right of the ?. If you were to use an expression, for example: DEBUG ? x*10/2+3 in the above code, the display would show: "x*10/2+3 = 503".

A special formatter, ASC, is also available for use only with the ? formatter to display ASCII characters, as in: DEBUG ASC ? x.

What if you need to display a table of data; multiple rows and columns? The Signed/Unsigned code (above) approaches this but, if you notice, the columns don't line up. The number formatters (DEC, HEX and BIN) have some useful variations to make the display fixed-width. Up to 5 digits can be displayed for decimal numbers. To fix the value to a specific number of decimal digits, you can use DEC1, DEC2, DEC3, DEC4 or DEC5. For example:

x       VAR     Byte

Init:
  x = 165

Main:
  DEBUG DEC5 x                          ' show decimal value of x
  END                                   '  in 5 digits

displays "00165". Notice that leading zeros? The display is "fixed" to 5 digits, no more and no less. Any unused digits will be filled with zeros.

Using DEC4 in the same code would display "0165". DEC3 would display "165". What would happen if we used DEC2? Regardless of the number, the BASIC Stamp will ensure that it is always the exact number of digits you specified. In this case, it would truncate the "1" and only display "65".

Using the fixed-width version of the formatters in the Signed/Unsigned code above, may result in the following code:

x       VAR     Word

Init:
  x = -65

Main:
  DEBUG "Signed:   ", SDEC5 x, "  ", ISHEX4 x, "  ", ISBIN16 x, CR
  DEBUG "Unsigned: ", DEC5 x, "  ", IHEX4 x, "  ", IBIN16 x
  END

and displays:

Signed: -00065 -$0041 -%0000000001000001
Unsigned: 65471 $FFBF %1111111110111111

Note: The columns don't line up exactly (due to the extra "sign" characters in the first row), but it certainly looks better than the alternative.

Displaying Strings (Byte Arrays)

If you have a string of characters to display (a byte array), you can use the STR formatter to do so. The STR formatter has two forms (as shown in the table above) for variable-width and fixed-width data. The example below is the variable-width form.

alpha   VAR     Byte(5)

Init:
  alpha(0) = "A"
  alpha(1) = "B"
  alpha(2) = "C"
  alpha(3) = "D"
  alpha(4) = 0

Main:
  DEBUG STR alpha, CR                   ' display "ABCD"
  END

This code displays "ABCD" on the screen. In this form, the STR formatter displays each character contained in the byte array until it finds a character that is equal to 0 (value 0, not "0"). This is convenient for use with the SERIN command's STR formatter, which appends 0's to the end of variable-width character string inputs. NOTE: If your byte array doesn't end with 0, the BASIC Stamp will read and output all RAM register contents until it finds a 0 or until it cycles through all RAM locations.

To specify a fixed-width format for the STR formatter, use the form STR alpha\n; where alpha is the byte array and n is the number of characters to print. Changing the DEBUG line in the example above to: DEBUG STR alpha\2 would display "AB" on the screen.

If you need to display the same ASCII character multiple times, the REP (repeat) formatter can help. REP takes the form: REP x\n ;where x is the character and n is the number of times to repeat it. For example:

  DEBUG REP "-"\10

would display 10 hyphens on the screen, "----------".

Since individual DEBUG instructions can grow to be fairly complicated, and since a program can contain many DEBUGs, you'll probably want to control the character positioning of the Debug Terminal screen. DEBUG supports a number of different control characters, some with pre-defined symbols. The Debug Terminal in the Windows® version of the editor supports all the control characters shown below, while the DOS version only supports a few of them.

Some of the control characters have pre-defined symbols associated with them. In your DEBUG commands, you can use those symbols, for example: DEBUG "Hello", CR displays "Hello" followed by a carriage return. You can always use the ASCII value for any of the control characters, however. For example: DEBUG "Hello", 13 is exactly the same as the code above.

The Move To control character is perhaps the most unique of the set. If the Debug Terminal receives this character, it expects to see an x and y position value to follow (in the next two characters received). The following line moves the cursor to column number 4 in row number 5 and displays "Hello":

  DEBUG CRSRXY, 4, 5, "Hello"

The upper-left cursor position is 0, 0 (that is column 0, line 0). The right-most cursor positions depend on the size of the Debug Terminal window (which is user adjustable). If a character position that is out of range is received, the Debug Terminal wraps back around to the opposite side of the screen.

The Clear EOL (end of line) control character clears the characters that appear to the right of, and on, the cursor's current position. The cursor is not moved by this action.

The Clear Down control character clears the characters that appear below, and on, the cursor's current line. The cursor is not moved by this action.

Name | Symbol | ASCII Value | Description
Clear Screen | CLS 1 | 0 | Clear the screen and place cursor at home position.
Home | HOME | 1 | Place cursor at home in upper-left corner of the screen.
Move To (x, y) | CRSRXY 2 | 2 | Move cursor to specified location (column, line). Must be followed by two values (x and then y)
Cursor Left | CRSRLF 2 | 3 | Move cursor one character to left.
Cursor Right | CRSRRT 2 | 4 | Move cursor one character to right.
Cursor Up | CRSRUP 2 | 5 | Move cursor one character up.
Cursor Down | CRSRDN 2 | 6 | Move cursor one character down.
Bell | BELL | 7 | Beep the PC speaker.
Backspace | BKSP | 8 | Back up cursor to left one space.
Tab | TAB | 9 | Tab to the next column.
Line Feed | LF | 10 | Move cursor down one line.
Clear to End of Line | CLREOL 2 | 11 | Clear line contents to the right of cursor.
Clear Down | CLRDN 2 | 12 | Clear screen contents below cursor.
Carriage Return | CR 1 | 13 | Move cursor to the first column of the next line (shift any data on the right down to that line as well)
Move To Column X | CRSRX 2 | 14 | Move cursor to specified column. Must be followed by byte value (x) for the column (0 is the left-most column)
Move To Line Y | CRSRY 2 | 15 | Move cursor to specified line. Must be followed by byte value (y) for the line (0 is the top-most line)

1 Supported by BS1 DEBUG command (others not supported).
2 This control character only works with the Windows® version of the editor software.

In the BS2 family, DEBUG is actually a special case of the SEROUT instruction. It is set for inverted (RS-232-compatible) serial output through the programming connector (the SOUT pin) at 9600 baud (BS2, BS2e, BS2sx, BS2p, and BS2pe) or 19.2 kBaud (BS2px), no parity, 8 data bits, and 1 stop bit. For example,

  DEBUG "Hello"

is exactly like:

  SEROUT 16, $4054, ["Hello"]

in terms of function (on a BS2). The DEBUG line actually takes less program space, and is obviously easier to type.

You may view DEBUG's output using a terminal program set to the above parameters, but you may have to modify either your carrier board or the serial cable to temporarily disconnect pin 3 of the BASIC Stamp (pin 4 of the DB-9 connector). See the SEROUT command for more detail.

Another method to decrease program space is to reduce the number of DEBUG instructions by spreading DEBUG data across multiple lines. To do this, each line that wraps around must end with a comma as in the example below:

  DEBUG "This is line 1", CR,
        "This is line 2"
The example above works identically to, but uses less program space than this version:
  DEBUG "This is line 1", CR
  DEBUG "This is line 2"

Note that spreading a DEBUG statement across multiple lines requires the declaration of PBASIC 2.5 syntax.

Related commands: DEBUGIN ( [image] ), and SEROUT


DEBUG / DEBUGIN Example

This demonstration illustrates sending information to and retrieving information from the DEBUG terminal window. Also illustrated is the unique ability to accept any valid numeric format using the NUM modifier. To enter binary or hexadecimal values, the number must be preceded by "%" (binary) or "$" (hex).

NOTE: This is written for the BS2 and will run on any of the BS2-family modules. Modify the $STAMP directive (as required) before downloading to the BS2e, BS2sx, BS2p, BS2pe, or BS2px.

' DEBUG_DEBUGIN.BS2
' This program demonstrates the ability to accept user input from the
' Debug terminal, and to accept numeric entry in any valid format.

' {$STAMP BS2}
' {$PBASIC 2.5}

myNum           VAR     Word

Main:
  DO
    DEBUG CLS, "Enter any number: "     ' prompt user
    DEBUGIN SNUM myNum                  ' accept number in any format

    DEBUG CRSRXY, 0, 2,                 ' display in all formats
          SDEC ? myNum,
          SHEX ? myNum,
          SBIN ? myNum
    PAUSE 3000
  LOOP                                  ' do it again
  END


DEBUG Examples

DEBUG
' DEBUG.BAS
' Demonstrates the use of the BS1 DEBUG instruction. The BS1 DEBUG defaults
' to decimal output and provides the name of the variable unless directed
' otherwise.

' {$STAMP BS1}
' {$PBASIC 1.0}

SYMBOL  addr    = B2                    ' EEPROM address
SYMBOL  char    = B3                    ' character to print

Messages:
  EEPROM ("The Parallax BASIC Stamp 1", 13, 0)

Main:
  char = "A"

  DEBUG CLS                             ' clear screen
  DEBUG char, CR                        ' standard decimal output
  DEBUG $char, CR                       ' hex ($)
  DEBUG %char, CR                       ' binary (%)
  DEBUG #char, CR                       ' value only (#)
  DEBUG "Your grade is: "               ' string
  DEBUG #@char, CR, CR                  ' value only, as ASCII (@)

  addr = 0                              ' point to message
  GOSUB Print_It
  DEBUG "The Parallax BASIC Stamp 1"    ' same message -- fast

  END

' This subroutine can be used to transmit a string stored in EEPROM to
' the DEBUG window. Note that this is very SLOW as for each character the
' entire DEBUG packet (97 bytes!) must be transmitted -- which means that
' you can transmit about five characters per second with this method.
'
' A better alternative to this subroutine is to BRANCH to DEBUG statements
' containing the entire string.

Print_It:
  READ addr, char                       ' get character from EEPROM
  addr = addr + 1                       ' point to next location
  IF char = 0 THEN Print_Done           ' if 0, terminate printing
  DEBUG #@char                          ' character to DEBUG window
  GOTO Print_It                         ' loop again

Print_Done:
  RETURN

This demonstration illustrates sending information to and retrieving information from the DEBUG terminal window. Also illustrated is the unique ability to accept any valid numeric format using the NUM modifier. To enter binary or hexadecimal values, the number must be preceded by "%" (binary) or "$" (hex).

NOTE: This is written for the BS2 and will run on any of the BS2-family modules. Modify the $STAMP directive (as required) before downloading to the BS2e, BS2sx, BS2p, BS2pe, or BS2px.

' DEBUG_DEBUGIN.BS2
' This program demonstrates the ability to accept user input from the
' Debug terminal, and to accept numeric entry in any valid format.

' {$STAMP BS2}
' {$PBASIC 2.5}

myNum           VAR     Word

Main:
  DO
    DEBUG CLS, "Enter a any number: "   ' prompt user
    DEBUGIN SNUM myNum                  ' accept number in any format

    DEBUG CRSRXY, 0, 2,                 ' display in all formats
          SDEC ? myNum,
          SHEX ? myNum,
          SBIN ? myNum
    PAUSE 3000
  LOOP                                  ' do it again
  END


 DEBUGIN

{$PBASIC 2.5} Example

Syntax: DEBUGIN InputData

Function
Retrieve information from the user via the DEBUG terminal window within the BASIC Stamp editor program.

  • InputData is list of variables and formatters that tells DEBUGIN what to do with incoming data. DEBUGIN can store data in a variable or array, interpret numeric text (decimal, binary, or hex) and store the corresponding value in a variable, wait for a fixed or variable sequence of bytes, or ignore a specified number of bytes. These actions can be combined in any order in the InputData list.

Quick Facts
 | BS2, BS2e, BS2sx, BS2p, and BS2pe | BS2px
Serial Protocol | Asychronous 9600 baud, N, 8, 1 Inverted polarity, Raw Data | Asychronous 19.2 kBaud, N, 8, 1 Inverted polarity, Raw Data

Explanation
DEBUGIN provides a convenient way for your BASIC Stamp accept input from the use via the DEBUG terminal. DEBUGIN can wait for, filter and convert incoming data in powerful ways, using the same techniques and modifiers as SERIN.

This simple example waits for a number from the user, then prints a message the specified number of times:

lines   VAR     Nib
idx     VAR     Nib

Main:
  DEBUG CLS, "How many lines to print (1 - 5)? --> "
  DEBUGIN DEC1 lines

  IF ((lines >= 1) AND (lines <= 5)) THEN
    DEBUG CR, CR
    FOR idx = 1 TO lines                        ' print message specified times
      DEBUG DEC1 idx, ". "
      DEBUG "BASIC Stamp!", CR
    NEXT
    END                                         ' end of program
  ELSE
    DEBUG CR, "Invalid entry!"                  ' warning message
    PAUSE 2000                                  ' wait 2 seconds
    GOTO Main                                   ' get another entry
  ENDIF

After you download this program, the BASIC Stamp Editor will open a Debug terminal on your PC screen and wait for an entry from the user. Since the DEC1 modifier is used with DEBUGIN, the program will ignore all keys except "0" - "9". If the value entered is between 1 and 5, the message will be printed, otherwise the program will display an "Invalid entry" message, then loop back and wait for another entry.

DEBUGIN is actually a special case of the SERIN instruction. It is set for inverted (RS-232-compatible) serial output through the programming connector (the SIN pin) at 9600 baud (BS2, BS2e, BS2sx, BS2p, and BS2pe) or 19.2 kBaud (BS2px), no parity, 8 data bits, and 1 stop bit. For example,

  DEBUGIN DEC1 lines

is exactly like:

  SERIN 16, $4054, [DEC1 lines]

in terms of function (on a BS2). The DEBUGIN line actually takes less program space, and is obviously easier to type.

The tables below list all the available conversion formatters and special formatters available to the DEBUGIN command. See the SERIN command for additional information and examples of their use.

Conversion Formatter | Type of Number | Numeric Characters Accepted | Notes
DEC{1..5} | Decimal, optionally limited to 1 - 5 digits | 0 through 9 | 1
SDEC{1..5} | Signed decimal, optionally limited to 1 - 5 digits | -, 0 through 9 | 1,2
HEX{1..4} | Hexadecimal, optionally limited to 1 - 4 digits | 0 through 9, A through F | 1,3
SHEX{1..4} | Signed hexadecimal, optionally limited to 1 - 4 digits | -, 0 through 9, A through F | 1,2,3
IHEX{1..4} | Indicated hexadecimal, optionally limited to 1 - 4 digits | $, 0 through 9, A through F | 1,3,4
ISHEX{1..4} | Signed, indicated hexadecimal, optionally limited to 1 - 4 digits | -, $, 0 through 9, A through F | 1,2,3,4
BIN{1..16} | Binary, optionally limited to 1 - 16 digits | 0, 1 | 1
SBIN{1..16} | Signed binary, optionally limited to 1 - 16 digits | -, 0, 1 | 1,2
IBIN{1..16} | Indicated binary, optionally limited to 1 - 16 digits | %, 0, 1 | 1,4
ISBIN{1..16} | Signed, indicated binary, optionally limited to 1 - 16 digits | -, %, 0, 1 | 1,2,4
NUM | Generic numeric input; hex or binary number must be indicated | $, %, 0 through 9, A through F | 1,3,4
SNUM | Similar to NUM with value treated as signed with range -32768 to +32767 | -, $, %, 0 through 9, A through F | 1,2,3,4

  1. All numeric conversions will continue to accept new data until receiving either the specified number of digits (ex: three digits for DEC3) or a non-numeric character.
  2. To be recognized as part of a number, the minus sign (-) must immediately precede a numeric character. The minus sign character occurring in non-numeric text is ignored and any character (including a space) between a minus and a number causes the minus to be ignored.
  3. The hexadecimal formatters are not case-sensitive; "a" through "f" means the same as "A" through "F".
  4. Indicated hexadecimal and binary formatters ignore all characters, even valid numerics, until they receive the appropriate prefix ($ for hexadecimal, % for binary). The indicated formatters can differentiate between text and hexadecimal (ex: ABC would be interpreted by HEX as a number but IHEX would ignore it unless expressed as $ABC). Likewise, the binary version can distinguish the decimal number 10 from the binary number %10. A prefix occurring in non-numeric text is ignored, and any character (including a space) between a prefix and a number causes the prefix to be ignored. Indicated, signed formatters require that the minus sign come before the prefix, as in -$1B45.

Special Formatter | Action
STR ByteArray \L {\E} | Input a character string of length L into an array. If specified, an end character E causes the string input to end before reaching length L. Remaining bytes are filled with 0s (zeros).
WAITSTR ByteArray {\L} | Wait for a sequence of bytes matching a string stored in an array variable, optionally limited to L characters. If the optional L argument is left off, the end of the array-string must be marked by a byte containing a zero (0).
SKIP Length | Ignore Length bytes of characters.

Special Formatter | Action
SPSTR L | Buffer length L bytes (up to 126) of serial characters to Scratchpad RAM, starting at location 0. Use GET to retrieve the characters.

idx     VAR     Nib
char    VAR     Byte

Setup:
  DEBUG CLS, "Enter (4-character) passcode: "

Main:
  DEBUGIN SPSTR 4
  DEBUG CLS, "Checking: "
  FOR idx = 0 TO 3
    GET idx, char
    DEBUG char
  NEXT
  END

The example above will redirect four characters from the DEBUG terminal input to Scratchpad locations 0 - 3.

Related commands: DEBUG and SERIN


 DO...LOOP

{$PBASIC 2.5} Example

Syntax:

DO { WHILE | UNTIL condition(s) }
Statement(s)
LOOP { WHILE | UNTIL condition(s) }

Function
Create a repeating loop that executes the program lines between DO and LOOP, optionally testing before or after the loop statements

  • Condition is an optional variable/constant/expression (0 - 65535) which determines whether the loop will run or terminate.
  • Statement is any valid PBASIC statement.

Quick Facts
 | BS2 Family
Maximum nested loops | 16
WHILE Condition evaluation | Run loop if Condition evaluates as True (1)
UNTIL Condition evaluation | Terminate loop if Condition evaluates as True (1)

Explanation
DO...LOOP loops let your program execute a series of instructions indefinitely, or until a specified condition terminates the loop. The simplest form is shown here:

Error_Message:
  DO
    DEBUG "Error...", CR
    PAUSE 2000
  LOOP

In this example the error message will be printed on the DEBUG screen every two seconds until the BASIC Stamp is reset. Simple DO...LOOP loops can be terminated with EXIT. For example:

Error_Message:
  DO
    DEBUG "Error...", CR
    PAUSE 1000
    IF (AckPin = 0) THEN EXIT                   ' wait for user button press
  LOOP
  GOTO Initialize                               ' re-initialize system

In this case the loop will continue until the pin called AckPin is pulled low, then the the loop will terminate and continue at the line GOTO Initialize.

More often than not, you will want to test some condition to determine whether the loop code should run or continue to run. A loop that tests the condition before running loop code is constructed like this:

reps    VAR     Nib

Print_Stars:
  DO WHILE (reps < 3)                           ' test before loop statements
    DEBUG "*"
    reps = reps + 1
  LOOP

In this program the loop code DEBUG "*" will not run unless the WHILE condition evaluates as True. Another way to write the loop is like this:

reps    VAR     Nib

Print_Stars:
  DO
    DEBUG "*"
    reps = reps + 1
  LOOP UNTIL (reps >= 3)                        ' test after loop statements

The difference is that with this loop, the loop statements will always run at least once before the condition is tested and will continue to as long as the UNTIL condition evaluates as False.

Note that WHILE (loop runs while TRUE) and UNTIL (loop runs until True) tests can be interchanged, but are generally used as illustrated above.

Related commands: EXIT ( [image] ) and FOR...NEXT


DO...LOOP Example

{$PBASIC 2.5} Syntax

NOTE: This is written for the BS2 and will run on any of the BS2-family modules. Modify the $STAMP directive (as required) before downloading to the BS2e, BS2sx, BS2p, BS2pe, or BS2px.

' DO-LOOP.BS2
' This program creates a little guessing game.  It starts by creating
' a (psuedo) random number between 1 and 10.  The inner loop will run
' until the answer is guessed or 10 tries have been attempted.  The
' outer loop has no condition and will cause the inner loop code to
' run until the BASIC Stamp is reprogrammed.

' {$STAMP BS2}
' {$PBASIC 2.5}

rVal            VAR     Word            ' random value
answer          VAR     Byte            ' game answer
guess           VAR     Byte            ' player guess
tries           VAR     Nib             ' number of tries

Main:
  DO
    RANDOM rVal
    answer = rVal.LOWBYTE */ 10 + 1     ' create 1 - 10 answer
    tries = 0

    DO                                  ' get answer until out of tries
      DEBUG CLS,
            "Guess an number (1 - 10): ",
            CLREOL
      DEBUGIN DEC guess                 ' get new guess
      tries = tries + 1                 ' update tries count
    LOOP UNTIL ((tries = 10) OR (guess = answer))

    IF (guess = answer) THEN            ' test reason for loop end
      DEBUG CR, "You got it!"
    ELSE
      DEBUG CR, "Sorry ... the answer was ", DEC answer, "."
    ENDIF
    PAUSE 1000
  LOOP                                  ' run again
  END


 DTMFOUT

Example

Syntax: DTMFOUT Pin, {OnTime, OffTime,} [Tone {, Tone...}]

Function
Generate dual-tone, multi-frequency tones (DTMF, i.e., telephone "touch" tones).

  • Pin is a variable/constant/expression (0 - 15) that specifies the I/O pin to use. This pin will be set to output mode during generation of tones and set to input mode afterwards.
  • OnTime is an optional variable/constant/expression (0 - 65535) specifying a duration of the tone. The unit of time and the default time for OnTime is described below.
  • OffTime is an optional variable/constant/expression (0 - 65535) specifying the length of silent pause after a tone (or between tones, if multiple tones are specified). The unit of time and the default time for OffTime is described below.
  • Tone is a variable/constant/expression (0 - 15) specifying the DTMF tone to generate. Tones 0 through 11 correspond to the standard layout of the telephone keypad, while 12 through 15 are the fourth-column tones used by phone test equipment and in ham-radio applications.

Quick Facts
 | BS2 / BS2e | BS2sx | BS2p | BS2pe | BS2px
Default OnTime | 200 ms | 80 ms | 55 ms | 196 ms | 34 ms
Default OffTime | 50 ms | 50 ms | 50 ms | 50 ms | 50 ms
Units in OnTime | 1 ms | 0.4 ms | 0.265 ms | 1 ms | 0.166 ms
Units in OffTime | 1 ms | 1 ms | 1 ms | 1 ms | 1 ms

Explanation
DTMF tones are used to dial the phone or remotely control certain radio equipment. The BASIC Stamp can generate these tones digitally using the DTMFOUT instruction.

This figure shows how to connect an audio amplifier or speaker to hear these tones:

and this figure shows how to connect the BASIC Stamp to the phone line:

The following DTMFOUT instruction will generate DTMF tones on I/O pin 0:

  ' Call Parallax
  DTMFOUT 0, [1, 9, 1, 6, 6, 2, 4, 8, 3, 3, 3]

If the BASIC Stamp is connected to the phone line properly, the above command would be equivalent to dialing 1-916-624-8333 from a phone keypad. If you wanted to slow the pace of the dialing to accommodate a noisy phone line or radio link, you could use the optional OnTime and OffTime values:

  ' Call Parallax; dial slowly.
  DTMFOUT 0, 500, 100, [1, 9, 1, 6, 6, 2, 4, 8, 3, 3, 3]
In this example, on a BS2 the OnTime is set to 500 ms (1/2 second) and OffTime to 100 ms (1/10th second).

Tone Value | Corresponding Telephone Key
0 - 9 | Digits 0 through 9
10 | Star (*)
11 | Pound (#)
12 - 15 | Fourth column tones A through D

The BASIC Stamp microcontroller is a purely digital device. DTMF tones are analog waveforms, consisting of a mixture of two sine waves at different audio frequencies. So how does a digital device generate analog output? The BASIC Stamp creates and mixes the sine waves mathematically, then uses the resulting stream of numbers to control the duty cycle of a very fast pulse-width modulation (PWM) routine. So what's actually coming out of the I/O pin is a rapid stream of pulses. The purpose of the filtering arrangements shown in the figures above is to smooth out the high-frequency PWM, leaving only the lower frequency audio behind.

Keep this in mind if you want to interface BASIC Stamp's DTMF output to radios and other equipment that could be adversely affected by the presence of high-frequency noise on the input. Make sure to filter the DTMF output thoroughly. The circuits above are only a starting point; you may want to use an active low-pass filter with a roll-off point around 2 kHz.

Related commands: SOUND ( [image] ) and FREQOUT ( [image] )


DTMFOUT Example

Syntax

NOTE: This is written for the BS2 and will run on any of the BS2-family modules. Modify the $STAMP directive (as required) before downloading to the BS2e, BS2sx, BS2p, BS2pe, or BS2px.

' DTMFOUT.BS2
' This demo program is a rudimentary memory dialer. Since DTMF digits fit
' within a nibble (four bits), the program below packs two DTMF digits into
' each byte of three EEPROM data tables. The end of a phone number is marked
' by the nibble $F, since this is not a valid phone-dialing digit.
' Conditional compilation sets the timing adjustment factor so that the
' output will sound the same on any BS2 module.

' {$STAMP BS2}
' {$PBASIC 2.5}

Spkr            PIN     10              ' DTMF output on pin 10

#SELECT $STAMP
  #CASE BS2, BS2E, BS2PE
    TmAdj       CON     $100            ' x 1.0 (time adjust)
  #CASE BS2SX
    TmAdj       CON     $280            ' x 2.5
  #CASE BS2P
    TmAdj       CON     $3C5            ' x 3.77
  #CASE BS2PX
    TmAdj       CON     $605            ' x 6.02
#ENDSELECT

eeLoc           VAR     Byte            ' EEPROM address of stored number
eeByte          VAR     Byte            ' Byte containing two DTMF digits
dtDig           VAR     eeByte.NIB1     ' Digit to dial
phone           VAR     Nib             ' Pick a phone #
hiLo            VAR     Bit             ' Bit to select upper and lower nib

Parallax        DATA    $19,$16,$62,$48,$33,$3F  ' Phone: 1-916-624-8333
ParallaxFax     DATA    $19,$16,$62,$48,$00,$3F  ' Phone: 1-916-624-8003
Information     DATA    $15,$20,$55,$51,$21,$2F  ' Phone: 1-520-555-1212

Main:
  FOR phone = 0 TO 2
    ' retrieve address
    LOOKUP phone, [Parallax, ParallaxFax, Information], eeLoc
    GOSUB Dial_Number
    PAUSE 2000
  NEXT
  END

Dial_Number:
  DO
    READ eeLoc, eeByte                  ' Retrieve byte from EEPROM
    eeLoc = eeLoc + 1                   ' point to next pair of digits
    FOR hiLo = 0 TO 1                   ' Dial upper and lower digits
      IF (dtDig = $F) THEN EXIT         ' Hex $F is end-of-number flag
      DTMFOUT Spkr,                     ' dial digit
              150 */ TmAdj, 25, [dtDig] ' 150 ms on, 25 ms off
      eeByte = eeByte << 4              ' Shift in next digit
    NEXT
  LOOP UNTIL (dtDig = $F)
  RETURN


 EEPROM

Example

Syntax: EEPROM {Location,} ( DataItem {, DataItem,...})

Function
Write data to the EEPROM during program download.

  • Location is an optional variable/constant (0 - 255) that specifies the starting location in the EEPROM at which data should be stored. If no location is given, data is written starting at the next available location.
  • DataItem is a constant (0 - 255) to be stored in EEPROM.

Explanation
When you download a program into the BASIC Stamp 1, it is stored in the EEPROM starting at the highest address (255) and working towards the lowest address. Most programs don't use the entire EEPROM, so the lower portion is available for other uses. The EEPROM directive allows you to define a set of data to store in the available EEPROM locations. It is called a "directive" rather than a "command" because it performs an activity at compile-time rather than at run-time (i.e., the EEPROM directive is not downloaded to the BASIC Stamp 1, but the data it contains is downloaded).

The simplest form of the EEPROM directive is something like the following:

EEPROM  (100, 200, 52, 45)

This example, when downloaded, will cause the values 100, 200, 52 and 45 to be written to EEPROM locations 0, 1, 2 and 3, respectively. You can then use the READ and WRITE commands in your code to access these locations and the data you've stored there

The EEPROM directive uses a counter, called a pointer, to keep track of available EEPROM addresses. The value of the pointer is initially 0. When a program is downloaded, the EEPROM directive stores the first byte value at the current pointer address, then increments (adds 1 to) the pointer. If the program contains more than one EEPROM directive, subsequent EEPROM directives start with the pointer value left by the previous EEPROM directive. For example, if the program contains:

EEPROM  (72, 69, 76, 76, 79)
EEPROM  (104, 101, 108, 108, 111)

The first EEPROM directive will start at location 0 and increment the pointer for each data value it stores (1, 2, 3, 4 and 5). The second EEPROM directive will start with the pointer value of 5 and work upward from there. As a result, the first 10 bytes of EEPROM will look like the following:

 | EEPROM Location (address)
 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
Contents | 72 | 69 | 76 | 76 | 79 | 104 | 101 | 108 | 108 | 111

What if you don't want to store values starting at location 0? Fortunately, the EEPROM directive has an option to specify the next location to use. You can specify the next location number (to set the pointer to) by using the optional Location argument before the list of DataItems. The following code writes the same data in the table above to locations 50 through 59:

EEPROM  50, (72, 69, 76, 76, 79, 104, 101, 108, 108, 111)

In this example, the Location argument is given and tells the EEPROM directive to store the following DataItem(s) starting at location 50. The DataItems in the list are stored in their respective locations (50, 51, 52... 59).

It is important to realize that the entire BASIC Stamp 1 EEPROM is overwritten during programming. Any EEPROM location not containing a PBASIC program or DataItems from an EEPROM directive is written with a 0.

A common use for EEPROM is to store strings; sequences of bytes representing text. PBASIC converts quoted text like "A" into the corresponding ASCII character code (65 in this case). To make data entry easier, you can place quotes around a whole chunk of text used in a EEPROM directive, and PBASIC will understand it to mean a series of bytes (see the last line of code below). The following three EEPROM directives are equivalent:

EEPROM  (72, 69, 76, 76, 79)
EEPROM  ("H", "E", "L", "L", "O")
EEPROM  ("HELLO")

All three lines of code, above, will result in the numbers 72, 69, 76, 76, and 79 being stored into EEPROM upon downloading. These numbers are simply the ASCII character codes for "H", "E", "L", "L", and "O", respectively. See the example program for a demonstration of storing and reading multiple text strings.

The EEPROM is organized as a sequential set of byte-sized memory locations. The EEPROM directive only stores bytes into EEPROM. If you try to store a word-size value, for example: EEPROM (1125), only the lower byte of the value will be stored (in this case, 101). This does not mean that you can't store word-sized values, however. A word consists of two bytes, called a low-byte and a high-byte. If you wanted to store the value 1125 using the EEPROM directive you'll have to calculate the low-byte and the high-byte and insert them in the list in the proper order, as in:

EEPROM  (101, 4)

The directive above will store the two bytes into two sequential EEPROM locations (the low-byte first, followed by the high-byte). We calculated this in the following manner: 1) high-byte is INT(value / 256) and 2) low-byte is value - (high-byte * 256).

To retrieve a word-size value, you'll need to use two READ commands and a word-size variable. For example,

SYMBOL  result  =  W1                   ' word-sized variable
SYMBOL  resLo   =  B2                   ' B2 is low-byte of W1
SYMBOL  resHi   =  B3                   ' B3 is high-byte of W1

EEPROM  (101, 4)

Main:
  READ 0, resLo
  READ 1, resHi
  DEBUG #result
  END

This code would write the low-byte and high-byte of the number 1125 into locations 0 and 1 during download. When the program runs, the two READ commands will read the low-byte and high-byte out of EEPROM (reconstructing it in a word-size variable) and then display the value on the screen. See the READ and WRITE commands for more information.

Related commands: READ, WRITE and DATA ( [image] )


EEPROM Example

Syntax
' EEPROM.BS1
' This program stores a couple of text strings into EEPROM with the EEPROM
' directive and then sends them, one character at a time via the SEROUT
' command.  This is a good demonstration of how to save program space by
' storing large amounts of data in EEPROM directly, rather than embedding
' the data into SEROUT commands.

' {$STAMP BS1}
' {$PBASIC 1.0}

SYMBOL  SOut            = 0             ' serial output

SYMBOL  idx             = B2            ' Holds current location number
SYMBOL  phrase          = B3
SYMBOL  char            = B4            ' Holds current character to print

Phrases:
  EEPROM ("Here is a long message that needs to be transmitted.", 13, 0)
  EEPROM ("Here is some more text to be transmitted.", 13, 0)

Main:
  idx = 0
  FOR phrase = 1 TO 2                   ' select phrase
    GOSUB Print_It                      ' print the phrase
    PAUSE 3000                          ' Pause for 3 seconds
  NEXT
  END

Print_It:
  READ idx, char                        ' get next character
  idx = idx + 1                         ' point to next EEPROM location
  IF char = 0 THEN Print_Done           ' if 0, we're done with this block
  SEROUT SOut, N2400, (char)            ' otherwise, transmit it
  'DEBUG #@char                         ' -- for demo with DEBUG (slower)
  GOTO Print_It

Print_Done:
  RETURN                                ' return to caller


 END

Syntax: END

Function
End the program, placing the BASIC Stamp into low-power mode indefinitely. This is equivalent to having a program that does not loop continuously; once the BASIC Stamp reaches the end of the PBASIC program, it enters low-power mode indefinitely. The END command is optional, but recommended.

Quick Facts
 | BS1 | BS2 | BS2e | BS2sx | BS2p | BS2pe | BS2px
Approximate current draw @ 5 VDC during Run * | 1 mA | 3 mA | 25 mA | 60 mA | 40 mA | 15 mA | 55 mA
Approximate current draw @ 5 VDC during END * | 25 µA | 50 µA | 200 µA | 500 µA | 350 µA | 36 µA | 450 µA
* Note: This is an approximate value, not including loads on the I/O pins.

Explanation
END puts the BASIC Stamp into its inactive, low-power mode. In this mode the Stamp's current draw (excluding loads driven by the I/O pins) is reduced to the amount shown above. END keeps the BASIC Stamp inactive until the reset line is activated, the power is cycled off and back on or the PC downloads another program.

Just as with the SLEEP command, pins will retain their input or output settings after the BASIC Stamp is deactivated by END. For example, if the BASIC Stamp is powering an LED when END executes, the LED will stay lit after END, but every 2.3 seconds, there will be a visible wink of the LED as the output pin switches to the input direction for 18 ms.

Related command: STOP ( [image] )


 EXIT

{$PBASIC 2.5} Example

Syntax: EXIT

Function
Causes the immediate termination of a loop construct (FOR...NEXT, DO...LOOP).

Explanation
The EXIT command allows a program to terminate a loop structure before the loop limit test is executed. While not required, EXIT is usually used as part of an IF..THEN construct to test a secondary condition for terminating a loop, or for testing a termination condition of an unconditional DO..LOOP structure.

col     VAR     Byte
row     VAR     Byte

Main:
  FOR col = 0 TO 3
    FOR row = 0 TO 15
      IF (row > 9) THEN EXIT
      DEBUG CRSRXY, (col * 8), row, DEC row, CR
    NEXT
  NEXT
  END

In this program, the FOR row = 0 TO 15 loop will not run past nine because the IF (row > 9) THEN EXIT contained within will force the loop to terminate when row is greater than nine. Note that the EXIT command only terminates the loop that contains it. In this program, the outer loop (col) will continue to run until complete.

Related commands: FOR...NEXT and DO...LOOP ( [image] )


EXIT Example

Syntax

NOTE: This is written for the BS2 and will run on any of the BS2-family modules. Modify the $STAMP directive (as required) before downloading to the BS2e, BS2sx, BS2p, BS2pe, or BS2px.

' EXIT.BS2
' This program demonstrates the early termination of DO...LOOP and
' FOR..NEXT loop structures.  IF...THEN is used to test a condition
' and when true, EXIT will terminate the loop.

' {$STAMP BS2}
' {$PBASIC 2.5}

col             VAR     Nib
row             VAR     Nib

Setup:
  col = 0

Main:
  DO WHILE (col < 10)                   ' attempt 10 iterations
    FOR row = 0 TO 15                   ' attempt 16 iterations
      IF (row > 9) THEN EXIT            ' terminate when row > 9
      DEBUG CRSRXY, (col * 8), row,     ' print col/row at location
            DEC col, "/", DEC row, CR
    NEXT
    col = col + 1                       ' update column
    IF (col = 3) THEN EXIT              ' terminate when col = 3
  LOOP
  END


 FOR...NEXT

Examples

Syntax [image] : FOR Counter = StartValue TO EndValue {STEP {-} StepValue} ... NEXT {Counter}
Syntax [image] : FOR Counter = StartValue TO EndValue {STEP StepValue} ... NEXT

Function
Create a repeating loop that executes the program lines between FOR and NEXT, incrementing or decrementing Counter according to StepValue until the value of the Counter variable passes the EndValue.

  • Counter is a variable (usually a byte or a word) used as a counter.
  • StartValue is a variable/constant/expression* (0 - 65535) that specifies the initial value of the variable (Counter).
  • EndValue is a variable/constant/expression* (0 - 65535) that specifies the end value of the variable (Counter). When the value of Counter is outside of the range StartValue to EndValue, the FOR...NEXT loop stops executing and the program goes on to the instruction after NEXT.
  • StepValue is an optional variable/constant/expression* (0 - 65535) by which the Counter increases or decreases with each iteration through the FOR...NEXT loop. On the BS1, use a minus sign (-)† in front of the StepValue to indicate a negative step. On all other BASIC Stamps, if StartValue is larger than EndValue, PBASIC understands StepValue to be negative, even though no minus sign is used.

* | Note: Expressions are not allowed as arguments on the BS1.
† | Note: Use a minus sign to indicate negative StepValues on the BS1.

Quick Facts
 | BS1 | BS2 Family
Max. nested commands | 8 | 16
To decrement counter variable | Set StartValue > EndValue and enter negative StepValue * | Set StartValue > EndValue
Counter comparison | Exit loop if Counter exceeds EndValue | Exit loop if Counter outside of range set by StartValue to EndValue
* Note: Direction (ie: increment/decrement) cannot be changed at runtime.

Explanation
FOR...NEXT loops let your program execute a series of instructions for a specified number of repetitions (called iterations). By default, each time through the loop, the counter variable is incremented by 1. It will continue to loop until the result of the counter is outside of the range set by StartValue and EndValue. Also, FOR...NEXT loops always execute at least once. The simplest form is shown here:

SYMBOL  reps    = B2                    ' FOR...NEXT loop counter

Main:
  FOR reps = 1 TO 3                     ' repeat with Reps = 1, 2, 3
    DEBUG  "*"                          ' print * on the screen
  NEXT
  END

reps    VAR     Nib                     ' FOR...NEXT loop counter

Main:
  FOR reps = 1 TO 3                     ' repeat with Reps = 1, 2, 3
    DEBUG  "*"                          ' print * on the screen
  NEXT
  END

In the above code, the FOR command sets Reps = 1. Then the DEBUG line (within the FOR...NEXT loop) is executed; printing an asterisk (*) on the screen. When the BASIC Stamp sees the NEXT command, it goes back to the previous FOR command, adds 1 to Reps and compares the result to the range set by StartValue and EndValue. If reps is still within range, it executes the code in the loop again. Each time the FOR...NEXT loop executes, the value of reps is updated (incremented by 1) and the code within the loop (the DEBUG line) is executed; printing another asterisk on the screen. This code will run through the loop three times; setting reps to 1, 2 and 3, and printing three asterisks on the screen. After the third loop, again the BASIC Stamp goes back up to the FOR command, adds 1 to reps and compares the result (4 in this case) to the range. Since the range is 1 to 3 and the value is 4 (outside the range) the FOR...NEXT loop is done and the BASIC Stamp will jump down to the first line of code following the NEXT command.

You can view the changing values of reps by including the reps variable in a DEBUG command within the loop:

SYMBOL  reps    = B2                    ' FOR...NEXT loop counter

Main:
  FOR reps = 1 TO 3                     ' repeat with Reps = 1, 2, 3
    DEBUG #reps, CR                     ' print number on the screen
  NEXT
  END

reps    VAR     Nib                     ' FOR...NEXT loop counter

Main:
  FOR reps = 1 TO 3                     ' repeat with Reps = 1, 2, 3
    DEBUG DEC reps, CR                  ' print number on the screen
  NEXT
  END

Running this example should display "1" , "2", and "3" on the screen.

FOR...NEXT can also be made to decrement (rather than increment) the counter variable. The BS1 does this when you specify a negative StepValue (as well as a StartValue that is greater than the EndValue). All other BASIC Stamps do this automatically when the StartValue is greater than the EndValue. Examples of both are shown below:

SYMBOL  reps    = B2                    ' FOR...NEXT loop counter

Main:
  FOR reps = 3 TO 1 STEP -1             ' repeat with Reps = 3, 2, 1
    DEBUG #reps, CR                     ' print number on the screen
  NEXT
  END

reps    VAR     Nib                     ' FOR...NEXT loop counter

Main:
  FOR reps = 3 TO 1                     ' repeat with Reps = 3, 2, 1
    DEBUG DEC reps, CR                  ' print number on the screen
  NEXT
  END

Note that the code for the BS2 series did not use the optional STEP argument. This is because we wanted to decrement by positive 1 anyway (the default unit) and the BASIC Stamp realizes it needs to decrement because the StartValue is greater than the EndValue. A negative StepValue on the BS2 series would be treated as its positive, two's compliment counterpart. For example, -1 in two's complement is 65535. So the following code executes only once:

reps    VAR     Nib                     ' FOR...NEXT loop counter

Main:
  FOR reps = 3 TO 1 STEP -1             ' decrement 3 by 65535
    DEBUG DEC reps, CR                  ' print number on the screen
  NEXT
  END

The above code would run through the loop once with Reps set to 3. The second time around, it would decrement Reps by 65535 (-1 is 65535 in two's compliment) effectively making the number -65532 (4 in two's compliment) which is outside the range of the loop.

All the arguments in the FOR...NEXT command can be constants, variables or expressions (on the BS2 series). This leads to some interesting uses. For example, if you make the StartValue and EndValue a variable, and change their values within the loop, you'll change the behavior of the loop itself. Try the following:

reps            VAR     Byte            ' counter for the FOR/NEXT loop
startVal        VAR     Byte
endVal          VAR     Byte

Setup:
  startVal = 1                          ' initialize startVal to 1
  endVal = 3                            ' initialize endVal to 3

Main:
  FOR reps = startVal TO endVal         ' repeat for 1 to 3
    DEBUG DEC reps, CR
    IF (reps = 3) THEN                  ' if reps = 3 then swap startVal and endVal
      startVal = 3                      '   otherwise continue loop
      endVal = 1
    ENDIF
  NEXT

Here the loop starts with a range of 1 to 3. First, the DEBUG line prints the value of reps. Then the IF...THEN line makes a decision; if reps is equal to 3, then swap the order of startVal and endVal, otherwise continue the loop execution. The next time through the loop (after startVal and endVal have been swapped), reps will be decremented instead of incremented because startVal is greater than endVal. The result is a display on the screen of the numbers 1, 2, 3, 2, 1.

The following example uses the value of reps as the stepValue. This creates a display of power's of 2 (1, 2, 4, 8, 16, 32, 64, etc):

SYMBOL  reps    = B2                    ' FOR...NEXT loop counter

Main:
  FOR reps = 1 TO 256 STEP reps         ' each loop add current value of Reps
    DEBUG reps                          ' show reps in Debug window.
  NEXT
  END

reps    VAR     Byte                    ' FOR...NEXT loop counter

Main:
  FOR reps = 1 TO 256 STEP reps         ' each loop add current value of Reps
    DEBUG ? DEC reps                    ' show reps in debug window.
  NEXT
  END

There is a potential bug that you should be careful to avoid. The BASIC Stamp uses unsigned 16-bit integer math for any math operation it performs, regardless of the size of values or variables. The maximum value the BASIC Stamp can internally calculate is 65535 (the largest 16-bit number). If you add 1 to 65535, you get 0 as the 16-bit register rolls over (like a car's odometer does when you exceed the maximum mileage it can display). Similarly, if you subtract 1 from 0, you'll get 65535 as the 16-bit register rolls under (a rollover in the opposite direction).

If you write a FOR...NEXT loop who's StepValue would cause the counter variable to go past 65535, this rollover may cause the loop to execute more times than you expect. Try the following example:

SYMBOL  reps    = W1                    ' FOR...NEXT loop counter

Main:
  FOR reps = 0 TO 65535 STEP 3000       ' each loop add 3000
    DEBUG  reps                         ' show reps in debug window
  NEXT
  END

reps    VAR     Word                    ' FOR...NEXT loop counter

Main:
  FOR reps = 0 TO 65535 STEP 3000       ' each loop add 3000
    DEBUG DEC ? reps                    ' show reps in debug window
  NEXT
  END

The value of reps increases by 3000 each trip through the loop. As it approaches the EndValue, an interesting thing happens; reps is: 57000, 60000, 63000, 464, 3464... It passes the EndValue, rolls over and keeps going. That's because the result of the calculation 63000 + 3000 exceeds the maximum capacity of a 16-bit number and then rolls over to 464. When the result of 464 is tested against the range ("Is reps > 0 and is reps < 65500?") it passes the test and the loop continues.

A similar symptom can be seen in a program who's EndValue is mistakenly set higher than what the counter variable can hold. The example below uses a byte-sized variable, but the EndValue is set to a number greater than what will fit in a byte:

SYMBOL  reps    = W1                    ' FOR...NEXT loop counter

Main:
  FOR reps = 0 TO 300                   ' each loop add 1
    DEBUG reps                          ' show reps in debug window
  NEXT
  END

reps    VAR     Byte                    ' FOR...NEXT loop counter

Main:
  FOR reps = 0 TO 300                   ' each loop add 1
    DEBUG DEC ? reps                    ' show reps in debug window
  NEXT
  END

Here, reps is a byte variable; which can only hold the number range 0 to 255. The EndValue is set to 300, however; greater than 255. This code will loop endlessly because when reps is 255 and the FOR...NEXT loop adds 1, reps becomes 0 (bytes will rollover after 255 just like words will rollover after 65535). The result, 0, is compared against the range (0 - 255) and it is found to be within the range, so the FOR...NEXT loop continues.

It's important to realize that on the BS2 series, the test is against the entire range, not just the EndValue. The code below is a slight modification of the previous example (the StartValue is 10 instead of 0) and will not loop endlessly.

reps    VAR     Byte                    ' FOR...NEXT loop counter

Main:
  FOR reps = 10 TO 300                  ' each loop add 1
    DEBUG DEC ? reps                    ' show reps in debug window
  NEXT
  END

Reps still rolls over to 0, as before, however, this time it is outside the range of 10 to 255. The loop stops, leaving reps at 0. Note that this code is still in error since reps will never reach 300 until it is declared as a Word.

NOTE: On the BS1, the loop will continue until Counter has gone past EndValue. The rollover error will still occur if the BS1 cannot determine if Counter went past EndValue.

Related commands: EXIT ( [image] ) and DO...LOOP ( [image] )


FOR...NEXT Examples

Syntax
' FOR-NEXT.BS1
' This example uses a FOR...NEXT loop to churn out a series of sequential
' squares (numbers 1, 2, 3, 4... raised to the second power) by using a
' variable to set the FOR...NEXT stepValue, and incrementing stepValue within
' the loop.  Sir Isaac Newton is generally credited with the discovery of
' this technique.

' {$STAMP BS1}
' {$PBASIC 1.0}

SYMBOL  square          = B2            ' FOR/NEXT counter
SYMBOL  stepSize        = B3            ' step size, increase by 2 each loop

Setup:
  stepSize = 1
  square = 1

Main:
  FOR square = 1 TO 250 STEP stepSize   ' show squares up to 250
    DEBUG square                        ' display on screen
    stepSize = stepSize + 2             ' add 2 to stepSize
  NEXT                                  ' loop until square > 250
  END

NOTE: This is written for the BS2 and will run on any of the BS2-family modules. Modify the $STAMP directive (as required) before downloading to the BS2e, BS2sx, BS2p, BS2pe, or BS2px.

' FOR-NEXT.BS2
' This example uses a FOR...NEXT loop to churn out a series of sequential
' squares (numbers 1, 2, 3, 4... raised to the second power) by using a
' variable to set the FOR...NEXT stepValue, and incrementing stepValue within
' the loop.  Sir Isaac Newton is generally credited with the discovery of
' this technique.

' {$STAMP BS2}
' {$PBASIC 2.5}

square          VAR     Byte            ' FOR/NEXT counter
stepSize        VAR     Byte            ' step size, increase by 2 each loop

Setup:
  stepSize = 1
  square = 1

Main:
  FOR square = 1 TO 250 STEP stepSize   ' show squares up to 250
    DEBUG DEC ? square                  ' display on screen
    stepSize = stepSize + 2             ' add 2 to stepSize
  NEXT                                  ' loop until square > 250
  END


 FREQOUT

Example

Syntax: FREQOUT Pin, Duration, Freq1 {, Freq2}

Function
Generate one or two sine-wave tones for a specified duration.

  • Pin a variable/constant/expression (0 - 15) that specifies the I/O pin to use. This pin will be set to output mode.
  • Duration a variable/constant/expression (0 - 65535) specifying the amount of time to generate the tone(s). The unit of time for Duration is described in the table below.
  • Freq1 is a variable/constant/expression (0 - 32767) specifying frequency of the first tone. The unit of Freq1 is described in the table below.
  • Freq2 is an optional argument exactly like Freq1. When specified, two frequencies will be mixed together on the specified I/O pin.

Quick Facts
 | BS2 and BS2e | BS2sx | BS2p | BS2pe | BS2px
Units in Duration | 1 ms | 0.4 ms | 0.265 ms | 1 ms | 0.166 ms
Units in Freq1 and Freq2 | 1 Hz | 2.5 Hz | 3.77 Hz | 1.51 Hz | 6.03 Hz
Range of frequency | 0 to 32767 Hz | 0 to 81.917 kHz | 0 to 123.531 kHz | 0 to 49.478 kHz | 0 to 197.585 kHz

Explanation
FREQOUT generates one or two sine waves using a pulse-width modulation algorithm. The circuits in the figure below work by filtering out the high-frequency PWM used to generate the sine waves. FREQOUT works over a very wide range of frequencies so at the upper end of its range, those PWM filters will also filter out most of the desired frequency. You may find it necessary to reduce values of the parallel capacitors shown in the circuit, or to devise a custom active filter for your application.

Here's a simple FREQOUT command:

  FREQOUT 2, 1000, 2500

On the BS2, this command generates a 2500 Hz tone for 1 second (1000 ms) on I/O pin 2. See the table above for timing data on other BASIC Stamps.

To play two tones on the same I/O pin at once:

  FREQOUT 2, 1000, 2500, 3000
This will generate a 2500 Hz and 3000 Hz tone (on the BS2) for 1 second. The frequencies will mix together for a chord- or bell-like sound. To generate a silent pause, specify frequency value(s) of 0.

Related commands: SOUND ( [image] ) and DTMFOUT ( [image] )


FREQOUT Example

Syntax

NOTE: This is written for the BS2 and will run on any of the BS2-family modules. Modify the $STAMP directive (as required) before downloading to the BS2e, BS2sx, BS2p, BS2pe, or BS2px.

' FREQOUT.BS2
' This program demonstrates a sound-effects generation by the BASIC Stamp.
' Conditional compilation sets timing and frequency adjustment factors so
' that the output will sound the same on any BS2 module.

' {$STAMP BS2}
' {$PBASIC 2.5}

Spkr            PIN     10              ' output pin for FREQOUT

#SELECT $STAMP
  #CASE BS2, BS2E
    TmAdj       CON     $100            ' x 1.0 (time adjust)
    FrAdj       CON     $100            ' x 1.0 (freq adjust)
  #CASE BS2SX
    TmAdj       CON     $280            ' x 2.5
    FrAdj       CON     $066            ' x 0.4
  #CASE BS2P
    TmAdj       CON     $3C5            ' x 3.77
    FrAdj       CON     $044            ' x 0.265
  #CASE BS2PE
    TmAdj       CON     $100            ' x 1.0
    FrAdj       CON     $0A9            ' x 0.66
  #CASE BS2PX
    TmAdj       CON     $607            ' x 6.02
    FrAdj       CON     $02A            ' x 0.166
#ENDSELECT

Main:
  DEBUG "Let's make a call...", CR
  ' combine 350 Hz & 440 Hz for dial tone
  FREQOUT Spkr, 2000 */ TmAdj, 350 */ FrAdj, 440 */ FrAdj
  ' dial number (digits 150 ms on, 25 ms off)
  DTMFOUT Spkr, 150 */ TmAdj, 25, [5, 5, 5, 1, 2, 1, 2]
  PAUSE 500

  ' bad connection (SIT sequence)
  FREQOUT Spkr, 375 */ TmAdj, 985 */ FrAdj
  FREQOUT Spkr, 375 */ TmAdj, 1371 */ FrAdj
  FREQOUT Spkr, 375 */ TmAdj, 1777 */ FrAdj

  DEBUG "Oops! -- try again...", CR
  PAUSE 1000
  DTMFOUT Spkr, 150 */ TmAdj, 25, [5, 5, 5, 2, 2, 2, 2]
  DEBUG "Ringing"
  FREQOUT Spkr, 2000 */ TmAdj, 440 */ FrAdj, 480 */ FrAdj
  PAUSE 4000
  FREQOUT Spkr, 2000 */ TmAdj, 440 */ FrAdj, 480 */ FrAdj
  INPUT Spkr
  DEBUG CLS, "Done."
  END


 GET

Example

Syntax: GET Location, {Word} Variable {, {Word} Variable ...}

Function
Read value(s) from Scratchpad RAM, starting at Location and store in Variable(s).

  • Location is a variable/constant/expression (0 – 63 for Bs2e and BS2sx, and 0 – 131 for BS2p, BS2pe, and BS2px) that specifies the Scratchpad RAM location to read from.
  • Variable is a variable (usually a Byte or Word) to store the value into.

Quick Facts
 | BS2e and BS2sx | BS2p, BS2pe, and BS2px
Scratchpad RAM size | 64 bytes (0 – 63) | 136 bytes (0 – 135)
General purpose locations | 0 - 62 | 0 – 126
Special use location | Current program slot number in read-only location 63. | Current program slot number in lowest nibble of read-only location 127. Current read/write slot number in highest nibble of location 127.
Additional locations | None | Locations 128 - 135 hold state of polled input pins.

Explanation
By default, the GET command reads a byte-sized value from the specified Scratchpad RAM location and stores it into variable. All values in all locations can be retrieved from within any of the eight program slots.

Scratchpad RAM is useful for passing data to programs in other program slots and for additional workspace. It is different than regular RAM in that symbol names cannot be assigned directly to locations and each location is always configured as a byte only. The following code will read the value at location 25, store it in a variable called temp and display it:

The following example illustrates this:

temp    VAR     Byte

Main:
  GET 25, temp
  DEBUG DEC temp
  END

When using the $PBASIC 2.5 directive, multiple sequential variables may be read from the Scratchpad RAM, starting at Location, and the Word modifier may be specified for 16-bit values.

' {$PBASIC 2.5}

value   VAR     Word
value2  VAR     Word
addr    VAR     Word                            ' EEPROM address
test    VAR     Byte                            ' test byte read back

Main:
  value = $11
  value2 = $2003
  PUT 0, value, Word value2                     ' write value to SP location 0
                                                '  and value2 to SP locations 1 & 2

  value = $FF                                   ' modify variables
  value2 = $FFFF

  GET 0, value, Word value2                     ' retrieve from Scratchpad

  DEBUG HEX2 ? value                            ' display
  DEBUG HEX4 ? value2
  END

The low nibble of location 63 (BS2e and BS2sx) and location 127 (BS2p, BS2pe, and BS2px) is a special, read-only location that always contains the number of the currently running program slot. On the BS2p, BS2pe, and BS2px, the high nibble of location 127 also contains the current program slot that will be used for the READ and WRITE commands. See the demo program for an example of use.

On the BS2p and BS2pe, the state of polled input pins can be retrieved from upper Scratchpad locations:

  • 128 : MAINIO pins 0 - 7
  • 129 : MAINIO pins 8 - 15
  • 130 : AUXIO pins 0 - 7
  • 131 : AUXIO pins 8 - 15

This information can be used to determine which input pin (or pins) has triggered a polled event.

Related commands: PUT ( [image] ), and READ


GET / PUT Example

NOTE: This is written for the BS2sx and will also run on the BS2e, BS2p, BS2pe, and BS2px. Modify the $STAMP directive (as required) before downloading to the BS2e, BS2p, BS2pe, or BS2px.

' GET_PUT1.BSX
' This example demonstrates the use of the GET AND PUT commands.  First,
' slot location is read using GET to display the currently running program
' number.  Then a set of values are written (PUT) into locations 0 TO 9.
' Afterwards, program number 1 is RUN.  This program is a BS2SX project
' consisting of GET_PUT1.BSX and GET_PUT2.BSX, but will run on the BS2e,
' BS2p, BS2pe, and BS2px without modification.

' {$STAMP BS2sx, GET_PUT2.BSX}
' {$PBASIC 2.5}

#SELECT $STAMP
  #CASE BS2
    #ERROR "BS2e or greater required."
  #CASE BS2E, BS2SX
    Slot        CON     63
  #CASE BS2P, BS2PE, BS2PX
    Slot        CON     127
#ENDSELECT

value           VAR     Byte
idx             VAR     Byte

Setup:
  GET Slot, value
  DEBUG "Program Slot #", DEC value.NIB0, CR

Main:
  FOR idx = 0 TO 9
    value = (idx + 3) * 8
    PUT idx, value
    DEBUG "  Writing: ", DEC2 value, " to location: ", DEC2 idx, CR
  NEXT
  DEBUG CR
  RUN 1
  END

' GET_PUT2.BSX
' This example demonstrates the use of the GET and PUT commands.  First,
' the Slot location is read using GET to display the currently running
' program number.  Then a set of values are read (GET) from locations
' 0 to 9 and displayed on the screen for verification.  This program is a
' BS2SX project consisting of GET_PUT1.BSX and GET_PUT2.BSX, but will run
' on the BS2e, BS2p, BS2pe, and BS2px without modification.

' {$STAMP BS2sx}
' {$PBASIC 2.5}

#SELECT $STAMP
  #CASE BS2
    #ERROR "BS2e or greater required."
  #CASE BS2E, BS2SX
    Slot        CON     63
  #CASE BS2P, BS2PE, BS2PX
    Slot        CON     127
#ENDSELECT

value           VAR     Byte
idx             VAR     Byte

Setup:
  GET Slot, value
  DEBUG "Program Slot #", DEC value.NIB0, CR

Main:
  FOR idx = 0 TO 9
    GET idx, value
    DEBUG "  Reading: ", DEC2 value, " from location: ", DEC2 idx, CR
  NEXT
  END


 GOSUB

Examples

Syntax: GOSUB Address

Function
Store the address of the next instruction after GOSUB, then go to the point in the program specified by Address; with the intention of returning to the stored address.

  • Address is a label that specifies where to go.

Quick Facts
 | BS1* | BS2 Family
Maximum GOSUBs per program | 16 | 256
Maximum nested GOSUBs | 4 | 4

* Note: Using GOSUB on the BS1 requires variables B12 and B13 (W6) making them unavailable for general program use.

Explanation
GOSUB is a close relative of GOTO, in fact, its name means, "GO to a SUBroutine". When a PBASIC program reaches a GOSUB, the program executes the code beginning at the specified address label. Unlike GOTO, GOSUB also stores the address of the instruction immediately following itself. When the program encounters a RETURN command, it interprets it to mean, "go to the instruction that follows the most recent GOSUB." In other words, a GOSUB makes the BASIC Stamp do a similar operation as you do when you see a table or figure reference in this manual; 1) you remember where you are, 2) you go to the table or figure and read the information there, and 3) when you've reached the end of it, you "return" to the place you were reading originally.

GOSUB Can Save EEPROM (Program) Space

GOSUB is mainly used to execute the same piece of code from multiple locations. If you have, for example, a block of three lines of code that need to be run from 10 different locations in your entire program you could simple copy and paste those three lines to each of those 10 locations. This would amount to a total of 30 lines of repetitive code (and extra space wasted in the program memory). A better solution is to place those three lines in a separate routine, complete with it's own label and followed by a RETURN command, then just use a GOSUB command at each of the 10 locations to access it. This technique can save a lot of program space.

Try the example below:

Main:
  GOSUB Hello
  DEBUG "How are you?", CR
  END

Hello:
  DEBUG "Hello my friend.", CR
  RETURN
The above code will start out by executing a GOSUB to the section of code beginning with the label Hello. It will print "Hello my friend." on the screen then RETURN to the line after the GOSUB...which prints "How are you?" and ENDs.

Watch Out For Subroutines That Your Program Can "Fall Into"

There's another interesting lesson here; what would happen if we removed the END command from this example? Since the BASIC Stamp reads the code from left to right / top to bottom (like the English language) once it had returned to and run the "How are you?" line, it would naturally "fall into" the Hello routine again. Additionally, at the end of the Hello routine, it would see the RETURN again (although it didn't GOSUB to that routine this time) and because there wasn't a previous place to return to, the BASIC Stamp will start the entire program over again. This would cause an endless loop. The important thing to remember here is to always make sure your program doesn't allow itself to "fall into" a subroutine.

NOTE: On the BS1, a RETURN without a GOSUB will return the program to the last GOSUB (or will end the program if no GOSUB was executed).

GOSUB Limitations

Only a limited number of GOSUBs are allowed per program (as shown in above), and they may be nested only four levels deep. In other words, the subroutine that's the destination of a GOSUB can contain a GOSUB to another subroutine, and so on, to a maximum depth (total number of GOSUBs before the first RETURN) of four. Any deeper, and the program will "forget" its way back to the starting point (the instruction following the very first GOSUB).

When GOSUBs are nested, each RETURN takes the program back to the instruction after the most-recent GOSUB. As is mentioned above, if the BASIC Stamp encounters a RETURN without a previous GOSUB, the entire program starts over from the beginning. Take care to avoid these phenomena.

Related command: RETURN and ON...GOSUB ( [image] )


GOSUB Examples

Syntax
' GOSUB.BS1
' This program is a guessing game that generates a random number in a
' subroutine called Pick_A_Number. It is written to stop after three
' guesses. To see a common bug associated with GOSUB, delete or comment
' out the line beginning with END after the FOR-NEXT loop. This means
' that after the loop is finished, the program will wander into the
' Pick_A_Number subroutine. When the RETURN at the end executes, the
' program will go back to the beginning of the program. This will cause
' the program to execute endlessly. Make sure that your programs can't
' accidentally execute subroutines!

' {$STAMP BS1}
' {$PBASIC 1.0}

SYMBOL  rounds          = B2            ' number of reps
SYMBOL  numGen          = W0            ' random number holder
SYMBOL  myNum           = B3            ' random number, 1-10

Setup:
  numGen = 11500                        ' initialize random "seed"

Main:
  FOR rounds = 1 TO 10
    DEBUG CLS, "Pick a number from 1 to 10", CR
    GOSUB Pick_A_Number
    PAUSE 2000                          ' dramatic pause
    DEBUG "My number was: ", #myNum     ' show the number
    PAUSE 1000                          ' another pause.
  NEXT
  DEBUG CLS, "Done"
  END                                   ' end program

' Random-number subroutine. A subroutine is just a piece of code with
' the RETURN instruction at the end. Always make sure your program enters
' subroutines with a GOSUB. If you don't, the RETURN won't have the
' correct address, and your program will have a bug!

Pick_A_Number:
  RANDOM numGen                         ' stir up the bits of NumGen.
  DEBUG numGen, CR
  myNum = numGen / 6550 MIN 1           ' scale to fit 1-10 range.
  RETURN                                ' go back to 1st instruction

NOTE: This is written for the BS2 and will run on any of the BS2-family modules. Modify the $STAMP directive (as required) before downloading to the BS2e, BS2sx, BS2p, BS2pe, or BS2px.

' GOSUB.BS2
' This program is a guessing game that generates a random number in a
' subroutine called Pick_A_Number. It is written to stop after three
' guesses. To see a common bug associated with GOSUB, delete or comment
' out the line beginning with END after the FOR-NEXT loop. This means
' that after the loop is finished, the program will wander into the
' Pick_A_Number subroutine. When the RETURN at the end executes, the
' program will go back to the beginning of the program. This will cause
' the program to execute endlessly. Make sure that your programs can't
' accidentally execute subroutines!

' {$STAMP BS2}
' {$PBASIC 2.5}

rounds          VAR     Byte            ' number of reps
numGen          VAR     Word            ' random number holder
myNum           VAR     Byte            ' random number, 1-10

Setup:
  numGen = 11500                        ' initialize random "seed"

Main:
  FOR rounds = 1 TO 10
    DEBUG CLS, "Pick a number from 1 to 10", CR
    GOSUB Pick_A_Number
    PAUSE 2000                          ' dramatic pause
    DEBUG "My number was: ", DEC myNum  ' show the number
    PAUSE 1000                          ' another pause.
  NEXT
  DEBUG CLS, "Done"
  END                                   ' end program

' Random-number subroutine. A subroutine is just a piece of code with
' the RETURN instruction at the end. Always make sure your program enters
' subroutines with a GOSUB. If you don't, the RETURN won't have the
' correct address, and your program will have a bug!

Pick_A_Number:
  RANDOM numGen                         ' stir up the bits of NumGen.
  DEBUG DEC ? numGen
  myNum = numGen / 6550 MIN 1           ' scale to fit 1-10 range.
  RETURN                                ' go back to 1st instruction
                                        '  after GOSUB that got us here


 GOTO

Example

Syntax: GOTO Address

Function
Jump the point in the program specified by Address.

  • Address is a label that specifies where to go.

Quick Facts
 | All BASIC Stamps
Max. GOTOs per program | Unlimited, but good programming practices suggest minimizing the use of GOTO.

Explanation
The GOTO command makes the BASIC Stamp execute the code that starts at the specified Address location. The BASIC Stamp reads PBASIC code from left-to-right, top-to-bottom, just like in the English language. The GOTO command forces the BASIC Stamp to jump to another section of code.

A common use for GOTO is to create endless loops; programs that repeat a group of instructions over and over. For example:

Hello:
  DEBUG "Hi", CR
  PAUSE 500
  GOTO Hello

The above code will print "Hi" on the screen, over and over again. The GOTO Hello line simply tells it to go back to the code that begins with the label Hello.

Related commands: ON...GOTO ( [image] ) and RUN ( [image] )


GOTO

Syntax

NOTE: This is written for the BS2 and will run on any BASIC Stamp module. Modify the $STAMP directive (as required) before downloading to the BS1, BS2e, BS2sx, BS2p, BS2pe, or BS2px.

' GOTO.BS2
' This program isn't practical at all, but demonstrates the use of GOTO to
' jump around the code.  This code jumps between three different routines,
' each of which print something different on the screen.  The routines are
' out of order for this example.

' {$STAMP BS2}

Start:
  GOTO Routine1

Routine2:
  DEBUG "We're in routine #2", CR
  PAUSE 1000
  GOTO Routine3

Routine1:
  DEBUG "We're in routine #1", CR
  PAUSE 1000
  GOTO Routine2

Routine3:
  DEBUG "We're in routine #3", CR
  PAUSE 1000
  GOTO Routine1


 HIGH

Example

Syntax: HIGH Pin

Function
Make the specified pin an output and high.

  • Pin is a variable/constant/expression (0 - 15) that specifies which I/O pin to set high. This pin will be placed into output mode.

* Note: Expressions are not allowed as arguments on the BS1. The range of the Pin argument on the BS1 is 0 - 7.

Explanation
The HIGH command sets the specified pin to 1 (a +5 volt level) and then sets its mode to output. For example,

  HIGH 6
does exactly the same thing as:

  PIN6 = 1
  DIR6 = 1

  OUT6 = 1
  DIR6 = 1
Using the HIGH command is faster in this case.

Related command: LOW


HIGH / LOW Example

Connect an LED and a 470 Ω resistor as show below for the demo program.

NOTE: This is written for the BS2 and will run on any BASIC Stamp module. Modify the $STAMP directive (as required) before downloading to the BS1, BS2e, BS2sx, BS2p, BS2pe, or BS2px.

' HIGH_LOW.BS2
' This simple program sets I/O pin 0 high for 1/2 second and low for
' 1/2 second in an endless loop.  Connect an LED to P0 for a simple
' blinker.

' {$STAMP BS2}

Main:
  HIGH 0
  PAUSE 500
  LOW 0
  PAUSE 500
  GOTO Main
  END


I2CIN / I2COUT Example

NOTE: This is written for the BS2p and will also run on the BS2pe and BS2px. Modify the $STAMP directive (as required) before downloading to the BS2pe or BS2px.

' I2C.BSP
' This program demonstrates writing and reading every location in a 24LC16B
' EEPROM using the BS2p/BS2pe.BS2px's I2C commands.  Connect the BS2p, BS2pe,
' or BS2px to the 24LC16B DIP EEPROM as shown in the diagram in the I2CIN
' or I2COUT command description.

' {$STAMP BS2p}
' {$PBASIC 2.5}

#IF ($STAMP < BS2P) #THEN
  #ERROR "Program requires BS2p, BS2pe, or BS2px."
#ENDIF

SDA             PIN     0               ' I2C SDA pin
SCL             PIN     SDA + 1

addr            VAR     Word            ' internal address
block           VAR     Nib             ' block address in 24LC16
value           VAR     Byte            ' value to write
check           VAR     Nib             ' for checking retuned values
result          VAR     Byte(16)        ' array for returned value

Write_To_EEPROM:
  DEBUG "Writing...", CR
  PAUSE 2000
  FOR addr = 0 TO 2047 STEP 16          ' loop through all addresses
    block = addr.NIB2 << 1              ' calculate block address
    value = addr >> 4                   ' create value from upper 8 bits
    ' write 16 bytes
    I2COUT SDA, $A0 | block, addr, [REP value\16]
    PAUSE 5
    DEBUG "Addr: ", DEC4 addr, "-", DEC4 addr + 15, "  ",
          "Value: ", DEC3 value, CR
  NEXT
  PAUSE 2000

Read_From_EEPROM:
  DEBUG CR, "Reading...", CR
  PAUSE  2000
  FOR addr = 0 TO 2047 STEP 16
    block = addr.NIB2 << 1
    value = addr >> 4
    I2CIN SDA, $A1 | block, addr, [STR result\16]
    FOR check = 0 TO 15
      IF (result(check) <> value) THEN Error
    NEXT
    DEBUG "Addr: ", DEC4 addr, "-", DEC4 addr + 15, "  ",
          "Value: ", DEC3 result, CR
  NEXT
  PAUSE 100
  DEBUG CR, "All locations passed"
  END

Error:
  DEBUG "Error at location: ", DEC4 addr + check, CR,
        "Found: ", DEC3 result(check), ", Expected: ", DEC3 value
  END


 I2CIN

Example

Syntax: I2CIN Pin, SlaveID, {Address {\LowAddress},} [InputData]

Function
Receive data from a device using the I2C® protocol.

  • Pin is a variable/constant/expression (0 or 8) that specifies which I/O pins to use. I2C devices require two I/O pins to communicate. The Pin argument serves a double purpose; specifying the first pin (for connection to the devices's SDA pin) and, indirectly, the other required pin (for connection to the devices's SCL pin). See explanation below. Both I/O pins will be toggled between output and input mode during the I2CIN command and both will be set to input mode by the end of the I2CIN command.
  • SlaveID is a variable/constant/expression (0 - 255) indicating the unique ID of the I2C device.
  • Address is a variable/constant/expression (0 - 255) indicating the desired address within the I2C device to receive data from. The Address argument may be used with the optional LowAddress argument to indicate a word-sized address value. Note that some devices like the PCF8574 do not require an internal address, so this parameter is optional (BS2p firmware 1.3 or later is required to omit the Address parameter).
  • LowAddress is a variable/constant/expression (0 - 255) indicating the low-byte of the word-sized address within the I2C device to receive data from. This argument must be used along with the Address argument.
  • InputData is a list of variables and modifiers that tells I2CIN what to do with incoming data. I2CIN can store data in a variable or array, interpret numeric text (decimal, binary, or hex) and store the corresponding value in a variable, wait for a fixed or variable sequence of bytes, or ignore a specified number of bytes. These actions can be combined in any order in the InputData list.

Quick Facts
 | BS2p, BS2pe, and BS2px
Value of Pin | 0 | 8
I/O Pin Arrangement | 0: Serial Data (SDA) pin 1: Serial Clock (SCL) pin | 8: Serial Data (SDA) pin 9: Serial Clock (SCL) pin
Transmission Rate | Approximately 81 kBits/sec (BS2p), 45 kBits/sec (BS2pe), 83 kBits/sec (BS2px) -- not including overhead.
Special Notes | Both the SDA and SCL pins must have 4.7 kΩ pull-up resisters. The I2CIN command does not allow for multiple masters. The BASIC Stamp cannot operate as an I2C slave device.

Explanation
The I2C protocol is a form of synchronous serial communication developed by Philips Semiconductor. It only requires two I/O pins and both pins can be shared between multiple I2C devices. The I2CIN command allows the BASIC Stamp to receive data from an I2C device.

The following is an example of the I2CIN command:

result  VAR     Byte

Main:
  I2CIN 0, $A1, 0, [result]
  STOP

This code will transmit a "read" command to an I2C device (connected to I/O pins 0 and 1) and then will receive one byte and store it in the variable result. Though it may seem strange, the I2CIN command first transmits some data and then receives data. It must first transmit information (ID, read/write and address) in order to tell the I2C device what information it would like to receive. The exact information transmitted ($A1, 0) depends on the I2C device that is being used.

The example above will read a byte of data from location 0 of a 24LC16B EEPROM from Microchip. The figure below shows the proper wiring for this example to work. The SlaveID argument ($A1) is both the ID of the chip and the command to read from the chip; the 1 means read. The Address argument (0) is the EEPROM location to read from. Note that the I2CIN command will make up to eight attempts to connect to the addressed device. If the device does not properly respond, the I2CIN command will timeout and the InputData will remain unchanged.

Note: The 4.7 kΩ resisters are required for the I2CIN command to function properly.

The I2CIN command's InputData argument is similar to the SERIN command's InputData argument. This means data can be received as ASCII character values, decimal, hexadecimal and binary translations and string data as in the examples below. (Assume the 24LC16B EEPROM is used and it has the string, "Value: 3A:101" stored, starting at location 0).

value   VAR     Byte(13)

Main:
  I2CIN 0, $A1, 0, [value]              ' receive ASCII code for "V"
  I2CIN 0, $A1, 0, [DEC value]          ' receive number 3
  I2CIN 0, $A1, 0, [HEX value]          ' receive number $3A
  I2CIN 0, $A1, 0, [BIN value]          ' receive number %101
  I2CIN 0, $A1, 0, [STR value\13]       ' receive string "Value: 3A:101"
  STOP

The tables below list all the available conversion formatters and special formatters available to the I2CIN command. See the SERIN command for additional information and examples of their use.

Conversion Formatter | Type of Number | Numeric Characters Accepted | Notes
DEC{1..5} | Decimal, optionally limited to 1 - 5 digits | 0 through 9 | 1
SDEC{1..5} | Signed decimal, optionally limited to 1 - 5 digits | -, 0 through 9 | 1,2
HEX{1..4} | Hexadecimal, optionally limited to 1 - 4 digits | 0 through 9, A through F | 1,3
SHEX{1..4} | Signed hexadecimal, optionally limited to 1 - 4 digits | -, 0 through 9, A through F | 1,2,3
IHEX{1..4} | Indicated hexadecimal, optionally limited to 1 - 4 digits | $, 0 through 9, A through F | 1,3,4
ISHEX{1..4} | Signed, indicated hexadecimal, optionally limited to 1 - 4 digits | -, $, 0 through 9, A through F | 1,2,3,4
BIN{1..16} | Binary, optionally limited to 1 - 16 digits | 0, 1 | 1
SBIN{1..16} | Signed binary, optionally limited to 1 - 16 digits | -, 0, 1 | 1,2
IBIN{1..16} | Indicated binary, optionally limited to 1 - 16 digits | %, 0, 1 | 1,4
ISBIN{1..16} | Signed, indicated binary, optionally limited to 1 - 16 digits | -, %, 0, 1 | 1,2,4
NUM | Generic numeric input; hex or binary number must be indicated | $, %, 0 through 9, A through F | 1,3,4
SNUM | Similar to NUM with value treated as signed with range -32768 to +32767 | -, $, %, 0 through 9, A through F | 1,2,3,4

  1. All numeric conversions will continue to accept new data until receiving either the specified number of digits (ex: three digits for DEC3) or a non-numeric character.
  2. To be recognized as part of a number, the minus sign (-) must immediately precede a numeric character. The minus sign character occurring in non-numeric text is ignored and any character (including a space) between a minus and a number causes the minus to be ignored.
  3. The hexadecimal formatters are not case-sensitive; "a" through "f" means the same as "A" through "F".
  4. Indicated hexadecimal and binary formatters ignore all characters, even valid numerics, until they receive the appropriate prefix ($ for hexadecimal, % for binary). The indicated formatters can differentiate between text and hexadecimal (ex: ABC would be interpreted by HEX as a number but IHEX would ignore it unless expressed as $ABC). Likewise, the binary version can distinguish the decimal number 10 from the binary number %10. A prefix occurring in non-numeric text is ignored, and any character (including a space) between a prefix and a number causes the prefix to be ignored. Indicated, signed formatters require that the minus sign come before the prefix, as in -$1B45.

Special Formatter | Action
STR ByteArray \L {\E} | Input a character string of length L into an array. If specified, an end character E causes the string input to end before reaching length L. Remaining bytes are filled with 0s (zeros).
WAITSTR ByteArray {\L} | Wait for a sequence of bytes matching a string stored in an array variable, optionally limited to L characters. If the optional L argument is left off, the end of the array-string must be marked by a byte containing a zero (0).
SKIP Length | Ignore Length bytes of characters.
SPSTR Length | Buffer Length bytes (up to 126) of serial characters to Scratchpad RAM, starting at location 0. Use GET to retrieve the characters.

The I2C protocol has a well-defined standard for the information passed at the start of each transmission. First of all, any information sent must be transmitted in units of one byte (8-bits). The first byte, we call the SlaveID, is an 8-bit pattern whose upper 7-bits contain the unique ID of the device you wish to communicate with. The lowest bit indicates whether this is a write operation (0) or a read operation (1).

SlaveID Format

7 | 6 | 5 | 4 | 3 | 2 | 1 | 0
A6 | A5 | A4 | A3 | A2 | A1 | A0 | R/W

The second byte, immediately following the SlaveID, is the Address. It indicates the 8-bit address (within the device) containing the data you would like to receive.

Some devices require more than eights bits of address. For this case, the optional LowAddress argument can be used for the low-byte of the required address. When using the LowAddress argument, the Address argument is effectively the high-byte of the address value. For example, if the entire address value is 2050, use 8 for the Address argument and 2 for the LowAddress argument (8 * 256 + 2 = 2050).

Following the last address byte is the first byte of data. This data byte may be transmitted or received by the BASIC Stamp. In the case of the I2CIN command, this data byte is transmitted by the device and received by the BASIC Stamp. Additionally, multiple data bytes can follow the address, depending on the I2C device. Note that every device has different limitations regarding how may contiguous bytes they can receive or transmit in one session. Be aware of these device limitations and program accordingly.

Every I2C transmission session begins with a Start Condition and ends with a Stop Condition. Additionally, immediately after every byte is transmitted, an extra clock cycle is used to send or receive an acknowledgment signal (ACK). All of these operations are automatically taken care of by the I2CIN command so that you need not be concerned with them. The general I2C transmission format is shown below.

Since the I2CIN command is intended for input only, it actually overrides the "R/W" bit (bit 0) in the SlaveID argument. This is done so that it can use the I2C protocol's "Combined Format" for receiving data. Put simply, this means a command such as:

  I2CIN 0, $A1, 10, [result]
actually transmits $A0, then 10, then $A1 and then it reads the data back from the device. The $A0 means "write", the 10 is the address to write to and, finally, the $A1 indicates a change of direction; to "read" the location, instead. Even though the I2CIN command really doesn't care what the value of the SlaveID's LSB is, it is suggested that you still set it appropriately for clarity.

Also note that the I2CIN command does not support multiple I2C masters and the BASIC Stamp cannot operate as an I2C slave device.

Related commands: I2COUT


 I2COUT

Example

Syntax: I2COUT Pin, SlaveID, {Address {\LowAddress},} [OutputData]

Function
Send data to a device using the I2C® protocol.

  • Pin is a variable/constant/expression (0 or 8) that specifies which I/O pins to use. I2C devices require two I/O pins to communicate. The Pin argument serves a double purpose; specifying the first pin (for connection to the device's SDA pin) and, indirectly, the other required pin (for connection to the device's SCL pin). See explanation below. Both I/O pins will be toggled between output and input mode during the I2COUT command and both will be set to input mode by the end of the I2COUT command.
  • SlaveID is a variable/constant/expression (0 - 255) indicating the unique ID of the I2C device.
  • Address is a variable/constant/expression (0 - 255) indicating the desired address within the I2C device to send data to. The Address argument may be used with the optional LowAddress argument to indicate a word-sized address value. Note that some devices like the PCF8574 do not require an internal address, so this parameter is optional (BS2p firmware 1.3 or later is required to omit the Address parameter).
  • LowAddress is a variable/constant/expression (0 - 255) indicating the low-byte of the word-sized address within the I2C device to send data to. This argument must be used along with the Address argument.
  • OutputData is a list of variables, constants, expressions and formatters that tells I2COUT how to format outgoing data. I2COUT can transmit individual or repeating bytes, convert values into decimal, hexadecimal or binary text representations, or transmit strings of bytes from variable arrays. These actions can be combined in any order in the OutputData list.

Quick Facts
 | BS2p, BS2pe, and BS2px
Value of Pin | 0 | 8
I/O Pin Arrangement | 0: Serial Data (SDA) pin 1: Serial Clock (SCL) pin | 8: Serial Data (SDA) pin 9: Serial Clock (SCL) pin
Transmission Rate | Approximately 81 kBits/sec (BS2p), 45 kBits/sec (BS2pe), 83 kBits/sec (BS2px) -- not including overhead.
Special Notes | Both the SDA and SCL pins must have 4.7 kΩ pull-up resisters.

Explanation
The I2C protocol is a form of synchronous serial communication developed by Philips Semiconductor. It only requires two I/O pins and both pins can be shared between multiple I2C devices. The I2COUT command allows the BASIC Stamp to send data to an I2C device.

The following is an example of the I2COUT command:

  I2COUT 0, $A0, 5, [100]

This code will transmit a "write" command to an I2C device (connected to I/O pins 0 and 1), followed by an address of 5 and finally will transmit the number 100.

The example above will write a byte of data to location 5 of a 24LC16B EEPROM from Microchip. The figure below shows the proper wiring for this example to work. The SlaveID argument ($A0) is both the ID of the chip and the command to write to the chip; the 0 means write. The Address argument (5) is the EEPROM location to write to.

Note: The 4.7 kΩ resisters are required for the I2COUT command to function properly.

The I2COUT command's OutputData argument is similar to the DEBUG and SEROUT command's OutputData argument. This means data can be sent as literal text, ASCII character values, repetitive values, decimal, hexadecimal and binary translations and string data as in the examples below. (Assume the 24LC16B EEPROM is being used).

value   VAR     Byte

Setup:
  value = 65

Main:
  I2COUT 0, $A0, 0, [value]             ' send ASCII character "A"
  I2COUT 0, $A0, 0, [REP value\5]       ' send "A" five times, i.e., "AAAAA"
  I2COUT 0, $A0, 0, [DEC value]         ' send "6" and "5"
  I2COUT 0, $A0, 0, [HEX value]         ' send "4" and "1"
  I2COUT 0, $A0, 0, [BIN value]         ' send "1000001"
  END

The tables below list all the available conversion formatters and special formatters available to the I2COUT command. See the DEBUG and SEROUT commands for additional information and examples of their use.

Conversion Formatter | Type of Number | Notes
DEC{1..5} | Decimal, optionally fixed to 1 - 5 digits | 1
SDEC{1..5} | Signed decimal, optionally fixed to 1 - 5 digits | 1,2
HEX{1..4} | Hexadecimal, optionally fixed to 1 - 4 digits | 1
SHEX{1..4} | Signed hexadecimal, optionally fixed to 1 - 4 digits | 1,2
IHEX{1..4} | Indicated hexadecimal, optionally fixed to 1 - 4 digits | 1
ISHEX{1..4} | Signed, indicated hexadecimal, optionally fixed to 1 - 4 digits ($ prefix) | 1,2
BIN{1..16} | Binary, optionally fixed to 1 - 16 digits | 1
SBIN{1..16} | Signed binary, optionally fixed to 1 - 16 digits | 1,2
IBIN{1..16} | Indicated binary, optionally fixed to 1 - 16 digits | 1
ISBIN{1..16} | Signed, indicated binary, optionally fixed to 1 - 16 digits | 1,2

  1. Fixed-digit formatters like DEC4 will pad the number with leading 0s if necessary; ex: DEC4 65 sends 0065. If a number is larger than the specified number of digits, the leading digits will be dropped; ex: DEC4 56422 sends 6422.
  2. Signed modifiers work under two's complement rules.

Special Formatter | Action
? | Displays "symbol = x' + carriage return; where x is a number. Default format is decimal, but may be combined with conversion formatters (ex: BIN ? x to display "x = binary_number").
ASC ? | Displays "symbol = 'x'" + carriage return; where x is an ASCII character.
STR ByteArray {\L} | Send character string from an array. The optional \L argument can be used to limit the output to L characters, otherwise, characters will be sent up to the first byte equal to 0 or the end of RAM space is reached.
REP Byte\L | Send a string consisting of Byte repeated L times (ex: REP "X"\10 sends "XXXXXXXXXX").

The I2C protocol has a well-defined standard for the information passed at the start of each transmission. First of all, any information sent must be transmitted in units of one byte (8-bits). The first byte, we call the SlaveID, is an 8-bit pattern whose upper 7-bits contain the unique ID of the device you wish to communicate with. The lowest bit indicates whether this is a write operation (0) or a read operation (1).

SlaveID Format

7 | 6 | 5 | 4 | 3 | 2 | 1 | 0
A6 | A5 | A4 | A3 | A2 | A1 | A0 | R/W

The second byte, immediately following the SlaveID, is the Address. It indicates the 8-bit address (within the device) where the OutputData is to be written (the first location if more than one byte is written). Note that the Address argument is optional and may be left unspecified for devices that don't require an address parameter.

Some devices require more than eights bits of address. For this case, the optional LowAddress argument can be used for the low-byte of the required address. When using the LowAddress argument, the Address argument is effectively the high-byte of the address value. For example, if the entire address value is 2050, use 8 for the Address argument and 2 for the LowAddress argument (8 * 256 + 2 = 2050).

Following the last address byte is the first byte of data. This data byte may be transmitted or received by the BASIC Stamp. In the case of the I2COUT command, this data byte is transmitted by the BASIC Stamp and received by the device. Additionally, multiple data bytes can follow the address, depending on the I2C device. Note that every device has different limitations regarding how may contiguous bytes they can receive or transmit in one session. Be aware of these device limitations and program accordingly.

Every I2C transmission session begins with a Start Condition and ends with a Stop Condition. Additionally, immediately after every byte is transmitted, an extra clock cycle is used to send or receive an acknowledgment signal (ACK). All of these operations are automatically taken care of by the I2CIN command so that you need not be concerned with them. The general I2C transmission format is shown below.

Since the I2COUT command is intended for output only, it actually overrides the "R/W" bit (bit 0) in the SlaveID argument. This is done to avoid device conflicts should the value be mistyped. Put simply, this means commands such as:

  I2COUT 0, $A0, 10, [0]

and

  I2COUT 0, $A1, 10, [0]

both transmit the same thing ($A0, then 10, then the data). Even though the I2COUT command really doesn't care what the value of the SlaveID's LSB is, it is suggested that you still set it appropriately for clarity.

Also note that the I2COUT command does not support multiple I2C masters and the BASIC Stamp cannot operate as an I2C slave device.

Related commands: I2CIN


 IF...THEN

{$PBASIC 1.0 and $PBASIC 2.0} Examples

Syntax: IF Condition THEN Address

Function
Evaluate Condition and, if it is true, go to the point in the program marked by Address.

  • Condition is a statement, such as "x = 7" that can be evaluated as True or False. The Condition can be a very simple or very complex relationship, as described below.
  • Address is a label that specifies where to go in the event that Condition is true.

Quick Facts
 | BS1 | BS2 Family
Comparison operators | =, <>, >, <, >=, <= | =, <>, >, <, >=, <=
Conditional Logic Operators | AND, OR | NOT, AND, OR, XOR
Format of condition | Variable Comparison Value; where Value is a variable or constant | Value1 Comparison Value2; where Value1 and Value2 can by any of variable, constant or expression
Parentheses | Not Allowed | Allowed

Explanation
IF...THEN is PBASIC's primary decision maker. It tests a condition and, if that condition is true, goes to a point in the program specified by an address label. The condition that IF...THEN tests is written as a mixture of comparison and logic operators. The available comparison operators are:

Comparison Operator Symbol | Definition
= | Equal
<> | Not Equal
> | Greater Than
< | Less Than
>= | Greater Than or Equal To
<= | Less Than or Equal To

Comparisons are always written in the form: Value1 Comparison Value2. The values to be compared can be any combination of variables (any size), constants, or expressions. NOTE: On the BS1, expressions are not allowed as arguments, and the Value1 (to the left of comparison) must be a variable.

The following example is an IF...THEN command with a simple condition:

  IF 10 < 200 THEN Main

This code will compare the number 10 to the number 200. If 10 is less than 200, the condition is true. In this case, 10 is less than 200 (and always will be), so the program will jump (or GOTO) the label called Main. Of course, this is a silly example (10 is always less than 200 so this line will always cause a jump to Main). Most of the time, you'll use at least one variable in your condition:

SYMBOL  value   = W1

Main:
  PULSIN 0, 1, value
  DEBUG #value, CR
  IF value < 4000 THEN Main
  DEBUG "Value was greater than 4000!"
  END

value   VAR     Word

Main:
  PULSIN 0, 1, value
  DEBUG DEC value, CR
  IF (value < 4000) THEN Main
  DEBUG "Value was greater than 4000!"
  END

Here, the BASIC Stamp will look for and measure a pulse on I/O pin 0, then compare the result, value, against 4000. If value is less than (<) 4000, it will jump back to Main. Each time through the loop, it displays the measured value and once it is greater than or equal to 4000, it displays, "Value was greater than 4000!"

On the BS2, BS2e, BS2sx, BS2p, and BS2pe, the values can be expressions as well. This leads to very flexible and sophisticated comparisons. The IF...THEN statement below is functionally the same as the one in the program above:

  IF (value < (45 * 100 - (25 * 20))) THEN Main

Here the BASIC Stamp evaluates the expression: 45 * 100 = 4500, 25 * 20 = 500, and 4500 - 500 = 4000. Then the BASIC Stamp performs the comparison: is value < 4000? Another example that is functionally the same:

  IF ((value / 100) < 40) THEN Main

It's important to realize that all comparisons are performed using unsigned, 16-bit math. This can lead to strange results if you mix signed and unsigned numbers in IF...THEN conditions. Watch what happens here when we include a signed number (-99):

  IF (-99 < 100) THEN Is_Less
  DEBUG  "Greater than or equal to 100"
  END

Is_Less:
  DEBUG "Less than 100"
  END

Although -99 is obviously less than 100, the program will say it is greater. The problem is that -99 is internally represented as the two's complement value 65437, which (using unsigned math) is greater than 100. This phenomena will occur whether or not the negative value is a constant, variable or expression.

IF...THEN supports the conditional logic operators NOT, AND, OR, and XOR. See the table below for a list of the operators and their effects. NOTE: The NOT and XOR operators are not available on the BS1.

The NOT operator inverts the outcome of a condition, changing False to True, and True to False. The following IF...THENs are equivalent:

  IF (x <> 100) THEN Not_Equal                  ' Jump to Not_Equal if x is not 100
  IF NOT (x = 100) THEN Not_Equal               ' Jump to Not_Equal if x is not 100
The operators AND, OR, and XOR can be used to join the results of two conditions to produce a single True or False result. AND and OR work the same as they do in everyday speech. Run the example below once with AND (as shown) and again, substituting OR for AND:

SYMBOL  value1  = B2
SYMBOL  value2  = B3

Setup:
  value1 = 5
  value2 = 9

Main:
  IF value1 = 5 AND value2 = 10 THEN Is_True    ' change AND to OR and see
  DEBUG  "Statement was false."                 '   what happens
  END

Is_True:
  DEBUG "Statement was true."
  END

value1  VAR     Byte
value2  VAR     Byte

Setup:
  value1 = 5
  value2 = 9

Main:
  ' Change AND to OR and see what happens
  IF (value1 = 5) AND (value2 = 10) THEN Is_True
  DEBUG  "Statement was false."
  END

Is_True:
  DEBUG "Statement was true."
  END

The condition "(value1 = 5) AND (value2 = 10)" is not true. Although value1 is 5, value2 is not 10. The AND operator works just as it does in English; both conditions must be true for the statement to be true. The OR operator also works in a familiar way; if one or the other or both conditions are true, then the statement is true. The XOR operator (short for exclusive-OR) may not be familiar, but it does have an English counterpart: If one condition or the other (but not both) is true, then the statement is true.

The table below summarizes the effects of the conditional logic operators. As with math, you can alter the order in which comparisons and logical operations are performed by using parentheses. Operations are normally evaluated left-to-right. Putting parentheses around an operation forces PBASIC 2.0 to evaluate it before operations not in parentheses. NOTE: On the BS1, parentheses are not allowed within arguments.

Condition A | NOT A
False | True
True | False

Condition A | Condition B | A AND B
False | False | False
False | True | False
True | False | False
True | True | True

Condition A | Condition B | A OR B
False | False | False
False | True | True
True | False | True
True | True | True

Condition A | Condition B | A XOR B
False | False | False
False | True | True
True | False | True
True | True | False

Unlike the IF...THEN commands in other BASIC's, PBASIC 1.0/2.0's IF...THEN can only go to a label as the result of a decision. It cannot conditionally perform some instruction, as in "IF x < 20 THEN y = y + 1" (This is possible using the $PBASIC 2.5 directive). To achieve this in PBASIC 1.0 and 2.0, you have to invert the logic using NOT and skip over the conditional instruction unless the condition is met:

  IF NOT (x < 20) THEN No_Inc           ' Don't increment y unless x < 20.
  y = y + 1                             ' Increment y if x < 20.

No_Inc:                                 ' Program continues.

You can also code a conditional GOSUB, as in "IF (x = 100) THEN GOSUB Centennial." In PBASIC 2.0:

  IF NOT (x = 100) THEN No_Cent
  GOSUB Centennial                      ' IF x = 100 THEN GOSUB Centennial.

No_Cent:                                ' Program continues.

Internally, the BASIC Stamp defines "False" as 0 and "True" as any value other than 0. Consider the following instructions:

flag    VAR     Bit

Setup:
  flag = 1

Test:
  IF flag THEN Is_True

Is_False:
  DEBUG "False", CR
  END

Is_True:
  DEBUG "True"
  END

Since flag is 1, IF...THEN would evaluate it as true and print the message "True" on the screen. Suppose you changed the IF...THEN command to read "IF NOT (flag) THEN IsTrue." That would also evaluate as True. Whoa! Isn't NOT 1 the same thing as 0? No, at least not in the 16-bit world of the BASIC Stamp.

Internally, the BASIC Stamp sees a bit variable containing 1 as the 16-bit number %0000000000000001. So it sees the NOT of that as %1111111111111110. Since any non-zero number is regarded as True, NOT 1 is True. Strange but true.

The easiest way to avoid the kinds of problems this might cause is to always use a conditional operator with IF...THEN. Change the example above to read IF (flag = 1) THEN Is_True. The result of the comparison will follow IF...THEN rules. Also, the logical operators will work as they should; IF NOT (flag = 1) THEN Is_True will correctly evaluate to False when flag contains 1.

This also means that you should only use the "named" conditional logic operators NOT, AND, OR, and XOR with IF...THEN. The conditional logic operators format their results correctly for IF...THEN instructions. The other logical operators, represented by symbols ~ & | and ^ do not; they are binary logic operators.

Related commands: IF...THEN...ELSE ( [image] ), BRANCH and ON..GOTO ( [image] )


 IF...THEN...ELSE

{$PBASIC 2.5} Example

Syntax:

IF Condition THEN
Statement(s)
{ ELSEIF Condition(s) THEN
Statement(s) }
{ ELSE
Statement(s) }
ENDIF

IF Condition THEN Statement(s) { ELSEIF Statement(s) } { ELSE Statement(s) }

Function
Evaluate Condition and, if it is true, execute the statement(s) following THEN, otherwise jump to and evaluate the ELSEIF condition. If no ELSEIF statement/block is provided, jump to and execute the statements that follow ELSE. If no ELSE block is provided, the program will continue at the line that follows ENDIF (or the next line when single-line syntax is used).

  • Condition is a statement, such as "x = 7" that can be evaluated as True or False. The Condition can be a very simple or very complex relationship, as described below.
  • Statement is any valid PBASIC statement. Multiple statements may be placed on the same line (though not recommended) by separating each statement with a colon ( : ).

Quick Facts
 | BS2 Family
Comparison operators | =, <>, >, <, >=, <=
Conditional Logic Operators | NOT, AND, OR, XOR
Format of condition | Value1 Comparison Value2; where Value1 and Value2 can be any of variable, constant or expression
Parentheses | Allowed
Nesting | Up to 16 levels

Explanation
IF...THEN...ELSE is a primary PBASIC decision maker that allows one block of code or [optionally] another to run based on the value (True or False) of a condition. The condition that IF...THEN...ELSE tests is written as a mixture of comparison and logic operators. The available comparison operators are:

Comparison Operator Symbol | Definition
= | Equal
<> | Not Equal
> | Greater Than
< | Less Than
>= | Greater Than or Equal To
<= | Less Than or Equal To

Comparisons are always written in the form: Value1 Comparison Value2. The values to be compared can be any combination of variables (any size), constants, or expressions.

value   VAR     Word

Main:
  DO
    PULSIN 0, 1, value                          ' measure pulse input
    DEBUG DEC value, CR
    IF (value > 4000) THEN                      ' evaluate duration
      DEBUG "Value was greater than 4000"
    ELSEIF (value = 4000) THEN
      DEBUG "Value was equal to 4000"
    ELSE
      DEBUG "Value was less than 4000"
    ENDIF
    DEBUG CR, CR
    PAUSE 1000
  LOOP

Here, the BASIC Stamp will look for and measure a pulse on I/O pin 0, then compare the result, value, against 4000. Based on this comparison, a message regarding the pulse width value will be printed.

In the following example, single-line syntax is used. Note that ENDIF is not required when using single-line formatting of IF...THEN...ELSE:

  DEBUG "Your grade is: "
  IF (score >= 90) THEN DEBUG "A", CR : ELSE DEBUG "B (or less)", CR

See IF...THEN for additional details on the use of comparison and conditional operators.

Related commands: IF...THEN and SELECT...CASE ( [image] )


IF...THEN...ELSE Example

{$PBASIC 2.5} Syntax

NOTE: This is written for the BS2 and will run on any of the BS2-family modules. Modify the $STAMP directive (as required) before downloading to the BS2e, BS2sx, BS2p, BS2pe, or BS2px.

' IF-THEN-ELSE.BS2
' The program below generates a series of 16-bit random numbers and tests
' each to determine whether they're evenly divisible by 3. If a number is
' evenly divisible by 3, then it is printed, otherwise, the program generates
' another random number. The program counts how many numbers it prints, and
' quits when this number reaches 10.

' {$STAMP BS2}
' {$PBASIC 2.5}                         ' version 2.5 required

sample          VAR     Word            ' Random number to be tested
hits            VAR     Nib             ' Number of hits
misses          VAR     Word            ' Number of misses

Setup:
  sample = 11500

Main:
  DO
    RANDOM sample                       ' Put a random number into sample
    IF ((sample // 3) = 0) THEN         ' divisible by 3?
      DEBUG DEC5 sample,                ' - yes, print value and message
            " is divisible by 3", CR
      hits = hits + 1                   ' count hits (divisble by 3)
    ELSE
      misses = misses + 1               ' count misses
    ENDIF
  LOOP UNTIL (hits = 10)                ' quit after 10 hits

  DEBUG CR,
        "All done.", CR, CR,            ' display results
        "Hits:    ", DEC hits, CR,
        "Misses:  ", DEC misses, CR,
        "Samples: ", DEC (hits + misses)
  END


IF...THEN Examples

Syntax
' IF-THEN.BS1
' The program below generates a series of 16-bit random numbers and tests
' each to determine whether they're evenly divisible by 3. If a number is
' evenly divisible by 3, then it is printed, otherwise, the program generates
' another random number.  The program counts how many numbers it prints, and
' quits when this number reaches 10.

' {$STAMP BS1}
' {$PBASIC 1.0}

SYMBOL  sample          = W0            ' Random number to be tested
SYMBOL  samps           = B2            ' Number of samples taken
SYMBOL  temp            = B3            ' Temporary workspace

Setup:
  sample = 11500

Mult3:
  RANDOM sample                         ' Put a random number into sample
  temp = sample // 3
  IF temp <> 0 THEN Mult3               ' Not multiple of 3? -- try again
    DEBUG #sample, "divides by 3", CR   ' show sample divisible by 3
    samps = samps + 1                   ' Count multiples of 3
    IF samps = 10 THEN Done             ' Quit with 10 samples
  GOTO Mult3                            ' keep checking

Done:
  DEBUG CR, "All done."
  END

NOTE: This is written for the BS2 and will run on any of the BS2-family modules. Modify the $STAMP directive (as required) before downloading to the BS2e, BS2sx, BS2p, BS2pe, or BS2px.

' IF-THEN.BS2
' The program below generates a series of 16-bit random numbers and tests
' each to determine whether they're evenly divisible by 3. If a number is
' evenly divisible by 3, then it is printed, otherwise, the program generates
' another random number.  The program counts how many numbers it prints, and
' quits when this number reaches 10.

' {$STAMP BS2}
' {$PBASIC 2.0}

sample          VAR     Word            ' Random number to be tested
samps           VAR     Nib             ' Number of samples taken
temp            VAR     Nib             ' Temporary workspace

Setup:
  sample = 11500

Mult3:
  RANDOM sample                         ' Put a random number into sample
  temp = sample // 3
  IF (temp <> 0) THEN Mult3             ' Not multiple of 3? -- try again
    DEBUG DEC5 sample, " divides by 3", CR
    samps = samps + 1                   ' Count multiples of 3
    IF samps = 10 THEN Done             ' Quit with 10 samples
  GOTO Mult3                            ' keep checking

Done:
  DEBUG CR, "All done."
  END


 INPUT

Examples

Syntax: INPUT Pin

Function
Make the specified pin an input.

  • Pin is a variable/constant/expression* (0 - 15) that specifies which I/O pin to set to input mode.

* Note: Expressions are not allowed as arguments on the BS1. The range of the Pin argument on the BS1 is 0 - 7.

Explanation
There are several ways to make a pin an input. When the BASIC Stamp is reset, all of the pins are inputs. Commands that rely on input pins, like PULSIN and SERIN, automatically change the specified pin to input. Writing 0s to particular bits of the variable DIRS makes the corresponding pins inputs. And then there’s the INPUT command.

When a pin is an input, your program can check its state by reading from the corresponding INS variable (PINS on the BS1). For example:

Setup:
  INPUT 4

Hold:
  IF PIN4 = 0 THEN Hold                         ' Stay here until P4 is 1

Setup:
  INPUT 4

Hold:
  IF (IN4 = 0) THEN Hold                        ' Stay here until P4 is 1
The code above will read the state of P4 as set by external circuitry. If nothing is connected to P4, it will alternate between states (1 or 0) apparently at random.

What happens if your program writes to the OUTS bit (PINS bit on the BS1) of a pin that is set up as an input? The value is stored in OUTS (PINS on the BS1), but has no effect on the outside world. If the pin is changed to output, the last value written to the corresponding OUTS bit (or PINS bit on the BS1) will appear on the pin. The example program shows how this works.

Related command: OUTPUT and REVERSE


INPUT / OUTPUT Examples

' INPUT_OUTPUT.BS1
' This program demonstrates how the input/output direction of a pin is
' determined by the corresponding bit of DIRS. It also shows that the
' state of the pin itself (as reflected by the corresponding bit of PINS)
' is determined by the outside world when the pin is an input, and by the
' corresponding bit of PINS when it's an output. To set up the demo,
' connect a 10k resistor from +5V to P7 on the BASIC Stamp. The resistor
' to +5V puts a high (1) on the pin when it's an input. The BASIC Stamp
' can override this state by writing a low (0) to bit 7 of OUTS and
' changing the pin to output.

' {$STAMP BS1}
' {$PBASIC 1.0}

Main:
  INPUT 7                               ' Make P7 an input
  DEBUG "State of P7: ", #PIN7, CR

  PIN7 = 0                              ' Write 0 to output latch
  DEBUG "After 0 written to OUT7: "
  DEBUG #PIN7, CR

  OUTPUT 7                              ' Make P7 an output
  DEBUG "After P7 changed to output: "
  DEBUG #PIN7
  END

NOTE: This is written for the BS2 and will run on any of the BS2-family modules. Modify the $STAMP directive (as required) before downloading to the BS2e, BS2sx, BS2p, BS2pe, or BS2px.

' INPUT_OUTPUT.BS2
' This program demonstrates how the input/output direction of a pin is
' determined by the corresponding bit of DIRS. It also shows that the
' state of the pin itself (as reflected by the corresponding bit of PINS)
' is determined by the outside world when the pin is an input, and by the
' corresponding bit of PINS when it's an output. To set up the demo,
' connect a 10k resistor from +5V to P7 on the BASIC Stamp. The resistor
' to +5V puts a high (1) on the pin when it's an input. The BASIC Stamp
' can override this state by writing a low (0) to bit 7 of OUTS and
' changing the pin to output.

' {$STAMP BS2}
' {$PBASIC 2.5}

Main:
  INPUT 7                               ' Make P7 an input
  DEBUG "State of P7: ",
        BIN1 IN7, CR

  OUT7 = 0                              ' Write 0 to output latch
  DEBUG "After 0 written to OUT7: ",
        BIN1 IN7, CR

  OUTPUT 7                              ' Make P7 an output
  DEBUG "After P7 changed to output: ",
        BIN1 IN7
  END


 IOTERM

Example

Syntax: IOTERM Port

Function
Switch program control to main I/O pins or auxiliary I/O pins (on the BS2p40 only) depending on the value of Port.

  • Port is a variable/constant/expression (0 - 1) that specifies which I/O port to use.

Quick Facts
 | BS2p, BS2pe, and BS2px
Values for Port | 0 = switch to main I/O group, 1 = switch to auxiliary I/O group.
I/O Pin IDs | 0 - 15 (after IOTERM command, all references affect physical pins 5 - 20 or 21 - 36 depending on state of Port).
Special Notes | The BS2p24, BS2p40, BS2pe24, and BS2px24 accept this command, however, only the BS2p40 gives access to the auxiliary I/O pins.

Explanation
The BS2p, BS2pe, and BS2px is available as a 24-pin module that is pin-compatible with the BS2, BS2e, and BS2sx. Also availabe is a 40-pin module called the BS2p40 with an additional 16 I/O pins (for a total of 32). The BS2p40's I/O pins are organized into two groups, called main and auxiliary. The I/O pins in each group can be accessed in the same manner (by referencing I/O pins 0 - 15) but access is only possible within one group at a time. The IOTERM command causes the BASIC Stamp to affect either the main or auxiliary I/O pins in all further code until the MAINIO, AUXIO or another IOTERM command is reached, or the BASIC Stamp is reset or power-cycled. The value of Port determines which group of I/O pins will be referenced. Using 0 for Port will switch to the main I/O group and using 1 for Port will switch to the auxiliary group.

The following example illustrates this:

  HIGH 0
  IOTERM 1
  LOW 0

The first line of the above example will set I/O pin 0 of the main I/O pins (physical pin 5) high. Afterward, the IOTERM command tells the BASIC Stamp that all commands following it should affect the auxiliary I/O pins (Port = 1). The following LOW command will set I/O pin 0 of the auxiliary I/O pins (physical pin 21) low.

Note that the main I/O and auxiliary I/O pins are independent of each other; the states of the main I/O pins remain unchanged while the program affects the auxiliary I/O pins, and vice versa.

Related commands: AUXIO and MAINIO


 LCDCMD

Example

Syntax: LCDCMD Pin, Command

Function
Send a command to an LCD display.

  • Pin is a variable/constant/expression (0 - 1 or 8 - 9) that specifies which I/O pins to use. The LCD requires, at most, seven I/O pins to operate. The Pin argument serves a double purpose; specifying the first pin and, indirectly the group of other required pins. See explanation below. All I/O pins will be set to output mode.
  • Command is a variable/constant/expression (0 - 255) indicating the LCD command to send.

Quick Facts
 | BS2p, BS2pe, and BS2px
Values for Pin | 0, 1, 8, or 9
I/O pin arrangement when Pin is 0 or 1 | 0 or 1 (depending on Pin) : LCD Enable (E) pin 2 : LCD Read/Write (R/W) pin 3 : LCD Register Select (RS) pin 4 - 7 : LCD Data Bus (DB4 - DB7, respectively) pins
I/O pin arrangement when Pin is 8 or 9 | 8 or 9 (depending on Pin) : LCD Enable (E) pin 10 : LCD Read/Write (R/W) pin 11 : LCD Register Select (RS) pin 12 - 15 : LCD Data Bus (DB4 - DB7, respectively) pins

Explanation
The three LCD commands (LCDCMD, LCDIN and LCDOUT) allow the BS2p, BS2pe, or BS2px to interface directly to standard LCD displays that feature a Hitachi 44780 controller (part #HD44780A). This includes many 1 x 16, 2 x 16, and 4 x 20 character LCD displays.

The Hitachi 44780 LCD controller supports a number of special instructions for initializing the display, moving the cursor, changing the default layout, etc. The LCDCMD command is used to send one of these instructions to the LCD. It is most commonly used to initialize the display upon a power-up or reset condition. Note that LCDCMD, LCDIN and LCDOUT use a 4-bit interface to the LCD which requires a specific initialization sequence before LCDIN and LCDOUT can be used. Specifics on the initialization sequence will follow.

The following is an example of the LCDCMD command:

  LCDCMD 1, 24

The preceding code will send the Scroll Left command (represented by the number 24) to the LCD whose enable pin is connected to I/O pin 1. This will cause the LCD display to scroll, or shift, the entire display one character to the left.

You may have noticed that the Pin argument in the example above was 1. The LCDCMD command actually uses more than just this I/O pin, however. The LCDCMD command requires seven I/O pins. This is because the standard LCD displays have a parallel interface, rather than a serial one. The Pin argument can be the numbers 0, 1, 8, or 9 and will result in the use of the I/O pins shown above. The figure below shows the required wiring for the above command to work.

Note that we could have used 0 for the Pin argument and moved the LCD's Enable pin (pin 6) to I/O pin 0. Similarly, using 9 for the Pin argument would have required us to wire the LCD's pins to I/O pins 9 through 15, rather than I/O pins 1 through 7.

When the LCD is first powered-up, it will be in an unknown state and must be properly configured before sending commands like the one shown above. This process is known as initializing the LCD and is the first thing your program should do upon starting up. The following code is a good example of LCD initialization. (Refer to Hitachi documentation for details).

Init_LCD:
  PAUSE 1000                            ' allow LCD to power-up
  LCDCMD 1, 48                          ' Send wake-up sequence (3x)
  PAUSE 5
  LCDCMD 1, 48
  PAUSE 1
  LCDCMD 1, 48
  PAUSE 1
  LCDCMD 1, 32                          ' Set data bus to 4-bit mode
  LCDCMD 1, 40                          ' Set 2-line mode with 5x8 font
  LCDCMD 1, 8                           ' Turn display off
  LCDCMD 1, 12                          ' Turn display on without cursor
  LCDCMD 1, 6                           ' Auto-increment cursor
  LCDCMD 1, 1                           ' Clear the display

This initialization code is the most commonly used sequence for a 2 x 16 and 4 x 20 LCD display (the 2-line mode instruction sets the 4 x 20 to 4-line mode). The PAUSE 1000 command is optional, but only if your program takes more than approximately 700 ms before it executes the Init_LCD code above. Without it, upon powering your circuit, the BASIC Stamp may talk to the LCD too early, the LCD will then miss some of the commands and the display will operate strangely, or not at all.

Do not change the "wake-up" and "4-bit mode" sequence commands. However, the commands below the line that says, "Set data bus to 4-bit mode" may be modified to set other desired modes.

The table below shows the most commonly used LCD commands. Here's an example:

  LCDCMD  1, 128 + 64

The preceding command will move the cursor to the first character position on the second line (on a 2 x 16 display). 128 is the Move To Display Address command and 64 is the location number. See the "Character Positioning" section below, for more information.

Common LCD Commands

 | Command (Decimal) | Description
Do Nothing | 0 | Don't perform any special function.
Clear Display | 1 | Move cursor and display to home position.
Home Display | 2 | Move cursor and display to home position.
Inc Cursor | 6 | Set cursor direction to right, without a display shift.
Display Off | 8 | Turn off display (display data is retained).
Display On | 12 | Turn on display without cursor (display is restored).
Blinking Cursor | 13 | Turn on display with blinking cursor.
Underline Cursor | 14 | Turn on display with underline cursor.
Cursor Left | 16 | Move cursor left one character.
Cursor Right | 20 | Move cursor right one character.
Scroll Left | 24 | Scroll display left one character.
Scroll Right | 28 | Scroll display right one character.
Move To CGRAM Address | 64 + address | Move pointer to Character Generator RAM location
Move To DDRAM Address | 128 + address | Move cursor to Display Data RAM location

While most users will only need the commands shown above, the table below details all of the instructions supported by the LCD (for advanced users). Many instructions are multipurpose, depending on the state of special bits. Clever manipulation of the instruction bits will allow for powerful control of the LCD.

 | Command Code (bits) |  |  |  |  |  |  |  | Description
 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0
Clear Display | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | Clear entire display and move cursor home (address 0)
Home Display | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | Move cursor home and return display to home position.
Entry Mode | 0 | 0 | 0 | 0 | 0 | 1 | M | S | Sets cursor direction (M: 0=left, 1=right) and display scrolling (S: 0=no scroll, 1=scroll)
Display/Cursor | 0 | 0 | 0 | 0 | 1 | D | U | B | Sets display on/off (D), underline cursor (U) and blinking block cursor (B). (0=off, 1=on)
Scroll Display / Shift Cursor | 0 | 0 | 0 | 1 | C | M | 0 | 0 | Shifts display or cursor (C: 0=cursor, 1=display) left or right (M: 0=left, 1=right).
Function Set | 0 | 0 | 1 | B | L | F | 0 | 0 | Sets buss size (B: 0=4-bits, 1=8-bits), number of lines (L: 0=1?line, 1=2-lines) and font size (F: 0=5x8, 1=5x10)
Move To CGRAM Address | O | 1 | A | A | A | A | A | A | Move pointer to Character Generator RAM location specified by address (A)
Move To DDRAM Address | 1 | A | A | A | A | A | A | A | Move cursor to Display Data RAM location specified by address (A)

The last command shown above (Move To DDRAM Address) is used to move the cursor to a specific position on the LCD. The LCD's DDRAM (Display Data RAM) is a fixed size with unique position number for each character cell. The viewable portion of the DDRAM depends on the LCD's logical view position (which can be altered with the Scroll Display command). The default view position is called the Home position; it means that the display's upper left character corresponds to DDRAM location 0. The diagrams below indicates the position numbers for characters on the LCD screen.

Note that the diagram shows the most common DDRAM mapping, though some LCD's may have organized the DDRAM differently. A little experimentation with your LCD may reveal this.

2 x 16 Display

 | On-screen Positions* |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  | Off-screen
Line 1 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | ... | 39
Line 2 | 64 | 65 | 66 | 67 | 68 | 69 | 79 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | ... | 103

* Assuming the display is in the home position

4 x 20 Display

Line 1 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19
Line 2 | 64 | 65 | 66 | 67 | 68 | 69 | 79 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83
Line 3 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39
Line 4 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103

On a standard 2 x 16 character display, the following command would move the cursor to the third column of the second line:

  LCDCMD 1, 128 + 66

The number 128 tells the LCD we wish to move the cursor and 66 is the location number of the desired position. Similarly, sending just 128 (128 + 0) would move the cursor to the first character of the first line (the upper left character if the display is at the home position).

You may have noticed that the 2 x 16 display has many locations that are not visible; they are to the right of the edge of the screen. These locations (16 - 39 and 80 to 103) become important for scrolling operations. For example, it is possible to move the cursor to location 16, print some text there and then issue a number of Scroll Left instructions (LCDCMD 1, 24) to slowly scroll the text onto the display from right to left. If you did so, the DDRAM positions that were on the left of the screen would now be past the left edge of the screen. For example:

  LCDCMD 1, 24
  LCDCMD 1, 24

would cause the screen to scroll to the left by two characters. At this point, the upper-left character in the display would actually be DDRAM location 2 and the lower-left character would be DDRAM location 66. Locations 0, 1, 64 and 65 would be off the left edge of the LCD and would no longer be visible. Some interesting effects can be achieved by taking advantage of this feature.

The 4 x 20 LCD has a strange DDRAM map. The upper-right character is location 19 and the next location, 20, appears as the first character of the third line. This strange mapping is due to constraints in the LCD controller and the manufacturers design, and unfortunately makes the scrolling features virtually useless on the 4 x 20 displays.

Even though the LCD requires many pins to talk to it, only the Enable pin needs to remain dedicated to the LCD and all the other pins can be multiplexed (shared) with certain other devices (if wired carefully). In addition, the I/O pin connected to the LCD's R/W pin is only necessary if the LCDIN command will be used in the application. If the LCDIN command will not be used, LCD pin 5 (R/W pin) can be connected to ground and I/O pin 2 (shown above) may be left disconnected. I/O pin 2 will still be set to output mode for each LCDCMD and LCDOUT command executed, however.

Related commands: LCDIN and LCDOUT


LCDCMD Example

Syntax

NOTE: This is written for the BS2p and will also run on the BS2pe and BS2px. Modify the $STAMP directive (as required) before downloading to BS2pe or BS2px.

' LCDCMD.BSP
' This program demonstrates initialization and printing on a 2 x 16
' character LCD display. The set of "LCD constants", below, are provided
' as pre-defined and useful LCD commands, though not all are actually
' used in this program.

' {$STAMP BS2p}
' {$PBASIC 2.5}

#IF ($STAMP < BS2P) #THEN
  #ERROR "Program requires BS2p, BS2pe, or BS2px."
#ENDIF

Lcd             PIN     0

LcdCls          CON     $01     ' clear the LCD
LcdHome         CON     $02     ' move cursor home
LcdCrsrL        CON     $10     ' move cursor left
LcdCrsrR        CON     $14     ' move cursor right
LcdDispL        CON     $18     ' shift chars left
LcdDispR        CON     $1C     ' shift chars right
LcdDDRam        CON     $80     ' Display Data RAM
LcdCGRam        CON     $40     ' Character Generator RAM
LcdLine1        CON     $80     ' DDRAM address of line 1
LcdLine2        CON     $C0     ' DDRAM address of line 2

Init_LCD:
  PAUSE 1000                    ' allow LCD to self-initialize first
  LCDCMD Lcd, %00110000         ' send wakeup sequence to LCD
  PAUSE 5                       ' pause required by LCD specs
  LCDCMD Lcd, %00110000
  PAUSE 0                       ' pause required by LCD specs
  LCDCMD Lcd, %00110000
  PAUSE 0                       ' pause required by LCD specs
  LCDCMD Lcd, %00100000         ' set data bus to 4-bit mode
  LCDCMD Lcd, %00101000         ' set to 2-line mode with 5x8 font
  LCDCMD Lcd, %00001100         ' display on without cursor
  LCDCMD Lcd, %00000110         ' auto-increment cursor

Main:
  DO
    LCDOUT Lcd, LcdCls, ["Hello, World!"]
    LCDOUT Lcd, LcdLine2, ["How are you?"]
    PAUSE 3000
    LCDCMD Lcd, LcdCls
    PAUSE 500
  LOOP
  END


 LCDIN

Example

Syntax: LCDIN Pin, Command, [InputData]

Function
Receive data from an LCD display.

  • Pin is a variable/constant/expression (0 - 1 or 8 - 9) that specifies which I/O pins to use. The LCD requires, at most, seven I/O pins to operate. The Pin argument serves a double purpose; specifying the first pin and, indirectly, the group of other required pins. See explanation below. All I/O pins will be set to output mode initially and the upper I/O pins (4 - 7 or 12 - 15) will be set to input mode by the end of the LCDIN command.
  • Command is a variable/constant/expression (0 - 255) indicating the LCD command to send.
  • InputData is a list of variables and formatters that tells LCDIN what to do with incoming data. LCDIN can store data in a variable or array, interpret numeric text (decimal, binary, or hex) and store the corresponding value in a variable, wait for a fixed or variable sequence of bytes, or ignore a specified number of bytes. These actions can be combined in any order in the InputData list.

Quick Facts
 | BS2p, BS2pe, and BS2px
Values for Pin | 0, 1, 8, or 9
I/O pin arrangement when Pin is 0 or 1 | 0 or 1 (depending on Pin) : LCD Enable (E) pin 2 : LCD Read/Write (R/W) pin 3 : LCD Register Select (RS) pin 4 - 7 : LCD Data Bus (DB4 - DB7, respectively) pins
I/O pin arrangement when Pin is 8 or 9 | 8 or 9 (depending on Pin) : LCD Enable (E) pin 10 : LCD Read/Write (R/W) pin 11 : LCD Register Select (RS) pin 12 - 15 : LCD Data Bus (DB4 - DB7, respectively) pins

Explanation
The three LCD commands (LCDCMD, LCDIN and LCDOUT) allow the BS2p, BS2pe, or BS2pe to interface directly to standard LCD displays that feature a Hitachi 44780 controller (part #HD44780A). This includes many 1 x 16, 2 x 16, and 4 x 20 character LCD displays. Note that LCDCMD, LCDIN and LCDOUT use a 4-bit interface to the LCD which requires a specific initialization sequence before LCDIN and LCDOUT can be used (see LCDCMD for initialization details).

The LCDIN command is used to send one instruction and then receive at least one data byte from the LCD's Character Generator RAM (CGRAM) or Display Data RAM (DDRAM). The following is an example of the LCDIN command:

char    VAR     Byte

Main:
  LCDIN 1, 128, [char]
  STOP

The preceding example will read the character value at location 0 of the DDRAM. See the "Character Positioning" section, below, for more information.

The LCDIN command actually uses more than just the I/O pin specified by the Pin argument. The LCDIN command requires seven I/O pins. This is because the standard LCD displays have a parallel interface, rather than a serial one. The Pin argument can be the numbers 0, 1, 8, or 9 and will result in the use of the I/O pins shown above. Please refer to the LCDCMD command description for information on properly wiring the LCD display.

When the LCD is first powered-up, it will be in an unknown state and must be properly configured before sending commands like the one shown above. This process is known as initializing the LCD and is the first thing your program should do upon starting up. Please refer to the LCDCMD command description for information on properly initializing the LCD display.

The LCDIN command's InputData argument is similar to the SERIN command's InputData argument. This means data can be received as ASCII character values, decimal, hexadecimal and binary translations and string data as in the examples below (assume the LCD display has "Value: 3A:101" starting at the first character of the first line on the screen).

value   VAR     Byte(13)

Main:
  LCDIN 1, 128, [value]                 ' receive ASCII code for "V"
  LCDIN 1, 128, [DEC value]             ' receive the number 3
  LCDIN 1, 128, [HEX value]             ' receive the number $3A
  LCDIN 1, 128, [BIN value]             ' receive the number %101
  LCDIN 1, 128, [STR value\13]          ' receive the string "Value: 3A:101"

The tables below list all the available conversion formatters and special formatters available to the LCDIN command. See the SERIN command for additional information and examples of their use.

Conversion Formatter | Type of Number | Numeric Characters Accepted | Notes
DEC{1..5} | Decimal, optionally limited to 1 - 5 digits | 0 through 9 | 1
SDEC{1..5} | Signed decimal, optionally limited to 1 - 5 digits | -, 0 through 9 | 1,2
HEX{1..4} | Hexadecimal, optionally limited to 1 - 4 digits | 0 through 9, A through F | 1,3
SHEX{1..4} | Signed hexadecimal, optionally limited to 1 - 4 digits | -, 0 through 9, A through F | 1,2,3
IHEX{1..4} | Indicated hexadecimal, optionally limited to 1 - 4 digits | $, 0 through 9, A through F | 1,3,4
ISHEX{1..4} | Signed, indicated hexadecimal, optionally limited to 1 - 4 digits | -, $, 0 through 9, A through F | 1,2,3,4
BIN{1..16} | Binary, optionally limited to 1 - 16 digits | 0, 1 | 1
SBIN{1..16} | Signed binary, optionally limited to 1 - 16 digits | -, 0, 1 | 1,2
IBIN{1..16} | Indicated binary, optionally limited to 1 - 16 digits | %, 0, 1 | 1,4
ISBIN{1..16} | Signed, indicated binary, optionally limited to 1 - 16 digits | -, %, 0, 1 | 1,2,4
NUM | Generic numeric input; hex or binary number must be indicated | $, %, 0 through 9, A through F | 1,3,4
SNUM | Similar to NUM with value treated as signed with range -32768 to +32767 | -, $, %, 0 through 9, A through F | 1,2,3,4

  1. All numeric conversions will continue to accept new data until receiving either the specified number of digits (ex: three digits for DEC3) or a non-numeric character.
  2. To be recognized as part of a number, the minus sign (-) must immediately precede a numeric character. The minus sign character occurring in non-numeric text is ignored and any character (including a space) between a minus and a number causes the minus to be ignored.
  3. The hexadecimal formatters are not case-sensitive; "a" through "f" means the same as "A" through "F".
  4. Indicated hexadecimal and binary formatters ignore all characters, even valid numerics, until they receive the appropriate prefix ($ for hexadecimal, % for binary). The indicated formatters can differentiate between text and hexadecimal (ex: ABC would be interpreted by HEX as a number but IHEX would ignore it unless expressed as $ABC). Likewise, the binary version can distinguish the decimal number 10 from the binary number %10. A prefix occurring in non-numeric text is ignored, and any character (including a space) between a prefix and a number causes the prefix to be ignored. Indicated, signed formatters require that the minus sign come before the prefix, as in -$1B45.

Special Formatter | Action
STR ByteArray \L {\E} | Input a character string of length L into an array. If specified, an end character E causes the string input to end before reaching length L. Remaining bytes are filled with 0s (zeros).
WAITSTR ByteArray {\L} | Wait for a sequence of bytes matching a string stored in an array variable, optionally limited to L characters. If the optional L argument is left off, the end of the array-string must be marked by a byte containing a zero (0).
SKIP Length | Ignore Length bytes of characters.
SPSTR Length | Buffer Length bytes (up to 126) of serial characters to Scratchpad RAM, starting at location 0. Use GET to retrieve the characters.

Some possible uses of the LCDIN command are 1) in combination with the LCDOUT command to store and read data from the unused DDRAM or CGRAM locations (as extra variable space), 2) to verify that the data from a previous LCDOUT command was received and processed properly by the LCD, and 3) to read character data from CGRAM for the purposes of modifying it and storing it as a custom character.

Related commands: LCDCMD and LCDOUT


LCDIN Example

Syntax

NOTE: This is written for the BS2p and will also run on the BS2pe and BS2px. Modify the $STAMP directive (as required) before downloading to BS2pe or BS2px.

' LCDIN.BSP
' This program demonstrates initialization, printing and reading from
' a 2 x 16 character LCD display.

' {$STAMP BS2p}
' {$PBASIC 2.5}

#IF ($STAMP < BS2P) #THEN
  #ERROR "Program requires BS2p, BS2pe, or BS2px."
#ENDIF

Lcd             PIN     0

LcdCls          CON     $01             ' clear the LCD
LcdHome         CON     $02             ' move cursor home
LcdCrsrL        CON     $10             ' move cursor left
LcdCrsrR        CON     $14             ' move cursor right
LcdDispL        CON     $18             ' shift chars left
LcdDispR        CON     $1C             ' shift chars right
LcdDDRam        CON     $80             ' Display Data RAM
LcdCGRam        CON     $40             ' Character Generator RAM
LcdLine1        CON     $80             ' DDRAM address of line 1
LcdLine2        CON     $C0             ' DDRAM address of line 2

char            VAR     Byte(16)

Init_LCD:
  PAUSE 1000                            ' allow LCD to self-initialize first
  LCDCMD Lcd, %00110000                 ' send wakeup sequence to LCD
  PAUSE 5                               ' pause required by LCD specs
  LCDCMD Lcd, %00110000
  PAUSE 0                               ' pause required by LCD specs
  LCDCMD Lcd, %00110000
  PAUSE 0                               ' pause required by LCD specs
  LCDCMD Lcd, %00100000                 ' set data bus to 4-bit mode
  LCDCMD Lcd, %00101000                 ' set to 2-line mode with 5x8 font
  LCDCMD Lcd, %00001100                 ' display on without cursor
  LCDCMD Lcd, %00000110                 ' auto-increment cursor

Main:
  DO
    LCDOUT Lcd, LcdCls, ["Hello!"]
    GOSUB Read_LCD_Screen
    PAUSE 3000
    LCDOUT Lcd, LcdCls, ["I'm a 2x16 LCD!"]
    GOSUB Read_LCD_Screen
    PAUSE 3000
  LOOP
  END

Read_LCD_Screen:
  DEBUG "LCD now says: "
  LCDIN Lcd, LcdLine1, [STR char\16]
  DEBUG STR char\16, CR
  RETURN


 LCDOUT

Example

Syntax: LCDOUT Pin, Command, [OutputData]

Function
Send data to an LCD display.

  • Pin is a variable/constant/expression (0 - 1 or 8 - 9) that specifies which I/O pins to use. The LCD requires, at most, seven I/O pins to operate. The Pin argument serves a double purpose; specifying the first pin and, indirectly, the group of other required pins. See explanation below. All I/O pins will be set to output mode initially and the upper I/O pins (4 - 7 or 12 - 15) will be set to output mode by the end of the LCDOUT command.
  • Command is a variable/constant/expression (0 - 255) indicating an LCD command to send.
  • OutputData is a list of variables, constants, expressions and formatters that tells LCDOUT how to format outgoing data. LCDOUT can transmit individual or repeating bytes, convert values into decimal, hex or binary text representations, or transmit strings of bytes from variable arrays. These actions can be combined in any order in the OutputData list.

Quick Facts
 | BS2p, BS2pe, and BS2px
Values for Pin | 0, 1, 8, or 9
I/O pin arrangement when Pin is 0 or 1 | 0 or 1 (depending on Pin) : LCD Enable (E) pin 2 : LCD Read/Write (R/W) pin 3 : LCD Register Select (RS) pin 4 - 7 : LCD Data Bus (DB4 - DB7, respectively) pins
I/O pin arrangement when Pin is 8 or 9 | 8 or 9 (depending on Pin) : LCD Enable (E) pin 10 : LCD Read/Write (R/W) pin 11 : LCD Register Select (RS) pin 12 - 15 : LCD Data Bus (DB4 - DB7, respectively) pins

Explanation
The three LCD commands (LCDCMD, LCDIN and LCDOUT) allow the BS2p, BS2pe, or BS2pe to interface directly to standard LCD displays that feature a Hitachi 44780 controller (part #HD44780A). This includes many 1 x 16, 2 x 16, and 4 x 20 character LCD displays. Note that LCDCMD, LCDIN and LCDOUT use a 4-bit interface to the LCD which requires a specific initialization sequence before LCDIN and LCDOUT can be used (see LCDCMD for initialization details).

The LCDOUT command is used to send one instruction followed by at least one data byte to the LCD. The data that is output is written to the LCD's Character Generator RAM (CGRAM) or Display Data RAM (DDRAM). The following is an example of the LCDOUT command:

  LCDOUT 1, 1, ["Hello World!"]

The preceding example will clear the LCD screen and then send "Hello World!" to the screen. The first argument (1) is the starting I/O pin number and the second argument (also 1) is the LCD's instruction for Clear Screen.

The LCDOUT command actually uses more than just the I/O pin specified by the Pin argument. The LCDOUT command requires seven I/O pins. This is because the standard LCD displays have a parallel interface, rather than a serial one. The Pin argument can be the numbers 0, 1, 8, or 9 and will result in the use of the I/O pins shown above. Please refer to the LCDCMD command description for information on properly wiring the LCD display.

When the LCD is first powered-up, it will be in an unknown state and must be properly configured before sending commands like the one shown above. This process is known as initializing the LCD and is the first thing your program should do upon starting up. Please refer to the LCDCMD command description for information on properly initializing the LCD display.

The LCDOUT command's OutputData argument is exactly like that of the DEBUG and SEROUT command's OutputData argument. This means data can be sent as literal text, ASCII character values, repetitive values, decimal, hexadecimal and binary translations and string data as in the examples below.

value   VAR     Byte

Setup:
  value = 65

Main:
  LCDOUT 1, 0, [value]                  ' send ASCII character "A"
  LCDOUT 1, 0, [REP value\5]            ' send "AAAAA"
  LCDOUT 1, 0, [DEC value]              ' send "6" and "5"
  LCDOUT 1, 0, [HEX value]              ' send "4" and "1"
  LCDOUT 1, 0, [BIN value]              ' send "1000001"
  STOP

The tables below list all the available conversion formatters and special formatters available to the LCDOUT command. See the DEBUG and SEROUT commands for additional information and examples of their use.

Conversion Formatter | Type of Number | Notes
DEC{1..5} | Decimal, optionally fixed to 1 - 5 digits | 1
SDEC{1..5} | Signed decimal, optionally fixed to 1 - 5 digits | 1,2
HEX{1..4} | Hexadecimal, optionally fixed to 1 - 4 digits | 1
SHEX{1..4} | Signed hexadecimal, optionally fixed to 1 - 4 digits | 1,2
IHEX{1..4} | Indicated hexadecimal, optionally fixed to 1 - 4 digits | 1
ISHEX{1..4} | Signed, indicated hexadecimal, optionally fixed to 1 - 4 digits ($ prefix) | 1,2
BIN{1..16} | Binary, optionally fixed to 1 - 16 digits | 1
SBIN{1..16} | Signed binary, optionally fixed to 1 - 16 digits | 1,2
IBIN{1..16} | Indicated binary, optionally fixed to 1 - 16 digits | 1
ISBIN{1..16} | Signed, indicated binary, optionally fixed to 1 - 16 digits | 1,2

  1. Fixed-digit formatters like DEC4 will pad the number with leading 0s if necessary; ex: DEC4 65 sends 0065. If a number is larger than the specified number of digits, the leading digits will be dropped; ex: DEC4 56422 sends 6422.
  2. Signed modifiers work under two's complement rules.

Special Formatter | Action
? | Displays "symbol = x' + carriage return; where x is a number. Default format is decimal, but may be combined with conversion formatters (ex: BIN ? x to display "x = binary_number").
ASC ? | Displays "symbol = 'x'" + carriage return; where x is an ASCII character.
STR ByteArray {\L} | Send character string from an array. The optional \L argument can be used to limit the output to L characters, otherwise, characters will be sent up to the first byte equal to 0 or the end of RAM space is reached.
REP Byte\L | Send a string consisting of Byte repeated L times (ex: REP "X"\10 sends "XXXXXXXXXX").

Using the Command Argument

The Command argument is useful for proceeding a set of data with a special LCD instruction. For example, the code below will move the cursor to location 64 (the first character on the second line) and print "Hi":

  LCDOUT 1, 128 + 64, ["Hi"]

The next example, below, will turn on the blinking block cursor and print "Yo!":

  LCDOUT 1, 13, ["Yo!"]

Occasionally, you will want to send data without preceding it with a command. To do this, simply use 0 for the Command argument, as in:

  LCDOUT 1, 0, ["Hello there!"]

Another use for the LCDOUT command is to access and create custom characters. The Hitachi 44780 controller has a built-in character set that is similar to the ASCII character set (at least for the first 128 characters). Most of these characters are stored in ROM and are not changeable, however, the first eight characters (ASCII 0 though 7) are programmable.

Each of the programmable characters is five pixels wide and eight pixels tall. It takes eight bytes to describe each character; one byte per row (the left-most three bits are ignored). For example, the character at ASCII location 0 is defined by the bit patterns stored in bytes 0 through 7 of Character Generator RAM (CGRAM). The character at ASCII location 1 is defined by the bit patterns stored in bytes 8 through 15 of CGRAM, and so on.

To create a custom character, use some graph paper to plot out the bit pattern (on and off pixels) in a 5 x 8 pattern, as shown in below. Then calculate the corresponding binary value of the bit pattern for each of the eight rows of character data.

Character Cell Structure and Data

After the data is calculated for each character (8 byte values per character), use the LCDOUT command with the "Move To CGRAM Address" instruction to insert the data into the character's CGRAM locations. For example, the code below will store the character shown in above into character 0's CGRAM data locations. Then it will place the cursor back on the display (DDRAM) and print the character on the screen.

  LCDOUT 1,  64+0, [00, 10, 10, 00, 17, 14, 06, 00]
  LCDOUT 1, 128+0, ["Custom Char: ", 0]

The number 64 in the Command argument is the LCD's "Move to CGRAM Address" instruction and the 0 that is added to it is the location of the first row of data for the character 0. The LCDOUT command will write the first OutputData value (00) to this location, the second OutputData value (10) to location 1, etc. If we wanted this custom character to affect character 1, instead of 0, we'd have to adjust value of the "Move To..." command, i.e., 64+8. To affect character 2, we'd use 64+16.

To try the example above, don't forget to execute the LCD initialization code (shown in the LCDCMD description) first and never forget to move the cursor back to the screen (as with the last command, above) when you're done writing the character data to CGRAM.

Related commands: LCDCMD and LCDIN


LCDOUT Example

Syntax

NOTE: This is written for the BS2p and will also run on the BS2pe and BS2px. Modify the $STAMP directive (as required) before downloading to BS2pe or BS2px.

' LCDOUT.BSP
' This program demonstrates initialization and printing on a 2x16
' character LCD display.

' {$STAMP BS2p}
' {$PBASIC 2.5}

#IF ($STAMP < BS2P) #THEN
  #ERROR "Program requires BS2p, BS2pe, or BS2px."
#ENDIF

Lcd             PIN     0

LcdCls          CON     $01             ' clear the LCD
LcdHome         CON     $02             ' move cursor home
LcdCrsrL        CON     $10             ' move cursor left
LcdCrsrR        CON     $14             ' move cursor right
LcdDispL        CON     $18             ' shift chars left
LcdDispR        CON     $1C             ' shift chars right
LcdDDRam        CON     $80             ' Display Data RAM
LcdCGRam        CON     $40             ' Character Generator RAM
LcdLine1        CON     $80             ' DDRAM address of line 1
LcdLine2        CON     $C0             ' DDRAM address of line 2

Init_LCD:
  PAUSE 1000                            ' allow LCD to self-initialize first
  LCDCMD Lcd, %00110000                 ' send wakeup sequence to LCD
  PAUSE 5                               ' pause required by LCD specs
  LCDCMD Lcd, %00110000
  PAUSE 0                               ' pause required by LCD specs
  LCDCMD Lcd, %00110000
  PAUSE 0                               ' pause required by LCD specs
  LCDCMD Lcd, %00100000                 ' set data bus to 4-bit mode
  LCDCMD Lcd, %00101000                 ' set to 2-line mode with 5x8 font
  LCDCMD Lcd, %00001100                 ' display on without cursor
  LCDCMD Lcd, %00000110                 ' auto-increment cursor

  LCDOUT Lcd, LcdCGRam,                 ' load custom chracter map
         [$00, $0A, $0A, $00, $11, $0E, $06, $00]

Main:
  DO
    LCDOUT Lcd, LcdCls, ["Hello my friend."]
    PAUSE 750
    LCDOUT Lcd, LcdLine2, ["How are you?"]
    PAUSE 1500
    LCDCMD Lcd, LcdCls
    LCDOUT Lcd, LcdLine1 + 1, ["I'm doing just"]
    LCDOUT Lcd, LcdLine2 + 4, ["fine!  ", 0]
    PAUSE 2000
  LOOP
  END


 LOOKDOWN

Examples

Syntax [image] : LOOKDOWN Target, (Value0, Value1, ...ValueN ), Variable
Syntax [image] : LOOKDOWN Target, {ComparisonOp} [Value0, Value1, ...ValueN], Variable

Function
Compare Target value to a list of values and store the index number of the first value that matches into Variable. If no value in the list matches, Variable is left unaffected. On the BS2, BS2e, BS2sx and BS2p, the optional ComparisonOp is used as criteria for the match; the default criteria is "equal to."

  • Target is a variable/constant/expression* (0 - 65535) to be compared to the values in the list.
  • ComparisonOp is an optional comparison operator (as described below) to be used as the criteria when comparing values. When no ComparisonOp is specified, equal to (=) is assumed. This argument is not available on the BS1.
  • Values are variables/constants/expressions* (0 - 65535) to be compared to Target.
  • Variable is a variable (usually a byte) that will be set to the index (0 - 255) of the matching value in the Values list. If no matching value is found, Variable is left unaffected.

* Note: Expressions are not allowed as arguments on the BS1.

Quick Facts
 | All BASIC Stamp Modules
Limit of value entries | 256
Starting index number | 0
If value list contains no match... | Variable is left unaffected

Explanation
LOOKDOWN works like the index in a book. In an index, you search for a topic and get the page number. LOOKDOWN searches for a target value in a list, and stores the index number of the first match in a variable. For example:

SYMBOL  value   = B2
SYMBOL  result  = B3

Setup:
  value = 17
  result = 15

Main:
  LOOKDOWN value, (26, 177, 13, 1, 0, 17, 99), result
  DEBUG "Value matches item ", #result, "in list"
  END

value   VAR     Byte
result  VAR     Byte

Setup:
  value = 17
  result = 15

Main:
  LOOKDOWN value, [26, 177, 13, 1, 0, 17, 99], result
  DEBUG "Value matches item ", DEC result, " in list"
  END

DEBUG prints, "Value matches item 5 in list" because the value (17) matches item 5 of [26, 177, 13, 1, 0, 17, 99]. Note that index numbers count up from 0, not 1; that is, in this list, 26 is item 0.

What happens if the value doesn't match any of the items in the list? Try changing "value = 17" to "value = 2." Since 2 is not on the list, LOOKDOWN leaves result unaffected. Since result contained 15 before LOOKDOWN executed, DEBUG prints "Value matches item 15 in list." By strategically setting the initial value of result, as we have here, your program can be written to detect when an item was not found in the list.

Don't forget that text phrases are just lists of byte values, so they too are eligible for LOOKDOWN searches, as in this example:

SYMBOL  value   = B2
SYMBOL  result  = B3

Setup:
  value = "f"
  result = 255

Main:
  LOOKDOWN value, ("The quick brown fox"), result
  DEBUG "Value matches item ", #result, "in list"
  END

value   VAR     Byte
result  VAR     Byte

Setup:
  value = "f"
  result = 255

Main:
  LOOKDOWN value, ["The quick brown fox"], result
  DEBUG "Value matches item ", DEC result, " in list"
  END

DEBUG prints, "Value matches item 16 in list" because the character at index item 16 is "f" in the phrase, "The quick brown fox".

The examples above show LOOKDOWN working with lists of constants, but it also works with variables and expressions also. Note, however, that expressions are not allowed as argument on the BS1.

On the BS2, BS2e, BS2sx, BS2p and BS2pe, the LOOKDOWN command can also use another criteria (other than "equal to") for its list. All of the examples above use LOOKDOWN's default comparison operator, =, that searches for an exact match. The entire list of ComaprisonOps is shown below. The "greater than" comparison operator (>) is used in the following example:

value   VAR     Byte
result  VAR     Byte

Setup:
  value = 17
  result = 15

Main:
  LOOKDOWN value, >[26, 177, 13, 1, 0, 17, 99], result
  DEBUG "Value greater than item ", DEC result, " in list"
  END

DEBUG prints, "Value greater than item 2 in list" because the first item the value 17 is greater than is 13 (which is item 2 in the list). Value is also greater than items 3 and 4, but these are ignored, because LOOKDOWN only cares about the first item that matches the criteria. This can require a certain amount of planning in devising the order of the list. See the example program.

LOOKDOWN comparison operators use unsigned 16-bit math. They will not work correctly with signed numbers, which are represented internally as two's complement (large 16-bit integers). For example, the two's complement representation of -99 is 65437. So although -99 is certainly less than 0, it would appear to be larger than zero to the LOOKDOWN comparison operators. The bottom line is: Don't used signed numbers with LOOKDOWN comparisons.

ComparisonOp Symbol | Description
= | Find the first value Target is equal to
<> | Find the first value Target is not equal to
> | Find the first value Target is greater than
< | Find the first value Target is less than
>= | Find the first value Target is greater than or equal to
<= | Find the first value Target is less than or equal to

A common application for LOOKDOWN is to use it in conjunction with the BRANCH command to create selective jumps based on a simple variable input:

SYMBOL  cmd     = B2

Setup:
  cmd = "M"

Main:
  LOOKDOWN cmd, ("SLMH"), cmd
  BRANCH cmd, (_Stop, _Low, _Medium, _High)
  DEBUG "Command not in list"
  END

_Stop:
  DEBUG "Stop"
  END

_Low:
  DEBUG "Low"
  END

_Medium:
  DEBUG "Medium"
  END

_High:
  DEBUG "High"
  END

cmd     VAR     Byte

Setup:
  cmd = "M"

Main:
  LOOKDOWN cmd, ["SLMH"], cmd
  BRANCH cmd, [_Stop, _Low, _Medium, _High]
  DEBUG "Command not in list"
  END

_Stop:
  DEBUG "Stop"
  END

_Low:
  DEBUG "Low"
  END

_Medium:
  DEBUG "Medium"
  END

_High:
  DEBUG "High"
  END

In this example, cmd contains "M" (ASCII 77). LOOKDOWN finds that this is item 2 of a list of one-character commands and stores 2 into cmd. BRANCH then goes to item 2 of its list, which is the program label "_Medium" at which point DEBUG prints "Medium" on the PC screen. This is a powerful method for interpreting user input, and a lot neater than the alternative IF...THEN instructions.

Another great use of LOOKDOWN is in combination with LOOKUP to "map" non-contiguous sets of numbers together. For example, you may have an application where certain numbers are received by the BASIC Stamp and, in response, the BASIC Stamp needs to send a specific set of numbers. This may be easy to code if the numbers are contiguous, or follow some known algebraic equation... but what if they don't? The table below shows some sample, non-contiguous inputs and the corresponding outputs the BASIC Stamp needs to respond with:

Index | Each of these values received (inputs): | Needs to result in each of these values sent (outputs):
0 | 5 | 16
1 | 14 | 17
2 | 1 | 18
3 | 43 | 24
4 | 26 | 10
5 | 22 | 12
6 | 30 | 11

So, if we receive the number 5, we need to output 16. If we received 43, we need to output 24, and so on. These numbers are not contiguous and they don't appear to be derived from any simple algorithm. We can solve this problem with two lines of code, as follows:

  LOOKDOWN value, [5, 14, 1, 43, 26, 22, 30], value
  LOOKUP   value, [16, 17, 18, 24, 10, 12, 11], value

Assuming our received number is in value, the first line (LOOKDOWN) will find the value in the list and store the index of the location that matches back into value. (This step "maps" the non-contiguous numbers: 5, 14, 1, etc, to a contiguous set of numbers: 0, 1, 2, etc). The second line (LOOKUP) takes our new value, finds the number at that location and stores it back into value. If the received value was 14, LOOKDOWN stores 1 into value and LOOKUP looks at the value at location 1 and stores 17 in value. The number 43 gets mapped to 3, 3 gets mapped to 24, and so on. This is a quick and easy fix for a potentially messy problem!

Related commands: LOOKUP


LOOKDOWN Examples

Syntax
' LOOKDOWN.BS1
' This program uses LOOKDOWN followed by LOOKUP to map the numbers:
' 0, 10, 50, 64, 71 and 98 to 35, 40, 58, 62, 79, and 83, respectively.
' All other numbers are mapped to 255.

' {$STAMP BS1}
' {$PBASIC 1.0}

SYMBOL  num     = W0                    ' holds current number
SYMBOL  result  = W1                    ' holds mapped result

Main:
  FOR num = 0 TO 100
    result = 255                        ' default value for no match
    LOOKDOWN num, (0, 10, 50, 64, 71, 98), result
    LOOKUP result, (35, 40, 58, 62, 79, 83), result
    DEBUG "Num = ", #num, "Result = ", #result, CR
    PAUSE 100
  NEXT
  END

NOTE: This is written for the BS2 and will run on any of the BS2-family modules. Modify the $STAMP directive (as required) before downloading to the BS2e, BS2sx, BS2p, BS2pe, or BS2px.

' LOOKDOWN.BS2
' This program uses LOOKDOWN to determine the number of decimal digits in
' a number. Since LOOKDOWN uses a zero-indexed table, the output will be
' the number of digits minus one, so this gets corrected in the following
' line.  Note that zero is considered a valid number and has one digit.

' {$STAMP BS2}
' {$PBASIC 2.5}

aNum            VAR     Word            ' random number
stpSz           VAR     Word            ' FOR-NEXT step size
numDig          VAR     Nib             ' digits in aNum

Setup:
  stpSz = 2

Main:
  FOR aNum = 0 TO 15000 STEP stpSz
    LOOKDOWN aNum, <[0, 10, 100, 1000, 10000, 65535], numDig
    ' right-justify output
    DEBUG "aNum = ", REP " "\(5-numDig), DEC aNum, TAB,
          "Digits = ", DEC numDig, CR
    PAUSE 250
    LOOKDOWN aNum, <[0, 10, 100, 1000, 10000, 65535], stpSz
    LOOKUP stpSz, [2, 2, 5, 25, 250, 500, 1000], stpSz
  NEXT
  END


 LOOKUP

Examples

Syntax [image] : LOOKUP Index, (Value0, Value1, ...ValueN), Variable
Syntax [image] : LOOKUP Index, [Value0, Value1, ...ValueN], Variable

Function
Find the value at location Index and store it in Variable. If Index exceeds the highest index value of the items in the list, Variable is left unaffected.

  • Index is a variable/constant/expression* (0 - 255) indicating the list item to retrieve.
  • Values are variables/constants/expressions* (0 - 65535).
  • Variables is a variable that will be set to the value at the Index location. If Index exceeds the highest location number, Variable is left unaffected.

* Note: Expressions are not allowed as arguments on the BS1.

Quick Facts
 | All BASIC Stamp Modules
Limit of value entries | 256
Starting index number | 0
If index exceeds the highest location... | Variable is left unaffected

Explanation
LOOKUP retrieves an item from a list based on the item's position, Index, in the list. For example:

SYMBOL  idx     = B2
SYMBOL  result  = B3

Setup:
  idx = 3
  result = 255

Main:
  LOOKUP idx, (26, 177, 13, 1, 0, 17, 99), result
  DEBUG  "Item ", #idx, "is: ", #result
  END

idx     VAR     Nib
result  VAR     Byte

Setup:
  idx = 3
  result = 255

Main:
  LOOKUP idx, [26, 177, 13, 1, 0, 17, 99], result
  DEBUG  "Item ", DEC idx, " is: ", DEC result
  END

In this example, DEBUG prints "Item 3 is: 1." Note that the first location number is 0. In the list above, item 0 is 26, item 1 is 177, etc.

If Index is beyond the end of the list, the result variable is unchanged. In the example above, if index were greater than 6, the message would have reported the result to be 255, because that's what result contained before LOOKUP executed.

Don't forget that text phrases are just lists of byte values, so they too are eligible for LOOKUP searches, as in this example:

SYMBOL  idx     = B2
SYMBOL  result  = B3

Setup:
  idx = 16
  result = "*"

Main:
  LOOKUP idx, ("The quick brown fox"), result
  DEBUG @result
  END

idx     VAR     Byte
result  VAR     Byte

Setup:
  idx = 16
  result = "*"

Main:
  LOOKUP idx, ["The quick brown fox"], result
  DEBUG ASC? result
  END

DEBUG prints, "Result = 'f'" because the character at index item 16 is "f" in the phrase, "The quick brown fox".

The examples above show LOOKUP working with lists of constants, but it also works with variables and expressions also. Note, however, that expressions are not allowed as argument on the BS1.

A great use of LOOKUP is in combination with LOOKDOWN to "map" non-contiguous sets of numbers together. For example, you may have an application where certain numbers are received by the BASIC Stamp and, in response, the BASIC Stamp needs to send a specific set of numbers. This may be easy to code if the numbers are contiguous, or follow some know algebraic equations… but what if they don't? The table below shows some sample, non-contiguous inputs and the corresponding outputs the BASIC Stamp needs to respond with:

Index | Each of these values received (inputs): | Needs to result in each of these values sent (outputs):
0 | 5 | 16
1 | 14 | 17
2 | 1 | 18
3 | 43 | 24
4 | 26 | 10
5 | 22 | 12
6 | 30 | 11

So, if we receive the number 5, we need to output 16. If we received 43, we need to output 24, and so on. These numbers are not contiguous and they don't appear to be derived from any simple algorithm. We can solve this problem with two lines of code, as follows:

  LOOKDOWN value, [5, 14, 1, 43, 26, 22, 30], value
  LOOKUP   value, [16, 17, 18, 24, 10, 12, 11], value

Assuming our received number is in value, the first line (LOOKDOWN) will find the value in the list and store the index of the location that matches back into value. (This step "maps" the non-contiguous numbers: 5, 14, 1, etc, to a contiguous set of numbers: 0, 1, 2, etc). The second line (LOOKUP) takes our new value, finds the number at that location and stores it back into value. If the received value was 14, LOOKDOWN stores 1 into value and LOOKUP looks at the value at location 1 and stores 17 in value. The number 43 gets mapped to 3, 3 gets mapped to 24, and so on. This is a quick and easy fix for a potentially messy problem!

Related command: LOOKDOWN


LOOKUP Examples

Syntax
' LOOKUP.BS1
' This program uses LOOKUP to create a Debug-window animation of a spinning
' propeller.  The animation consists of the four ASCII characters | / - \
' which, when printed rapidly in order at a fixed location, appear to spin.
' A little imagination helps a lot here....

' {$STAMP BS1}
' {$PBAsic 1.0}

SYMBOL  idx             = B2
SYMBOL  frame           = B3

Spinner:
  LOOKUP idx, ("|/-\"), frame           ' lookup current frame character
  DEBUG CLS, "Spinner: ", #@frame       ' display
  idx = idx + 1 // 4                    ' update frame index (0..3)
  GOTO Spinner                          ' loop forever
  END

NOTE: This is written for the BS2 and will run on any of the BS2-family modules. Modify the $STAMP directive (as required) before downloading to the BS2e, BS2sx, BS2p, BS2pe, or BS2px.

' LOOKUP.BS2
' This program uses LOOKUP to create a Debug-window animation of a spinning
' propeller.  The animation consists of the four ASCII characters | / - \
' which, when printed rapidly in order at a fixed location, appear to spin.
' A little imagination helps a lot here....

' {$STAMP BS2}
' {$PBASIC 2.5}

idx             VAR     Nib
frame           VAR     Byte

Spinner:
  DO
    LOOKUP idx, ["|/-\"], frame         ' lookup current frame character
    DEBUG HOME, "Spinner: ", frame      ' display
    PAUSE 150                           ' pause between frames
    idx = idx + 1 // 4                  ' update frame index (0..3)
  LOOP                                  ' loop forever
  END


 LOW

Example

Syntax: LOW Pin

Function
Make the specified pin output low.

  • Pin is a variable/constant/expression (0 - 15) that specifies which I/O pin to set low. This pin will be placed into output mode.

* Note: Expressions are not allowed as arguments on the BS1. The range of the Pin argument on the BS1 is 0 - 7.

Explanation
The LOW command sets the specified pin to 0 (a 0 volt level) and then sets its mode to output. For example,

  LOW 6
does exactly the same thing as:

  PIN6 = 0
  DIR6 = 1

  OUT6 = 0
  DIR6 = 1
Using the LOW command is faster in this case.

Related command: HIGH


 MAINIO

Example

Syntax: MAINIO

Function
Switch from control of auxiliary I/O pins to main I/O pins (on the BS2p40 only).

Quick Facts
 | BS2p / BS2pe / BS2px
I/O Pin IDs | 0 - 15 (just like auxiliary I/O, but after MAINIO command, all references affect physical pins 5 - 20).
Special Notes | The BS2p, BS2pe, and BS2px modules accept this command, however, only the BS2p40 gives access to the auxiliary I/O pins.

Explanation
The BS2p, BS2pe, and BS2px is available as a 24-pin module that is pin-compatible with the BS2, BS2e, and BS2sx. Also availabe is a 40-pin module called the BS2p40 with an additional 16 I/O pins (for a total of 32). The BS2p40's extra, or auxiliary, I/O pins can be accessed in the same manner as the main I/O pins (by using the IDs 0 to 15) but only after issuing an AUXIO or IOTERM 1 command. The MAINIO command causes the BASIC Stamp to affect the main I/O pins (the default) instead of the auxiliary I/O pins in all further code until the AUXIO or IOTERM 1 command is reached, or the BASIC Stamp is reset or power-cycled.

The following example illustrates this:

  AUXIO
  HIGH 0
  MAINIO
  LOW 0
The first line of the above example will tell the BASIC Stamp to affect the auxiliary I/O pins in the commands following it. Line 2, sets I/O pin 0 of the auxiliary I/O pins (physical pin 21) high. Afterward, the MAINIO command tells the BASIC Stamp that all commands following it should affect the main I/O pins. The last command, LOW, will set I/O pin 0 of the main I/O pins (physical pin 5) low.

Note that the main I/O and auxiliary I/O pins are independent of each other; the states of the main I/O pins remain unchanged while the program affects the auxiliary I/O pins, and vice versa.

Related commands: AUXIO and IOTERM


 NAP

Example

Syntax: NAP Period

Function
Enter sleep mode for a short time. Power consumption is reduced as indicated in the table below assuming no loads are being driven.

  • Period is a variable/constant/expression* (0 - 7) that specifies the duration of the reduced-power "nap." The low-power duration is 2Period x 18 milliseconds.

* Note: Expressions are not allowed as arguments on the BS1.

Quick Facts
 | BS1 | BS2 | BS2e | BS2sx | BS2p | BS2pe | BS2px
Current Draw during Run | 1 mA | 3 mA | 25 mA | 60 mA | 40 mA | 15 mA | 55 mA
Current Draw during NAP | 25 µA | 50 µA | 200 µA | 500 µA | 350 µA | 36 µA | 450 µA
Accuracy of NAP | -50 to 100% (±10% @ 75°F with stable power supply)

Explanation
NAP uses the same shutdown/startup mechanism as SLEEP, with one big difference. During SLEEP, the BASIC Stamp automatically compensates for variations in the speed of the watchdog timer oscillator that serves as its alarm clock. As a result, longer SLEEP intervals are accurate to approximately ±1 percent.

Period | Length of NAP
0 | 18 ms
1 | 36 ms
2 | 72 ms
3 | 144 ms
4 | 288 ms
5 | 576 ms
6 | 1152 ms (1.152 seconds)
7 | 2304 ms (2.304 seconds)

NAP intervals are directly controlled by the watchdog timer without compensation. Variations in temperature, supply voltage, and manufacturing tolerance of the BASIC Stamp's interpreter chip can cause the actual timing to vary by as much as -50, +100 percent (i.e., a Period of 0, NAP can range from 9 to 36 ms). At room temperature with a fresh battery or other stable power supply, variations in the length of a NAP will be less than ±10 percent.

One great use for NAP is in a battery-powered application where at least some small amount of time is spent doing nothing. For example, you may have a program that loops endlessly, performing some task, and pausing for approximately 100 ms each time through the loop. You could replace your PAUSE 100 with NAP 3, as long as the timing of the 100 ms pause was not critical. The NAP 3 would effectively pause your program for about 144 milliseconds and, at the same time, would place the BASIC Stamp in low-power mode, which would extend your battery life.

If your application is driving loads (sourcing or sinking current through output-high or output-low pins) during a NAP, current will be interrupted for about 18 milliseconds when the BASIC Stamp wakes up. The reason is that the watchdog-timer reset that awakens the BASIC Stamp also causes all of the pins to switch to input mode for approximately 18 milliseconds. When the interpreter firmware regains control of the processor, it restores the I/O direction dictated by your program.

If you plan to use END, NAP, or SLEEP in your programs, make sure that your loads can tolerate these power outages. The simplest solution is often to connect resistors high or low (to +5V or ground) as appropriate to ensure a continuing supply of current during the reset glitch.

The demo program can be used to demonstrate the effects of the NAP glitch with an LED and resistor.

Related command: SLEEP


NAP Example

Syntax

Connect an LED and 470 Ω resistor as shown below for the demo program.

NOTE: This is written for the BS2 and will run on any BASIC Stamp module. Modify the $STAMP directive (as required) before downloading to the BS1, BS2e, BS2sx, BS2p, BS2pe, or BS2px.

' NAP.BS2
' The program below lights an LED by placing a low on pin 0. This completes
' the circuit from +5V, through the LED and resistor, to ground. During the
' NAP interval, the LED stays lit, but blinks off for a fraction of a second.
' This blink is caused by the NAP wakeup mechanism.  During wakeup, all pins
' briefly slip into input mode, effectively disconnecting them from loads.

' {$STAMP BS2}

Setup:
  LOW 0                                 ' turn LED on

Snooze:
  NAP 4                                 ' nap for 288 ms
  GOTO Snooze
  END


 ON...GOSUB

{$PBASIC 2.5} Example
Syntax: ON Offset GOSUB Address1, Address2, ...AddressN

Function
Store the address of the next instruction after ON..GOSUB, then go to the Address specified by offset (if in range) with the intention of returning to the stored address. If Offset-1 is greater than the number of elements in the address table, the program continues at the line following ON..GOSUB.

  • Offset is a variable/constant/expression (0 - 255) that specifies the index of the address, in the list, to branch to (0 - N).
  • Addresses are labels that specify where to go. ON...GOSUB will ignore any list entries beyond offset 255.

Quick Facts
 | BS2 Family
Limit of Address entries | 256
Maximum GOSUBs per program | 256 (each table entry counts as a GOSUB)

Explanation
The ON...GOSUB instruction is useful when you want to write something like this:

  IF (value = 0) THEN GOSUB Case_0
  IF (value = 1) THEN GOSUB Case_1
  IF (value = 2) THEN GOSUB Case_2

You can use ON...GOSUB to organize this into a single statement:

  ON value GOSUB Case_0, Case_1, Case_2
This works exactly the same as the previous IF...THEN example. If the value isn't in range (in this case if value is greater than 2), ON...GOSUB does nothing and the program continues with the next instruction after ON...GOSUB.

Related commands: GOSUB, RETURN, ON...GOTO ( [image] )


ON...GOSUB Example

{$PBASIC 2.5} Syntax

NOTE: This is written for the BS2 and will run on any of the BS2-family modules. Modify the $STAMP directive (as required) before downloading to the BS2e, BS2sx, BS2p, BS2pe, or BS2px.

' ON-GOSUB.BS2
' This program demonstrates a simple task manager that can be used in
' a variety of applications.  It is particularly useful in robotics and
' industrial applications.  The advantage of this design is that task
' code modules may be called from other places in the program, including
' other tasks, and the overal program flow is maintained.

' {$STAMP BS2}
' {$PBASIC 2.5}

task            VAR     Nib

Main:
  DO
    ON task GOSUB Task_0, Task_1, Task_2        ' run current task
    task = task + 1 // 3                        ' update task pointer
    PAUSE 1000
  LOOP
  END

Task_0:
  DEBUG "Running Task 0", CR
  RETURN

Task_1:
  DEBUG "Running Task 1", CR
  RETURN

Task_2:
  DEBUG "Running Task 2", CR
  RETURN


 ON...GOTO

{$PBASIC 2.5} Example
Syntax: ON Offset GOTO Address1, Address2, ...AddressN

Function
Go to the address specified by offset (if in range).

  • Offset is a variable/constant/expression (0 - 255) that specifies the index of the address, in the list, to branch to (0 - N).
  • Addresses are labels that specify where to go. ON...GOTO will ignore any list entries beyond offset 255.

Quick Facts
 | BS2 Family
Limit of Address entries | 256

Explanation
The ON...GOTO instruction is useful when you want to write something like this:

  IF idx = 0 THEN Case_0                ' idx = 0: jump to label "Case_0"
  IF idx = 1 THEN Case_1                ' idx = 1: jump to label "Case_1"
  IF idx = 2 THEN Case_2                ' idx = 2: jump to label "Case_2"

You can use ON...GOTO to organize this into a single statement:

  ON idx GOTO Case_0, Case_1, Case_2
This works exactly the same as the previous IF...THEN example. If the value isn't in range (in this case if value is greater than 2), ON...GOTO does nothing and the program continues with the next instruction after ON...GOTO.

Related commands: GOTO, BRANCH, IF...THEN, ON...GOSUB ( [image] )


BRANCH Examples

 ON...GOTO Example

{$PBASIC 2.5} Syntax

NOTE: This is written for the BS2 and will run on any of the BS2-family modules. Modify the $STAMP directive (as required) before downloading to the BS2e, BS2sx, BS2p, BS2pe, or BS2px.

' ON-GOTO.BS2
' This program shows how the value of idx controls the destination of the
' ON...GOTO instruction.

' {$STAMP BS2}
' {$PBASIC 2.5}

idx             VAR     Byte

Main:
  DEBUG "idx: ", DEC idx, " "
  ON idx GOTO Case_0, Case_1, Case_2    ' if idx = 0..2 goto label
  DEBUG "ON..GOTO target error.", CR    ' message if idx is out of range

Update:
  idx = idx + 1 // 4                    ' force idx to be 0..3
  PAUSE 1000
  GOTO Main

Case_0:
  DEBUG "Running Case_0 routine", CR
  GOTO Update

Case_1:
  DEBUG "Running Case_1 routine", CR
  GOTO Update

Case_2:
  DEBUG "Running Case_2 routine", CR
  GOTO Update


 Binary Operators

Binary operators require two arguments.

+ Addition
The Addition operator (+) adds variables and/or constants, returning a 16-bit result. Works exactly as you would expect with unsigned integers from 0 to 65535. If the result of addition is larger than 65535, the carry bit will be lost. If the values added are signed 16-bit numbers and the destination is a 16-bit variable, the result of the addition will be correct in both sign and value.

SYMBOL  value1  = W0
SYMBOL  value2  = W1

Main:
  value1 = -99
  value2 = 100
  value1 = value1 + value2                      ' Add the numbers
  DEBUG value1                                  ' Show the result (1)
  END

value1  VAR     Word
value2  VAR     Word

Main:
  value1 = -1575
  value2 = 976
  value1 = value1 + value2                      ' Add the numbers
  DEBUG SDEC ? value1                           ' Show the result (-599)
  END

- Subtraction
The Subtraction operator (-) subtracts variables and/or constants, returning a 16-bit result. Works exactly as you would expect with unsigned integers from 0 to 65535. If the result is negative, it will be correctly expressed as a signed 16-bit number.

SYMBOL  value1  = W0
SYMBOL  value2  = W1

Main:
  value1 = 199
  value2 = 100
  value1 = value1 - value2                      ' Subtract value2 from value1
  DEBUG value1                                  ' Show the result (99)
  END

value1  VAR     Word
value2  VAR     Word

Main:
  value1 = 1000
  value2 = 1999
  value1 = value1 - value2                      ' Subtract value2 from value1
  DEBUG SDEC ? value1                           ' Show the result (-999)
  END

* Multiplication
The Multiply operator (*) multiplies variables and/or constants, returning the low 16 bits of the result. Works exactly as you would expect with unsigned integers from 0 to 65535. If the result of multiplication is larger than 65535, the excess bits will be lost. Multiplication of signed variables will be correct in both number and sign, provided that the result is in the range -32767 to +32767.

SYMBOL  value1  = W0
SYMBOL  value2  = W1

Main:
  value1 = 1000
  value2 = 19
  value1 = value1 * value2                      ' Multiply the numbers
  DEBUG value1                                  ' Show the result (19000)
  END

value1  VAR     Word
value2  VAR     Word

Main:
  value1 = 1000
  value2 = 19
  value1 = value1 * value2                      ' Multiply the numbers
  DEBUG SDEC ? value1                           ' Show the result (19000)
  END

** Multiply High (Returns Upper 16 Bits)
The Multiply High operator (**) multiplies variables and/or constants, returning the high 16 bits of the result. When you multiply two 16-bit values, the result can be as large as 32 bits. Since the largest variable supported by PBASIC is 16 bits, the highest 16 bits of a 32-bit multiplication result are normally lost. The ** (double-star) instruction gives you these upper 16 bits. For example, suppose you multiply 65000 ($FDE8) by itself. The result is 4,225,000,000 or $FBD46240. The * (star, or normal multiplication) instruction would return the lower 16 bits, $6240. The ** instruction returns $FBD4.

SYMBOL  value1  = W0
SYMBOL  value2  = W1

Main:
  value1 = $FDE8
  value2 = value1 ** value1                     ' Multiply value1 by itself
  DEBUG $value2                                 ' Show upper 16 bits
  END

value1  VAR     Word
value2  VAR     Word

Main:
  value1 = $FDE8
  value1 = value1 ** value1                     ' Multiply value1 by itself
  DEBUG HEX ? value1                            ' Show upper 16 bits
  END

An interesting application of the ** operator is to multiply by a known fractional value less than one. The fraction value is expressed in units of 1/65536. To find the fractional ** parameter, multiply the fraction part by 65536. Example:

SYMBOL  Frac    = 47554                         ' = 0.72562 x 65536
SYMBOL  value   = W0

Test:
  value = 10000
  value = value ** Frac                         ' Multiply 10000 by 0.72562
  DEBUG value                                   ' Show result (7256)

Frac    CON     47554                           ' = 0.72562 x 65536
value   VAR     Word

Test:
  value = 10000
  value = value ** Frac                         ' Multiply 10000 by 0.72562
  DEBUG ? value                                 ' Show result (7256)

*/ Multiply Middle (Returns Middle 16 Bits)
The Multiply Middle operator (*/) multiplies variables and/or constants, returning the middle 16 bits of the 32-bit result. This has the effect of multiplying a value by a whole number and a fraction. The whole number is the upper byte of the multiplier (0 to 255 whole units) and the fraction is the lower byte of the multiplier (0 to 255 units of 1/256 each). The */ (star-slash) instruction gives you an excellent workaround for the BASIC Stamp's integer-only math. Suppose you want to multiply a value by 1.5. The whole number, and therefore the upper byte of the multiplier, would be 1, and the lower byte (fractional part) would be 128, since 128/256 = 0.5. It may be clearer to express the */ multiplier in hex—as $0180—since hex keeps the contents of the upper and lower bytes separate.

value1  VAR     Word

Main:
  value1 = 100
  value1= value1 */ $0180                       ' Multiply by 1.5 [1 + (128/256)]
  DEBUG ? value1                                ' Show result (150)
  END

To calculate constants for use with the */ instruction, put the whole number portion in the upper byte, then use the following formula for the value of the lower byte: Hint: INT(fraction * 256). For instance, take Pi (3.14159). The upper byte would be $03 (the whole number), and the lower would be INT(0.14159 * 256) = 36 ($24). So the constant Pi for use with */ would be $0324. This isn’t a perfect match for Pi, but the error is only about 0.1%.

/ Division
The Division operator (/) divides variables and/or constants, returning a 16-bit result. Works exactly as you would expect with unsigned integers from 0 to 65535. Use / only with positive values; signed values do not provide correct results. Here’s an example of unsigned division:

SYMBOL  value1  = W0
SYMBOL  value2  = W1

Main:
  value1 = 1000
  value2 = 5
  value1 = value1 / value2                      ' Divide the numbers
  DEBUG value1                                  ' Show the result (200)
  END

value1  VAR     Word
Value2  VAR     Word

Main:
  value1 = 1000
  value2 = 5
  value1 = value1 / value2                      ' Divide the numbers
  DEBUG DEC ? value1                            ' Show the result (200)
  END

A workaround to the inability to divide signed numbers is to have your program divide absolute values, then negate the result if one (and only one) of the operands was negative. All values must lie within the range of -32767 to +32767.

sign    VAR     Bit                             ' bit to hold the sign
value1  VAR     Word
Value2  VAR     Word

Main:
  value1 = 100
  value2 = -3200
  sign = value1.Bit15 ^ value2.Bit15            ' determine result sign
  value2 = ABS value2 / ABS value1              ' divide absolute values
  IF (sign = 1) THEN value2 = -value2           ' correct sign if negative
  DEBUG SDEC ? value2                           ' show the result (-32)
  END

// Modulus (Remainder of Division)
The Modulus operator (//) returns the remainder left after dividing one value by another. Some division problems don’t have a whole-number result; they return a whole number and a fraction. For example, 1000 / 6 = 166.667. Integer math doesn’t allow the fractional portion of the result, so 1000 / 6 = 166. However, 166 is an approximate answer, because 166 * 6 = 996. The division operation left a remainder of 4. The // (double-slash) returns the remainder of a given division operation. Naturally, numbers that divide evenly, such as 1000 / 5, produce a remainder of 0.

SYMBOL  value1  = W0
SYMBOL  value2  = W1

Main:
  value1 = 1000
  value2 = 6
  value1 = value1 // value2                     ' get remainder of value1 / value2
  DEBUG value1                                  ' show the result (4)
  END

value1  VAR     Word
value2  VAR     Word

Main:
  value1 = 1000
  value2 = 6
  value1 = value1 // value2                     ' get remainder of value1 / value2
  DEBUG DEC ? value1                            ' show the result (4)
  END

MIN Limits a Value to Specified Low
The Minimum operator (MIN) limits a value to a specified 16-bit positive minimum. The syntax of MIN is:

result = Value MIN Limit

Where Value is a constant or variable value to perform the MIN function upon and Limit is the minimum value that Value is allowed to be. Its logic is, 'if Value is less than Limit, then make result = Limit; if Value is greater than or equal to Limit, make result = Value.' MIN works in positive math only; its comparisons are not valid when used on two’s complement negative numbers, since the positive-integer representation of a number like -1 ($FFFF or 65535 in unsigned decimal) is larger than that of a number like 10 ($000A or 10 decimal). Use MIN only with unsigned integers. Because of the way fixed-size integers work, you should be careful when using an expression involving MIN 0. For example, 0 - 1 MIN 0 will result in 65535 because of the way fixed-size integers wrap around.

SYMBOL  value1  = W0
SYMBOL  value2  = W1

Main:
  FOR value1 = 100 TO 0 STEP -10                ' walk value1 from 100 to 0
    value2 = value1 MIN 50                      ' use MIN to clamp at 50
    DEBUG value2                                ' show "clamped" value
  NEXT
  END

value1  VAR     Word
value2  VAR     Word

Main:
  FOR value1 = 100 TO 0 STEP 10                 ' walk value1 from 100 to 0
    value2 = value1 MIN 50                      ' use MIN to clamp at 50
    DEBUG DEC ? value2 MIN 50                   ' show "clamped" value
  NEXT
  END

MAX Limits a Value to Specified High
The Maximum operator (MAX) limits a value to a specified 16-bit positive maximum. The syntax of MAX is:

Value MAX Limit

Where Value is a constant or variable value to perform the MAX function upon and Limit is the maximum value that Value is allowed to be. Its logic is, ‘if Value is greater than Limit, then make result = Limit; if Value is less than or equal to Limit, make result = Value.’ MAX works in positive math only; its comparisons are not valid when used on two’s complement negative numbers, since the positive-integer representation of a number like -1 ($FFFF or 65535 in unsigned decimal) is larger than that of a number like 10 ($000A or 10 decimal). Use MAX only with unsigned integers. Because of the way fixed-size integers work, you should be careful when using an expression involving MAX 65535. For example, 65535+1 MAX 65535 will result in 0 because of the way fixed-size integers wrap around.

SYMBOL  value1  = W0
SYMBOL  value2  = W1

Main:
  FOR value1 = 0 TO 100 STEP 10                 ' Walk value1 from 0 to 100
    value2 = value1  MAX  50                    ' Use MAX to clamp at 50
    DEBUG  value2                               ' Show "clamped" value
  NEXT
  END

value   VAR     Word

Main:
  FOR value = 0 TO 100 STEP 10                  ' Walk value from 0 to 100
    DEBUG ? value MAX 50                        ' Show "clamped" value
  NEXT
  END

DIG Returns Specified Digit of Number
The Digit operator (DIG) returns the specified decimal digit of a 16-bit positive value. Digits are numbered from 0 (the right-most digit) to 4 (the left-most digit of a 16-bit number; 0 to 65535).

value   VAR     Word
idx     VAR     Nib

Main:
  value = 9742
  DEBUG ? value DIG 2                           ' Show digit 2 (7)

  FOR idx = 0 TO 4
    DEBUG ? value DIG idx                       ' Show digits 0 - 4 of 9742
  NEXT
  END

REV Reverses specified number of bits
The Reverse operator (REV) returns a reversed (mirrored) copy of a specified number of bits of a value, starting with the rightmost bit (LSB). For instance, %10101101 REV 4 would return %1011, a mirror image of the first four bits of the value.

  DEBUG BIN4 ? %11001010 REV 4                  ' Mirror lower 4 bits (%0101)

<< Shift Bits Left by Specified Amount
The Shift Left operator (<<) shifts the bits of a value to the left a specified number of places. Bits shifted off the left end of a number are lost; bits shifted into the right end of the number are 0s. Shifting the bits of a value left n number of times has the same effect as multiplying that number by 2 to the nth power. For instance 100 << 3 (shift the bits of the decimal number 100 left three places) is equivalent to 100 * 23.

value   VAR     Word
idx     VAR     Byte

Main:
  value = %1111111111111111

  FOR idx = 1 TO 16                             ' loop 16 times
    DEBUG BIN16 ? Value << idx                  ' display shifted value
  NEXT
  END

>> Shift Bits Right by Specified Amount
The Shift Right operator (>>) shifts the bits of a variable to the right a specified number of places. Bits shifted off the right end of a number are lost; bits shifted into the left end of the number are 0s. Shifting the bits of a value right n number of times has the same effect as dividing that number by 2 to the nth power. For instance 100 >> 3 (shift the bits of the decimal number 100 right three places) is equivalent to 100 / 23.

value   VAR     Word
idx     VAR     Byte

Main:
  value = %1111111111111111

  FOR idx = 1 TO 16                             ' loop 16 times
    DEBUG BIN16 ? Value >> idx                  ' display shifted value
  NEXT
  END

& Bitwise AND
The AND (&) operator returns the bitwise AND of two values. Each bit of the values is subject to the following logic:

    0 & 0 = 0
    0 & 1 = 0
    1 & 0 = 0
    1 & 1 = 1

The result returned by & will contain 1s in only those bit positions in which both input values contain 1s.

SYMBOL  value1  = B0
SYMBOL  value2  = B1
SYMBOL  result  = B2

Main:
  value1 = %00001111
  value2 = %10101101
  result = value1 & value2
  DEBUG %result                                 ' Show AND result (%00001101)
  END

  DEBUG BIN8 ? %00001111 & %10101101            ' Show AND result (%00001101)

| Bitwise OR
The OR (|) operator returns the bitwise OR of two values. Each bit of the values is subject to the following logic:

    0 | 0 = 0
    0 | 1 = 1
    1 | 0 = 1
    1 | 1 = 1

The result returned by | will contain 1s in any bit positions in which one or the other (or both) input values contain 1s.

SYMBOL  value1  = B0
SYMBOL  value2  = B1
SYMBOL  result  = B2

Main:
  value1 = %00001111
  value2 = %10101001
  result = value1 | value2
  DEBUG  %result                                ' Show OR result (%10101111)
  END

  DEBUG BIN8 ? %00001111 | %10101001            ' Show OR result (%10101111)

^ Bitwise XOR
The Exclusive OR operator (|) returns the bitwise exclusive OR of two values. Each bit of the values is subject to the following logic:

    0 ^ 0 = 0
    0 ^ 1 = 1
    1 ^ 0 = 1
    1 ^ 1 = 0

The result returned by ^ will contain 1s in any bit positions in which one or the other (but not both) input values contain 1s.

SYMBOL  value1  = B0
SYMBOL  value2  = B1
SYMBOL  result  = B2

Main:
  value1 = %00001111
  value2 = %10101001
  result = value1 ^ value2
  DEBUG  %result                                ' Show OR result (%10100110)
  END

  DEBUG BIN8 ? %00001111 ^ %10101001            ' Show OR result (%10100110)

&/ Bitwise AND NOT
The AND NOT operator (&/) returns the bitwise AND NOT of two values. Each bit of the values is subject to the following logic:

    0 &/ 0 = 0
    0 &/ 1 = 0
    1 &/ 0 = 1
    1 &/ 1 = 0

The result returned by &/ will contain 1s in any bit positions in which the first value is 1 and the second value is 0.

SYMBOL  value1  = B0
SYMBOL  value2  = B1
SYMBOL  result  = B2

Main:
  value1 = %00001111
  value2 = %10101001
  result = value1 &/ value2
  DEBUG  %result                                ' Show AND NOT result (%00000110)
  END

|/ Bitwise OR NOT
The OR NOT operator (|/) returns the bitwise OR NOT of two values. Each bit of the values is subject to the following logic:

    0 |/ 0 = 1
    0 |/ 1 = 0
    1 |/ 0 = 1
    1 |/ 1 = 1

The result returned by |/ will contain 1s in any bit positions in which the first value is 1 or the second value is 0.

SYMBOL  value1  = B0
SYMBOL  value2  = B1
SYMBOL  result  = B2

Main:
  value1 = %00001111
  value2 = %10101001
  result = value1 |/ value2
  DEBUG  %result                                ' Show OR NOT result (%01011111)
  END

^/ Bitwise XOR NOT
The XOR NOT operator (^/) returns the bitwise XOR NOT of two values. Each bit of the values is subject to the following logic:

    0 ^/ 0 = 1
    0 ^/ 1 = 0
    1 ^/ 0 = 0
    1 ^/ 1 = 1

The result returned by ^/ will contain 1s in any bit positions in which the first value and second values are equal.

SYMBOL  value1  = B0
SYMBOL  value2  = B1
SYMBOL  result  = B2

Main:
  value1 = %00001111
  value2 = %10101001
  result = value1 ^/ value2
  DEBUG  %result                                ' Show OR NOT result (%01011001)
  END

AND Logical AND
The AND operator returns the logical AND of two values or expressions. Note that in the BASIC Stamp, a non-zero value is considered True (T), zero is considered False (F). The values/expressions are subject to the following logic:

    F AND F = F
    F AND T = F
    T AND F = F
    T AND T = T

The result returned by AND will be True or False.

score   VAR     Byte
avg     VAR     Byte

Main:
  score = 93
  avg = 89

  IF (score > 80) AND (avg > 70) THEN
    DEBUG "Promote to next grade."              ' both conditions are True
  ELSE
    DEBUG "Consider additional tutoring."       ' at least one condition is False
  ENDIF
  END

OR Logical OR
The OR operator returns the logical OR of two values or expressions. Note that in the BASIC Stamp, a non-zero value is considered True (T), zero is considered False (F). The values/expressions are subject to the following logic:

    F OR F = F
    F OR T = T
    T OR F = T
    T OR T = T

The result returned by OR will be True or False.

score   VAR     Byte
avg     VAR     Byte

Main:
  score = 63
  avg = 89

  IF (score < 80) OR (avg < 70) THEN
    DEBUG "Consider additional tutoring."       ' at least one condition is True
  ELSE
    DEBUG "Promote to next grade."              ' both conditions are False
  ENDIF
  END

XOR Logical XOR
The XOR operator returns the logical Exclusive OR of two values or expressions. Note that in the BASIC Stamp, a non-zero value is considered True (T), zero is considered False (F). The values/expressions are subject to the following logic:

    F XOR F = F
    F XOR T = T
    T XOR F = T
    T XOR T = F

The XOR operator can be confusing at first. An easy way to remember the logic is: If one or the other is True -- but not both -- then the result is True, otherwise the result is False.

The result returned by OR will be True or False.

turnL   VAR     Bit
turnR   VAR     Bit

Main:
  turnL = 0
  turnR = 1

  IF (turnL = 1) XOR (turnR = 1) THEN           ' one or other is True
    DEBUG "Turning - ", "L" + ("R" - "L" * turnR)
  ELSE
    DEBUG "Continue straight."                  ' both True or both False
  ENDIF
  END

ATN Returns ArcTangent of Vector (X, Y)
The Arctangent operator (ATN) returns the angle to the vector specified by X and Y coordinate values. In the BASIC Stamp, the angle is returned in binary radians (0 to 255) instead of degrees (0 to 359). Coordinate input values are limited to -127 to 127 (signed bytes) as shown in the diagram below:

idx     VAR     Nib                             ' loop counter
xCoord  VAR     Byte                            ' x coordinate of vector
yCoord  VAR     Byte                            ' y coordinate of vector
brads   VAR     Word                            ' angle in brads
degr    VAR     Word                            ' angle in degrees

Main:
  FOR idx = 0 TO 7                              ' load vector data

    LOOKUP idx, [ 1, 1, 0, -1, -1, -1,  0,  1], xCoord
    LOOKUP idx, [ 0, 1, 1,  1,  0, -1, -1, -1], yCoord

    brads = xCoord ATN yCoord                   ' get angle of vector
    degr = brads * 180 / 128                    ' convert to degrees

    DEBUG DEC (idx + 1), ": ",
          "ATN (", SDEC xCoord, ", ", SDEC yCoord, ")",
          CRSRX, 18, "= ", DEC brads, "  (", DEC degr, ")", CR
  NEXT
  END

HYP Returns Hypotenuse
The Hypotenuse operator (HYP) returns the length of the hypotenuse of a right triangle with sides of length A and B. Side length (vector) input values are limited to -127 to 127 (signed bytes).

  DEBUG ? 3 HYP 4                               ' display hypotenuse of 5


 Unary Operators

Unary operators work with a single argument.

ABS Returns Absolute Value
The Absolute Value operator (ABS) converts a signed (two’s complement) 16-bit number to its absolute value. The absolute value of a number is a positive number representing the difference between that number and 0. For example, the absolute value of -99 is 99. The absolute value of 99 is also 99. ABS works on two’s complement negative numbers. Here's an example of ABS at work:

result  VAR     Word

Main:
  result = -99
  DEBUG SDEC ? result                           ' Display -99
  DEBUG SDEC ? ABS result                       ' Display 99
  END

- Negate
The Negative operator (-) negates a 16-bit number (converts to its two’s complement).

SYMBOL  result = W1

Main:
  result = -99                                  ' Initialize result
  result = result + 100                         ' Add 100 to it
  DEBUG result                                  ' Display result (1)
  END

result  VAR     Word

Main:
  result = -99                                  ' Initialize result
  DEBUG SDEC result                             ' Display result (-99)
  result = result + 100                         ' Add 100 to it
  DEBUG SDEC result                             ' Display result (1)
  END

~ Invert Bits
The Inverse operator (~) complements (inverts) the bits of a number. Each bit that contains a 1 is changed to 0 and each bit containing 0 is changed to 1. This process is also known as a "bitwise NOT" and one's compliment.

    ~0 = 1
    ~1 = 0

result  VAR     Byte

Main:
  result = %11110001                            ' Store bits in result
  DEBUG BIN8 ? result                           ' Display %11110001
  result = ~result                              ' Complement result
  DEBUG BIN8 ? result                           ' Display %00001110
  END

DCD 2n-power Decoder
The Decoder operator (DCD) is a 2n-power decoder of a four-bit value. DCD accepts a value from 0 to 15, and returns a 16-bit number with the bit, described by value, set to 1.

result  VAR     Word

Main:
  result = DCD 12                               ' Set bit 12.
  DEBUG BIN ? result                            ' Display %0001000000000000
  END

NCD Priority Encoder of 16-bit value
The Encoder operator (NCD) is a "priority" encoder of a 16-bit value. NCD takes a 16-bit value, finds the highest bit containing a 1 and returns the bit position plus one (1 through 16). If no bit is set (the input value is 0) NCD returns 0. NCD is a fast way to get an answer to the question "What is the largest power of two that this value is greater than or equal to?" The value NCD returns will be that power, plus one.

result  VAR     Nib

Main:
  result = %1101                                ' Highest bit set is bit 3
  DEBUG ? NCD result                            ' Show the NCD of Result (4)
  END

SIN Returns Signed Sine of Angle
The Sine operator (SIN) returns the two’s complement, 16-bit Sine of an angle specified as an 8-bit (0 to 255) value. To understand the SIN operator more completely, let’s look at a typical Sine function. By definition: given a circle with a radius of 1 unit (known as a unit circle), the Sine is the y-coordinate distance from the center of the circle to its edge at a given angle. Angles are measured relative to the 3-o'clock position on the circle, increasing as you go around the circle counterclockwise.

At the origin point (0 degrees) the Sine is 0, because that point has the same y (vertical) coordinate as the circle center. At 45 degrees the Sine is 0.707. At 90 degrees, Sine is 1. At 180 degrees, Sine is 0 again. At 270 degrees, Sine is -1.

The BASIC Stamp SIN operator breaks the circle into 0 to 255 units instead of 0 to 359 degrees. Some textbooks call this unit a binary radian or brad. Each brad is equivalent to 1.406 degrees. And instead of a unit circle, which results in fractional Sine values between 0 and 1, BASIC Stamp SIN is based on a 127-unit circle. Results are given in two’s complement form in order to accommodate negative values. So, at the origin, SIN is 0. At 45 degrees (32 brads), Sine is 90. At 90 degrees (64 brads), Sine is 127. At 180 degrees (128 brads), Sine is 0 again. At 270 degrees (192 brads), Sine is -127.

See the image below for the relationship between degrees and brads and how the SIN function values relate to to the 127-unit circle.

degr    VAR     Word
sine    VAR     Word

Main:
  FOR degr = 0 TO 359 STEP 45                   ' Use degrees
    sine = SIN (degr * 128 / 180)               ' Convert to brads, do SIN
    DEBUG "Angle: ", DEC degr, TAB              ' Display results
    DEBUG "Sine:  ", SDEC sine, CR
  NEXT
  END

COS Returns signed Cosine of angle
The Cosine operator (COS) returns the two’s complement, 16-bit Cosine of an angle specified as an 8-bit (0 to 255) value. To understand the COS operator more completely, let’s look at a typical Cosine function. By definition: given a circle with a radius of 1 unit (known as a unit circle), the Cosine is the x-coordinate distance from the center of the circle to its edge at a given angle. Angles are measured relative to the 3-o'clock position on the circle, increasing as you go around the circle counterclockwise.

At the origin point (0 degrees) the Cosine is 1, because that point has the same x (horizontal) coordinate as the circle radius. At 45 degrees the Cosine is 0.707. At 90 degrees, Cosine is 0. At 180 degrees, Cosine is -1. At 270 degrees, Cosine is 0 again.

The BASIC Stamp COS operator breaks the circle into 0 to 255 units instead of 0 to 359 degrees. Some textbooks call this unit a binary radian or brad. Each brad is equivalent to 1.406 degrees. And instead of a unit circle, which results in fractional Cosine values between 0 and 1, BASIC Stamp COS is based on a 127-unit circle. Results are given in two’s complement form in order to accommodate negative values. So, at the origin, COS is 127. At 45 degrees (32 brads), COS is 90. At 90 degrees (64 brads), COS is 0. At 180 degrees (128 brads), Cosine is -127. At 270 degrees (192 brads), Cosine is 0 again.

See the image below for the relationship between degrees and brads and how the COS function values relate to to the 127-unit circle.

degr    VAR     Word
cosine  VAR     Word

Main:
  FOR degr = 0 TO 359 STEP 45                   ' Use degrees
    cosine = COS (degr * 128 / 180)             ' Convert to brads, do COS
    DEBUG "Angle:  ", DEC degr, TAB             ' Display results
    DEBUG "Cosine: ", SDEC cosine, CR
  NEXT
  END

SQR Returns Square Root of value
The Square Root operator (SQR) computes the integer square root of an unsigned 16-bit number. (The number must be unsigned since the square root of a negative number is an 'imaginary' number.) Remember that most square roots have a fractional part that the BASIC Stamp discards when doing its integer-only math. So it computes the square root of 100 as 10 (correct), but the square root of 99 as 9 (the actual is close to 9.95).

Main:
  DEBUG SQR 100                                 ' Display 10
  DEBUG SQR 99                                  ' Display 9 (due to truncation)
  END

NOT Logical NOT
The NOT operator returns the logical NOT of an expression. Note that in the BASIC Stamp, a non-zero value is considered True (T), zero is considered False (F). The expression is subject to the following logic:

    NOT F = T
    NOT T = F

The result returned by NOT will be True or False.

speed   VAR     Byte

Main:
  DEBUG CLS, "Enter speed: "
  DEBUGIN DEC speed
  IF NOT (speed < 65) THEN                      ' speed must be less than 65
    DEBUG CR, "Sorry ... too fast!"
  ELSE
    DEBUG CR, "Enjoy your trip."
  ENDIF
  END


 OUTPUT

Examples

Syntax: OUTPUT Pin

Function
Make the specified pin an output.

  • Pin is a variable/constant/expression* (0 - 15) that specifies which I/O pin to set to output mode

* Note: Expressions are not allowed as arguments on the BS1. The range of the Pin argument on the BS1 is 0 - 7.

Explanation
There are several ways to make a pin an output. Commands that rely on output pins, like PULSOUT and SEROUT, automatically change the specified pin to output. Writing 1s to particular bits of the variable DIRS makes the corresponding pins outputs. And then there’s the OUTPUT command.

When a pin is an output, your program can change its state by writing to the corresponding bit in the OUTS variable (PINS on the BS1). For example:

  OUTPUT 4
  PIN4 = 1

  OUTPUT 4
  OUT4 = 1
When your program changes a pin from input to output, whatever state happens to be in the corresponding bit of OUTS (PINS on the BS1) sets the initial state of the pin. To simultaneously make a pin an output and set its state use the HIGH and LOW commands.

Related commands: INPUT and REVERSE


 OWIN

Example

Syntax: OWIN Pin, Mode, [InputData]

Function
Receive data from a device using the Maxim/Dallas Semiconductor 1-Wire® protocol.

  • Pin is a variable/constant/expression (0 - 15) that specifies which I/O pin to use. 1-Wire devices require only one I/O pin (called DQ) to communicate. This I/O pin will be toggled between output and input mode during the OWIN command and will be set to input mode by the end of the OWIN command.
  • Mode is a variable/constant/expression (0 - 15) indicating the mode of data transfer. The Mode argument controls placement of reset pulses (and detection of presence pulses) as well as byte vs. bit input and normal vs. high speed. See explanation below.
  • InputData is a list of variables and modifiers that tells OWIN what to do with incoming data. OWIN can store data in a variable or array, interpret numeric text (decimal, binary, or hex) and store the corresponding value in a variable, wait for a fixed or variable sequence of bytes, or ignore a specified number of bytes. These actions can be combined in any order in the InputData list.

Quick Facts
 | BS2p, BS2pe, and BS2px
Receive Rate | Approximately 20 kBits/sec (low speed, not including reset pulse)
Special Notes | The DQ pin (specified by Pin) must have a 4.7 kΩ pull-up resister.

Explanation
The 1-Wire protocol is a form of asynchronous serial communication developed by Maxim/Dallas Semiconductor. It only requires one I/O pin and that pin can be shared between multiple 1-Wire devices. The OWIN command allows the BASIC Stamp to receive data from a 1-Wire device.

The following is an example of the OWIN command:

result  VAR     Byte

Main:
  OWIN 0, 1, [result]
  STOP

This code will transmit a "reset" pulse to a 1-Wire device (connected to I/O pin 0) and then will detect the device's "presence" pulse and then receive one byte and store it in the variable result.

The Mode argument is used to control placement of reset pulses (and detection of presence pulses) and to designate byte vs. bit input and normal vs. high speed†. The tables below show the meaning of each of the four bits of Mode and some of the 16 possible values and their effect.

Mode Format bits

Bit | Function
0 | Front-End Reset • 0 = No reset • 1 = Generate reset before data
1 | Back-End Reset • 0 = No reset • 1 = Generate reset after data
2 | Bit / Byte Transfer • 0 = Byte • 1 = Bit
3 | Low / High Speed† • 0 = Low • 1 = High

Example OWIN Mode Values

Mode | Effect
0 | No Reset, Byte mode, Low speed
1 | Reset before data, Byte mode, Low speed
2 | Reset after data, Byte mode, Low speed
3 | Reset before and after data, Byte mode, Low speed
4 | No Reset, Bit mode, Low speed
5 | Reset before data, Bit mode, Low speed
6 | Reset after data, Bit mode, Low speed
7 | Reset before and after data, Bit mode, Low speed
8 | No Reset, Byte mode, High speed†
9 | Reset before data, Byte mode, High speed†

† The BS2pe is not capable of High-Speed transfers.

The proper value for Mode depends on the 1-Wire device and the portion of the communication you're working on. Please consult the data sheet for the device in question to determine the correct value for Mode. In many cases, however, when using the OWIN command, Mode should be set for either No Reset (to receive data from a transaction already started by a OWOUT command) or a Back-End Reset (to terminate the session after data is received). This may vary due to device and application requirements, however.

When using the Bit (rather than Byte) mode of data transfer, all variables in the InputData argument will only receive one bit. For example, the following code could be used to receive two bits using this mode:

bitOne  VAR     Bit
bitTwo  VAR     Bit

Main:
  OWIN 0, 6, [bitOne, bitTwo]
  STOP

In the code above, we chose the value "6" for Mode. This sets Bit transfer and Back-End Reset modes. Also, we could have chosen to make the bitOne and bitTwo variables each a byte in size, but they still would only have received one bit each in the OWIN command (due to the Mode selected).

The OWIN command's InputData argument is similar to the SERIN command's InputData argument. This means data can be received as ASCII character values, decimal, hexadecimal and binary translations and string data as in the examples below. (Assume a 1-Wire device is used and that it transmits the string, "Value: 3A:101" every time it receives a Front-End Reset pulse).

value   VAR     Byte(13)

Main:
  OWIN 0, 1, [value]                    ' receive ASCII code for "V"
  OWIN 0, 1, [DEC value]                ' receive the number 3
  OWIN 0, 1, [HEX value]                ' receive the number $3A
  OWIN 0, 1, [BIN value]                ' receive the number %101
  OWIN 0, 1, [STR value\13]             ' receive the string "Value: 3A:101"
  STOP

The tables below list all the available special formatters and conversion formatters available to the OWIN command. See the SERIN command for additional information and examples of their use.

Special Formatter | Action
STR ByteArray \L {\E} | Input a character string of length L into an array. If specified, an end character E causes the string input to end before reaching length L. Remaining bytes are filled with 0s (zeros).
WAITSTR ByteArray {\L} | Wait for a sequence of bytes matching a string stored in an array variable, optionally limited to L characters. If the optional L argument is left off, the end of the array-string must be marked by a byte containing a zero (0).
SKIP Length | Ignore Length bytes of characters.
SPSTR Length | Buffer Length bytes (up to 126) of serial characters to Scratchpad RAM, starting at location 0. Use GET to retrieve the characters.

Conversion Formatter | Type of Number | Numeric Characters Accepted | Notes
DEC{1..5} | Decimal, optionally limited to 1 - 5 digits | 0 through 9 | 1
SDEC{1..5} | Signed decimal, optionally limited to 1 - 5 digits | -, 0 through 9 | 1,2
HEX{1..4} | Hexadecimal, optionally limited to 1 - 4 digits | 0 through 9, A through F | 1,3
SHEX{1..4} | Signed hexadecimal, optionally limited to 1 - 4 digits | -, 0 through 9, A through F | 1,2,3
IHEX{1..4} | Indicated hexadecimal, optionally limited to 1 - 4 digits | $, 0 through 9, A through F | 1,3,4
ISHEX{1..4} | Signed, indicated hexadecimal, optionally limited to 1 - 4 digits | -, $, 0 through 9, A through F | 1,2,3,4
BIN{1..16} | Binary, optionally limited to 1 - 16 digits | 0, 1 | 1
SBIN{1..16} | Signed binary, optionally limited to 1 - 16 digits | -, 0, 1 | 1,2
IBIN{1..16} | Indicated binary, optionally limited to 1 - 16 digits | %, 0, 1 | 1,4
ISBIN{1..16} | Signed, indicated binary, optionally limited to 1 - 16 digits | -, %, 0, 1 | 1,2,4
NUM | Generic numeric input; hex or binary number must be indicated | $, %, 0 through 9, A through F | 1,3,4
SNUM | Similar to NUM with value treated as signed with range -32768 to +32767 | -, $, %, 0 through 9, A through F | 1,2,3,4

  1. All numeric conversions will continue to accept new data until receiving either the specified number of digits (ex: three digits for DEC3) or a non-numeric character.
  2. To be recognized as part of a number, the minus sign (-) must immediately precede a numeric character. The minus sign character occurring in non-numeric text is ignored and any character (including a space) between a minus and a number causes the minus to be ignored.
  3. The hexadecimal formatters are not case-sensitive; "a" through "f" means the same as "A" through "F".
  4. Indicated hexadecimal and binary formatters ignore all characters, even valid numerics, until they receive the appropriate prefix ($ for hexadecimal, % for binary). The indicated formatters can differentiate between text and hexadecimal (ex: ABC would be interpreted by HEX as a number but IHEX would ignore it unless expressed as $ABC). Likewise, the binary version can distinguish the decimal number 10 from the binary number %10. A prefix occurring in non-numeric text is ignored, and any character (including a space) between a prefix and a number causes the prefix to be ignored. Indicated, signed formatters require that the minus sign come before the prefix, as in -$1B45.

The 1-Wire Protocol Format

The 1-Wire protocol has a well-defined standard for transaction sequences. Every transaction sequence consists of four parts: 1) Initialization, 2) ROM Function Command, 3) Memory Function Command, and 4) Transaction/Data. Additionally, the ROM Function Command and Memory Function Command are always 8 bits wide (1 byte in size) and is sent least-significant-bit (LSB) first.

The Initialization part consists of a reset pulse (generated by the master) and will be followed by a presence pulse (generated by all slave devices). The figure below details the reset pulse generated by the BASIC Stamp and a typical presence pulse generated by a 1-Wire slave, in response.

This reset pulse is controlled by the lowest two bits of the Mode argument in the OWIN command. It can be made to appear before the ROM Function Command (ex: Mode = 1), after the Transaction/Data portion (ex: Mode = 2), before and after the entire transaction (ex: Mode = 3) or not at all (ex: Mode = 0). See the section on Mode, above, for more information.

Following the Initialization part is the ROM Function Command. The ROM Function Command is used to address the desired 1-Wire device. The table below shows common ROM Function Commands. If only a single 1-Wire device is connected, the Skip ROM command can be used to address it. If more than one 1-Wire device is attached, the BASIC Stamp will ultimately have to address them individually using the Match ROM command.

Command | Value (HEX) | Action
Read ROM | $33 | Reads the 64-bit ID of the 1-Wire device. This command can only be used if there is a single 1-Wire device on the line.
Match ROM | $55 | This command, followed by a 64-bit ID, allows the BASIC Stamp to address a specific 1-Wire device.
Skip ROM | $CC | Address a 1-Wire device without its 64-bit ID. This command can only be used if there is a single 1-Wire device on the line.
Search ROM | $F0 | Reads the 64-bit IDs of all the 1-Wire devices on the line. A process of elimination is used to distinguish each unique device.

The third part, the Memory Function Command, allows the BASIC Stamp to address specific memory locations, or features, of the 1-Wire device. Refer to the 1-Wire device's data sheet for a list of the available Memory Function Commands.

Finally, the Transaction/Data section is used to read or write data to the 1-Wire device. The OWIN command will read data at this point in the transaction. A read is accomplished by generating a brief low-pulse and sampling the line within 15 ms of the falling edge of the pulse. This is called a "Read Slot." The figure below shows typical Read Slots performed by the BASIC Stamp. See the OWOUT command for information on Write Slots.

Related commands: OWOUT


OWIN / OWOUT Example

This program uses a Dallas Semiconductor DS1820 Digital Thermometer device connected as follows. Note that the 4.7 kΩ pull-up resister is required for proper operation.

NOTE: This is written for the BS2p and will also run on the BS2pe and BS2px. Modify the $STAMP directive (as required) before downloading to BS2pe or BS2px.

' OWIN_OWOUT.BSP
' This program demonstrates interfacing to a Dallas Semiconductor DS1822
' 1-Wire Digital Thermometer chip using the BS2p's 1-Wire commands. Connect
' the BS2p/BS2pe/BS2px to the DS1822 as shown in the diagram in the OWIN or
' OWOUT command description. This program uses a simplified approach that
' ignores the fractional portion of the temperature.

' {$STAMP BS2p}
' {$PBASIC 2.5}

DQ              PIN     0               ' 1-Wire buss pin

RdROM           CON     $33             ' read serial number
MatchROM        CON     $55             ' match SN -- for multiple devices
SkipROM         CON     $CC             ' ignore SN -- use for one device
CvrtTmp         CON     $44             ' start temperature conversion
RdSP            CON     $BE             ' read DS1822 scratchpad

tempIn          VAR     Word            ' raw temperature
sign            VAR     tempIn.BIT11    ' 1 = negative temperature
tLo             VAR     tempIn.BYTE0
tHi             VAR     tempIn.BYTE1
tSign           VAR     Bit             ' saved sign bit
tempC           VAR     Word            ' final Celsius temp
tempF           VAR     Word            ' final Fahrenheit temp

Main:
  DO
    GOSUB Get_Temperature               ' read temperature from DS1822
    DEBUG HOME,                         ' display
          "DS1822", CR,
          "------", CR,
          SDEC tempC, " C ", CR,
          SDEC tempF, " F "
    PAUSE 1000
  LOOP
  END

Get_Temperature:
  OWOUT DQ, 1, [SkipROM, CvrtTmp]       ' send convert temperatrue command
  DO                                    ' wait on conversion
    PAUSE 25                            ' small loop pad
    OWIN DQ, 4, [tempIn]                ' check status (bit transfer)
  LOOP UNTIL (tempIn)                   ' 1 when complete
  OWOUT DQ, 1, [SkipROM, RdSP]          ' read DS1822 scratchpad
  OWIN  DQ, 2, [tLo, tHi]               ' get raw temp data
  tSign = sign                          ' save sign bit
  tempC = tempIn >> 4                   ' round to whole degrees
  tempC.BYTE1 = $FF * tSign             ' correct 2's compliment bits
  tempF = (ABS tempC) * 9 / 5           ' start F conversion
  IF (tSign) THEN                       ' finish F conversion
    tempF = 32 - tempF                  ' C was negative
  ELSE
    tempF = tempF + 32                  ' C was positive
  ENDIF
  RETURN


 OWOUT

Example

Syntax: OWOUT Pin, Mode, [OutputData]

Function
Send data to a device using the Maxim/Dallas Semiconductor 1-Wire® protocol.

  • Pin is a variable/constant/expression (0 - 15) that specifies which I/O pin to use. 1-Wire devices require only one I/O pin (called DQ) to communicate. This I/O pin will be toggled between output and input mode during the OWOUT command and will be set to input mode by the end of the OWOUT command.
  • Mode is a variable/constant/expression (0 - 15) indicating the mode of data transfer. The Mode argument controls placement of reset pulses (and detection of presence pulses) as well as byte vs. bit input and normal vs. high† speed. See explanation below.
  • OutputData is a list of variables and modifiers that tells OWOUT how to format outgoing data. OWOUT can transmit individual or repeating bytes, convert values into decimal, hexadecimal or binary text representations, or transmit strings of bytes from variable arrays. These actions can be combined in any order in the OutputData list.

Quick Facts
 | BS2p, BS2pe, and BS2px
Transmission Rate | Approximately 20 kbits/sec (low speed, not including reset pulse)
Special Notes | The DQ pin (specified by Pin) must have a 4.7 kΩ pull-up resister.

Explanation
The 1-Wire protocol is a form of asynchronous serial communication developed by Maxim/Dallas Semiconductor. It only requires one I/O pin and that pin can be shared between multiple 1-Wire devices. The OWOUT command allows the BASIC Stamp to send data to a 1-Wire device.

The following is an example of the OWOUT command:

  OWOUT 0, 1, [$4E]

This code will transmit a "reset" pulse to a 1-Wire device (connected to I/O pin 0) and then will detect the device's "presence" pulse and then transmit one byte (the value $4E).

The Mode argument is used to control placement of reset pulses (and detection of presence pulses) and to designate byte vs. bit input and normal vs. high speed†. The tables below show the meaning of each of the four bits of Mode and some of the 16 possible values and their effect.

Mode Format bits

Bit | Function
0 | Front-End Reset • 0 = No reset • 1 = Generate reset before data
1 | Back-End Reset • 0 = No reset • 1 = Generate reset after data
2 | Bit / Byte Transfer • 0 = Byte • 1 = Bit
3 | Low / High Speed† • 0 = Low • 1 = High

Example OWIN Mode Values

Mode | Effect
0 | No Reset, Byte mode, Low speed
1 | Reset before data, Byte mode, Low speed
2 | Reset after data, Byte mode, Low speed
3 | Reset before and after data, Byte mode, Low speed
4 | No Reset, Bit mode, Low speed
5 | Reset before data, Bit mode, Low speed
6 | Reset after data, Bit mode, Low speed
7 | Reset before and after data, Bit mode, Low speed
8 | No Reset, Byte mode, High speed†
9 | Reset before data, Byte mode, High speed†

† The BS2pe is not capable of High Speed transfers.

The proper value for Mode depends on the 1-Wire device and the portion of the communication you're working on. Please consult the data sheet for the device in question to determine the correct value for Mode. In many cases, however, when using the OWOUT command, Mode should be set for a Front-End Reset (to initialize the transaction). This may vary due to device and application requirements, however.

When using the Bit (rather than Byte) mode of data transfer, all variables in the OutputData argument will only transmit one bit. For example, the following code could be used to send two bits using this mode:

bitOne  VAR     Bit
bitTwo  VAR     Bit

Init:
  bitOne = 0
  bitTwo = 1

Main:
  OWOUT 0, 5, [bitOne, bitTwo]
  STOP

In the code above, we chose the value "5" for Mode. This sets Bit transfer and Front-End Reset modes. Also, we could have chosen to make the bitOne and bitTwo variables each a byte in size, but the BASIC Stamp would still only use the their lowest bit (Bit0) as the value to transmit in the OWOUT command (due to the Mode we chose).

The OWOUT command's OutputData argument is similar to the DEBUG and SEROUT command's OutputData argument. This means data can be sent as literal text, ASCII character values, repetitive values, decimal, hexadecimal and binary translations and string data as in the examples below.

value   VAR     Byte

Init:
  value = 65

Main:
  OWOUT 0, 1, [value]                                   ' send ASCII character "A"
  OWOUT 0, 1, [REP value\5]                             ' send "A" 5x, ie: "AAAAA"
  OWOUT 0, 1, [DEC value]                               ' send "6" and "5"
  OWOUT 0, 1, [HEX value]                               ' send "4" and "1"
  OWOUT 0, 1, [BIN value]                               ' send "1000001"
  STOP

The tables below list all the available special formatters and conversion formatters available to the OWOUT command. See the DEBUG and SEROUT commands for additional information and examples of their use.

Special Formatter | Action
? | Displays "symbol = x' + carriage return; where x is a number. Default format is decimal, but may be combined with conversion formatters (ex: BIN ? x to display "x = binary_number").
ASC ? | Displays "symbol = 'x'" + carriage return; where x is an ASCII character.
STR ByteArray {\L} | Send character string from an array. The optional \L argument can be used to limit the output to L characters, otherwise, characters will be sent up to the first byte equal to 0 r the end of RAM space is reached.
REP Byte\L | Send a string consisting of Byte repeated L times (ex: REP "X"\10 sends "XXXXXXXXXX").

Conversion Formatter | Type of Number | Notes
DEC{1..5} | Decimal, optionally fixed to 1 - 5 digits | 1
SDEC{1..5} | Signed decimal, optionally fixed to 1 - 5 digits | 1,2
HEX{1..4} | Hexadecimal, optionally fixed to 1 - 4 digits | 1
SHEX{1..4} | Signed hexadecimal, optionally fixed to 1 - 4 digits | 1,2
IHEX{1..4} | Indicated hexadecimal, optionally fixed to 1 - 4 digits | 1
ISHEX{1..4} | Signed, indicated hexadecimal, optionally fixed to 1 - 4 digits ($ prefix) | 1,2
BIN{1..16} | Binary, optionally fixed to 1 - 16 digits | 1
SBIN{1..16} | Signed binary, optionally fixed to 1 - 16 digits | 1,2
IBIN{1..16} | Indicated binary, optionally fixed to 1 - 16 digits | 1
ISBIN{1..16} | Signed, indicated binary, optionally fixed to 1 - 16 digits | 1,2

  1. Fixed-digit formatters like DEC4 will pad the number with leading 0s if necessary; ex: DEC4 65 sends 0065. If a number is larger than the specified number of digits, the leading digits will be dropped; ex: DEC4 56422 sends 6422.
  2. Signed modifiers work under two's complement rules.

The 1-Wire Protocol Format

The 1-Wire protocol has a well-defined standard for transaction sequences. Every transaction sequence consists of four parts: 1) Initialization, 2) ROM Function Command, 3) Memory Function Command, and 4) Transaction/Data. Additionally, the ROM Function Command and Memory Function Command are always 8 bits wide (1 byte in size) and is sent least-significant-bit (LSB) first.

The Initialization part consists of a reset pulse (generated by the master) and will be followed by a presence pulse (generated by all slave devices). The figure below details the reset pulse generated by the BASIC Stamp and a typical presence pulse generated by a 1-Wire slave, in response.

This reset pulse is controlled by the lowest two bits of the Mode argument in the OWIN command. It can be made to appear before the ROM Function Command (ex: Mode = 1), after the Transaction/Data portion (ex: Mode = 2), before and after the entire transaction (ex: Mode = 3) or not at all (ex: Mode = 0). See the section on Mode, above, for more information.

Following the Initialization part is the ROM Function Command. The ROM Function Command is used to address the desired 1-Wire device. The table below shows common ROM Function Commands. If only a single 1-Wire device is connected, the Match ROM command can be used to address it. If more than one 1-Wire device is attached, the BASIC Stamp will ultimately have to address them individually using the Match ROM command.

Command | Value (HEX) | Action
Read ROM | $33 | Reads the 64-bit ID of the 1-Wire device. This command can only be used if there is a single 1-Wire device on the line.
Match ROM | $55 | This command, followed by a 64-bit ID, allows the BASIC Stamp to address a specific 1-Wire device.
Skip ROM | $CC | Address a 1-Wire device without its 64-bit ID. This command can only be used if there is a single 1-Wire device on the line.
Search ROM | $F0 | Reads the 64-bit IDs of all the 1-Wire devices on the line. A process of elimination is used to distinguish each unique device.

The third part, the Memory Function Command, allows the BASIC Stamp to address specific memory locations, or features, of the 1-Wire device. Refer to the 1-Wire device's data sheet for a list of the available Memory Function Commands.

Finally, the Transaction/Data section is used to read or write data to the 1-Wire device. The OWOUT command will write data at this point in the transaction. A write is accomplished by generating a low-pulse of a varying width to indicate a 0 or a 1. This is called a "Write Slot" and must be at least 60 us wide. The figure below shows typical Write Slots performed by the BASIC Stamp. See the OWIN command for information on Read Slots.

Related commands: OWIN


 PAUSE

Example

Syntax: PAUSE Duration

Function
Pause the program (do nothing) for the specified Duration.

  • Duration is a variable/constant/expression* (0 - 65535) that specifies the duration of the pause. The unit of time for Duration is one millisecond.

* Note: Expressions are not allowed as arguments on the BS1.

Explanation
PAUSE delays the execution of the next program instruction for the specified number of milliseconds. For example:

Flash:
  LOW 0
  PAUSE 100
  HIGH 0
  PAUSE 100
  GOTO Flash

This code causes pin 0 to go low for 100 ms, then high for 100 ms. The delays produced by PAUSE are as accurate as the ceramic-resonator time base (on the BASIC Stamp modules), ±1 percent. When you use PAUSE in timing-critical applications, keep in mind the relatively low speed of the PBASIC interpreter. This is the time required for the BASIC Stamp to read and interpret an instruction stored in the EEPROM.

Related command: POLLWAIT ( [image] )


PAUSE Example

Syntax

NOTE: This is written for the BS2 and will run on any BASIC Stamp module. Modify the $STAMP directive (as required) before downloading to the BS1, BS2e, BS2sx, BS2p, BS2pe, or BS2px.

' PAUSE.BS2
' This program demonstrates the PAUSE command's time delays. Once a second,
' the program will put the message, "Paused..." on the screen.

' {$STAMP BS2}

Main:
  DEBUG "Paused...", CR
  PAUSE 1000
  GOTO Main


 POLLIN

Example

Syntax: POLLIN Pin, State

Function
Specify a polled-input pin and active state.

  • Pin is a variable/constant/expression (0 - 15) that specifies the I/O pin to use. This I/O pin will be set to input mode.
  • State is a variable/constant/expression (0 - 1) that specifies whether to poll the I/O pin for a low (0) or a high (1) level.

Quick Facts
BS2p, BS2pe, and BS2px
Available actions in response to reaching the desired State
  1. Nothing,
  2. Set polled-output pins to a specified state,
  3. Run another program (in a specified program-slot),
  4. Wait (pause program execution) until desired State is reached,
  5. Any combination of 2, 3 and 4, above.
Special Notes
  • The polled-input pins are monitored (polled) in-between each command within the PBASIC code.
  • On the BS2p40 polled-input pins can be defined on both main and auxiliary I/O pins. These are all active regardless of which group the program happens to be using at the time of a polling event.
  • Polled input pins are stored in special Scratchpad RAM locations. Use GET to retrieve.
    • Location 128 : MAINIO Pins 0 - 7
    • Location 129 : MAINIO Pins 8 - 15
    • Location 130 : AUXIO Pins 0 - 7
    • Location 131 : AUXIO Pins 8 - 15

Explanation
The POLLIN command is one of a family of unique "polling" commands on the BS2p, BS2pe, and BS2px modules. The other commands in this family include POLLMODE, POLLOUT, POLLRUN and POLLWAIT. The POLLIN command is used to specify an input pin to monitor, or "poll", in-between instructions during the rest of the PBASIC program. The BASIC Stamp will then perform some activity (in between instructions) when the specified State is detected. The activity performed depends on the POLLMODE, POLLOUT and POLLRUN commands.

The "polling" commands allow the BASIC Stamp to respond to certain I/O pin events at a faster rate than what is normally possible through manual PBASIC programming. The term "poll" comes from the fact that the BASIC Stamp's interpreter periodically checks the state of the designated polled-input pins. It "polls" these pins after the end of each PBASIC instruction and before it reads the next PBASIC instruction from the user program; giving the appearance that it is polling "in the background".

This feature should not be confused with the concept of interrupts, as the BASIC Stamp does not support true interrupts.

The following is an example of the POLLIN command:

  POLLIN 0, 0
  POLLMODE 2

The POLLIN command in the above code will cause the BASIC Stamp to set I/O pin 0 to an input mode and get ready to poll it for a low (0) state. The BASIC Stamp will not actually start polling until it is set to the appropriate mode, however. The second line, POLLMODE, initiates the polling process (see the POLLMODE description for more information). From then on, as the BASIC Stamp executes the rest of the program, it will check for a low level (logic 0) on I/O pin 0, in-between instructions.

In the code above, no obvious action will be noticed since we didn't tell the BASIC Stamp what to do when it detects a change on the I/O pin. One possible action the BASIC Stamp can be instructed to take is to change the state of an output, called a polled-output. Take a look at the next example:

Setup:
  POLLIN 0, 0
  POLLOUT 1, 1
  POLLMODE 2

Main
  DEBUG "Looping...", CR
  GOTO Main

In this example, in addition to an endless loop, we've added another polling command called POLLOUT (see the POLLOUT description for more information). Our POLLOUT command tells the BASIC Stamp to set I/O pin 1 to an output mode and set it high (1) when it detects the desired poll state. The poll state is the low (0) level on I/O pin 0 that POLLIN told it to look for. If the polled-input pin is high, it will set polled-output pin 1 to low (0), instead.

Once the program reaches the endless loop, starting at Main, it will continuously print "Looping..." on the PC screen. In between reading the DEBUG command and the GOTO command (and vice versa) it will check polled-input pin 0 and set polled-output pin 1 accordingly. In this case, when I/O pin 0 is set low, the BASIC Stamp will set I/O pin 1 high. When I/O pin 0 is set high, the BASIC Stamp will set I/O pin 1 low. It will continue to perform this operation, in-between each command in the loop, endlessly.

It's important to note that, in this example, only the DEBUG and GOTO commands are being executed over and over again. The first three lines of code are only run once, yet their effects are "remembered" by the BASIC Stamp throughout the rest of the program.

If the polling commands were not used, the program would have to look like the one below in order to achieve the same effect.

Setup:
  INPUT 0
  OUTPUT 1

Main:
  OUT1 = ~IN0
  DEBUG  "Looping...", CR
  OUT1 = ~IN0
  GOTO Main

In this example, we create the inverse relationship of input pin 0 and output pin 1 manually, in-between the DEBUG and GOTO lines. Though the effects are the same as when using the polling commands, this program actually takes a little longer to run and consumes 7 additional bytes of program (EEPROM) space. Clearly, using the polling commands is more efficient.

You can have as many polled-input and polled-output pins as you have available. If multiple polled-input pins are defined, any one of them can trigger changes on the polled-output pins that are also defined. For example:

Setup:
  POLLIN 0, 1
  POLLIN 1, 1
  POLLOUT 2, 1
  POLLMODE 2

Main:
  DEBUG "Looping...", CR
  GOTO Main

This code sets I/O pins 0 and 1 to polled-input pins (looking for a high (1) state) and sets I/O pin 2 to be a polled-output pin (with a high-active state). If either I/O pin 0 or 1 goes high, the BASIC Stamp will set I/O pin 2 high. This works similar to a logical OR operation. The truth table below shows all the possible states of these two polled-input pins and the corresponding states the BASIC Stamp will set the polled-output pin to.

Polled-Inputs |  | Polled-Output
0 | 1 | 2
0 | 0 | 0
0 | 1 | 1
1 | 0 | 1
1 | 1 | 1

Normally, any polled-output pins reflect the state changes continuously, as described above. The POLLMODE command supports another feature, however, where the polled-output pins will latch the active state; they will change only once (when the poll state is reached) and stay in the new state until the PBASIC program tells it to change again. See the POLLMODE description for more information.

Other possible actions in response to polled-input states are: 1) Running another program (in a specified program slot), 2) Waiting (pausing program execution with or without low-power mode) until the poll state is reached, or 3) Any combination of the above-mentioned actions.

Related commands: POLLOUT and POLLMODE


POLLIN / POLLOUT / POLLMODE Example

NOTE: This is written for the BS2p and will also run on the BS2pe and BS2px. Modify the $STAMP directive (as required) before downloading to BS2pe or BS2px.

' POLL.BSP
' This program demonstrates POLLIN, POLLOUT, and the use of the POLLMODE
' instruction.  Connect active-low inputs to pins 0, 1, 2, and 3.  Then
' connect an LED to pin 7. The program will print "." to the Debug
' window until one of the alarm buttons are pressed.  This will cause
' the termination of the main loop.  At this point the program will
' save the latched bits, clear them (and the polling process), then
' report the input(s) that triggered the alarm.

' {$STAMP BS2p}
' {$PBASIC 2.5}

FDoor           PIN     0
BDoor           PIN     1
Patio           PIN     2
Rst             PIN     3
AlarmLed        PIN     7

alarms          VAR     Byte            ' alarm bits
idx             VAR     Nib             ' loop control

Setup:
  POLLIN FDoor, 0                       ' define alarm inputs
  POLLIN BDoor, 0
  POLLIN Patio, 0
  POLLOUT AlarmLed, 1                   ' alarm indicator
  POLLMODE 10                           ' activate latched polling
  DEBUG CLS,
        "Alarms Activated", CR

Main:
  DO
    DEBUG "."                           ' foreground activity
    PAUSE 50
  LOOP UNTIL (AlarmLed = 1)             ' loop until LED is on
  GET 128, alarms                       ' get alarm bits
  POLLMODE 0                            ' deactivate polling

Report:
  DEBUG CLS,                            ' alarms report
        "Front Door : ", CR,
        "Back Door  : ", CR,
        "Patio      : ", CR

  FOR idx = 0 TO 2                      ' scan alarm bits
    DEBUG CRSRXY, 13, idx               ' move cursor
    IF (alarms.LOWBIT(idx)) THEN        ' report each bit status
      DEBUG "Alarm", CR
    ELSE
      DEBUG "-", CR
    ENDIF
  NEXT
  DEBUG CR, "Press RESET to clear..."
  DO : LOOP UNTIL (Rst = 0)             ' wait until Rst pressed
  GOTO Setup
  END


 POLLMODE

Example

Syntax: POLLMODE Mode

Function
Specify a polled command mode.

  • Mode is a variable/constant/expression (0 - 15) that indicates the mode in which to process the polled command configuration.

Quick Facts
BS2p, BS2pe, and BS2px
Special Notes
  • Polled-output pins will either change states continuously, just once or not at all, depending on the POLLMODE command
  • A poll mode of 2 or 4 is required for a POLLWAIT command to work
  • If both polled-outputs and polled-run are active, the polled-output event will occur before the polled-run event.

Explanation
The POLLMODE command is one of a family of unique "polling" commands on the BS2p, BS2pe, and BS2px modules. The other commands in this family include POLLIN, POLLOUT, POLLRUN and POLLWAIT. The POLLMODE command is used to specify the mode in which polling events and activities are processed. This activity will occur in between instructions during the rest of the PBASIC program.

The "polling" commands allow the BASIC Stamp to respond to certain I/O pin events at a faster rate than what is normally possible through manual PBASIC programming. The term "poll" comes from the fact that the BASIC Stamp's interpreter periodically checks the state of the designated polled-input pins. It "polls" these pins after the end of each PBASIC instruction and before it reads the next PBASIC instruction from the user program; giving the appearance that it is polling "in the background".

This feature should not be confused with the concept of interrupts, as the BASIC Stamp does not support true interrupts.

The POLLMODE command sets one of 15 possible modes for the polling commands. It is used mainly before and/or after any POLLIN, POLLOUT and POLLRUN commands to disable and enable the polling features as desired. The table below shows the mode values and their effect.

Mode | Effect
0 | Deactivate polling, clear polled-input and output configuration.
1 | Deactivate polling, save polled-input and output configuration.
2 | Activate polling with polled-output action (and polled-wait) only.
31 | Activate polling with polled-run action only.
42 | Activate polling with polled-output/polled-wait and polled-run actions.
53 | Clear polled-input configuration.
63 | Clear polled-output configuration.
73 | Clear polled-input and output configuration.
8 - 15 | Same at 0 - 7 except polled-output states are latched.

1 | After the polled-run action occurs, the mode switches to 1 (deactivated, saved)
2 | After the polled-run action occurs, the mode switches to 2 (activated, outputs)
3 | These modes do not override the previous mode. Also, the output state of polled-outputs does not change as a result of these modes.

The polled-run modes, 3 and 4, are unique. As soon as the polled-run action occurs, the mode switches to 1 (deactivated, saved) or 2 (activated, outputs), respectively. This is so that the BASIC Stamp doesn't continuously go to the start of the designated program slot while the polled-inputs are in the desired poll state. Without this "one shot" feature, your program would appear to lock-up as long as the polled-inputs are in the designated state.

The clear configuration modes, 5, 6 and 7, are also unique. These modes do not override the previous mode. For example, if polled-inputs, polled-outputs and a polled-run configuration was set and the mode was set to 4 (activated, outputs and run) and later the program issued a POLLMODE 6 command, the polled-output configuration would be cleared but the mode would switch back to 4... still allowing the run action. This also means if, later still, the program issues a POLLOUT command, this polled-output would take effect immediately (since the mode is still 4). Also note that these modes do not change the output state of previously defined polled-output pins.

The POLLMODE command determines what action, if any, will occur in response to a polled-input event. This command works in conjunction with the POLLIN, POLLOUT and POLLRUN commands. The following is an example of the POLLMODE command:

Setup:
  POLLIN 0, 0
  POLLOUT 1, 1
  POLLMODE 2

Main:
  DEBUG "Looping...", CR
  GOTO Main

In this example, the first two lines configure I/O pin 0 as a polled-input (looking for a low state) and I/O pin 1 as a polled-output (going high if I/O pin 0 goes low, and vice versa). The third line, POLLMODE, initiates the polling process and configures polled-outputs to be active. From then on, as the BASIC Stamp executes the rest of the program, it will check for a low level (logic 0) on I/O pin 0 in between instructions and will set I/O pin 1 accordingly.

If, in the above example, the poll mode was set to 1 (which means deactivate polling but save configuration) I/O pins 0 and 1 would still be defined the same way, and I/O pin 1 would still be set to output mode, but no polling would take place during the rest of the program.

Here's another example that demonstrates mode 1 (deactivate but save configuration).

Setup:
  POLLIN 0, 0
  POLLOUT 1, 1
  POLLMODE 2

  DEBUG "Polling configured", CR

Main:
  POLLMODE 1
  DEBUG "No polling allowed here...", CR
  PAUSE 1000
  POLLMODE 2

Poll_Now:
  DEBUG  "Polling now...", CR
  GOTO Poll_Now

In this case, polling is configured and activated before "Polling configured" is printed on the screen. Once we reach the Main routine, however, polling is disabled (via the POLLMODE 1 command) and no polling occurs during the printing of "No polling allowed here..." or during the 1 second pause afterward. Finally, polling is activated again, and since the configuration was saved (because of mode 1, before) the polling activity acts just like it did initially for the remainder of the program. The ability to temporarily disable polling, without changing the configuration, can be a powerful feature for certain "critical" parts of a program.

The following example contains two programs. The first should be downloaded into program slot 0 and the second into program slot 1. We'll assume they are called POLL0.BSP and POLL1.BSP, respectively (as defined in the $STAMP directive lines).

' ----- Program #1 (Slot 0) -----
' {$STAMP BS2p, POLL1.BSP}

Setup:
  POLLIN 0, 0
  POLLOUT 1, 1
  POLLRUN 1
  POLLMODE 4

Main:
  DEBUG "Program 1", CR
  GOTO Main

' ----- Program #2 (Slot 1) -----
' {$STAMP BS2p}

DEBUG "Switching...", CR

Again:
  DEBUG "Program 2", CR
  GOTO Again

In this example (containing two programs; one is slot 0 and the other in slot 1) program 1 (slot 0) will configure polled-input pin 0 to detect a low state and polled-output 1 to go high in response. Program 1 also configures a polled-run activity (see the POLLRUN description for more information) to run the program in slot 1. The POLLMODE setting activates the polled-output and the polled-run. Then, program 1 continuously prints "Program 1" on the PC screen.

Once I/O pin 0 goes low, however, the BASIC Stamp will set I/O pin 1 high, then execution will be switched to the program in slot 1 (program 2). Program 2 will first print "Switching..." on the PC screen and then will continuously print "Program 2". From this point forward, I/O pin 1 will continue to be set low and high in response to changes occurring on I/O pin 0, but the polled-run activity is disabled and the BASIC Stamp endlessly runs the code in program 2's Again routine.

Related commands: POLLIN, POLLOUT, POLLRUN, and POLLWAIT


 POLLOUT

Example

Syntax: POLLOUT Pin, State

Function
Specify a polled-output pin and active state.

  • Pin is a variable/constant/expression (0 - 15) that specifies the I/O pin to use. This I/O pin will be set to output mode.
  • State is a variable/constant/expression (0 - 1) that specifies whether to set the I/O pin low (0) or high (1) when a polled-input pin changes to its poll state.

Quick Facts
BS2p, BS2pe, and BS2px
Special Notes
  • The POLLOUT command will immediately change the I/O pin to an output mode and set its level opposite to that of State, regardless of the polled-input states or the polled mode.
  • Polled-output pins will either change states continuously, just once or not at all, depending on the POLLMODE command.
  • On the BS2p40 polled-output pins can be defined on both main and and auxiliary I/O pins. These are all active regardless of which group the program happens to be using at the time of a polling event.
  • If both polled-outputs and polled-run are active, the polled-output event will occur before the polled-run event.

Explanation
The POLLOUT command is one of a family of unique "polling" commands on the BS2p, BS2pe, and BS2px modules. The other commands in this family include POLLIN, POLLMODE, POLLRUN and POLLWAIT. The POLLOUT command is used to specify an output pin that changes states in response to changes on any of the defined polled-input pins. This activity will occur in between instructions during the rest of the PBASIC program.

The "polling" commands allow the BASIC Stamp to respond to certain I/O pin events at a faster rate than what is normally possible through manual PBASIC programming. The term "poll" comes from the fact that the BASIC Stamp's interpreter periodically checks the state of the designated polled-input pins. It "polls" these pins after the end of each PBASIC instruction and before it reads the next PBASIC instruction from the user program; giving the appearance that it is polling "in the background".

This feature should not be confused with the concept of interrupts, as the BASIC Stamp does not support true interrupts.

The POLLOUT command achieves one of three possible actions in response to a polled-input event. This command works in conjunction with the POLLIN and POLLMODE commands. The following is an example of the POLLOUT command:

Setup:
  POLLIN 0, 0
  POLLOUT 1, 1
  POLLMODE 2

Main:
  DEBUG "Looping...", CR
  GOTO Main

In this example, the POLLOUT command tells the BASIC Stamp to set I/O pin 1 to an output mode and set it high (1) when it detects the desired poll state. The poll state is the low (0) level on I/O pin 0 that POLLIN told it to look for. If the polled-input pin is high, the BASIC Stamp will set polled-output pin 1 to low (0), instead. The BASIC Stamp will not actually start polling until it is set to the appropriate mode, however. The third line, POLLMODE, initiates the polling process (see the POLLMODE description for more information). From then on, as the BASIC Stamp executes the rest of the program, it will check for a low level (logic 0) on I/O pin 0 in between instructions.

Once the program reaches the endless loop, at Main, it will continuously print "Looping...." on the PC screen. In between reading the DEBUG command and the GOTO command (and vice versa) it will check polled-input pin 0 and set polled-output pin 1 accordingly. In this case, when I/O pin 0 is set low, the BASIC Stamp will set I/O pin 1 high. When I/O pin 0 is set high, the BASIC Stamp will set I/O pin 1 low. It will continue to perform this operation, in between each command in the loop, endlessly.

It's important to note that in this example only the DEBUG and GOTO commands are being executed over and over again. The first three lines of code are only run once, yet their effects are "remembered" by the BASIC Stamp throughout the rest of the program.

If the polling commands were not used, the program would have to look like the one below in order to achieve the same effect.

Setup:
  INPUT 0
  OUTPUT 1

Main:
  OUT1 = ~IN0
  DEBUG  "Looping...", CR
  OUT1 = ~IN0
  GOTO Main

In this example, we create the inverse relationship of input pin 0 and output pin 1 manually, in-between the DEBUG and GOTO lines. Though the effects are the same as when using the polling commands, this program actually takes a little longer to run and consumes 7 additional bytes of program (EEPROM) space. Clearly, using the polling commands is more efficient.

You can have as many polled-input and polled-output pins as you have available. If multiple polled-input pins are defined, any one of them can trigger changes on the polled-output pins that are also defined. For example:

Setup:
  POLLIN 0, 1
  POLLIN 1, 1
  POLLOUT 2, 1
  POLLMODE 2

Main:
  DEBUG "Looping...", CR
  GOTO Main

This code sets I/O pins 0 and 1 to polled-input pins (looking for a high (1) state) and sets I/O pin 2 to be a polled-output pin (with a high-active state). If either I/O pin 0 or 1 goes high, the BASIC Stamp will set I/O pin 2 high. This works similar to a logical OR operation. The truth table below shows all the possible states of these two polled-input pins and the corresponding states the BASIC Stamp will set the polled-output pin to.

Polled-Inputs |  | Polled-Output
0 | 1 | 2
0 | 0 | 0
0 | 1 | 1
1 | 0 | 1
1 | 1 | 1

Normally, any polled-output pins reflect the state changes continuously, as described above. The POLLMODE command supports another feature, however, where the polled-output pins will latch the active state; they will change only once (when the poll state is reached) and stay in the new state until the PBASIC program tells it to change again. See the POLLMODE description for more information.

A clever use of the "latched" feature is to set a polled-output to be the same as the polled-input. For example, suppose an application needed to respond in some way if a polled-input pin goes high, but it doesn't need to respond immediately, and the other tasks should not be interrupted. In essence, we need a way to know if the pin has gone high since the last time we checked it. Look at this example:

idx     VAR     Byte

Setup:
  POLLOUT 0, 1                          ' pin 0 is polled-output, high
  POLLIN 0, 1                           ' pin 0 back to polled-input, high
  POLLMODE 10                           ' Set mode to latch the polled-output

Work:                                   ' kill time waiting for polled
  FOR idx = 1 TO 20                     '   event
    DEBUG  "Working....", CR
  NEXT
  IF (OUT0 = 0) THEN Work

Respond:                                ' Response message
  DEBUG CR,
        "You set my pin high!", CR
  POLLMODE 10                           ' Reset polled-output's latch function
  GOTO Work

Here, we set I/O pin 0 to a polled-output, then immediately set it to a polled-input. Then we set the polled-mode to latch the polled-outputs. Since the POLLIN command occurred after the POLLOUT, I/O pin 0 will be an input, but the polling feature will still affect the OUT0 bit (output latch for I/O pin 0). Then, the program performs some work, and once in a while, checks the state of OUT0. If OUT0 is 0, I/O pin 0 was never seen to go high. If, however, OUT0 is 1, I/O pin 0 must have gone high while the program was doing other work, and now it can respond in the proper manner. This even works if the pin had gone high and then low again before we check it (as long as it was high at some point in between the instructions in our Work routine.

It is important to note that during the time between the POLLOUT and POLLIN commands, I/O pin 0 will be set to an output direction. This can cause a temporary short with the circuitry connected to I/O pin 0, so it is vital that a large enough series resister (perhaps 220 ohms or greater) be inserted on that pin to protect the external device and the BASIC Stamp.

Related commands: POLLIN and POLLMODE


 POLLRUN

Example

Syntax: POLLRUN ProgramSlot

Function
Specify a program to run upon a polled-input event.

  • ProgramSlot is a variable/constant/expression (0 - 7) that specifies the program slot to run when a polled-input event occurs.

Quick Facts
BS2p, BS2pe, and BS2px
Default Slot The default polled-run slot is 0. If no POLLRUN command is given and a poll mode of 3 or 4 is set, the program in slot 0 will run in response to a polled-input event.
Special Notes
  • If both polled-outputs and polled-run are active, the polled-output event will occur before the polled-run event.

Explanation
The POLLRUN command is one of a family of unique "polling" commands on the BS2p, BS2pe, and BS2px modules. The other commands in this family include POLLIN, POLLMODE, POLLOUT and POLLWAIT. The POLLRUN command is used to specify a program slot to run in response to a polled event. This activity can occur in between any two instructions within the rest of the PBASIC program.

The "polling" commands allow the BASIC Stamp to respond to certain I/O pin events at a faster rate than what is normally possible through manual PBASIC programming. The term "poll" comes from the fact that the BASIC Stamp's interpreter periodically checks the state of the designated polled-input pins. It "polls" these pins after the end of each PBASIC instruction and before it reads the next PBASIC instruction from the user program; giving the appearance that it is polling "in the background". This feature should not be confused with the concept of interrupts, as the BASIC Stamp does not support true interrupts.

The following is a simple example of the POLLRUN command:

Setup:
  POLLIN 0, 0
  POLLRUN 1
  POLLMODE 3

Main:
  DEBUG "Waiting in Program Slot 0...", CR
  GOTO Main

The first line of the above code will set up I/O pin 0 as a polled-input pin looking for a low (0) state. The second line, POLLRUN, tells the BASIC Stamp that when I/O pin 0 goes low, it should switch execution over to the program residing in program slot 1. The third line, POLLMODE, activates the polled-run configuration.

Once the BASIC Stamp reaches the Main routine, it will continuously print "Waiting in Program Slot 0..." on the PC screen. In between reading the DEBUG and GOTO commands, however, the BASIC Stamp will poll I/O pin 0 and check for a high or low state. If the state of pin 0 is high, it will do nothing and continue as normal. If the state of pin 1 is low, it will switch execution over to the program in slot 1 (the second program is not shown in this example). The switch to another program slot works exactly like with the RUN command; the designated program is run and the BASIC Stamp does not "return" to the previous program (similar to a GOTO command).

Note that in order for the polled-run activity to occur, the poll mode must be set to either 3 or 4 (the two modes that activate polled-run). Also note, that the polled-run modes, 3 and 4, are unique. As soon as the polled-run action occurs, the mode switches to 1 (deactivated, saved) or 2 (activated, outputs), respectively. This is so that the BASIC Stamp doesn't continuously go to the start of the designated program slot while the polled-inputs are in the desired poll state. Without this "one shot" feature, your program would appear to lock-up as long as the polled-inputs are in the designated state.

After the program switch takes place, the ProgramSlot value is maintained. Any future change to poll mode 3 or 4, without another POLLRUN command, will result in the previously defined program slot being used.

Related commands: RUN ( [image] ), and POLLMODE ( [image] )


POLLRUN Example

Syntax

NOTE: This is written for the BS2p and will also run on the BS2pe and BS2px. Modify the $STAMP directive (as required) before downloading to BS2pe or BS2px.

' POLLRUN0.BSP
' This program demonstrates the POLLRUN command.  It is intended to be
' downloaded to program slot 0, and the program called PROGRUN1.BSP
' should be downloaded to program slot 1.  I/O pin 0 is set to watch for
' a low signal.  Once the Main routine starts running, the program
' continuously prints it's program slot number to the screen.  If I/O
' pin 0 goes low, the program in program slot 1 (which should be
' POLLRUN1.BSP) is run.

' {$STAMP BS2p, POLLRUN1.BSP}
' {$PBASIC 2.5}

pgmSlot         VAR     Byte

Setup:
  POLLIN  0, 0                          ' polled-input, look for 0
  POLLRUN 1                             ' run slot 1 on polled activation
  POLLMODE 3                            ' enable polling

Main:
  GET 127, pgmSlot
  DEBUG "Running Program #", DEC pgmSlot.LOWNIB, CR
  GOTO Main
  END

' POLLRUN1.BSP
' This program demonstrates the POLLRUN command.  It is intended to be
' downloaded to program slot 1, and the program called PROGRUN0.BSP
' should be downloaded to program slot 0.  This program is run when
' program 0 detects a low on I/O pin 0 via the polled commands.

' {$STAMP BS2p}
' {$PBASIC 2.5}

pgmSlot         VAR     Byte

Main:
  GET 127, pgmSlot
  DEBUG "Running Program #", DEC pgmSlot.LOWNIB, CR
  GOTO Main
  END


 POLLWAIT

Example

Syntax: POLLWAIT Period

Function
Pause program execution, in a low-power mode, in units of Period until any polled-input pin reaches the desired poll state.

  • Period is a variable/constant/expression (0 - 8) that specifies the duration of the low-power state. The low-power duration is 2Period x 18 milliseconds. The table below indicates the low-power duration for any given Period. Using 8 as the Period is a special case; the BS2p, BS2pe, and BS2px will not go into low-power mode and will respond quicker to polled-inputs.

Quick Facts
BS2p | BS2pe | BS2px
Current draw during POLLWAIT | 350 µA | 36 µA | 450 µA
Response time with Period
set to 8 		Less than 160 µS Less than 250 µS Less than 100 µS
Special Notes
  • Poll mode must be 2 or 4 and at least one polled-input must be set to activate POLLWAIT
    (POLLWAIT will be ignored otherwise).
  • If both polled-wait and polled-run are active, the polled-run event will occur immediately after the polled-wait detects an event.

Explanation
The POLLWAIT command is one of a family of unique "polling" commands on the BS2p and BS2pe modules. The other commands in this family include POLLIN, POLLMODE, POLLOUT and POLLRUN. The POLLWAIT command is used to pause program execution and go into a low-power state until any polled-input pin reaches the desired poll state.

The "polling" commands allow the BASIC Stamp to respond to certain I/O pin events at a faster rate than what is normally possible through manual PBASIC programming. The term "poll" comes from the fact that the BASIC Stamp's interpreter periodically checks the state of the designated polled-input pins. It "polls" these pins after the end of each PBASIC instruction and before it reads the next PBASIC instruction from the user program; giving the appearance that it is polling "in the background". This feature should not be confused with the concept of interrupts, as the BASIC Stamp does not support true interrupts.

The POLLWAIT command is unique among the polling commands in that it actually causes execution to halt, until a polled-input pin event occurs. The Period argument is similar to that of the NAP command; using the values 0 to 7 specifies the duration of the low-power period. After the low-power period is over, the BASIC Stamp polls the polled-input pins and determines if any meet the desired poll state. If no polled-input is in the desired state (as set by POLLIN command) the BASIC Stamp goes back into low-power mode, again, for the same duration as before. If any polled-input is in the desired state, however, the BASIC Stamp will continue execution with the next line of code.

A Period of 8, makes the BASIC Stamp pause execution in normal running mode (not low-power mode) until a polled-input event occurs. The response time is indicated in the table below. Since the response time is so fast, this feature can be used to synchronize a portion of PBASIC code to an incoming pulse

Period | Length of Low-Power Mode
0 | 18 ms
1 | 36 ms
2 | 72 ms
3 | 144 ms
4 | 288 ms
5 | 576 ms
6 | 1152 ms (1.152 seconds)
7 | 2304 ms (2.304 seconds)
8 | No power-down

The following is a simple example of the POLLWAIT command.

Setup:
  POLLIN 0, 0
  POLLMODE 2

Main:
  POLLWAIT 0
  TOGGLE 1
  GOTO Main

In this example, the POLLIN command sets I/O pin 0 to be a polled-input pin looking for a low (0) state. The Main routine immediately runs a POLLWAIT command and specifies a Period of 0 (with results in a low-power state of 18 ms). This means that every 18 milliseconds, the BASIC Stamp wakes-up and checks I/O pin 0 for a low. If I/O pin 0 is high, it goes back to sleep for another 18 milliseconds. If I/O pin 0 is low, it runs the next line of code, which toggles the state of I/O pin 1. Then the loop starts all over again. Note: Due to the nature of low-power mode, I/O pin 1 may toggle between high and low (at 18 millisecond intervals in this case) even if I/O pin 0 stays low. This is an artifact of the "reset" condition in the interpreter chip that occurs when the chip wakes up from a low-power state. Upon this "reset" condition, all the I/O pins are switched to inputs for approximately 18 milliseconds. It is the switching to inputs that will cause I/O pin 1 to appear to toggle. See the NAP or SLEEP commands for more information.

If low-power mode is not required, change the POLLWAIT command in the example above to "POLLWAIT 8" instead. This will have the effect of keeping the BASIC Stamp in normal running mode (i.e., no low-power glitches) and will also cause the TOGGLE command to execute in a much shorter amount of time after a polled-input event occurs.

Related commands: PAUSE and POLLMODE ( [image] )


POLLWAIT Example

Syntax

NOTE: This is written for the BS2p and will also run on the BS2pe and BS2px. Modify the $STAMP directive (as required) before downloading to BS2pe or BS2px.

' POLLWAIT.BSP
' This program demonstrates the POLLWAIT command.  I/O pin 0 is set to
' watch for a low signal.  Once the Main routine starts running, the
' POLLWAIT command causes the program to halt until the polled event
' happens (I/O pin is low) then it prints a message on the PC screen.
' It will do nothing until I/O pin is low.

' {$STAMP BS2p}
' {$PBASIC 2.5}

Setup:
  POLLIN 0, 0                           ' polled-input, look for 0
  POLLMODE 2                            ' enable polling

Main:
  POLLWAIT 8                            ' Wait for polled event
  DEBUG "I/O pin 0 is LOW!", CR         ' Print message
  GOTO Main


 POT

Example

Syntax: POT Pin, Scale, Variable

Function
Read a 5 kΩ to 50 kΩ potentiometer, thermistor, photocell, or other variable resistance.

  • Pin is a variable/constant (0 - 7) that specifies the I/O pin to use. This pin will be set to output mode initially, then to input mode.
  • Scale is a variable/constant (0 - 255) used to scale the command's internal 16-bit result. See Explanation below for steps to finding the scale value to use for your circuit.
  • Variable is a variable (usually a byte) where the final result of the reading will be stored. Internally, the POT command calculates a 16-bit value, which is scaled down to an 8-bit value.

Explanation
POT reads a variable resistance and returns a value (0 - 255) representing the amount of time it took to discharge the capacitor through the resistance. Pin must be connected to one side of the variable resistance, whose other side is connected through a capacitor to ground, as shown below.

POT works by first setting the specified I/O pin to an output and setting its state high. This step places +5 volts on one side of the capacitor and ground (0 volts) on the other side, which charges the capacitor. POT will hold the pin high for 10 milliseconds to charge the capacitor. It is important to select component values that will allow the capacitor to charge in this period. If, for example, a 50 kΩ potentiometer is used with a 0.1 µF cap, the maximum charge time would be:

Charge time: 5 x (50 x 103) x (0.1 x 10-6) = 25 x 10-3

The full charge time (5 TC) is 25 x 10-3 or 25 milliseconds. Obviously, the capacitor would never fully charge when the potentiometer is at its maximum position. In this case, changing the capacitor to 0.01 µF reduces the charge time to 2.5 milliseconds; well within the range of the POT function.

After the capacitor is charged the I/O pin to an input mode and POT starts its timer. Initially the I/O pin will see a high (1) that will eventually drop to a low (0) when the capacitor discharges past the 1.4-volt threshold. The timer stops once the low is seen. The value of the variable resistor affects the time it takes to discharge the capacitor from 5 volts to approximately 1.4 volts.

The 16-bit reading is multiplied by (Scale ÷ 256), so a scale value of 128 would reduce the range by approximately 50%, a scale of 64 would reduce to 25%, and so on. The amount by which the internal value must be scaled varies with the size of the resistor being used.

Finding the best Scale value:

  1. Build the circuit shown above and plug the BS1 into the PC.
  2. Select Run | POT Scaling.
    A special calibration window appears, allowing you to find the best value.
  3. The window asks for the number of the I/O pin to which the variable resistor is connected. Select the appropriate pin (0 - 7).
  4. The editor downloads a short program to the BS1 (this overwrites any program already stored in the BS1).
  5. Two numbers will be displayed: scale and value. Adjust the resistor until the smallest number is shown for scale (assuming you can adjust the resistor, as with a potentiometer).
  6. Once you've found the smallest number for scale, you're done. This number should be used for the Scale in the POT command.
  7. Optionally, you can verify the scale number found above by selecting the POT Value checkbox. This locks the scale and causes the BS1 to read the resistor continuously. The window displays the value. If the scale is good, you should be able to adjust the resistor, achieving a 0-255 reading for the value (or as close as possible). To change the scale value and repeat this step, just uncheck the box. Continue this process until you find the best scale.

Related commands: RCTIME ( [image] )


POT Example

Syntax

' POT.BS1
' This program demonstrates the use of the POT command.  Connect one side
' of a 10K potiometer to P0.  To the other side of the potentiomenter
' connect a 0.1 uF capacitor, and then connect the second side of the
' capacitor to Vss (ground).  Before running demo program, use the
' Run | POT Scaling dialog to determine the best Scale factor.

' {$STAMP BS1}
' {$PBASIC 1.0}

SYMBOL  PotPin          = 0             ' 10K pot connected to P0
SYMBOL  Scale           = 110           ' scale value for test circuit

SYMBOL  level           = B2            ' storage of pot "level"

Main:
  POT PotPin, Scale, level              ' read pot level
  DEBUG CLS, "Level = ", #level         ' display
  PAUSE 50                              ' short delay
  GOTO Main                             ' repeat forever
  END


 PULSIN

Examples

Syntax: PULSIN Pin, State, Variable

Function
Measure the width of a pulse on Pin described by State and store the result in Variable.

  • Pin is a variable/constant/expression* (0 - 15) that specifies the I/O pin to use. This pin will be set to input mode.
  • State is a variable/constant/expression* (0 - 1) that specifies whether the pulse to be measured is low (0) or high (1). A low pulse begins with a 1-to-0 transition and a high pulse begins with a 0-to-1 transition.
  • Variable is a variable (usually a word) in which the measured pulse duration will be stored. The unit of time for Variable is described below.

* Note: Expressions are not allowed as arguments on the BS1. The range of the Pin argument on the BS1 is 0 - 7.

Quick Facts
 | BS1 | BS2, BS2e, and BS2pe | BS2sx, BS2p, and BS2px
Units in Variable | 10 µs | 2 µs | 0.8 µs
Maximum pulse width | 655.35 ms | 131.07 ms | 52.428 ms

Explanation
PULSIN is like a fast stopwatch that is triggered by a change in state (0 or 1) on the specified pin. The entire width of the specified pulse (high or low) is measured, in units shown above and stored in Variable.

Many analog properties (voltage, resistance, capacitance, frequency, duty cycle) can be measured in terms of pulse duration. This makes PULSIN a valuable form of analog-to-digital conversion.

PULSIN will wait for the desired pulse, for up to the maximum pulse width it can measure, shown in the table above. If it sees the desired pulse it measures the time until the end of the pulse and stores the result in Variable. If it never sees the start of the pulse, or the pulse is too long (greater than the Maximum Pulse Width shown above), PULSIN "times out" and store 0 in Variable. This operation keeps your program from locking-up should the desired pulse never occur.

Regardless of the size of Variable, PULSIN internally uses a 16-bit timer. Unless the pulse widths are known to be short enough to fit in an 8-bit result, it is recommended using a word-sized variable. Not doing so may result in strange and misleading results as the BASIC Stamp will only store the lower 8-bits into a byte variable.

Related command: PULSOUT and COUNT ( [image] )


PULSIN Example

Syntax
' PULSIN.BS1
' This program uses PULSIN to measure a pulse generated by discharging a
' 0.1 uF capacitor through a 1K resistor. Pressing the switch generates
' the pulse, which should ideally be approximately 120 us (12 PULSIN units
' of 10 us) long. Variations in component values may produce results that
' are up to 10 units off from this value. For more information on calculating
' resistor-capacitor timing, see the RCTIME command.

' {$STAMP BS1}
' {$PBASIC 1.0}

SYMBOL  Pulse           = 7             ' pulse input pin

SYMBOL  time            = W1            ' pulse width (10 uS units)

Main:
  PULSIN Pulse, 1, time                 ' measure positive pulse
  IF time = 0 THEN Main                 ' if 0, try again
  DEBUG CLS, time                       '   else display result
  GOTO Main
  END

NOTE: This is written for the BS2 and will run on any of the BS2-family modules. Modify the $STAMP directive (as required) before downloading to the BS2e, BS2sx, BS2p, BS2pe, or BS2px.

' PULSIN.BS2
' This program uses PULSIN to measure a pulse generated by discharging a
' 0.1 uF capacitor through a 1K resistor. Pressing the switch generates
' the pulse, which should ideally be approximately 120 us (60 PULSIN units
' of 2 us) long (for BS2 and BS2e). Variations in component values may
' produce results that are up to 10 units off from this value.  For more
' information on calculating resistor-capacitor timing, see the RCTIME
' command.

' {$STAMP BS2}
' {$PBASIC 2.5}

Pulse           PIN     7               ' pulse input pin

#SELECT $STAMP
  #CASE BS2, BS2E, BS2PE
    Scale       CON     $200            ' 2.0 us per unit
  #CASE BS2SX, BS2P, BS2PX
    Scale       CON     $0CC            ' 0.8 us per unit
#ENDSELECT

time            VAR     Word

Main:
  PULSIN Pulse, 1, time                 ' measure positive pulse
  IF (time > 0) THEN                    ' if not 0
    DEBUG HOME,
          DEC time, " units ", CLREOL   ' display raw input
    time = time */ Scale                ' adjust for Stamp
    DEBUG CR,
          DEC time, " us  "             ' display microseconds
  ELSE
    DEBUG CLS, "Out of Range"           ' else error message
  ENDIF
  PAUSE 200
  GOTO Main
  END


 PULSOUT

Example

Syntax: PULSOUT Pin, Duration

Function
Generate a pulse on Pin with a width of Duration.

  • Pin is a variable/constant/expression* (0 - 15) that specifies the I/O pin to use. This pin will be set to output mode.
  • Duration is a variable/constant/expression* (0 - 65535) that specifies the duration of the pulse. The unit of time for Duration is described below.

* Note: Expressions are not allowed as arguments on the BS1. The range of the Pin argument on the BS1 is 0 - 7.

Quick Facts
 | BS1 | BS2, BS2e, and BS2pe | BS2sx, BS2p, and BS2px
Units in Duration | 10 µs | 2 µs | 0.8 µs
Maximum pulse width | 655.35 ms | 131.07 ms | 52.428 ms

Explanation
PULSOUT sets Pin to output mode, inverts the state of that pin; waits for the specified Duration; then inverts the state of the pin again; returning the bit to its original state. The unit of Duration is described above. The following example will generate a 100 µs pulse on I/O pin 5:

  PULSOUT 5, 50                         ' generate a pulse on pin 5

The polarity of the pulse depends on the state of the pin before the command executes. In the example above, if pin 5 was low, PULSOUT would produce a positive pulse. If the pin was high, PULSOUT would produce a negative pulse.

If the pin is an input, the output state bit, OUT5 (PIN5 on the BS1) won't necessarily match the state of the pin. What happens then? For example: Pin 7 is an input (DIR7 = 0) and pulled high by a resistor as shown below. Suppose that pin 7 is low when we execute the instruction:

  PULSOUT 7, 5                          ' generate a pulse on pin 7

The figure below shows the sequence of events on that pin. Initially, pin 7 is high. Its output driver is turned off (because it is in input mode), so the 10 kΩ resistor sets the state on the pin. When PULSOUT executes, it turns on the output driver, allowing OUT7 (PIN7 on the BS1) to control the pin.

Since OUT7 (PIN7 on the BS1) is 0, the pin goes low when made an output. After a few microseconds of preparation, PULSOUT inverts the state of the pin; from low to high. It leaves the pin in that state for the specified time (10µs if using a BS2) and then inverts it again, leaving the pin in its original (output) state.

Related command: PULSIN


PULSOUT Examples

Syntax

Connect an LED and 470 Ω resistor as shown below for the demo program.

' PULSOUT.BS1
' This program blinks an LED on for 25 ms at 1-second intervals. Connect an
' LED (active-low) to I/O pin 0.

' {$STAMP BS1}
' {$PBASIC 1.0}

Setup:
  HIGH 0                                ' make P0 high (LED off)

Main:
  PULSOUT 0, 2500                       ' flash LED for 25 ms
  PAUSE 1000                            ' one second delay
  GOTO Main
  END

NOTE: This is written for the BS2 and will run on any of the BS2-family modules. Modify the $STAMP directive (as required) before downloading to the BS2e, BS2sx, BS2p, BS2pe, or BS2px.

' PULSOUT.BS2
' This program blinks an LED on for 25 ms at 1-second intervals. Connect an
' LED (active-low) to I/O pin 0.

' {$STAMP BS2}
' {$PBASIC 2.5}

#SELECT $STAMP
  #CASE BS2, BS2E, BS2PE
    Scale       CON     500             ' to ms for 2 us per unit
  #CASE BS2SX, BS2P, BS2PX
    Scale       CON     1250            ' to ms for 0.8 us per unit
#ENDSELECT

Flash           CON     25 * Scale      ' 25 milliseconds

Setup:
  HIGH 0                                ' make P0 high (LED off)

Main:
  PULSOUT 0, Flash                      ' flash LED
  PAUSE 1000                            ' one second delay
  GOTO Main
  END


 PUT

Example

Syntax: PUT Location, {Word} DataItem {, {Word} DataItem ...}

Function
Put DataItem(s) into Scratchpad RAM, starting at Location and building upward.

  • Location is a variable/constant/expression (0 – 62 for BS2e and BS2sx, and 0 – 126 for BS2p, BS2pe, and BS2px) that specifies the Scratchpad RAM location to write to.
  • Value is a variable/constant/expression to store in RAM.

Quick Facts
 | BS2e and BS2sx | BS2p, BS2pe, and BS2px
Scratchpad RAM size and organization | 64 bytes (0 – 63) | 136 bytes (0 – 135)
General purpose locations | 0 - 62 | 0 – 126
Special use location | Current program slot number in read-only location 63. | Current program slot number in lowest nibble of read-only location 127. Current read/write slot number in highest nibble of location 127.
Additional locations | None | Locations 128 - 131 hold state of polled input pins.

Explanation
The PUT command writes a value into the specified Scratchpad RAM location(s). All values in the general-purpose locations can be written to from within any of the eight program slots.

Scratchpad RAM is useful for passing data to programs in other program slots and for additional workspace. It is different than regular RAM in that symbol names cannot be assigned directly to locations and each location is always configured as a byte only. The following code will write the value 100 to location 25, read it back out with GET and display it:

The following example illustrates this:

temp    VAR     Byte

Main:
  PUT 25, 100
  GET 25, temp
  DEBUG DEC temp
  END

When using $PBASIC 2.5 syntax, Word-sized variables can be written to the Scratchpad RAM with a single PUT statement, as well as multiple items to consecutive locations. The Word modifier writes the low-byte first, then the high-byte ("Little Endian").

' {$PBASIC 2.5}

value   VAR     Word
value2  VAR     Word
addr    VAR     Word                    ' EEPROM address
test    VAR     Byte                    ' test byte read back

Main:
  value = $11
  value2 = $2003
  PUT 0, value, Word value2             ' write value to SP location 0
                                        '  and value2 to SP locations 1 & 2

  value = $FF                           ' modify variables
  value2 = $FFFF

  GET 0, value, Word value2             ' retrieve from Scratchpad

  DEBUG HEX2 ? value                    ' display
  DEBUG HEX4 ? value2
  END

Most Scratchpad RAM locations are available for general use. The highest location (63 for BS2e/BS2sx and 127 for BS2p/BS2pe) is a special, read-only, location that always contains the number of the currently running program slot. On the BS2p/BS2pe, the upper nibble of location 127 also contains the current program slot that will be used for the READ and WRITE commands. Any values written to this location will be ignored.

Related commands: GET ( [image] ), and WRITE


 PWM

Examples

Syntax: PWM Pin, Duty, Duration

Function
Convert a digital value to analog output via pulse-width modulation.

  • Pin is a variable/constant/expression* (0 - 15) that specifies the I/O pin to use. This pin will be set to output mode initially then set to input mode when the command finishes.
  • Duty is a variable/constant/expression* (0 - 255) that specifies the analog output level (0 to 5V).
  • Duration is a variable/constant/expression* (0 - 255) that specifies the duration of the PWM output.

* Note: Expressions are not allowed as arguments on the BS1. The range of the Pin argument on the BS1 is 0 - 7.

Quick Facts
 | BS1 | BS2 and BS2e | BS2sx | BS2p | BS2pe | BS2px
Units in Duration | 5 ms | 1 ms | 0.4 ms | 0.65 ms | 1.62 ms | 0.4 ms
Average voltage equation | Average Voltage = (Duty ÷ 255) x 5 volts
Require charge time (Duration ) equation | Charge time = 5 x R x C, Duration = Charge time ÷ Units in Duration
Special Notes | Pin is set to output initially, and set to input at end

Explanation
Pulse-width modulation (PWM) allows the BASIC Stamp (a purely digital device) to generate an analog voltage. The basic idea is this: If you make a pin output high, the voltage at that pin will be close to 5V. Output low is close to 0V. What if you switched the pin rapidly between high and low so that it was high half the time and low half the time? The average voltage over time would be halfway between 0 and 5V (2.5V). PWM emits a burst of 1s and 0s whose ratio is proportional to the duty value you specify.

The proportion of 1s to 0s in PWM is called the duty cycle. The duty cycle controls the analog voltage in a very direct way; the higher the duty cycle the higher the voltage. In the case of the BASIC Stamp, the duty cycle can range from 0 to 255. Duty is literally the proportion of 1s to 0s output by the PWM command. To determine the proportional PWM output voltage, use this formula: (Duty ÷ 255) x 5V. For example, if Duty is 100, (100 ÷ 255) x 5V = 1.96V; PWM outputs a train of pulses whose average voltage is 1.96V.

In order to convert PWM into an analog voltage we have to filter out the pulses and store the average voltage. The resistor/capacitor combination shown below will do the job. The capacitor will hold the voltage set by PWM even after the instruction has finished. How long it will hold the voltage depends on how much current is drawn from it by external circuitry, and the internal leakage of the capacitor. In order to hold the voltage relatively steady, a program must periodically repeat the PWM instruction to give the capacitor a fresh charge.

Just as it takes time to discharge a capacitor, it also takes time to charge it in the first place. The PWM command lets you specify the charging time in terms of PWM duration. The timing for the units in Duration is shown in in the table above. So, on the BS2, to charge a capacitor for five milliseconds, you would specify five units in Duration.

How do you determine how long to charge a capacitor? Use this rule-of-thumb formula: Charge time = 5 x R x C. For instance, the circuit below uses a 10 kΩ (10 x 103 ohm) resistor and a 1 µF (1 x 10-6 F) capacitor:

Charge time = 5 x 10 x 103 x 1 x 10-6 = 50 x 10-3 seconds, or 50 milliseconds.

Since, on the BS2, each unit in Duration is approximately a millisecond, it would take at least 50 units to charge the capacitor. Assuming the circuit is connected to P0, here's the complete PWM instruction:

  PWM 0, 100, 50                        ' Put a 1.96V charge on cap (BS2, BS2e)

To charge the same circuit to the same level using a BS2sx, the Duration would require adjustment as follows:

  PWM 0, 100, 125                       ' Put a 1.96V charge on cap (BS2sx)

After outputting the PWM pulses, the BASIC Stamp leaves the pin in input mode (0 in the corresponding bit of DIRS). In input mode, the pin's output driver is effectively disconnected. If it were not, the steady output state of the pin would change the voltage on the capacitor and undo the voltage setting established by PWM. Keep in mind that leakage currents of up to 1 µA can flow into or out of this "disconnected" pin. Over time, these small currents will cause the voltage on the capacitor to drift. The same applies for leakage current from an op-amp's input, as well as the capacitor's own internal leakage. Executing PWM occasionally will reset the capacitor voltage to the intended value.

PWM charges the capacitor; the load presented by your circuit discharges it. How long the charge lasts (and therefore how often your program should repeat the PWM command to refresh the charge) depends on how much current the circuit draws, and how stable the voltage must be. You may need to buffer PWM output with a simple op-amp follower if your load or stability requirements are more than the passive circuit can handle.

The term "PWM" applies only loosely to the action of the BASIC Stamp's PWM command. Most systems that output PWM do so by splitting a fixed period of time into an on time (1) and an off time (0). Suppose the interval is 1 ms and the duty cycle is 100 ÷ 255. Conventional PWM would turn the output on for 0.39 ms and off for 0.61 ms, repeating this process each millisecond. The main advantage of this kind of PWM is its predictability; you know the exact frequency of the pulses (in this case, 1 kHz), and their widths are controlled by the duty cycle.

BASIC Stamp's PWM does not work this way. It outputs a rapid sequence of on/off pulses, as short as 1.6 µs in duration, whose overall proportion over the course of a full PWM cycle of approximately a millisecond is equal to the duty cycle. This has the advantage of very quickly zeroing in on the desired output voltage, but it does not produce the neat, orderly pulses that you might expect. All BS2 modules also uses this high-speed PWM technique to generate pseudo-sine wave tones with the DTMFOUT and FREQOUT instructions.


PWM Example

Syntax
' PWM.BS1
' Connect a voltmeter (such as a digital multimeter set to its voltage
' range) to the output of the circuit shown in the figure for the PWM
' command (in the manual).  Run the program and observe the readings on
' the meter. They should come very close to 1.96V, then decrease slightly
' as the capacitor discharges. Try varying the interval between PWM bursts
' (by changing the PAUSE value) and the number of PWM cycles to see their
' effect.

' {$STAMP BS1}
' {$PBASIC 1.0}

Main:
  PWM 0, 100, 10                        ' PWM at 100/255 duty (~50 ms)
  PAUSE 1000                            ' wait one second
  GOTO Main
  END

NOTE: This is written for the BS2 and will run on any of the BS2-family modules. Modify the $STAMP directive (as required) before downloading to the BS2e, BS2sx, BS2p, BS2pe, or BS2px.

' PWM.BS2
' Connect a voltmeter (such as a digital multimeter set to its voltage
' range) to the output of the circuit shown in the figure for the PWM
' command (in the manual).  Run the program and observe the readings on
' the meter. They should come very close to 1.96V, then decrease slightly
' as the capacitor discharges. Try varying the interval between PWM bursts
' (by changing the PAUSE value) and the number of PWM cycles to see their
' effect.

' {$STAMP BS2p}
' {$PBASIC 2.5}

#SELECT $STAMP
  #CASE BS2, BS2E
    CycAdj      CON     $100            ' x 1.0, cycle ajustment (for ms)
  #CASE BS2SX
    CycAdj      CON     $280            ' x 2.5
  #CASE BS2P
    CycAdj      CON     $187            ' x 1.53
  #CASE BS2PE
    CycAdj      CON     $09E            ' x 0.62
  #CASE BS2PX
    CycAdj      CON     $280            ' x 2.5
#ENDSELECT

Cycles          CON     50

Main:
  PWM 0, 100, (Cycles */ CycAdj)        ' PWM at 100/255 duty (~50 ms)
  PAUSE 1000                            ' wait one second
  GOTO Main
  END


 RANDOM

Examples

Syntax: RANDOM Variable

Function
Generate a pseudo-random number.

  • Variable is a variable (usually a word) whose bits will be scrambled to produce a random number. Variable acts as RANDOM's input and its result output. Each pass through RANDOM stores the next number, in the pseudo-random sequence, in Variable.

Explanation
RANDOM generates pseudo-random numbers ranging from 0 to 65535. They're called "pseudo-random" because they appear random, but are generated by a logic operation that uses the initial value in Variable to "tap" into a sequence of 65535 essentially random numbers. If the same initial value, called the "seed", is always used, then the same sequence of numbers is generated. The following example demonstrates this:

SYMBOL  result  = W1

Main:
  result = 11000                        ' set initial "seed" value
  RANDOM result                         ' generate random number
  DEBUG result                          ' show the result on screen
  GOTO Main

result  VAR     Word

Main:
  result = 11000                        ' set initial "seed" value
  RANDOM result                         ' generate random number
  DEBUG DEC ? result                    ' show the result on screen
  GOTO Main

In this example, the same number would appear on the screen over and over again. This is because the same seed value was used each time; specifically, the first line of the loop sets result to 11000. The RANDOM command really needs a different seed value each time. Moving the "Result =" line out of the loop will solve this problem, as in:

SYMBOL  result  = W1

Setup:
  result = 11000                        ' set initial "seed" value

Main:
  RANDOM result                         ' generate random number
  DEBUG result                          ' show the result on screen
  GOTO Main
  END

result  VAR     Word

Setup:
  result = 11000                        ' set initial "seed" value

Main:
  RANDOM result                         ' generate random number
  DEBUG DEC ? result                    ' show the result on screen
  GOTO Main
  END

Here, result is only initialized once, before the loop. Each time through the loop, the previous value of result, generated by RANDOM, is used as the next seed value. This generates a more desirable set of pseudo-random numbers.

In applications requiring more apparent randomness, it's necessary to "seed" RANDOM with a more random value every time. For instance, in the example program, RANDOM is executed continuously (using the previous resulting number as the next seed value) while the program waits for the user to press a button. Since the user can't control the timing of button presses very accurately, the results approach true randomness.


RANDOM Examples

Syntax
' RANDOM.BS1
' Connect a button to I/O pin 7 as shown in the figure in the RANDOM
' command description and run this program. This program uses RANDOM to
' simulate a coin toss. After 100 trials, it reports the total number of
' heads and tails thrown.

' {$STAMP BS1}
' {$PBASIC 1.0}

SYMBOL  Btn             = 7                     ' button input

SYMBOL  flip            = W0                    ' a random number
SYMBOL  coin            = BIT0                  ' a bit from random number
SYMBOL  trials          = B2                    ' number of flips
SYMBOL  heads           = B3                    ' throws that come up heads
SYMBOL  tails           = B4                    ' throws that come up tails
SYMBOL  btnWrk          = B5                    ' workspace for BUTTON

Start:
  DEBUG CLS, "Press the button to toss coin.", CR

Main:
  FOR trials = 1 TO 100                         ' flip coin 100 times

Hold:
    RANDOM flip                                 ' randomize while waiting
    BUTTON Btn, 0, 250, 100, btnWrk, 0, Hold    ' wait for button press
    BRANCH coin, (Head, Tail)                   ' 0 = heads, 1 = tails

Head:
    DEBUG CR, "Heads!"
    heads = heads + 1                           ' increment heads counter
    GOTO Next_Toss

Tail:
    DEBUG CR, "Tails..."
    tails = tails + 1                           ' increment heads counter

Next_Toss:
  NEXT

  DEBUG CR, CR, "Heads: ", #heads, CR, "Tails: ", #tails
  END

NOTE: This is written for the BS2 and will run on any of the BS2-family modules. Modify the $STAMP directive (as required) before downloading to the BS2e, BS2sx, BS2p, BS2pe, or BS2px.

' RANDOM.BS2
' Connect a button to I/O pin 7 as shown in the figure in the RANDOM
' command description and run this program. This program uses RANDOM to
' simulate a coin toss. After 100 trials, it reports the total number of
' heads and tails thrown.

' {$STAMP BS2}
' {$PBASIC 2.5}

Btn             PIN     7                       ' button input

flip            VAR     Word                    ' a random number
coin            VAR     flip.BIT0               ' Bit0 of the random number
trials          VAR     Byte                    ' number of flips
heads           VAR     Byte                    ' throws that come up heads
tails           VAR     Byte                    ' throws that come up tails
btnWrk          VAR     Byte                    ' workspace for BUTTON

Start:
  DEBUG CLS, "Press button to start"

Main:
  FOR trials = 1 TO 100                         ' flip coin 100 times

Hold:
    RANDOM flip                                 ' randomize while waiting
    BUTTON Btin, 0, 250, 100, btnWrk, 0, Hold   ' wait for button press
    IF (coin = 0) THEN                          ' 0 = heads, 1 = tails
      DEBUG CR, "Heads!"
      heads = heads + 1                         ' increment heads counter
    ELSE
      DEBUG CR, "Tails..."
      tails = tails + 1                         ' increment tails counter
    ENDIF
  NEXT

Done:
  DEBUG CR, CR, "Heads: ", DEC heads, " Tails: ", DEC tails
  END


 RCTIME

Examples

Syntax: RCTIME Pin, State, Variable

Function
Measure time while Pin remains in State; usually to measure the charge/discharge time of resistor/capacitor (RC) circuit..

  • Pin is a variable/constant/expression (0 - 15) that specifies the I/O pin to use. This pin will be placed into input mode.
  • State is a variable/constant/expression (0 - 1) that specifies the desired state to measure. Once Pin is not in State, the command ends and stores the result in Variable.
  • Variable is a variable (usually a word) in which the time measurement will be stored. The unit of time for Variable is described below.

Quick Facts
 | BS2, BS2e, and BS2pe | BS2sx | BS2p | BS2px
Units in Variable | 2 µs | 0.8 µs | 0.75 µs | 0.75 µs
Maximum pulse width | 131.07 ms | 52.428 ms | 49.151 ms | 49.151 ms

Explanation
RCTIME can be used to measure the charge or discharge time of a resistor/capacitor circuit. This allows you to measure resistance or capacitance; use R or C sensors such as thermistors or capacitive humidity sensors or respond to user input through a potentiometer. In a broader sense, RCTIME can also serve as a fast, precise stopwatch for events of very short duration.

When RCTIME executes, it starts a counter (who's unit of time is shown above). It stops this counter as soon as the specified pin is no longer in State (0 or 1). If pin is not in State when the instruction executes, RCTIME will return 1 in Variable, since the instruction requires one timing cycle to discover this fact. If pin remains in State longer than 65535 timing cycles RCTIME returns 0.

The figure below shows suitable RC circuits for use with RCTIME. Circuits A are preferred, because the BASIC Stamp's logic threshold is approximately 1.4 volts. This means that the voltage seen by the pin will start at 5V then fall to 1.4V (a span of 3.6V) before RCTIME stops. With Circuit B, the voltage will start at 0V and rise to 1.4V (spanning only 1.4V) before RCTIME stops. For the same combination of R and C, Circuits A will yield a higher count, and therefore more resolution than Circuit B.

Before RCTIME executes, the capacitor must be put into the state specified in the RCTIME instruction. For example, with Circuit A, the capacitor must be charged until the top plate at 5V.

Here's a typical sequence of instructions for Circuit A (assuming I/O pin 7 is used):

result  VAR     Word

Test:
  HIGH 7                                ' charge the cap
  PAUSE 1                               '   for 1 ms
  RCTIME 7, 1, result                   ' measure RC discharge time
  DEBUG DEC ? result                    ' display result
  END

Using RCTIME is very straightforward, except for one detail: For a given R and C, what value will RCTIME return? It's easy to figure, based on a value called the RC time constant, or tau (τ) for short. Tau represents the time required for a given RC combination to charge or discharge by 63 percent of the total change in voltage that they will undergo. More importantly, the value t is used in the generalized RC timing calculation. Tau's formula is just R multiplied by C:

τ = R x C

The general RC timing formula uses τ to tell us the time required for an RC circuit to change from one voltage to another:

time = -τ x ( ln(Vfinal / Vinitial) )

In this formula ln is the natural logarithm; it's a key on most scientific calculators. Let's do some math. Assume we're interested in a 10 kΩ resistor and 0.1 µF capacitor. Calculate τ:

τ = (10 x 103) x (0.1 x 10-6) = 1 x 10-3

The RC time constant is 1 x 10-3 or 1 millisecond. Now calculate the time required for this RC circuit to go from 5V to 1.4V (as in Circuit A):

Time = -1 x 10-3 x ( ln(5.0v ÷ 1.4v) ) = 1.273 x 10-3

On the BS2, the unit of time is 2 µs, that time (1.273 x 10-3) works out to about 635 units. With a 10 kΩ resistor and 0.1 µF capacitor, RCTIME would return a value of approximately 635. Since Vinitial and Vfinal doesn't change, we can use a simplified rule of thumb to estimate RCTIME results for Circuit A:

RCTIME units = 635 x R (in kΩ) x C (in µF)

Another handy rule of thumb can help you calculate how long to charge/discharge the capacitor before RCTIME. In the example above that's the purpose of the HIGH and PAUSE commands. A given RC charges or discharges 98 percent of the way in five time constants (5 x R x C). In Circuits A and B, the charge/discharge current passes through the 220 Ω series resistor and the capacitor. So if the capacitor were 0.1 µF, the minimum charge/discharge time should be:

Charge time = 5 x 220 x (0.1 x 10-6) = 110 x 10-6

So it takes only 110 µs for the capacitor to charge/discharge, meaning that the one millisecond charge/discharge time of the example is plenty.

A final note about the circuits above: You may be wondering why the 220 Ω resistor is necessary at all. Consider what would happen if resistor R was a potentiometer, and were adjusted to 0 Ω. When the I/O pin went high to discharge the capacitor, it would see a short direct to ground. The 220 Ω series resistor would limit the short circuit current to 5V ÷ 220 Ω = 23 mA and protect the BASIC Stamp from damage. (Actual current would be quite a bit less due to internal resistance of the pin's output driver, but you get the idea.)

Related command: POT ( [image] )


RCTIME Examples

Syntax

NOTE: This is written for the BS2 and will run on any of the BS2-family modules. Modify the $STAMP directive (as required) before downloading to the BS2e, BS2sx, BS2p, BS2pe, or BS2px.

' RCTIME1.BS2
' This program shows the standard use of the RCTIME instruction measuring
' an RC charge/discharge time. Use the circuit in the RCTIME description
' (in the manual) with R = 10K pot and C = 0.1 uF. Connect the circuit to
' pin 7 and run the program.  Adjust the pot and watch the value shown on
' the Debug screen change.

' {$STAMP BS2}
' {$PBASIC 2.5}

RC              PIN     7

result          VAR     Word

Main:
  DO
    HIGH RC                             ' charge the cap
    PAUSE 1                             '   for 1 ms
    RCTIME RC, 1, result                ' measure RC discharge time
    DEBUG HOME, DEC result              ' display value
    PAUSE 50
  LOOP
  END

NOTE: This is written for the BS2 and will run on any of the BS2-family modules. Modify the $STAMP directive (as required) before downloading to the BS2e, BS2sx, BS2p, BS2pe, or BS2px.

' RCTIME2.BS2
' This program illustrates the use of RCTIME as a fast stopwatch. The
' program energizes a relay coil, then measures how long it takes for the
' relay contacts to close.  The circuit for this program can be found in
' the manual. Note that RCTIME doesn't start timing instantly -- as with
' all PBASIC instructions, it must be fetched from program EEPROM before
' it can execute.

' {$STAMP BS2}
' {$PBASIC 2.5}

Coil            PIN     6
RC              PIN     7

#SELECT $STAMP
  #CASE BS2, BS2E, BS2PE
    Adjust      CON     $200            ' x 2 us per unit
  #CASE BS2SX
    Adjust      CON     $0CC            ' x 0.8 us per unit
  #CASE BS2P
    Adjust      CON     $0C0            ' x 0.75 us per unit
  #CASE BS2PX
    Adjust      CON     $0C0            ' x 0.75 us per unit
#ENDSELECT

result          VAR     Word

Main:
  DO
    LOW Coil                            ' energize relay coil
    RCTIME RC, 1, result                ' measure time to contact closure
    result = result */ Adjust           ' adjust for device
    DEBUG "Time to close: ",
          DEC Result, CR
    HIGH Coil                           ' release relay
    PAUSE 1000                          ' wait one second
  LOOP
  END


 READ

Examples

Syntax [image]: READ Location, Variable
Syntax [image]: READ Location, {Word} Variable {, {Word} Variable, ...}

Function
Read value at Location in EEPROM and store the result in result in Variable.

  • Location Location is a variable/constant/expression* (0 - 255 on BS1, 0 - 2047 on all other BASIC Stamps) that specifies the EEPROM address to read from.
  • Variable is a variable (usually a byte) where the value is stored.

* Note: Expressions are not allowed as arguments on the BS1.

Quick Facts
 | BS1 | BS2, BS2e, and BS2sx | BS2p, BS2pe, and BS2px
Range of EEPROM locations | 0 to 255 | 0 to 2047 | 0 to 2047 (see notes below)
Special Notes | N/A | READ only works with current program slot on BS2e and BS2sx. | READ works with any program slot as set by the STORE command.

Explanation
The EEPROM is used for both program storage (which builds downward from address 255 on BS1, 2047 on all other BASIC Stamps) and data storage (which builds upward from address 0). The READ instruction retrieves a value from any EEPROM address and stores it in Variable. When the optional Word modifier ($PBASIC 2.5 required) is used, the low byte of Variable is read from Location, the high byte of Variable from Location + 1.

Any location within the EEPROM can be read (including your PBASIC program's tokens) at run-time. This feature is mainly used to retrieve long-term data from EEPROM; data stored in EEPROM is not lost when the power is removed.

The following READ command retrieves the value at location 100 and stores it into the variable called Result:

SYMBOL  result  = B2

Main:
  READ 100, result
  END

result  VAR     Byte

Main:
  READ 100, result
  END
The EEPROM is organized as a sequential set of byte-sized memory locations. The READ command retrieves byte-sized values from EEPROM. This does not mean that you can't read word-sized values, however. A word consists of two bytes, called a low-byte and a high-byte. If you wanted to read a word-sized value, you can use two READ commands and a word-size variable (along with some handy modifiers). For example,

SYMBOL  result  =  W1                   ' word-sized variable
SYMBOL  resLo   =  B2                   ' low-byte of W1
SYMBOL  resHi   =  B3                   ' high-byte of W1

EEPROM  (101, 4)                        ' Store word-sized value

Main:
  READ 0, resLo
  READ 1, resHi
  DEBUG #result
  END

result  VAR     Word

DATA    Word    1125                    ' Store word-sized value

Main:
  READ 0, result.LowByte
  READ 1, result.HighByte
  DEBUG DEC ? result
  END

This code uses the EEPROM or DATA directive to write the low-byte and high-byte of the number 1125 into locations 0 and 1 during download. When the program runs, the two READ commands will read the low-byte and high-byte out of EEPROM (reconstructing it in a word-size variable) and then display the value on the screen.

When using $PBASIC 2.5 syntax, word-sized variables can be retrieved with a single READ statement, as well as multiple items from consecutive locations.

' {$PBASIC 2.5}

idNum   VAR     Word
score   VAR     Byte

ID_Rec  DATA    Word 1125, 75           ' Store multiple items

Main:
  READ ID_Rec, Word idNum, score        ' Read multiple variables
  DEBUG DEC ? idNum                     ' Display them
  DEBUG DEC ? score
  END

Note that the EEPROM and DATA directives store data in the EEPROM before the program runs, however, the WRITE command can be used to store data while the program is running. Additionally, the EEPROM locations can be read an unlimited number of times, but EEPROM locations can be worn out by excessive writes. See the WRITE command for more information.

When using the READ and WRITE commands, take care to ensure that your program doesn't overwrite itself. On the BS1, location 255 holds the address of the last instruction in your program. Therefore, your program can use any space below the address given in location 255. For example, if location 255 holds the value 100, then your program can use locations 0-99 for data.

On other BASIC Stamps, you'll need to view the Memory Map of the program before you download it, to determine the last EEPROM location used.

On the BS2p, BS2pe, and BS2px the READ and WRITE commands can affect locations in any program slot as set by the STORE command. See the STORE command for more information.

Related commands: WRITE, EEPROM ( [image] ), DATA ( [image] ), STORE ( [image] ), and GET ( [image] )


READ Examples

Syntax
' READ.BS1
' This program reads a string of data stored in EEPROM. The EEPROM data is
' downloaded to the BS1 at compile-time and remains there (even with the
' power off) until overwritten. Put ASCII characters into EEPROM, followed
' by 0, which will serve as the end-of-message marker.  For programs with
' multiple strings, use the Memory Map window to find the starting character
' address.

' {$STAMP BS1}
' {$PBASIC 1.0}

SYMBOL  strAddr         = B2
SYMBOL  char            = B3

Msg1:
  EEPROM ("BS1", 13, "EEPROM Storage!", 0)

Main:
  strAddr = 0                           ' set to start of message
  GOSUB String_Out
  END

String_Out:
  READ strAddr, char                    ' read byte from EEPROM
  strAddr = strAddr + 1                 ' point to next character
  IF char = 0 THEN StrOut_Exit          ' if 0, exit routine
  DEBUG #@char                          ' otherwise print char
  GOTO String_Out                       ' get next character

StrOut_Exit:
  RETURN

NOTE: This is written for the BS2 and will run on any of the BS2-family modules. Modify the $STAMP directive (as required) before downloading to the BS2e, BS2sx, BS2p, BS2pe, or BS2px.

' READ.BS2
' This program reads a string of data stored in EEPROM. The EEPROM data is
' downloaded to the BS2 at compile-time and remains there (even with the
' power off) until overwritten. Put ASCII characters into EEPROM, followed
' by 0, which will serve as the end-of-message marker.

' {$STAMP BS2}
' {$PBASIC 2.5}

strAddr         VAR     Word
char            VAR     Byte

Msg1            DATA    "BS2", CR, "EEPROM Storage!", 0

Main:
  strAddr = Msg                         ' set to start of message
  GOSUB String_Out
  END

String_Out:
  DO
    READ strAddr, char                  ' read byte from EEPROM
    strAddr = strAddr + 1               ' point to next character
    IF (char = 0) THEN EXIT             ' if 0, exit routine
    DEBUG char                          ' otherwise print char
  LOOP
  RETURN


 RETURN

Example

Syntax: RETURN

Function
Return from a subroutine, assuming there was a previous GOSUB or ON...GOSUB executed.

Quick Facts
 | All BASIC Stamp Modules
Maximum number of RETURNs per program | Unlimited. However, the number of GOSUBs is limited. See GOSUB for more information.

Explanation
RETURN sends the program back to the address (instruction) immediately following the most recent GOSUB. If RETURN is executed without a prior GOSUB, the BASIC Stamp will return to the first executable line of the program; usually resulting in a logical bug in the code. See the GOSUB command for more information.

Note: On the BS1, a RETURN without a GOSUB will return the program to the last GOSUB (or will end the program if no GOSUB was executed)

The example below will start out by GOSUB-ing to the section of code beginning with the label Hello. It will print "Hello my friend." on the screen then RETURN to the line after the GOSUB, which prints "How are you?" and ENDs.

Main:
  GOSUB Hello
  DEBUG "How are you?", CR
  END

Hello:
  DEBUG "Hello my friend.", CR
  RETURN

Watch Out For Subroutines That Your Program Can "Fall Into"

There's another interesting lesson here; what would happen if we removed the END command from this example? Since the BASIC Stamp reads the code from left to right, top to bottom (like the English language) once it had returned to and run the "How are you?" line, it would naturally "fall into" the Hello routine again. Additionally, at the end of the Hello routine, it would see the RETURN again (although it didn't GOSUB to that routine this time) and because there wasn't a previous place to return to, the BASIC Stamp will start the entire program over again. This would cause an endless loop. The important thing to remember here is to always make sure your program doesn't allow itself to "fall into" a subroutine.

Related commands: GOSUB and ON...GOSUB ( [image] )


RETURN Example

Syntax

NOTE: This is written for the BS2 and will run on any BASIC Stamp module. Modify the $STAMP directive (as required) before downloading to the BS1, BS2e, BS2sx, BS2p, BS2pe, or BS2px.

' RETURN.BS2
' This program demonstrates a potential bug caused by allowing a program to
' "fall into" a subroutine.  The program was intented to indicate that it
' is "Starting...", then "Executing Subroutine,", then "Returned..." from
' the subroutine and stop.  Since we left out the END command (indicated in
' the comments), the program then falls into the subroutine, displays
' "Executing..." again and then RETURNs to the start of the program and
' runs continuously in an endless loop.

' {$STAMP BS2}

Reset:
  DEBUG "Starting Program", CR          ' show start-up

Main:
  PAUSE 1000
  GOSUB Demo_Sub                        ' call the subroutine
  PAUSE 1000
  DEBUG "Returned from Subroutine", CR  ' show that we're back
  PAUSE 1000
                                        ' <-- Forgot to put END here

Demo_Sub:
  DEBUG "  Executing Subroutine", CR    ' show subroutine activity
  RETURN


 REVERSE

Examples

Syntax: REVERSE Pin

Function
Reverse the data direction of the specified pin.

  • Pin is a variable/constant/expression* (0 – 15) that specifies the I/O pin to use. This pin will be placed into the mode opposite of its current input/output mode.

* Note: Expressions are not allowed as arguments on the BS1. The range of the Pin argument on the BS1 is 0 - 7.

Explanation
REVERSE is convenient way to switch the I/O direction of a pin. If the pin is an input, REVERSE makes it an output; if it's an output, REVERSE makes it an input.

Remember that "input" really has two meanings: (1) Setting a pin to input makes it possible to check the state (1 or 0) of external circuitry connected to that pin. The current state is in the corresponding bit of the INS register (PINS on the BS1). (2) Setting a pin to input also disconnects the output driver, the corresponding bit of OUTS (PINS on the BS1).

The example programs illustrate this second fact with a two-tone LED blinker.

Related commands: INPUT and OUTPUT


REVERSE Examples

Syntax

Connect an LED and two resistors as shown below for the demo program.

' REVERSE.BS1
' Connect the circuit shown in the REVERSE command description to I/O pin
' 0 and run this program.  The LED will alternate between two states, dim
' and bright. The BASIC Stamp is using the REVERSE command to toggling I/O
' pin 0 between input and output states. When pin 0 is an input, current
' flows through R1, through the LED, through R2 to ground. Pin 0 is
' effectively disconnected and doesn't play a part in the circuit. The total
' resistance encountered by current flowing through the LED is R1 + R2 = 1220
' ohms. When pin 0 is reversed to an output, current flows through R1, through
' the LED, and into pin 0 to ground (because of the 0 written to PIN0). The
' total resistance encountered by current flowing through the LED is R1,
' 220 ohms. With only 20% of the resistance, the LED glows brighter.

' {$STAMP BS1}
' {$PBASIC 1.0}

Setup:
  PIN0 = 0                              ' Put a low in the pin 0
                                        '  output driver
Main:
  PAUSE 250                             ' 1/4th second pause
  REVERSE 0                             ' reverse pin 0 I/O direction
  GOTO Main                             ' do forever

NOTE: This is written for the BS2 and will run on any of the BS2-family modules. Modify the $STAMP directive (as required) before downloading to the BS2e, BS2sx, BS2p, BS2pe, or BS2px.

' REVERSE.BS2
' Connect the circuit shown in the REVERSE command description to I/O pin
' 0 and run this program.  The LED will alternate between two states, dim
' and bright. The BASIC Stamp is using the REVERSE command to toggling I/O
' pin 0 between input and output states. When pin 0 is an input, current
' flows through R1, through the LED, through R2 to ground. Pin 0 is
' effectively disconnected and doesn't play a part in the circuit. The total
' resistance encountered by current flowing through the LED is R1 + R2 = 1220
' ohms. When pin 0 is reversed to an output, current flows through R1, through
' the LED, and into pin 0 to ground (because of the 0 written to OUT0). The
' total resistance encountered by current flowing through the LED is R1,
' 220 ohms. With only 20% of the resistance, the LED glows brighter.

' {$STAMP BS2}
' {$PBASIC 2.5}

Setup:
  OUT0 = 0                              ' Put a low in the pin 0
                                        '  output driver
Main:
  PAUSE 250                             ' 1/4th second pause
  REVERSE 0                             ' reverse pin 0 I/O direction
  GOTO Main                             ' do forever


 RUN

Example

Syntax: RUN ProgramSlot

Function
Switches execution to another BASIC Stamp program (in a different program slot).

  • ProgramSlot is a variable/constant/expression (0 – 7) that specifies the program slot to run.

Quick Facts
 | BS2e | BS2sx | BS2p | BS2pe | BS2px
Number of program slots | 8 (numbered 0 to 7) †
Time delay to switch between program slots | 770 µs | 300 µs | 250 µs | 736 µs | 195 µs
Special Notes | RUN is similar to a GOTO...you can not "return" from a RUN
† The BS2pe has 16 slots, but only slots 0 - 7 are avaiable for programs. Slots 8 - 15 may be used for data storage.

Explanation
The BS2e, BS2sx, BS2p, and BS2px have a total of 16 kilobytes of code space; the BS2pe has 16 kilobytes of code space and an additional 16 kilobytes of data space. This EEPROM space is organized into slots of 2 kilobytes (2048 bytes) each. Up to eight different programs can be downloaded to the BASIC Stamp (one program per slot). When the BASIC Stamp powers up, or is reset, the program in slot 0 is executed.

The RUN command allows you to activate another program and causes the BASIC Stamp to stay in the newly activated program until it receives another RUN command, or until a power-down or reset condition occurs. The RUN command is similar to a GOTO command in that it allows you to "goto" another program. Normally a master-type program will be used in program slot 0 (since slot 0 runs first) and will control initial execution of the other programs.

Look at the following example (there are two programs here, make sure to download them into program slots 0 and 1, respectively):

Download the following two lines into program slot 0:

  DEBUG "Hello "
  RUN 1

Download the following three lines into program slot 1:

  DEBUG "World!", CR
  PAUSE 1000
  RUN 0
The above two programs (assuming they have been downloaded into program slots 0 and 1, respectively) will display "Hello World!" on the screen. Program 0 is the first to run and it displays "Hello ", then issues a RUN 1 command. The BASIC Stamp then starts execution of program 1, from its first line of code, which causes "World!" to be displayed. Program 1 then pauses for one second and the runs program 0 again.

What Happens To I/O Pins And RAM When Using RUN?

The I/O pins retain their current state (directions and output latches) and all Variable and Scratchpad RAM locations retain their current data during a transition between programs with the RUN command. If sharing data between programs within Variable RAM, make sure to keep similar variable declarations (defined in the same order) in all programs so that the variables align themselves on the proper word, byte, nibble and bit boundaries across programs. The following programs illustrate what happens with mismatched variable declarations:

' Download this program to Slot 0

cats    VAR     Byte
dogs    VAR     Byte

Setup:
  cats = 3
  dogs = 1

Main:
  DEBUG "In Slot 0", CR
  DEBUG ? cats
  DEBUG ? dogs
  RUN 1

' Download this program to Slot 1

cats    VAR     Byte
dogs    VAR     Byte
fleas   VAR     Word

Main:
  DEBUG "In Slot 1", CR
  DEBUG ? cats
  DEBUG ? dogs
  DEBUG ? fleas
  END

When the Slot 1 program runs you may be surprised to see that cats and dogs are now zero and fleas are up to 259! - even though we didn't explicitly define them. What happenend? The key to remember is that variable names are simply pointers to RAM addresses, and the PBASIC compiler assigns variable names to RAM in descending order by size. This means that in the Slot 1 program, fleas was assigned to RAM locations 0 and 1 which are holding the values 3 and 1 respecitively. Since words are stored low-byte first, the value 259 for fleas makes sense (3 + (1 * 256)).

Any program number specified above 7 will wrap around and result in running one of the 8 programs (RUN 8 will run program 0, RUN 9 will run program 1, etc). The current program slot can be read from the last byte of the Scratchpad RAM. Example:

  #SELECT $STAMP
    #CASE BS2
      pgmSlot = 0                       ' everything in slot 0
      rwSlot = 0
    #CASE BS2E, BS2SX
      READ 63, pgmSlot                  ' read current slot
      rwSlot = pgmSlot                  ' READ/WRITE slot is same
    #CASE BS2P, BS2PE, BS2PX
      READ 127, pgmSlot                 ' get slot control byte
      rwSlot = rwSlot.HIGHNIB           ' READ/WRITE in high nibble
      pgmSlot = pgmSlot.LOWNIB          ' pgm slot in low nibble
  #ENDSELECT

Related command: POLLRUN ( [image] )


RUN Example

Syntax

NOTE: This is written for the BS2sx and will also run on the BS2e, BS2p, BS2pe, and BS2px. Modify the $STAMP directive (as required) before downloading to the BS2e, BS2p, BS2pe, or BS2px.

' RUN1.BSX
' This example demonstrates the use of the RUN command.  First, the SPRAM
' location that holds the current slot is read using the GET command to
' display the currently running program number.  Then a set of values (based
' on the program number) are displayed on the screen.  Afterwards, program
' number 1 is run. This program is a BS2sx project consisting of RUN1.BSX
' and RUN2.BSX, but will run on all multi-slot BASIC Stamps.

' {$STAMP BS2sx, RUN2.BSX}
' {$PBASIC 2.5}

#SELECT $STAMP                          ' set SPRAM of slot number
  #CASE BS2
    #ERROR "Multi-slot BASIC Stamp required."
  #CASE BS2E, BS2SX
    Slot        CON     63
  #CASE BS2P, BS2PE, BS2PX
    Slot        CON     127
#ENDSELECT

slotNum         VAR     Nib             ' current slot
idx             VAR     Nib             ' loop counter
value           VAR     Byte            ' value from EEPROM

EEtable         DATA    100, 40, 80, 32, 90
                DATA    200, 65, 23, 77, 91

Setup:
  GET Slot, slotNum                     ' read current slot
  DEBUG  "Program #", DEC slotNum, CR   ' display

Main:
  FOR idx = 0 TO 4                      ' read/display table values
    READ (slotNum * 5) + idx, value
    DEBUG DEC3 value, " "
  NEXT
  DEBUG CR
  PAUSE 1000

  RUN 1                                 ' run Slot 1 pgm

' RUN2.BSX
' This example demonstrates the use of the RUN command.  First, the SPRAM
' location that holds the current slot is read using the GET command to
' display the currently running program number.  Then a set of values (based
' on the program number) are displayed on the screen.  Afterwards, program
' number 0 is run. This program is a BS2sx project consisting of RUN1.BSX
' and RUN2.BSX, but will run on all multi-slot BASIC Stamps.

' {$STAMP BS2sx}
' {$PBASIC 2.5}

#SELECT $STAMP                          ' set SPRAM of slot number
  #CASE BS2
    #ERROR "Multi-slot BASIC Stamp required."
  #CASE BS2E, BS2SX
    Slot        CON     63
  #CASE BS2P, BS2PE, BS2PX
    Slot        CON     127
#ENDSELECT

slotNum         VAR     Nib             ' current slot
idx             VAR     Nib             ' loop counter
value           VAR     Byte            ' value from EEPROM

EEtable         DATA    100, 40, 80, 32, 90
                DATA    200, 65, 23, 77, 91

Setup:
  GET Slot, slotNum                     ' read current slot
  DEBUG  "Program #", DEC slotNum, CR   ' display

Main:
  FOR idx = 0 TO 4                      ' read/display table values
    READ (slotNum * 5) + idx, value
    DEBUG DEC3 value, " "
  NEXT
  DEBUG CR
  PAUSE 1000

  RUN 0                                 ' back to Slot 0 pgm


 SELECT...CASE

{$PBASIC 2.5} Example

Syntax:

SELECT Expression
CASE Condition(s)
Statement(s)
{ CASE Condition(s)
Statement(s)
CASE ELSE
Statement(s) }
ENDSELECT

Function
Evaluate Expression and then conditionally execute a block of code based on comparison to Condition(s). After executing a block of code the program continues at the line that follows ENDSELECT. If no conditions are found True and a CASE ELSE block is included, the CASE ELSE code statements will execute.

  • Expression is a variable, a constant or an expression.
  • Condition is a statement, that can be evaluated as True or False. The Condition can be a very simple or very complex relationship, as described below. Multiple conditions within the same CASE can be separated by commas ( , ).
  • Statement(s) is any valid PBASIC statement or statements. Multiple statements may be placed on the same line (though not recommended) by separating each statement with a colon ( : ).

Quick Facts
 | BS2 Family
Comparison operators | = (assumed if no operator), <>, >, <, >=, <=
Conditional Logic Operators | NOT, AND, OR, XOR
Condition format | condition_op value or value1 TO value2
Parentheses | Allowed
Nesting | Up to 16 levels

Explanation
SELECT...CASE is an advanced decision making structure and is often used to replace compound IF...THEN...ELSE structures. The available comparison operators are:

Comparison Operator Symbol | Definition
= | Equal (assumed)
<> | Not Equal
> | Greater Than
< | Less Than
>= | Greater Than or Equal To
<= | Less Than or Equal To

Example:

  SELECT irCmd
    CASE 0 TO 3
      HIGH irCmd                        ' enable selected output
      FREQOUT Spkr, 50, 880             ' beep

    CASE AllOff, Mute
      OutA = %0000                      ' all outputs off

    CASE ELSE                           ' invalid command
      DEBUG "Bad Command", CR
  ENDSELECT

Here, the BASIC Stamp will examine the value of variable irCmd. If irCmd is between zero and three (inclusive), the associated output (P0 .. P3) will be made high and and the speaker will beep. If irCmd is equal to either AllOff or Mute (constants), then outputs P0 - P3 will be made low. On any other value of irCmd, a message will be displayed that indicates an invalid command.

See IF...THEN for additional details on the use of comparison and conditional operators.

Related commands: IF...THEN and IF...THEN...ELSE ( [image] )


SELECT...CASE Example

{$PBASIC 2.5} Syntax

NOTE: This is written for the BS2 and will run on any of the BS2-family modules. Modify the $STAMP directive (as required) before downloading to the BS2e, BS2sx, BS2p, BS2pe, or BS2px.

' SELECT-CASE.BS2
' This program generates a series of 16-bit random numbers and tests each
' to determine odd or even, and where it falls in the possible range:
' lower third, middle third, or upper third.  The program is useful for
' testing various seed values for RANDOM.

' {$STAMP BS2}
' {$PBASIC 2.5}

test            VAR     Byte            ' counter for tests
sample          VAR     Word            ' random number to be tested
odd             VAR     Byte            ' odd throws
even            VAR     Byte            ' even throws
isLo            VAR     Byte            ' sample in lower third
isMid           VAR     Byte            '        in middle thrid
isHi            VAR     Byte            '        in upper third

Main:
  sample = 11000                        ' initialize seed
  FOR test = 1 TO 100                   ' "throw" 100 times
    RANDOM sample                       ' randomize

    IF (sample.BIT0) THEN               ' check odd/even bit
      odd = odd + 1                     ' increment odd count
    ELSE
      even = even + 1                   ' increment even count
    ENDIF

    SELECT sample
      CASE <= 21845                     ' test lower third
        isLo = isLo + 1

      CASE 21846 TO 43691               ' test middle third
        isMid = isMid + 1

      CASE ELSE                         ' otherwise upper third
        isHi = isHi + 1
    ENDSELECT
  NEXT

Show_Results:
  DEBUG CLS,
        "Odd Throws.... ", DEC odd, "%", CR,
        "Even Throws... ", DEC even, "%", CR,
        "Low........... ", DEC isLo, "%", CR,
        "Mid........... ", DEC isMid, "%", CR,
        "High.......... ", DEC isHi, "%", CR
  END


 SERIN

Examples

Syntax [image] : SERIN Rpin, Baudmode, {(Qualifier),} {#} InputData
Syntax [image] : SERIN Rpin {\Fpin}, Baudmode, {Plabel,} {Timeout, Tlabel,} [InputData]

Function
Receive asynchronous serial data (e.g., RS-232 data).

  • Rpin is a variable/constant/expression* (0 - 16) that specifies the I/O pin through which the serial data will be received. This pin will be set to input mode. On the BS2, BS2e, BS2sx, BS2p, BS2pe, and BS2px, if Rpin is set to 16, the BASIC Stamp uses the dedicated serial-input pin (SIN, physical pin 2), which is normally used by the Stamp Editor during the download process.
  • Fpin is an optional variable/constant/expression* (0 - 15) that specifies the I/O pin to indicate flow control status on. This pin will be set to output mode.
  • Baudmode is variable/constant/expression* (0 - 7 on the BS1, 0 - 65535 on all other BASIC Stamps) that specifies serial timing and configuration.
  • Qualifier is an optional variable/constant (0 - 255) indicating data that must be received before execution can continue. Multiple qualifiers can be indicated with commas separating them.
  • Plabel is an optional label indicating where the program should go in the event of a parity error. This argument should only be provided if Baudmode indicates 7 bits, and even parity.
  • Timeout is an optional variable/constant/expression* (0 - 65535) that tells SERIN how long to wait for incoming data. If data does not arrive in time, the program will jump to the address specified by Tlabel.
  • Tlabel is an optional label that must be provided along with Timeout, indicating where the program should go in the event that data does not arrive within the period specified by Timeout.
  • InputData† is list of variables and formatters that tells SERIN what to do with incoming data. SERIN can store data in a variable or array, interpret numeric text (decimal, binary, or hex) and store the corresponding value in a variable, wait for a fixed or variable sequence of bytes, or ignore a specified number of bytes. These actions can be combined in any order in the InputData list.

* | NOTE: Expressions are not allowed as arguments on the BS1. The range of the Rpin argument on the BS1 is 0 - 7.
† | NOTE: The BS1's InputData argument can only be a list of variables and the optional decimal modifier (#).

Quick Facts
 | BS1 | BS2 and BS2e | BS2sx | BS2p | BS2pe | BS2px
Units in Timeout | N/A | 1 ms | 0.4 ms | 0.4 ms | 1 ms | 0.4 ms
Baud Range | 300, 600, 1200, and 2400 only | 243 to 50K | 608 to 115.2K | 608 to 115.2K | 243 to 50K | 972 to 115.2K
Baud Limit with Flow Control | N/A | 19.2K | 19.2K | 19.2K | 19.2K | 19.2K
Limit to Qualifiers | Unlimited | 6 (in WAIT formatter)
I/O Pins Available | 0 - 7 | 0 - 15 | 0 - 15 | 0 - 15 (in current I/O block) | 0 - 15 (in current I/O block) | 0 - 15 (in current I/O block)
Other Serial Port Pins | N/A | SIN pin (physical pin 2) when Rpin = 16

Explanation
One of the most popular forms of communication between electronic devices is serial communication. There are two major types of serial communication; asynchronous and synchronous. The SERIN and SEROUT commands are used to receive and send asynchronous serial data. See the SHIFTIN and SHIFTOUT command for information on the synchronous method.

SERIN can wait for, filter and convert incoming data in powerful ways. SERIN deserves some lengthy discussion, below, since all this power brings some complexity.

The term asynchronous means "no clock." More specifically, "asynchronous serial communication" means data is transmitted and received without the use of a separate "clock" wire. Data can be sent using as little as two wires; one for data and one for ground. The PC's serial ports (also called COM ports or RS-232 ports) use asynchronous serial communication. Note: the other kind of serial communication, synchronous, uses at least three wires; one for clock, one for data and one for ground.

RS-232 is the electrical specification for the signals that PC serial ports use. Unlike normal logic, where a 5 volts is a logic 1 and 0 volts is logic 0, RS-232 uses -12 volts for logic 1 and +12 volts for logic 0. This specification allows communication over longer wire lengths without amplification.

Most circuits that work with RS-232 use a line driver/receiver. This component does two things: (1) it converts the ±12 volts of RS-232 to TTL-compatible 0 to 5-volt levels and (2) it inverts the relationship of the voltage levels, so that 5 volts = logic 1 and 0 volts = logic 0.

All BASIC Stamps (except the BS1) have a line receiver on its SIN pin (Rpin = 16). See the "Hardware" section of the "Introduction to the BASIC Stamps" chapter. The SIN pin goes to a PC's serial data-out pin on the DB-9 connector built into BASIC Stamp development boards. The connector is wired to allow both programming and run-time serial communication (unless you are using the Stamp 2 Carrier Board which is only designed for programming). For the built-in serial port set the Rpin argument to 16 in the SERIN command.

All BASIC Stamps (including the BS1) can also receive RS-232 data through any of their I/O pins (Rpin = 0 - 7 for BS1, Rpin = 0 - 15 on all other BASIC Stamps). The I/O pins don't need a line receiver, just a 22 kΩ resistor. The resistor limits current into the I/O pin's built-in clamping diodes, which keep input voltages within a safe range.

Note: The connections shown in red are normally not necessary. They indicate optional connections to defeat hardware handshaking requirements.
Note: A line driver may have to be used between the I/O pin and the receiving serial port to ensure proper communication.

Function | DB-9 | DB-25
Data Carrier Detect (DCD) | 1 | 8
Receive Data (RD) | 2 | 3
Transmit Data (TD) | 3 | 2
Data Terminal Ready (DTR) | 4 | 20
Signal Ground (SG) | 5 | 7
Data Set Ready (DSR) | 6 | 6
Request To Send (RTS) | 7 | 4
Clear To Send (CTS) | 8 | 5

The figure above shows the pinouts of the two styles of PC serial ports and how to connect them to the BASIC Stamp's I/O pin (the 22 kΩ resister is not needed if connecting to the SIN pin). Though not normally needed, the figure also shows loop back connections that defeat hardware handshaking used by some PC software. Note that PC serial ports are always male connectors. The 25-pin style of serial port (called a DB-25) looks similar to a printer (parallel) port except that it is male, whereas a parallel port is female.

Asynchronous serial communication relies on precise timing. Both the sender and receiver must be set for identical timing, usually expressed in bits per second (bps) called baud.

On all BASIC Stamps, SERIN requires a value called Baudmode that tells it the important characteristics of the incoming serial data; the bit period, number of data and parity bits, and polarity.

On the BS1, serial communication is limited to: no-parity, 8-data bits and 1-stop bit at one of four different speeds: 300, 600, 1200 or 2400 baud. The table below indicates the Baudmode value or symbols to use when selecting the desired mode.

Baudmode Value | Symbol | Baud Rate | Polarity
0 | T2400 | 2400 | TRUE
1 | T1200 | 1200 | TRUE
2 | T600 | 600 | TRUE
3 | T300 | 300 | TRUE
4 | N2400 | 2400 | INVERTED
5 | N1200 | 1200 | INVERTED
6 | N600 | 600 | INVERTED
7 | N300 | 300 | INVERTED

On the BS2, BS2e, BS2sx, BS2p, BS2pe, and BS2px, serial communication is very flexible. The Baudmode argument for SERIN accepts a 16-bit value that determines its characteristics: 1-stop bit, 8-data bits/no-parity or 7-data bits/even-parity and virtually any speed from as low as 300 baud to greater than 100K baud (depending on the BASIC Stamp). The information below shows how Baudmode is calculated and show common baud modes for standard serial baud rates.

Baudmode Calculation:

  1. Determine the bit period (bits 0 - 11)
    • BS2, BS2e, and BS2pe = INT(1,000,000 ÷ baud rate) - 20
    • BS2sx and BS2p = INT(2,500,000 ÷ baud rate) - 20
    • BS2px = INT(4,000,000 ÷ baud rate) - 20

      Note: INT means 'Convert to integer.' -- drop the numbers to the right of the decimal point.
  2. Set data bits and parity (bit 13)
    • 8-bit / No Parity = 0
    • 7-bit / Even Parity = 8192
  3. Select polarity bit (bit 14)
    • True = 0
    • Inverted = 16384

Common Baud Rates and Corresponding Values

Baud Rate | 8-bit No Parity INVERTED | 8-bit No Parity TRUE | 7-bit Even Parity INVERTED | 7-bit Even Parity TRUE
300 | 19697 | 3313 | 27889 | 11505
600 | 18030 | 1646 | 26222 | 9838
1200 | 17197 | 813 | 25389 | 9005
2400 | 16780 | 396 | 24972 | 8588
4800 * | 16572 | 188 | 24764 | 8380
9600 * | 16468 | 84 | 24660 | 8276
* The BASIC Stamp 2 and BASIC Stamp 2e may have trouble synchronizing with the incoming serial stream at this rate and higher due to the lack of a hardware input buffer. Use only simple variables and no formatters to try to solve this problem.

Baud Rate | 8-bit No Parity INVERTED | 8-bit No Parity TRUE | 7-bit Even Parity INVERTED | 7-bit Even Parity TRUE
1200 | 18447 | 2063 | 26639 | 10255
2400 | 17405 | 1021 | 25597 | 9213
4800 * | 16884 | 500 | 25076 | 8692
9600 * | 16624 | 240 | 24816 | 8432
* The BASIC Stamp 2sx and BASIC Stamp 2p may have trouble synchronizing with the incoming serial stream at this rate and higher due to the lack of a hardware input buffer. Use only simple variables and no formatters to try to solve this problem.

Baud Rate | 8-bit No Parity INVERTED | 8-bit No Parity TRUE | 7-bit Even Parity INVERTED | 7-bit Even Parity TRUE
1200 | 19697 | 3313 | 27889 | 11505
2400 | 18030 | 1646 | 26222 | 9838
4800 * | 17197 | 813 | 25389 | 9005
9600 * | 16780 | 396 | 24972 | 8588
* The BASIC Stamp 2sx and BASIC Stamp 2p may have trouble synchronizing with the incoming serial stream at this rate and higher due to the lack of a hardware input buffer. Use only simple variables and no formatters to try to solve this problem.

If you're communicating with existing software or hardware, its speed(s) and mode(s) will determine your choice of baud rate and mode. In general, 7-bit/even-parity (7E) mode is used for text, and 8-bit/no-parity (8N) for byte-oriented data. Note: the most common mode is 8-bit/no-parity, even when the data transmitted is just text. Most devices that use a 7-bit data mode do so in order to take advantage of the parity feature. Parity can detect some communication errors, but to use it you lose one data bit. This means that incoming data bytes transferred in 7E (even-parity) mode can only represent values from 0 to 127, rather than the 0 to 255 of 8N (no-parity) mode.

Usually a device requires only one stop bit per byte. Occasionally, however, you may find a device that requires 2 or more stop bits. Since a stop bit is really just a delay between transmitted bytes (leaving the line in a resting state) the BASIC Stamp can receive transmissions with multiple stop bits per byte without any trouble. In fact, sometimes it is desirable to have multiple stop bits (see the "SERIN Troubleshooting" section, below, for more information).

The example below will receive a single byte through I/O pin 1 at 2400 baud, 8N1, inverted:

SYMBOL  sData   = B0

Main:
  SERIN 1, N2400, sData
  END

sData   VAR     Byte

Main:
  SERIN 1, 16780, [sData]                       ' baudmode set for BS2
  END

Here, SERIN will wait for and receive a single byte of data through pin 1 and store it in the variable sData. If the BASIC Stamp were connected to a PC running a terminal program (set to the same baud rate) and the user pressed the "A" key on the keyboard, after the SERIN command executed, the variable sData would contain 65, the ASCII code for the letter "A".

What would happen if, using the example above, the user pressed the "1" key? The result would be that sData would contain the value 49 (the ASCII code for the character "1"). This is a critical point to remember: every time you press a character on the keyboard, the computer receives the ASCII value of that character. It is up to the receiving side (in serial communication) to interpret the values as necessary. In this case, perhaps we actually wanted sData to end up with the value 1, rather than the ASCII code 49.

The SERIN command provides a formatter, called the decimal formatter, which will interpret this for us. Look at the following code:

SYMBOL  sData   = B2

Main:
  SERIN 1, N2400, #sData
  END

sData   VAR     Byte

Main:
  SERIN 1, 16780, [DEC sData]
  END

Notice the decimal formatter in the SERIN command. It is the "#" (for the BS1) or "DEC" (for the other BASIC Stamps) that appears just to the left of the sData variable. This tells SERIN to convert incoming text representing decimal numbers into true-decimal form and store the result in sData. If the user running the terminal software pressed the "1", "2" and then "3" keys followed by a space or other non-numeric text, the value 123 will be stored in sData. Afterwards, the program can perform any numeric operation on the number just like with any other number. Without the decimal formatter, however, you would have been forced to receive each character ("1", "2" and "3") separately, and then would still have to do some manual conversion to arrive at the number 123 (one hundred twenty three) before you can do the desired calculations on it.

Decimal Formatter Specifics
The decimal formatter is designed to seek out text that represents decimal numbers. The characters that represent decimal numbers are the characters "0" through "9". Once the SERIN command is asked to use the decimal formatter for a particular variable, it monitors the incoming serial data, looking for the first decimal character. Once it finds the first decimal character, it will continue looking for more (accumulating the entire multi-digit number) until is finds a non-decimal numeric character. Keep in mind that it will not finish until it finds at least one decimal character followed by at least one non-decimal character.

To further illustrate this, consider the following examples (assuming we're using the same code example as above):

  1. Serial input: ABC
    Result: The BASIC Stamp halts at the SERIN command, continuously waiting for decimal text.
  2. Serial input: 123 (with no characters following it)
    Result: The BASIC Stamp halts at the SERIN command. It recognizes the characters "1", "2" and "3" as the number one hundred twenty three, but since no characters follow the "3", it waits continuously, since there's no way to tell whether 123 is the entire number or not.
  3. Serial input: 123 (followed by a space character)
    Result: Similar to example 2, above, except once the space character is received, the BASIC Stamp knows the entire number is 123, and stores this value in sData. The SERIN command then ends, allowing the next line of code, if any, to run.
  4. Serial input: 123A
    Result: Same as example 3, above. The "A" character, just like the space character, is the first non-decimal text after the number 123, indicating to the BASIC Stamp that it has received the entire number.
  5. Serial input: ABCD123EFGH
    Result: Similar to examples 3 and 4 above. The characters "ABCD" are ignored (since they're not decimal text), the characters "123" are evaluated to be the number 123 and the following character, "E", indicates to the BASIC Stamp that it has received the entire number.

Of course, as with all numbers in the BASIC Stamp, the final result is limited to 16 bits (up to the number 65535). If a number larger than this is received by the decimal formatter, the end result will look strange because the result rolled-over the maximum 16-bit value.

While BS1 is limited to the decimal formatter (#) shown above, the BS2, BS2e, BS2sx, BS2p, BS2pe, and BS2px have many more conversion formatters available for the SERIN command. If not using a BS1, see the "Additional Conversion Formatters" section below for more information.

The SERIN command can also be configured to wait for specified data before it retrieves any additional input. For example, suppose a device that is attached to the BASIC Stamp is known to send many different sequences of data, but the only data you desire happens to appear right after the unique characters, "XYZ". The BS1 has optional Qualifier arguments for this purpose. On the BS2, BS2e, BS2sx, BS2p, BS2pe, and BS2px a special formatter called WAIT can be used for this.

SYMBOL  sData   = B2

Main:
  SERIN 1, N2400, ("XYZ"), #sData
  END

sData   VAR     Byte

Main:
  SERIN 1, 16780, [WAIT("XYZ"), DEC sData]
  END

The above code waits for the characters "X", "Y" and "Z" to be received, in that order, and then it looks for a decimal number to follow. If the device in this example were to send the characters "XYZ100" followed by a carriage return or some other non-decimal numeric character, the sData variable would end up with the number 100 after the SERIN line finishes. If the device sent some data other than "XYZ" followed by a number, the BASIC Stamp would continue to wait at the SERIN command.

The BS1 will accept an unlimited number of Qualifiers. The BS2, BS2e, BS2sx, BS2p, BS2pe, and BS2px will only accept up to six bytes (characters) in the WAIT formatter.

Keep in mind that when we type "XYZ" into the SERIN command, the BASIC Stamp actually uses the ASCII codes for each of those characters for its tasks. We could also have typed: 88, 89, 90 in place of "XYZ" and the code would run the same way since 88 is the ASCII code for the "X" character, 89 is the ASCII code for the "Y" character, and so on. Also note, serial communication with the BASIC Stamp is case sensitive. If the device mentioned above sent, "xYZ" or "xyZ", or some other combination of lower and upper-case characters, the BASIC Stamp would have ignored it because we told it to look for "XYZ" (all capital letters).

The BS1's SERIN command is limited to previously-mentioned features. If you are not using a BS1, please continue reading about the additional features below.

The decimal formatter is only one of a whole family of conversion formatters available with SERIN on the BS2, BS2e, BS2sx, BS2p, BS2pe, and BS2px. See the table below for a list of available conversion formatters. All of the conversion formatters work similar to the decimal formatter (as described in the "Decimal Formatter Specifics" section, above). The formatters receive bytes of data, waiting for the first byte that falls within the range of characters they accept (e.g., "0" or "1" for binary, "0" to "9" for decimal, "0" to "9" and "A" to "F" for hex, and "+" or "-" for signed variations of any type). Once they receive a numeric character, they keep accepting input until a non-numeric character arrives or (in the case of the fixed length formatters) the maximum specified number of digits arrives.

While very effective at filtering and converting input text, the formatters aren't completely foolproof. As mentioned before, many conversion formatters will keep accepting text until the first non-numeric text arrives, even if the resulting value exceeds the size of the variable. After SERIN, a byte variable will contain the lowest 8 bits of the value entered and a word would contain the lowest 16 bits. You can control this to some degree by using a formatter that specifies the number of digits, such as DEC2, which would accept values only in the range of 0 to 99.

Conversion Formatter | Type of Number | Numeric Characters Accepted | Notes
DEC{1..5} | Decimal, optionally limited to 1 - 5 digits | 0 through 9 | 1
SDEC{1..5} | Signed decimal, optionally limited to 1 - 5 digits | -, 0 through 9 | 1,2
HEX{1..4} | Hexadecimal, optionally limited to 1 - 4 digits | 0 through 9, A through F | 1,3
SHEX{1..4} | Signed hexadecimal, optionally limited to 1 - 4 digits | -, 0 through 9, A through F | 1,2,3
IHEX{1..4} | Indicated hexadecimal, optionally limited to 1 - 4 digits | $, 0 through 9, A through F | 1,3,4
ISHEX{1..4} | Signed, indicated hexadecimal, optionally limited to 1 - 4 digits | -, $, 0 through 9, A through F | 1,2,3,4
BIN{1..16} | Binary, optionally limited to1 - 16 digits | 0, 1 | 1
SBIN{1..16} | Signed binary, optionally limited to 1 - 16 digits | -, 0, 1 | 1,2
IBIN{1..16} | Indicated binary, optionally limited to 1 - 16 digits | %, 0, 1 | 1,4
ISBIN{1..16} | Signed, indicated binary, optionally limited to 1 - 16 digits | -, %, 0, 1 | 1,2,4
NUM | Generic numeric input; hex or binary number must be indicated | $, %, 0 through 9, A through F | 1,3,4
SNUM | Similar to NUM with value treated as signed with range -32768 to +32767 | -, $, %, 0 through 9, A through F | 1,2,3,4

  1. All numeric conversions will continue to accept new data until receiving either the specified number of digits (ex: three digits for DEC3) or a non-numeric character.
  2. To be recognized as part of a number, the minus sign (-) must immediately precede a numeric character. The minus sign character occurring in non-numeric text is ignored and any character (including a space) between a minus and a number causes the minus to be ignored.
  3. The hexadecimal formatters are not case-sensitive; "a" through "f" means the same as "A" through "F".
  4. Indicated hexadecimal and binary formatters ignore all characters, even valid numerics, until they receive the appropriate prefix ($ for hexadecimal, % for binary). The indicated formatters can differentiate between text and hexadecimal (ex: ABC would be interpreted by HEX as a number but IHEX would ignore it unless expressed as $ABC). Likewise, the binary version can distinguish the decimal number 10 from the binary number %10. A prefix occurring in non-numeric text is ignored, and any character (including a space) between a prefix and a number causes the prefix to be ignored. Indicated, signed formatters require that the minus sign come before the prefix, as in -$1B45.

The BS2, BS2e, BS2sx, BS2p, BS2pe, and BS2px also have special formatters for handling a string of characters, a sequence of characters and undesirable characters. See the table below for a list of these special formatters.

Special Formatter | Action
STR ByteArray \L {\E} | Input a character string of length L into an array. If specified, an end character E causes the string input to end before reaching length L. Remaining bytes are filled with 0s (zeros).
WAIT (Value) | Wait for a sequence of bytes specified by value. Value can be numbers separated by commas or quoted text (ex: 65, 66, 67 or "ABC"). The WAIT formatter is limited to a maximum of six characters.
WAITSTR ByteArray {\L} | Wait for a sequence of bytes matching a string stored in an array variable, optionally limited to L characters. If the optional L argument is left off, the end of the array-string must be marked by a byte containing a zero (0).
SKIP Length | Ignore Length bytes of characters.

Special Formatter | Action
SPSTR L | Buffer length L bytes (up to 126) of serial characters to Scratchpad RAM, starting at location 0. Use GET to retrieve the characters.

The string formatter is useful for receiving a string of characters into a byte array variable. A string of characters is a set of characters that are arranged or accessed in a certain order. The characters "ABC" could be stored in a string with the "A" first, followed by the "B" and then followed by the "C." A byte array is a similar concept to a string; it contains data that is arranged in a certain order. Each of the elements in an array is the same size. The string "ABC" could be stored in a byte array containing three bytes (elements).

Here is an example that receives nine bytes through I/O pin 1 at 9600 bps, N81/inverted and stores them in a 10-byte array:

serStr  VAR     Byte(10)                        ' Make a 10-byte array

Main:
  serStr(9) = 0                                 ' Put 0 in last byte
  SERIN 1, 16468, [STR serStr\9]                ' Get 9-byte string
  DEBUG STR serString                           ' Display the string
  END

If the serial input were "hello*" DEBUG would display "hello" since it collects bytes up to (but not including) the end character. It fills the unused bytes up to the specified length with 0s. DEBUG's normal STR formatter understands a 0 to mean end-of-string. However, if you use DEBUG's fixed-length string modifier, STR ByteArray\L, you will inadvertently clear the DEBUG screen. The fixed-length specification forces DEBUG to read and process the 0s at the end of the string, and 0 is equivalent to DEBUG's CLS (clear-screen) instruction! Be alert for the consequences of mixing fixed- and variable-length string operations.

As shown before, SERIN can compare incoming data with a predefined sequence of bytes using the WAIT formatter. The simplest form waits for a sequence of up to six bytes specified as part of the InputData list, like so:

  SERIN 1, 16468, [WAIT ("SESAME")]             ' Wait for word SESAME
  DEBUG "Password accepted"

SERIN will wait for that word, and the program will not continue until it is received. Since WAIT is looking for an exact match for a sequence of bytes, it is case-sensitive-"sesame" or "SESAmE" or any other variation from "SESAME" would be ignored.

SERIN can also wait for a sequence that matches a string stored in an array variable with the WAITSTR formatter. In the example below, we'll capture a string with STR then have WAITSTR look for an exact match:

serStr  VAR     Byte(10)                        ' Make a 10-byte array

Main:
  serString(9) = 0                              ' Put 0 in last byte
  SERIN 1, 16468, [STR serStr\9\"!"]            ' Input password string
  DEBUG "Waiting for: ", STR serString, CR
  SERIN 1, 16468, [WAITSTR  serStr]             ' Wait for the password
  DEBUG "Password accepted!", CR
  END

You can also use WAITSTR with fixed-length strings as in the following example:

serStr  VAR     Byte(4)                         ' Make a 4-byte array

Main:
  DEBUG "Enter a 4-character password", CR
  SERIN 1, 16468, [STR serStr\4]                ' Get the string
  DEBUG "Waiting for: ", STR serStr\4, CR
  SERIN 1, 16468, [WAITSTR serStr\4]            ' Wait for a match
  DEBUG "Password accepted!", CR
  END

SERIN's InputData can be structured as a sophisticated list of actions to perform on the incoming data. This allows you to process incoming data in powerful ways. For example, suppose you have a serial stream that contains "pos: xxxx yyyy" (where xxxx and yyyy are 4-digit numbers) and you want to capture just the decimal y value. The following code would do the trick:

yCoord  VAR     Word                            ' y coordinate

Main:
  SERIN 1, 16468, [WAIT ("pos: "), SKIP 4, DEC yCoord]
  DEBUG ? yCoord
  END

The items of the InputData list work together to locate the label "pos: ", skip over the four-byte x data, then convert and capture the decimal y data. This sequence assumes that the x data is always four digits long; if its length varies, the following code would be more appropriate:

yCoord  VAR     Word

Main:
  SERIN 1, 16468, [WAIT ("pos: "), DEC yCoord, DEC yCoord]
  DEBUG ? yOffset
  END

The unwanted x data is stored in yCoord then replaced by the desired y data. This is a sneaky way to filter out a number of any size without using an extra variable. With a little creativity, you can combine the InputData modifiers to filter and extract almost any data.

Parity is a simple error-checking feature. When a serial sender is set for even parity (the mode the BASIC Stamps support) it counts the number of 1s in an outgoing byte and uses the parity bit to make that number even. For instance, if it is sending the 7-bit value: %0011010, it sets the parity bit to 1 in order to make an even number of 1s (four).

The receiver also counts the data bits to calculate what the parity bit should be. If it matches the parity bit received, the serial receiver assumes that the data was received correctly. Of course, this is not necessarily true, since two incorrectly received bits could make parity seem correct when the data was wrong, or the parity bit itself could be bad when the rest of the data was okay.

Many systems that work exclusively with text use (or can be set for) 7-bit/even-parity mode. The tables above show appropriate BaudMode settings for different BASIC Stamps. For example, with the BS2, to receive one data byte through pin 1 at 9600 baud, 7E, inverted:

sData   VAR     Byte

Main:
  SERIN 1, 24660, [sData]
  END

That instruction will work, but it doesn't tell the BS2 what to do in the event of a parity error. Here's an improved version that uses the optional Plabel argument:

sData   VAR     Byte

Main:
  SERIN 1, 24660, Bad_Data, [sData]
  DEBUG ? sData
  STOP

Bad_Data:
  DEBUG  "Parity error"
  STOP

If the parity matches, the program continues at the DEBUG instruction after SERIN. If the parity doesn't match, the program goes to the label Bad_Data. Note that a parity error takes precedence over other InputData specifications (as soon as an error is detected, SERIN aborts and goes to the Plabel routine).

In all the examples above, the only way to end the SERIN instruction (other than RESET or power-off) is to give SERIN the serial data it wants. If no serial data arrives, the program is stuck. However, you can tell the BASIC Stamp to abort SERIN if it doesn't receive data within a specified number of milliseconds. For instance, to receive a decimal number through pin 1 at 9600 baud, 8N, inverted and abort SERIN after two seconds (2000 milliseconds) of inactivity on the serial input.

result  VAR     Byte

Main:
  SERIN 1, 16468, 2000, No_Data, [DEC result]
  DEBUG CLS, ? result
  STOP

No_Data:
  DEBUG CLS, "Timed out"
  STOP

If no data arrives within two seconds, the program aborts SERIN and continues at the label No_Data. Note that on multi-byte input, the timeout timer is reset after the receipt of any valid data byte; with long timeout values this factor could have an adverse affect on program operation if data packets are transmitted with gaps between individual data bytes. Finally, be cautious when using very short timeout values. Without external flow control, very short timeout values may cause the program to branch to the Tlabel address unnecessarily.

Here's a very important concept: this timeout feature is not picky about the kind of data SERIN receives; if any serial data is received, it prevents the timeout. In the example above, SERIN wants a decimal number. But even if SERIN received letters "ABCD..." at intervals of less than two seconds, it would never abort.

You can combine parity and serial timeout. Here is an example for the BS2 designed to receive a decimal number through pin 1 at 2400 baud, 7E, inverted with a 10-second timeout:

result  VAR     Byte

Again:
  SERIN 1, 24660, Bad_Data, 10000, No_Data, [DEC result]
  DEBUG CLS, ? result
  GOTO Again

No_Data:
  DEBUG CLS, "Timed out"
  GOTO Again

Bad_Data:
  DEBUG CLS, "Parity error"
  GOTO Again

When you design an application that requires serial communication between BASIC Stamps, you have to work within these limitations:

  • When the BASIC Stamp is sending or receiving data, it can't execute other instructions.
  • When the BASIC Stamp is executing other instructions, it can't send or receive data. The BASIC Stamp does not have a serial buffer as there is in PCs. At most serial rates, the BASIC Stamp cannot receive data via SERIN, process it, and execute another SERIN in time to catch the next chunk of data, unless there are significant pauses between data transmissions.

These limitations can sometimes be addressed by using flow control; the Fpin option for SERIN and SEROUT (at baud rates of up to the limitation shown above). Through Fpin, SERIN can tell a BASIC Stamp sender when it is ready to receive data. (For that matter, Fpin flow control follows the rules of other serial handshaking schemes, but most computers other than the BASIC Stamp cannot start and stop serial transmission on a byte-by-byte basis. That's why this discussion is limited to communication between BASIC Stamps).

Here's an example using flow control on the BS2 (data through I/O pin 1, flow control through I/O pin 0, 9600 baud, N8, non-inverted):

sData   VAR     Byte

Main:
  SERIN 1\0, 84, [sData]
  STOP

When SERIN executes, I/O pin 1 (Rpin) is made an input in preparation for incoming data, and I/O pin 0 (FPin) is made output low, to signal "go" to the sender. After SERIN finishes receiving, I/O pin 0 goes high to tell the sender to stop. If an inverted BaudMode had been specified, the FPin's responses would have been reversed. Here's the relationship of serial polarity to FPin states.

 | Ready to Receive ("Go") | Not Ready to Receive ("Stop")
Inverted | Fpin is High (1) | Fpin is Low (0)
Non-Inverted | Fpin is Low (0) | Fpin is High (1)

See the example program for a flow control example using two BS2s. In the demo program example, without flow control, the sender would transmit the whole word "HELLO!" in about 6 ms. The receiver would catch the first byte at most; by the time it got back from the first 1-second PAUSE, the rest of the data would be long gone. With flow control, communication is flawless since the sender waits for the receiver to catch up.

In the figure below, I/O pin 0, FPin, is pulled to ground through a 10 kΩ resistor. This is to ensure that the sender sees a stop signal (0 for inverted communications) when the receiver is being programmed.

SERIN Troubleshooting

Serial communication, because of its complexity, can be very difficult to work with at times. Please follow these guidelines when developing a project using the SERIN and SEROUT commands:

  1. Always build your project in steps.
    1. Start with small, manageable pieces of code, that deals with serial communication) and test them, one at a time.
    2. Add more and more small pieces, testing them each time, as you go.
    3. Never write a large portion of code that works with serial communication without testing its smallest workable pieces first.
  2. Pay attention to timing.
    1. Be very careful to calculate and overestimate the amount of time operations should take within the BASIC Stamp. Misunderstanding the timing constraints is the source of most problems with code that communicate serially.
    2. If the serial communication in your project is bidirectional, the above statement is even more critical.
  3. Pay attention to wiring.
    1. Take extra time to study and verify serial communication wiring diagrams. A mistake in wiring can cause strange problems in communication, or no communication at all. Make sure to connect the ground pins (Vss) between the devices that are communicating serially.
  4. Verify port setting on the PC and in the SERIN/SEROUT commands.
    1. Unmatched settings on the sender and receiver side will cause garbled data transfers or no data transfers. If the data you receive is unreadable, it is most likely a baud rate setting error.
  5. If receiving data from another device that is not a BASIC Stamp, try to use baud rates of 4800 and below.
    1. Because of additional overhead in the BASIC Stamp, and the fact that the BASIC Stamp has no hardware receive buffer for serial communication, received data may sometimes be missed or garbled. If this occurs, try lowering the baud rate (if possible), adding extra stop bits, and not using formatters in the SERIN command. Using simple variables (not arrays) and no formatters will increase the chance that the BASIC Stamp can receive the data properly.
  6. Be sure to study the effects of SERIN formatters
    1. Because of additional overhead in the BASIC Stamp, and the fact that the BASIC Stamp has no hardware receive buffer for serial communication, received data may sometimes be missed or garbled. If this occurs, try lowering the baud rate (if possible), adding extra stop bits, and not using formatters in the SERIN command. Using simple variables (not arrays) and no formatters will increase the chance that the BASIC Stamp can receive the data properly.
  7. When using a BS2-family module, you can simplify Baudmode parameter selection by using conditional compilation. The example below can be included in the standard programming template and will handle most serial IO requirements. Remember that defining constants does not affect compiled program space, and yet does make program debugging easier.
' {$PBASIC 2.5}

#SELECT $STAMP
  #CASE BS2, BS2E, BS2PE
    T1200       CON     813
    T2400       CON     396
    T4800       CON     188
    T9600       CON     84
    T19K2       CON     32
    T38K4       CON     6
  #CASE BS2SX, BS2P
    T1200       CON     2063
    T2400       CON     1021
    T4800       CON     500
    T9600       CON     240
    T19K2       CON     110
    T38K4       CON     45
  #CASE BS2PX
    T1200       CON     3313
    T2400       CON     1646
    T4800       CON     813
    T9600       CON     396
    T19K2       CON     188
    T38K4       CON     84
#ENDSELECT

SevenBit        CON     $2000
Inverted        CON     $4000
Open            CON     $8000

Baud            CON     T9600 + Inverted        ' match DEBUG

Related commands: SEROUT and DEBUGIN ( [image] )


SERIN Examples

Syntax
' SERIN.BS1
' This program waits for the characters "A", "B", "C", and "D" to arrive
' at the serial input (inverted, 2400 baud, N81), followed by a number,
' then a carriage-return or some other non-number character.  The number is
' then displayed in the Debug window.

' {$STAMP BS1}
' {$PBASIC 1.0}

SYMBOL  SIn             = 0
SYMBOL  Baud            = N2400

SYMBOL  result          = W1

Main:
  SERIN SIn, Baud, ("ABCD"), #result
  DEBUG #result, CR
  GOTO Main
  END

NOTE: This is written for the BS2 and will run on any of the BS2-family modules. Modify the $STAMP directive (as required) before downloading to the BS2e, BS2sx, BS2p, BS2pe, or BS2px.

' SERIN_SEROUT1.BS2
' Using two BS2-IC's, connect the circuit shown in the SERIN command
' description and run this program on the BASIC Stamp designated as the
' Sender. This program demonstrates the use of Flow Control (FPin).
' Without flow control, the sender would transmit the whole word "Hello!"
' in about 1.5 ms. The receiver would catch the first byte at most; by the
' time it got back from the first 1-second PAUSE, the rest of the data
' would be long gone. With flow control, communication is flawless since
' the sender waits for the receiver to catch up.

' {$STAMP BS2}
' {$PBASIC 2.5}

SO              PIN     1               ' serial output
FC              PIN     0               ' flow control pin

#SELECT $STAMP
  #CASE BS2, BS2E, BS2PE
    T1200       CON     813
    T2400       CON     396
    T9600       CON     84
    T19K2       CON     32
    T38K4       CON     6
  #CASE BS2SX, BS2P
    T1200       CON     2063
    T2400       CON     1021
    T9600       CON     240
    T19K2       CON     110
    T38K4       CON     45
  #CASE BS2PX
    T1200       CON     3313
    T2400       CON     1646
    T9600       CON     396
    T19K2       CON     188
    T38K4       CON     84
#ENDSELECT

Inverted        CON     $4000
Open            CON     $8000
Baud            CON     T38K4 + Inverted

Main:
  DO
    SEROUT SO\FC, Baud, ["Hello!", CR]  ' send the greeting
    PAUSE 2500                          ' wait 2.5 seconds
  LOOP                                  ' repeat forever
  END

' SERIN_SEROUT2.BS2
' Using two BS2-IC's, connect the circuit shown in the SERIN command
' description and run this program on the BASIC Stamp designated as the
' Receiver.  This program demonstrates the use of Flow Control (FPin).
' Without flow control, the sender would transmit the whole word "Hello!"
' in about 1.5 ms. The receiver would catch the first byte at most; by the
' time it got back from the first 1-second PAUSE, the rest of the data
' would be long gone. With flow control, communication is flawless since
' the sender waits for the receiver to catch up.

' {$STAMP BS2}
' {$PBASIC 2.5}

SI              PIN     0               ' serial input
FC              PIN     1               ' flow control pin

#SELECT $STAMP
  #CASE BS2, BS2E, BS2PE
    T1200       CON     813
    T2400       CON     396
    T9600       CON     84
    T19K2       CON     32
    T38K4       CON     6
  #CASE BS2SX, BS2P
    T1200       CON     2063
    T2400       CON     1021
    T9600       CON     240
    T19K2       CON     110
    T38K4       CON     45
  #CASE BS2PX
    T1200       CON     3313
    T2400       CON     1646
    T9600       CON     396
    T19K2       CON     188
    T38K4       CON     84
#ENDSELECT

Inverted        CON     $4000
Open            CON     $8000
Baud            CON     T38K4 + Inverted

letter          VAR     Byte

Main:
  DO
    SERIN SI\FC, Baud, [letter]         ' recieve one byte
    DEBUG letter                        ' display on screen
    PAUSE 1000                          ' wait one second
  LOOP                                  ' repeat forever
  END


 SEROUT

Examples

Syntax [image] : SEROUT Tpin, Baudmode, ({#} OutputData)
Syntax [image] : SEROUT Tpin {\Fpin}, Baudmode, {Pace,} {Timeout, Tlabel,} [OutputData]

Function
Transmit asynchronous serial data (e.g., RS-232 data).

  • Tpin is a variable/constant/expression* (0 - 16) that specifies the I/O pin through which the serial data will be transmitted. This pin will be set to output mode. On the BS2, BS2e, BS2sx, BS2p, BS2pe, and BS2px, if Tpin is set to 16, the BASIC Stamp uses the dedicated serial-output pin (SOUT, physical pin 1), which is normally used by the Stamp Editor during the download process.
  • Fpin is an optional variable/constant/expression* (0 - 15) that specifies the I/O pin to monitor for flow control status. This pin will be set to input mode. NOTE: Fpin must be specified to use the optional Timeout and Tlabel arguments in the SEROUT command.
  • Baudmode is variable/constant/expression* (0 - 7 on the BS1, 0 - 65535 on all other BASIC Stamps) that specifies serial timing and configuration.
  • Pace is an optional variable/constant/expression (0 - 65535) that determines the length of the pause between transmitted bytes. NOTE: Pace cannot be used simultaneously with Timeout.
  • Timeout is an optional variable/constant/expression* (0 - 65535) that tells SEROUT how long to wait for Fpin permission to send. If permission does not arrive in time, the program will jump to the address specified by Tlabel. NOTE: Fpin must be specified to use the optional Timeout and Tlabel arguments in the SEROUT command.
  • Tlabel is an optional label that must be provided along with Timeout. Tlabel indicates where the program should go in the event that permission to send data is not granted within the period specified by Timeout.
  • OutputData† is list of variables, constants, expressions and formatters that tells SEROUT how to format outgoing data. SEROUT can transmit individual or repeating bytes, convert values into decimal, hex or binary text representations, or transmit strings of bytes from variable arrays. These actions can be combined in any order in the OutputData list.

* | NOTE: Expressions are not allowed as arguments on the BS1. The range of the Tpin argument on the BS1 is 0 - 7.
† | NOTE: The BS1's OutputData argument can only be a list of variables and the optional decimal modifier (#).

Quick Facts
 | BS1 | BS2 and BS2e | BS2sx | BS2p | BS2pe | BS2px
Units in Pace | N/A | 1 ms | 1 ms | 1 ms | 1 ms | 1 ms
Units in Timeout | N/A | 1 ms | 0.4 ms | 0.4 ms | 1 ms | 0.4 ms
Baud Range | 300, 600, 1200, and 2400 only | 243 to 50K | 608 to 115.2K | 608 to 115.2K | 243 to 50K | 972 to 115.2K
Baud Limit with Flow Control | N/A | 19.2K | 19.2K | 19.2K | 19.2K | 19.2K
I/O Pins Available | 0 - 7 | 0 - 15 | 0 - 15 | 0 - 15 (in current I/O block) | 0 - 15 (in current I/O block) | 0 - 15 (in current I/O block)
Other Serial Port Pins | N/A | SOUT pin (physical pin 2) when Tpin = 16

Explanation
One of the most popular forms of communication between electronic devices is serial communication. There are two major types of serial communication; asynchronous and synchronous. The SERIN and SEROUT commands are used to receive and send asynchronous serial data. See the SHIFTIN and SHIFTOUT command for information on the synchronous method.

The following information is supplemental to what is discussed in the SERIN command section. Please read through the SERIN command section for additional information.

All BASIC Stamps (except the BS1) have a line driver on its SOUT pin (Tpin = 16). See the "Hardware" section of the "Introduction to the BASIC Stamps" chapter. The SOUT pin goes to a PC's serial data-in pin on the DB-9 connector built into BASIC Stamp development boards. The connector is wired to allow both programming and run-time serial communication (unless you are using the Stamp 2 Carrier Board which is only designed for programming). For the built-in serial port set the Tpin argument to 16 in the SEROUT command.

All BASIC Stamps (including the BS1) can also transmit RS-232 data through any of their I/O pins (Tpin = 0 - 7 for BS1, Tpin = 0 - 15 on all other BASIC Stamps). The I/O pins only provide a 0 to +5 volt swing (outside of RS-232 specs) and may need to be connected through a line driver for proper operation with all serial ports. Most serial ports are able to recognize a 0 to +5 volt swing, however. See the figure below sample wiring.

Note: The connections shown in red are normally not necessary. They indicate optional connections to defeat hardware handshaking requirements.
Note: A line driver may have to be used between the I/O pin and the receiving serial port to ensure proper communication.

Function | DB-9 | DB-25
Data Carrier Detect (DCD) | 1 | 8
Receive Data (RD) | 2 | 3
Transmit Data (TD) | 3 | 2
Data Terminal Ready (DTR) | 4 | 20
Signal Ground (SG) | 5 | 7
Data Set Ready (DSR) | 6 | 6
Request To Send (RTS) | 7 | 4
Clear To Send (CTS) | 8 | 5

The figure above shows the pinouts of the two styles of PC serial ports and how to connect them to the BASIC Stamp's I/O pin. Though not normally needed, the figure also shows loop back connections that defeat hardware handshaking used by some PC software. Note that PC serial ports are always male connectors. The 25-pin style of serial port (called a DB-25) looks similar to a printer (parallel) port except that it is male, whereas a parallel port is female.

Asynchronous serial communication relies on precise timing. Both the sender and receiver must be set for identical timing, usually expressed in bits per second (bps) called baud.

On all BASIC Stamps, SEROUT requires a value called Baudmode that tells it the important characteristics of the outgoing serial data; the bit period, number of data and parity bits, and polarity.

On the BS1, serial communication is limited to: no-parity, 8-data bits and 1-stop bit at one of four different speeds: 300, 600, 1200 or 2400 baud. The table below indicates the Baudmode value or symbols to use when selecting the desired mode.

Baudmode Value | Symbol | Baud Rate | Polarity
0 | T2400 | 2400 | TRUE (always driven)
1 | T1200 | 1200 | TRUE (always driven)
2 | T600 | 600 | TRUE (always driven)
3 | T300 | 300 | TRUE (always driven)
4 | N2400 | 2400 | INVERTED (always driven)
5 | N1200 | 1200 | INVERTED (always driven)
6 | N600 | 600 | INVERTED (always driven)
7 | N300 | 300 | INVERTED (always driven)
8 | OT2400 | 2400 | TRUE (open drain, driven high)
9 | OT1200 | 1200 | TRUE (open drain, driven high)
10 | OT600 | 600 | TRUE (open drain, driven high)
11 | OT300 | 300 | TRUE (open drain, driven high)
12 | ON2400 | 2400 | INVERTED (open source, driven low)
13 | ON1200 | 1200 | INVERTED (open source, driven low)
14 | ON600 | 600 | INVERTED (open source, driven low)
15 | N300 | 300 | INVERTED (open source, driven low)

On the BS2, BS2e, BS2sx, BS2p, BS2pe, and BS2px, serial communication is very flexible. The Baudmode argument for SEROUT accepts a 16-bit value that determines its characteristics: 1-stop bit, 8-data bits/no-parity or 7-data bits/even-parity and virtually any speed from as low as 300 baud to greater than 100K baud (depending on the BASIC Stamp). The information below shows how Baudmode is calculated and show common baud modes for standard serial baud rates.

Baudmode Calculation:

  1. Determine the bit period (bits 0 - 11)
    • BS2, BS2e, and BS2pe = INT(1,000,000 ÷ baud rate) - 20
    • BS2sx and BS2p = INT(2,500,000 ÷ baud rate) - 20
    • BS2px = INT(4,000,000 ÷ baud rate) - 20

      Note: INT means 'Convert to integer.' -- drop the numbers to the right of the decimal point.
  2. Set data bits and parity (bit 13)
    • 8-bit / No Parity = 0
    • 7-bit / Even Parity = 8192
  3. Select polarity bit (bit 14)
    • True = 0
    • Inverted = 16384
  4. Select driven or open output (bit 15)
    • Driven = 0
    • Open = 32768

Common Baud Rates and Corresponding Values

Baud Rate | 8-bit No Parity INVERTED | 8-bit No Parity TRUE | 7-bit Even Parity INVERTED | 7-bit Even Parity TRUE
300 | 19697 | 3313 | 27889 | 11505
600 | 18030 | 1646 | 26222 | 9838
1200 | 17197 | 813 | 25389 | 9005
2400 | 16780 | 396 | 24972 | 8588
4800 | 16572 | 188 | 24764 | 8380
9600 | 16468 | 84 | 24660 | 8276
NOTE: For "open" baudmodes used in networking, add 32768 ($8000) to the values from the table above. If the dedicated serial port (Tpin = 16) is used the data is inverted and driven regardless of the baudmode setting.

Baud Rate | 8-bit No Parity INVERTED | 8-bit No Parity TRUE | 7-bit Even Parity INVERTED | 7-bit Even Parity TRUE
1200 | 18447 | 2063 | 26639 | 10255
2400 | 17405 | 1021 | 25597 | 9213
4800 | 16884 | 500 | 25076 | 8692
9600 | 16624 | 240 | 24816 | 8432
NOTE: For "open" baudmodes used in networking, add 32768 ($8000) to the values from the table above. If the dedicated serial port (Tpin = 16) is used the data is inverted and driven regardless of the baudmode setting.

Baud Rate | 8-bit No Parity INVERTED | 8-bit No Parity TRUE | 7-bit Even Parity INVERTED | 7-bit Even Parity TRUE
1200 | 19697 | 3313 | 27889 | 11505
2400 | 18030 | 1646 | 26222 | 9838
4800 | 17197 | 813 | 25389 | 9005
9600 | 16780 | 396 | 24972 | 8588
NOTE: For "open" baudmodes used in networking, add 32768 ($8000) to the values from the table above. If the dedicated serial port (Tpin = 16) is used the data is inverted and driven regardless of the baudmode setting.

If you're communicating with existing software or hardware, its speed(s) and mode(s) will determine your choice of baud rate and mode. See the SERIN command description for more information.

The example below will transmit a single byte through I/O pin 1 at 2400 baud, 8N1, inverted:

  SEROUT 1, N2400, (65)

  SEROUT 1, 16780, [65]                         ' baudmode set for BS2/e/pe

  SEROUT 1, 17405, [65]                         ' baudmode set for BS2sx/p

Here, SEROUT will transmit a byte equal to 65 (the ASCII value of the character "A") through pin 1. If the BASIC Stamp were connected to a PC running a terminal program (set to the same baud rate) the character "A" would appear on the screen.

What if you really wanted the value 65 to appear on the screen? If you remember from the discussion in the SERIN command, "It is up to the receiving side (in serial communication) to interpret the values..." In this case, the PC is interpreting the byte-sized value to be the ASCII code for the character "A". Unless you're also writing the software for the PC, you can't change how the PC interprets the incoming serial data, so to solve this problem, the data needs to be translated before it is sent.

The SEROUT command provides a formatter, called the decimal formatter, which will translate the value 65 to two ASCII codes for the characters "6" and "5" and then transmit them. Look at the following code:

  SEROUT 1, N2400, (#65)

  SEROUT 1, 16780, [DEC 65]

  SEROUT 1, 17405, [DEC 65]

Notice the decimal formatter in the SEROUT command. It is the "#" (for the BS1) or "DEC" (for the other BASIC Stamps) that appears just to the left of the number 65. This tells SEROUT to convert the number into separate ASCII characters which represent the value in decimal form. If the value 65 in the code were changed to 123, the SEROUT command would send three bytes (49, 50 and 51) corresponding to the characters "1", "2" and "3".

The BS2, BS2e, BS2sx, BS2p, BS2pev and BS2px have many more conversion formatters available for the SEROUT command. See below for more information.

The SEROUT command sends quoted text exactly as it appears in the OutputData list:

  SEROUT 1, N2400, ("HELLO", CR)
  SEROUT 1, N2400, ("Num = ", #100)

  SEROUT 1, 16780, ["HELLO", CR]
  SEROUT 1, 16780, ["Num = ", DEC 100]

  SEROUT 1, 17405, ["HELLO", CR]
  SEROUT 1, 17405, ["Num = ", DEC 100]

The above code will display "HELLO" on one line and "Num = 100" on the next line. Notice that you can combine data to output in one SEROUT command, separated by commas. In the example above, we could have written it as one line of code, with "HELLO", CR, "Num = ", DEC 100 in the OutputData list.

The BS1's SEROUT command is limited to above-mentioned features. If you are not using a BS1, please continue reading about the additional features below.

The SEROUT command can also be configured to pause between transmitted bytes. This is the purpose of the optional Pace argument. For example (9600 baud N8, inverted):

  SEROUT 1, 16468, 1000, ["Slowly"]             ' baudmode set for BS2

Here, the BASIC Stamp transmits the word "Slowly" with a 1 second delay between each character. See the table above for units of the Pace argument. One good reason to use the Pace feature is to support devices that require more than one stop bit. Normally, the BASIC Stamp sends data as fast as it can (with a minimum of 1 stop bit between bytes). Since a stop bit is really just a resting state in the line (no data transmitted), using the Pace option will effectively add multiple stop bits. Since the requirement for 2 or more stop bits (on some devices) is really just a "minimum" requirement, the receiving side should receive this data correctly.

Keep in mind that when we type something like "XYZ" into the SEROUT command, the BASIC Stamp actually uses the ASCII codes for each of those characters for its tasks. We could also typed: 88, 89, 90 in place of "XYZ" and the program would run the same way since 88 is the ASCII code for the "X" character, 89 is the ASCII code for the "Y" character, and so on.

The decimal formatter is only one of a whole family of conversion formatters available with SEROUT on the BS2, BS2e, BS2sx, BS2p, BS2pe, and BS2px. See the table below for a list of available conversion formatters. All of the conversion formatters work similar to the decimal formatter. The formatters translate the value into separate bytes of data until the entire number is translated or until the indicated number of digits (in the case of the fixed length formatters) is translated.

Conversion Formatter | Type of Number | Notes
DEC{1..5} | Decimal, optionally fixed to 1 - 5 digits | 1
SDEC{1..5} | Signed decimal, optionally fixed to 1 - 5 digits | 1,2
HEX{1..4} | Hexadecimal, optionally fixed to 1 - 4 digits | 1
SHEX{1..4} | Signed hexadecimal, optionally fixed to 1 - 4 digits | 1,2
IHEX{1..4} | Indicated hexadecimal, optionally fixed to 1 - 4 digits | 1
ISHEX{1..4} | Signed, indicated hexadecimal, optionally fixed to 1 - 4 digits ($ prefix) | 1,2
BIN{1..16} | Binary, optionally fixed to1 - 16 digits | 1
SBIN{1..16} | Signed binary, optionally fixed to 1 - 16 digits | 1,2
IBIN{1..16} | Indicated binary, optionally fixed to 1 - 16 digits | 1
ISBIN{1..16} | Signed, indicated binary, optionally fixed to 1 - 16 digits | 1,2

  1. Fixed-digit formatters like DEC4 will pad the number with leading 0s if necessary; ex: DEC4 65 sends 0065. If a number is larger than the specified number of digits, the leading digits will be dropped; ex: DEC4 56422 sends 6422.
  2. Signed modifiers work under two's complement rules.

The BS2, BS2e, BS2sx, BS2p, BS2pe, and BS2px also have special formatters for outputting a string of characters, repeated characters and undesirable characters.

Special Formatter | Action
? | Displays "symbol = x' + carriage return; where x is a number. Default format is decimal, but may be combined with conversion formatters (ex: BIN ? x to display "x = binary_number").
ASC ? | Displays "symbol = 'x'" + carriage return; where x is an ASCII character.
STR ByteArray {\L} | Send character string from an array. The optional \L argument can be used to limit the output to L characters, otherwise, characters will be sent up to the first byte equal to 0 or the end of RAM space is reached.
REP Byte\L | Send a string consisting of Byte repeated L times (ex: REP "X"\10 sends "XXXXXXXXXX").

The string formatter is useful for transmitting a string of characters from a byte array variable. A string of characters is a set of characters that are arranged or accessed in a certain order. The characters "ABC" could be stored in a string with the "A" first, followed by the "B" and then followed by the "C." A byte array is a similar concept to a string; it contains data that is arranged in a certain order. Each of the elements in an array is the same size. The string "ABC" could be stored in a byte array containing three bytes (elements).

Here is an example that transmits five bytes (from a byte array) through I/O pin 1 at 9600 bps, N81/inverted:

serStr  VAR     Byte(5)                         ' Make a 5-byte array.

Main:
  serStr(0) = "H"
  serStr(1) = "E"
  serStr(2) = "L"
  serStr(3) = "L"
  serStr(4) = "O"

  SEROUT 1, 16468, [STR serStr\5]               ' Send 5-byte string

Note that we use the optional \L argument of STR. If we didn't specify this, the BASIC Stamp would try to keep sending characters until it found a byte equal to 0. Since we didn't specify a last byte of 0 in the array, we chose to tell it explicitly to only send 5 characters.

Parity is a simple error-checking feature. When the SEROUT command's Baudmode is set for even parity it counts the number of 1s in the outgoing byte and uses the parity bit to make that number even. For instance, if it is sending the 7-bit value: %0011010, it sets the parity bit to 1 in order to make an even number of 1s (four).

The receiver also counts the data bits to calculate what the parity bit should be. If it matches the parity bit received, the serial receiver assumes that the data was received correctly. Of course, this is not necessarily true, since two incorrectly received bits could make parity seem correct when the data was wrong, or the parity bit itself could be bad when the rest of the data was OK. Parity errors are only detected on the receiver side. Generally, the receiver determines how to handle the error. In a more robust application, the receiver and transmitter might be set up such that the receiver can request a re-send of data that was received with a parity error.

When you design an application that requires serial communication between BASIC Stamps, you have to work within these limitations:

  • When the BASIC Stamp is sending or receiving data, it can't execute other instructions.
  • When the BASIC Stamp is executing other instructions, it can't send or receive data. The BASIC Stamp does not have a serial buffer as there is in PCs. At most serial rates, the BASIC Stamp cannot receive data via SERIN, process it, and execute another SERIN in time to catch the next chunk of data, unless there are significant pauses between data transmissions.

These limitations can sometimes be addressed by using flow control; the Fpin option for SERIN and SEROUT (at baud rates of up to the limitation shown above). Through Fpin, SERIN can tell a BASIC Stamp sender when it is ready to receive data and SEROUT (on the sender) will wait for permission to send. (For that matter, Fpin flow control follows the rules of other serial handshaking schemes, but most computers other than the BASIC Stamp cannot start and stop serial transmission on a byte-by-byte basis. That's why this discussion is limited to communication between BASIC Stamps.)

Here's an example using flow control on the BS2 (data through I/O pin 1, flow control through I/O pin 0, 9600 baud, N8, non-inverted):

sData   VAR     Byte

Main:
  SEROUT 1\0, 84, [sData]                       ' baudmode set for BS2

When SEROUT executes, I/O pin 1 (Tpin) is made an output, and I/O pin 0 (Fpin) is made an input, to wait for the "go" signal from the receiver. Here's the relationship of serial polarity to Fpin states.

 | Ready to Receive ("Go") | Not Ready to Receive ("Stop")
Inverted | Fpin is High (1) | Fpin is Low (0)
Non-Inverted | Fpin is Low (0) | Fpin is High (1)

See the example program for a flow control example using two BS2s. In the demo program example, without flow control, the sender would transmit the whole word "HELLO!" in about 6 ms. The receiver would catch the first byte at most; by the time it got back from the first 1-second PAUSE, the rest of the data would be long gone. With flow control, communication is flawless since the sender waits for the receiver to catch up.

In the figure below, I/O pin 0, Fpin, is pulled to ground through a 10 kΩ resistor. This is to ensure that the sender sees a stop signal (0 for inverted communications) when the receiver is being programmed.

In the flow control examples above, the only way the SEROUT instruction will end (other than RESET or power-off) is if the receiver allows it to send the entire OutputData list. If Fpin permission never occurs, the program is stuck. However, you can tell the BASIC Stamp to abort SEROUT if it doesn't receive Fpin permission within a specified time period. For instance, to transmit a decimal number through pin 1 at 9600 baud, 8N, inverted and abort SEROUT after 2 seconds (2000 ms) if no Fpin permission arrives on I/O pin 0:

Main:
  SEROUT 1\0, 16468, 2000, No_Permission, [DEC 150]
  STOP

No_Permission:
  DEBUG CLS, "Timed out"
  STOP

If no Fpin permission arrives within 2 seconds, the program aborts SEROUT and continues at the label NoPermission.

The SEROUT command supports open-drain and open-source output, which makes it possible to network multiple BASIC Stamps on a single pair of wires. These "open baudmodes" only actively drive the Tpin in one state (for the other state, they simply disconnect the pin; setting it to an input mode). If two BASIC Stamps in a network had their SEROUT lines connected together (while a third device listened on that line) and the BASIC Stamps were using always-driven baudmodes, they could simultaneously output two opposite states (i.e., +5 volts and ground). This would create a short circuit. The heavy current flow would likely damage the I/O pins or the BASIC Stamps themselves. Since the open baudmodes only drive in one state and float in the other, there's no chance of this kind of short.

The polarity selected for SEROUT determines which state is driven and which is open as shown below:

 | State (0) | State (1) | Resistor pulled to...
Inverted | Open | Driven | Gnd (Vss)
Non-Inverted | Driven | Open | +5V (Vdd)

Since open baudmodes only drive to one state, they need a resistor to pull the networked line into the other state, as shown in the table above and the figures below.

Open baudmodes allow the BASIC Stamp to share a line, but it is up to your program to resolve other networking issues such as who talks when and how to detect, prevent and fix data errors.

SEROUT Open-Drain circuit:

SEROUT Open-Source circuit:

SEROUT Troubleshooting

Serial communication, because of its complexity, can be very difficult to work with at times. Please follow these guidelines when developing a project using the SERIN and SEROUT commands:

  1. Always build your project in steps.
    1. Start with small, manageable pieces of code, that deals with serial communication) and test them, one at a time.
    2. Add more and more small pieces, testing them each time, as you go.
    3. Never write a large portion of code that works with serial communication without testing its smallest workable pieces first.
  2. Pay attention to timing.
    1. Be very careful to calculate and overestimate the amount of time operations should take within the BASIC Stamp. Misunderstanding the timing constraints is the source of most problems with code that communicate serially.
    2. If the serial communication in your project is bidirectional, the above statement is even more critical.
  3. Pay attention to wiring.
    1. Take extra time to study and verify serial communication wiring diagrams. A mistake in wiring can cause strange problems in communication, or no communication at all. Make sure to connect the ground pins (Vss) between the devices that are communicating serially.
  4. Verify port setting on the PC and in the SERIN/SEROUT commands.
    1. Unmatched settings on the sender and receiver side will cause garbled data transfers or no data transfers. If the data you receive is unreadable, it is most likely a baud rate setting error.
  5. If data transmitted to the Stamp Editor's Debug Terminal is garbled, verify the output format.
    1. A common mistake is to send data with SEROUT in ASCII format. For example, SEROUT 16, 84, [ 0 ] instead of SEROUT 16, 84, [ DEC 0 ]. The first example will send a byte equal to 0 to the PC, resulting in the DEBUG Terminal clearing the screen (since 0 is the control character for a clear-screen action).
  6. When using a BS2-family module, you can simplify Baudmode parameter selection by using conditional compilation. The example below can be included in the standard programming template and will handle most serial IO requirements. Remember that defining constants does not affect compiled program space, and yet does make program debugging easier.
' {$PBASIC 2.5}

#SELECT $STAMP
  #CASE BS2, BS2E, BS2PE
    T1200       CON     813
    T2400       CON     396
    T4800       CON     188
    T9600       CON     84
    T19K2       CON     32
    T38K4       CON     6
  #CASE BS2SX, BS2P
    T1200       CON     2063
    T2400       CON     1021
    T4800       CON     500
    T9600       CON     240
    T19K2       CON     110
    T38K4       CON     45
  #CASE BS2PX
    T1200       CON     3313
    T2400       CON     1646
    T4800       CON     813
    T9600       CON     396
    T19K2       CON     188
    T38K4       CON     84
#ENDSELECT

SevenBit        CON     $2000
Inverted        CON     $4000
Open            CON     $8000

Baud            CON     T9600 + Inverted        ' match DEBUG

Related commands: SERIN and DEBUG


SEROUT Examples

Syntax
' SEROUT.BS1
' This program transmits the string "ABCD" followed by a number and a
' carriage-return at 2400 baud, inverted, N81 format.

' {$STAMP BS1}
' {$PBASIC 1.0}

SYMBOL  SOut            = 1
SYMBOL  Baud            = N2400

SYMBOL  value           = W1

Setup:
  value = 1

Main:
  SEROUT SOut, Baud, ("ABCD", #value)
  value = value + 1
  PAUSE 250
  GOTO Main
  END

NOTE: This is written for the BS2 and will run on any of the BS2-family modules. Modify the $STAMP directive (as required) before downloading to the BS2e, BS2sx, BS2p, BS2pe, or BS2px.

' SERIN_SEROUT1.BS2
' Using two BS2-IC's, connect the circuit shown in the SERIN command
' description and run this program on the BASIC Stamp designated as the
' Sender. This program demonstrates the use of Flow Control (FPin).
' Without flow control, the sender would transmit the whole word "Hello!"
' in about 1.5 ms. The receiver would catch the first byte at most; by the
' time it got back from the first 1-second PAUSE, the rest of the data
' would be long gone. With flow control, communication is flawless since
' the sender waits for the receiver to catch up.

' {$STAMP BS2}
' {$PBASIC 2.5}

SO              PIN     1               ' serial output
FC              PIN     0               ' flow control pin

#SELECT $STAMP
  #CASE BS2, BS2E, BS2PE
    T1200       CON     813
    T2400       CON     396
    T9600       CON     84
    T19K2       CON     32
    T38K4       CON     6
  #CASE BS2SX, BS2P
    T1200       CON     2063
    T2400       CON     1021
    T9600       CON     240
    T19K2       CON     110
    T38K4       CON     45
  #CASE BS2PX
    T1200       CON     3313
    T2400       CON     1646
    T9600       CON     396
    T19K2       CON     188
    T38K4       CON     84
#ENDSELECT

Inverted        CON     $4000
Open            CON     $8000
Baud            CON     T38K4 + Inverted

Main:
  DO
    SEROUT SO\FC, Baud, ["Hello!", CR]  ' send the greeting
    PAUSE 2500                          ' wait 2.5 seconds
  LOOP                                  ' repeat forever
  END

' SERIN_SEROUT2.BS2
' Using two BS2-IC's, connect the circuit shown in the SERIN command
' description and run this program on the BASIC Stamp designated as the
' Receiver.  This program demonstrates the use of Flow Control (FPin).
' Without flow control, the sender would transmit the whole word "Hello!"
' in about 1.5 ms. The receiver would catch the first byte at most; by the
' time it got back from the first 1-second PAUSE, the rest of the data
' would be long gone. With flow control, communication is flawless since
' the sender waits for the receiver to catch up.

' {$STAMP BS2}
' {$PBASIC 2.5}

SI              PIN     0               ' serial input
FC              PIN     1               ' flow control pin

#SELECT $STAMP
  #CASE BS2, BS2E, BS2PE
    T1200       CON     813
    T2400       CON     396
    T9600       CON     84
    T19K2       CON     32
    T38K4       CON     6
  #CASE BS2SX, BS2P
    T1200       CON     2063
    T2400       CON     1021
    T9600       CON     240
    T19K2       CON     110
    T38K4       CON     45
  #CASE BS2PX
    T1200       CON     3313
    T2400       CON     1646
    T9600       CON     396
    T19K2       CON     188
    T38K4       CON     84
#ENDSELECT

Inverted        CON     $4000
Open            CON     $8000
Baud            CON     T38K4 + Inverted

letter          VAR     Byte

Main:
  DO
    SERIN SI/FC, Baud, [letter]         ' recieve one byte
    DEBUG letter                        ' display on screen
    PAUSE 1000                          ' wait one second
  LOOP                                  ' repeat forever
  END


 SHIFTIN

Example

Syntax: SHIFTIN Dpin, Cpin, Mode, [Variable {\Bits} {, Variable {\Bits}...}]

Function
Shift data in from a synchronous serial device.

  • Dpin is a variable/constant/expression (0 - 15) that specifies the I/O pin that will be connected to the synchronous serial device's data output. This pin will be set to input mode.
  • Cpin is a variable/constant/expression (0 - 15) that specifies the I/O pin that will be connected to the synchronous serial device's clock input. This pin will be set to output mode.
  • Mode is a variable/constant/expression (0 - 3), or one of four predefined symbols, that tells SHIFTIN the order in which data bits are to be arranged and the relationship of clock pulses to valid data. See the table below for value and symbol definitions.
  • Variable is a variable in which incoming data bits will be stored.
  • Bits is an optional variable/constant/expression (1 - 16) specifying how many bits are to be input by SHIFTIN. If no Bits entry is given, SHIFTIN defaults to 8 bits.

Quick Facts
 | BS2, BS2e, and BS2pe | BS2sx and BS2p | BS2px
Timing of T0 and T1 | 14 µs / 46 µs | 5.6 µs / 18 µs | 3.6 µs / 11.8 µs
Transmission Rate | ~ 16 kBits/Sec | ~ 42 kBits/Sec | ~ 65 kBits/Sec

Explanation
SHIFTIN and SHIFTOUT provide an easy method of acquiring data from synchronous serial devices. Synchronous serial differs from asynchronous serial (like SERIN and SEROUT) in that the timing of data bits (on a data line) is specified in relationship to clock pulses (on a clock line). Data bits may be valid after the rising or falling edge of the clock line. This kind of serial protocol is commonly used by controller peripherals like ADCs, DACs, clocks, memory devices, etc.

At their heart, synchronous-serial devices are essentially shift-registers; trains of flip-flops that pass data bits along in a bucket brigade fashion to a single data output pin. Another bit is output each time the appropriate edge (rising or falling, depending on the device) appears on the clock line.

The SHIFTIN instruction first causes the clock pin to output low and the data pin to switch to input mode. Then, SHIFTIN either reads the data pin and generates a clock pulse (PRE mode) or generates a clock pulse then reads the data pin (POST mode). SHIFTIN continues to generate clock pulses and read the data pin for as many data bits as are required.

Making SHIFTIN work with a particular device is a matter of matching the mode and number of bits to that device's protocol. Most manufacturers use a timing diagram to illustrate the relationship of clock and data. Items to look for include: 1) which bit of the data arrives first; most significant bit (MSB) or least significant bit (LSB) and 2) is the first data bit ready before the first clock pulse (PRE) or after the first clock pulse (POST). The table below shows the values and symbols available for the Mode argument.

Symbol | Value | Meaning
MSBPRE | 0 | Data is MSB-first; sample bits before clock pulse
LSBPRE | 1 | Data is lsb-first; sample bits before clock pulse
MSBPOST | 2 | Data is MSB-first; sample bits after clock pulse
LSBPOST | 3 | Data is LSB-first; sample bits after clock pulse

SHIFTIN Timing

Here is a simple example:

result  VAR     Byte

Main:
  SHIFTIN 0, 1, MSBPRE, [result]
  END

Here, the SHIFTIN command will read I/O pin 0 (the Dpin) and will generate a clock signal on I/O 1 (the Cpin). The data that arrives on the Dpin depends on the device connected to it. Let's say, for example, that a shift register is connected and has a value of $AF (10101111) waiting to be sent. Additionally, let's assume that the shift register sends out the most significant bit first, and the first bit is on the Dpin before the first clock pulse (MSBPRE). The SHIFTIN command above will generate eight clock pulses and sample the data pin (Dpin) eight times. Afterward, the result variable will contain the value $AF.

By default, SHIFTIN acquires eight bits, but you can set it to shift any number of bits from 1 to 16 with the Bits argument. For example:

result  VAR     Byte

Main:
  SHIFTIN 0, 1, MSBPRE, [result\4]
  END

Will only input the first 4 bits. In the example discussed above, the result variable will be left with %1010.

Some devices return more than 16 bits. For example, most 8-bit shift registers can be daisy-chained together to form any multiple of 8 bits; 16, 24, 32, 40... To solve this, you can use a single SHIFTIN instruction with multiple variables. Each variable can be assigned a particular number of bits with the Bits argument. As in:

dataLo  VAR     Word
dataHi  VAR     Byte

Main:
  SHIFTIN 0, 1, MSBPRE, [dataHi\4, dataLo\16]
  STOP

The code above will first shift in four bits into dataHi and then 16 bits into dataLo. The two variables together make up a 20 bit value.

Related command: SHIFTOUT


SHIFTIN Example

Syntax

NOTE: This is written for the BS2 and will run on any of the BS2-family modules. Modify the $STAMP directive (as required) before downloading to the BS2e, BS2sx, BS2p, BS2pe, or BS2px.

' SHIFTIN.BS2
' This program uses the SHIFTIN instruction to interface with the ADC0831
' 8-bit analog-to-digital converter from National Semiconductor.

' {$STAMP BS2}
' {$PBASIC 2.5}

CS              PIN     0                       ' chip select
AData           PIN     1                       ' data pin
Clk             PIN     2                       ' clock pin

adcRes          VAR     Byte                    ' ADC result

Setup:
  HIGH CS                                       ' deselect ADC

' In the loop below, just three lines of code are required to read the
' ADC0831. The SHIFTIN command does most of the work.  The mode argument in
' the SHIFTIN command specifies MSB or LSB-first and whether to sample data
' before or after the clock. In this case, we chose MSB-first, post-clock.
' The ADC0831 precedes its data output with a dummy bit, which we take care
' of by specifying 9 bits of data instead of 8.

Main:
  DO
    LOW CS                                      ' activate the ADC0831
    SHIFTIN AData, Clk, MSBPOST, [adcRes\9]     ' shift in the data
    HIGH CS                                     ' deactivate ADC0831
    DEBUG ? adcRes                              ' show conversion result
    PAUSE 1000                                  ' wait one second
  LOOP                                          ' repeat
  END


 SHIFTOUT

Example

Syntax: SHIFTOUT Dpin, Cpin, Mode, [OutputData {\Bits} {,OutputData {\Bits}...}]

Function
Shift data out to a synchronous serial device.

  • Dpin is a variable/constant/expression (0 - 15) that specifies the I/O pin that will be connected to the synchronous serial device's data input. This pin will be set to output mode.
  • Cpin is a variable/constant/expression (0 - 15) that specifies the I/O pin that will be connected to the synchronous serial device's clock input. This pin will be set to output mode.
  • Mode is a variable/constant/expression (0 - 1), or one of two predefined symbols, that tells SHIFTOUT the order in which data bits are to be arranged. See the table below for value and symbol definitions.
  • OutputData is a variable/constant/expression containing the data to be sent.
  • Bits is an optional variable/constant/expression (1 - 16) specifying how many bits are to be output by SHIFTOUT. If no Bits entry is given SHIFTOUT defaults to 8 bits. When the Bits entry is given, the BASIC Stamp transmits the rightmost number of bits specified, regardless of the Mode.

Quick Facts
 | BS2, BS2e, and BS2pe | BS2sx and BS2p | BS2px
Timing of Th, Tl, Ta and Tb | 14 µs / 46 µs / 15 µs / 30 µs | 5.6 µs / 18 µs / 6.3 µs / 12.5 µs | 3.6 µs / 11.8 µs / 4.0 µs / 7.8 µs
Transmission Rate | ~ 16 kBits/Sec | ~ 42 kBits/Sec | ~ 65 kBits/Sec

Explanation
SHIFTIN and SHIFTOUT provide an easy method of acquiring data from synchronous serial devices. Synchronous serial differs from asynchronous serial (like SERIN and SEROUT) in that the timing of data bits (on a data line) is specified in relationship to clock pulses (on a clock line). Data bits may be valid after the rising or falling edge of the clock line. This kind of serial protocol is commonly used by controller peripherals like ADCs, DACs, clocks, memory devices, etc.

At their heart, synchronous-serial devices are essentially shift-registers; trains of flip-flops that pass data bits along in a bucket brigade fashion to a single data output pin. Another bit is output each time the appropriate edge (rising or falling, depending on the device) appears on the clock line.

The SHIFTOUT instruction first causes the clock pin to output low and the data pin to switch to output mode. Then, SHIFTOUT sets the data pin to the next bit state to be output and generates a clock pulse. SHIFTOUT continues to generate clock pulses and places the next data bit on the data pin for as many data bits as are required for transmission.

Making SHIFTOUT work with a particular device is a matter of matching the mode and number of bits to that device's protocol. Most manufacturers use a timing diagram to illustrate the relationship of clock and data. One of the most important items to look for is which bit of the data should be transmitted first; most significant bit (MSB) or least significant bit (LSB). The table below shows the values and symbols available for the Mode argument

Symbol | Value | Meaning
LSBFIRST | 0 | Data is shifted out LSB-first
MSBFIRST | 1 | Data is shifted out MSB-first

(MSB is most-significant bit; the highest or left-most bit of a Nibble, Byte, or Word. LSB is the least-significant bit; the lowest or right-most bit of a Nibble, Byte, or Word.)

SHIFTOUT Timing

Here is a simple example:

  SHIFTOUT 0, 1, MSBFIRST, [250]

Here, the SHIFTOUT command will write to I/O pin 0 (the Dpin) and will generate a clock signal on I/O 1 (the Cpin). The SHIFTOUT command will generate eight clock pulses while writing each bit (of the 8-bit value 250) onto the data pin (Dpin). In this case, it will start with the most significant bit first as indicated by the Mode value of MSBFIRST.

By default, SHIFTOUT transmits eight bits, but you can set it to shift any number of bits from 1 to 16 with the Bits argument. For example:

  SHIFTOUT 0, 1, MSBFIRST, [250\4]

Will output only the lowest (rightmost) four bits (%1010 in this case). But what if you want to output the leftmost bits of a given value? By adding the right-shift operator (>>) to the code you can adjust the output as required:

  SHIFTOUT 0, 1, MSBFIRST, [(250 >> 2)\6]

Will output the upper six bits (%111110 in this case).

Some devices require more than 16 bits. To solve this, you can use a single SHIFTOUT command with multiple values. Each value can be assigned a particular number of bits with the Bits argument. As in:

  SHIFTOUT 0, 1, MSBFIRST, [250\4, 1045\16]

The preceding example will first shift out four bits of the number 250 (%1010) and then 16 bits of the number 1045 (%0000010000010101). The two values together make up a 20 bit value.

In the examples above, specific numbers were entered as the data to transmit, but, of course, the SHIFTOUT command will accept variables and expressions for the OutputData and even for the Bits argument.

Related commands: SHIFTIN


SHIFTOUT Example

Syntax

NOTE: This is written for the BS2 and will run on any of the BS2-family modules. Modify the $STAMP directive (as required) before downloading to the BS2e, BS2sx, BS2p, BS2pe, or BS2px.

' SHIFTOUT.BS2
' This program uses the SHIFTOUT command to interface to the 74HC595 shift
' register as an 8-bit output port.  The '595 requires a minimum of three
' inputs: data, clock, and latch. See the figure in the SHIFTOUT command
' description in the manual for wiring information. SHIFTOUT automatically
' handles the data and clock, pulsing the clock to shift data bits into the
' '595. An extra step (pulsing the latch input) is required to move the
' shifted bits in parallel onto the '595's output pins. Note: this code does
' not control the output-enable or reset lines of the '595. This means that
' before the BASIC Stamp first sends, the '595's output latches are turned
' on and may contain random data. In critical applications, you should hold
' output-enable high (disabled) until the BASIC Stamp can take control.

' {$STAMP BS2}
' {$PBASIC 2.5}

Dpin            PIN     0                       ' data pin to 74HC595
Clk             PIN     1                       ' shift clock to 74HC595
Latch           PIN     2                       ' latch 74HC595 outputs

counter         VAR     Byte

Setup:
  LOW Latch                                     ' initialize latch output

' This loop moves the 8-bit value 'counter' onto the output lines of the
' '595, pauses, then increments counter and repeats.  The data is shifted
' MSB first so that the MSB appears on pin QH and the lsb on QA. Changing
' MSBFIRST to LSBFIRST causes the data to appear backwards on the outputs.

Main:
  DO
    SHIFTOUT Dpin, Clk, MSBFIRST, [counter]     ' send the bits
    PULSOUT Latch, 1                            ' transfer to outputs
    PAUSE 100                                   ' Wait 0.1 seconds
    counter = counter + 1                       ' increment counter
  LOOP
  END


 SLEEP

Example

Syntax: SLEEP Duration

Function
Put the BASIC Stamp into low-power mode for a specified period.

  • Duration is a variable/constant/expression* (1 - 65535) that specifies the duration of sleep. The unit of time for Duration is one second, though the BASIC Stamp rounds up to the nearest multiple of 2.3 seconds.

* Note: Expressions are not allowed as arguments on the BS1.

Quick Facts
 | BS1 | BS2 | BS2e | BS2sx | BS2p | BS2pe | BS2px
Current Draw during Run | 1 mA | 3 mA | 25 mA | 60 mA | 40 mA | 15 mA | 55 mA
Current Draw during SLEEP | 25 µA | 50 µA | 200 µA | 500 µA | 350 µA | 36 µA | 450 µA
Accuracy of SLEEP | ±1% @ 75°F with stable power supply

Explanation
SLEEP allows the BASIC Stamp to turn itself off, then turn back on after a programmed duration. The length of SLEEP can range from 2.3 seconds to slightly over 18 hours. Power consumption is reduced to the amount described in the table above, assuming no loads are being driven. The resolution of the SLEEP instruction is 2.304 seconds. SLEEP rounds the specified number of seconds up to the nearest multiple of 2.304. For example, SLEEP 1 causes 2.3 seconds of sleep, while SLEEP 10 causes 11.52 seconds (5 x 2.304) of sleep.

Pins retain their previous I/O directions during SLEEP. However, outputs are interrupted every 2.3 seconds during SLEEP due to the way the chip keeps time. The alarm clock that wakes the BASIC Stamp up is called the watchdog timer. The watchdog is a resistor/capacitor oscillator built into the interpreter chip. During SLEEP, the chip periodically wakes up and adjusts a counter to determine how long it has been asleep. If it isn't time to wake up, the chip "hits the snooze bar" and goes back to sleep.

To ensure accuracy of SLEEP intervals, the BASIC Stamp periodically compares the watchdog timer to the more-accurate resonator time base. It calculates a correction factor that it uses during SLEEP. As a result, longer SLEEP intervals are accurate to approximately ±1 percent.

If your application is driving loads (sourcing or sinking current through output-high or output-low pins) during SLEEP, current will be interrupted for about 18 ms when the BASIC Stamp wakes up every 2.3 seconds. The reason is that the watchdog-timer reset that awakens the BASIC Stamp also causes all of the pins to switch to input mode for approximately 18 ms. When the interpreter firmware regains control of the processor, it restores the I/O directions dictated by your program.

If you plan to use END, NAP, or SLEEP in your programs, make sure that your loads can tolerate these periodic power outages. The simplest solution is often to connect resistors high or low (to +5V or ground) as appropriate to ensure a continuing supply of current during the reset glitch.

The demo program can be used to demonstrate the effects of the SLEEP glitch with an LED and resistor.

Related command: END, NAP, and POLLWAIT ( [image] )


SLEEP Example

Syntax

Connect an LED and 470 Ω resistor as shown below for the demo program.

NOTE: This is written for the BS2 and will also run on the BS1, BS2e, BS2sx, BS2p, BS2pe, and BS2px. Modify the $STAMP directive (as required) before downloading to the BS1, BS2e, BS2sx, BS2p, BS2pe, or BS2px.

' SLEEP.BS2
' This program lights an LED and then goes to sleep. Connect an LED to pin
' 0 as shown in the description of SLEEP in the manual and run the program.
' The LED will turn on, then the BASIC Stamp will go to sleep. During sleep,
' the LED will remain on, but will blink at intervals of approximately 2.3
' seconds due to the watchdog timeout and reset.

' {$STAMP BS2}

Setup:
  LOW 0                                 ' turn LED on

Snooze:
  SLEEP 10                              ' sleep for 10 seconds
  GOTO Snooze
  END


 SOUND

Example

Syntax: SOUND Pin, (Note, Duration {, Note, Duration...})

Function
Generate square-wave tones for a specified duration.

  • Pin is a variable/constant (0 - 7) that specifies the I/O pin to use. This pin will be set to output mode.
  • Note is a variable/constant (0 - 255) specifying the type and frequency of the tone. 1 - 127 are ascending tones and 128 - 255 are ascending white noises ranging from buzzing (128) to hissing (255).
  • Duration is a variable/constant (1 - 255) specifying the amount of time to generate the tone(s). The unit of time for Duration is 12 ms.

Explanation
SOUND generates one of 255 square-wave frequencies on an I/O pin. The output pin should be connected as shown in the circuits below.

The tones produced by SOUND can vary in frequency from 94.8 Hz (1) to 10,550 Hz (127). If you need to determine the frequency corresponding to a given note value, or need to find the note value that will give you best approximation for a given frequency, use the equations below.

Note = 127 - (((1 ÷ Frequency) - 0.000095) ÷ 0.000083)

-- and --

Frequency = (1 ÷ (0.000095 + ((127 - Note) x 0.000083))

Note, in the above equations, Frequency is in Hertz (Hz).

Related command: FREQOUT ( [image] )


SOUND Example

Syntax
' SOUND.BS1
' This program generates a constant tone 25 followed by an ascending tones.
' Both the tones have the same duration.

' {$STAMP BS1}
' {$PBASIC 1.0}

SYMBOL  tone            = B2

Main:
  FOR tone = 0 TO 255
    SOUND 0, (25, 10, tone, 10)
  NEXT
  END


 STOP

Example

Syntax: STOP

Function
Stops program execution.

Explanation
STOP prevents the BASIC Stamp from executing any further instructions until it is reset. The following actions will reset the BASIC Stamp:

  1. Pressing and releasing the RESET button on the development board.
  2. Driving the RES pin low then letting it float (high).
  3. Downloading a new program.
  4. Disconnecting then reconnecting the power.
STOP differs from END in two respects:
  1. STOP does not put the BASIC Stamp into low-power mode. The BASIC Stamp draws just as much current as if it were actively running program instructions.
  2. The output glitch that occurs after a program has been halted with END does not occur after a program that uses STOP.

Related command: END


STOP Example

Syntax

Connect an LED and 470 Ω resistor as shown below for the demo program.

NOTE: This is written for the BS2 and will run on any of the BS2-family modules. Modify the $STAMP directive (as required) before downloading to the BS2e, BS2sx, BS2p, BS2pe, or BS2px.

' STOP.BS2
' This program is similar to SLEEP.BS2 except that the LED will not blink
' since the BASIC Stamp does not go into low power mode.  Use the circuit
' shown in the description of the SLEEP command for this example.

' {$STAMP BS2}
' {$PBASIC 2.5}

Main:
  LOW 0                                 ' turn LED on
  STOP                                  ' stop program


 STORE

Examples

Syntax: STORE ProgramSlot

Function
Designate a program slot for the READ and WRITE instructions to operate upon.

  • ProgramSlot is a variable/constant/expression (BS2p and BS2px: 0 – 7, BS2pe: 0 - 15) that specifies the program slot† to use for READ and WRITE instructions.

† Note: On the BS2pe, slots 8 - 15 are only available for data (READ and WRITE); they cannot be used to run programs.

Quick Facts
 | BS2p and BS2px | BS2pe
Program Slot Range | 0 - 7 | 0 - 15
Related Commands | READ and WRITE

Explanation
STORE tells the BS2p, BS2pe, or BS2px which program slot to use when a READ or WRITE instruction is executed. The STORE command only affects the READ and WRITE instructions.

The STORE command allows a program to access all EEPROM locations that exist on the BS2p, BS2pe, and BS2px, regardless of which program is running or which program slot is active. The READ and WRITE commands can only access locations 0 to 2047 within a single program slot. The STORE command switches the program slot that the READ and WRITE commands operate on. This short subroutine demonstrates the use of STORE:

Move_Block:
  FOR idx = 0 TO (blockLen - 1)         ' move blockLen bytes
    STORE srcSlot                       ' point to source slot
    READ srcAddr + idx, eeByte          ' read source byte
    STORE tgtSlot                       ' point to target slot
    WRITE tgtAddr + idx, eeByte         ' write byte to target slot
  NEXT
  RETURN

The default program slot that the READ and WRITE instructions operate on is the currently running program. The STORE command can be used to temporarily change this, to any program slot. The change will remain in effect until another STORE command is issued, or until another program slot is executed. The current slot used by READ and WRITE (as set by STORE) can be read from byte 127 of the Scratchpad RAM. Example:

  #SELECT $STAMP
    #CASE BS2
      pgmSlot = 0                       ' everything in slot 0
      rwSlot = 0
    #CASE BS2E, BS2SX
      GET 63, pgmSlot                   ' read current slot
      rwSlot = pgmSlot                  ' READ/WRITE slot is same
    #CASE BS2P, BS2PE, BS2PX
      GET 127, pgmSlot                  ' get slot control byte
      rwSlot = rwSlot.HIGHNIB           ' READ/WRITE in high nibble
      pgmSlot = pgmSlot.LOWNIB          ' pgm slot in low nibble
  #ENDSELECT

Related commands: READ and WRITE


STORE Example

Syntax

NOTE: This is written for the BS2p and will also run on the BS2pe and BS2px. Modify the $STAMP directive (as required) before downloading to the BS2pe or BS2px.

' STORE0.BSP
' This program demonstrates the STORE command and how it affects the READ
' and WRITE commands.  This program "STORE0.BSP" is intended to be down-
' loaded into program slot 0.  It is meant to work with STORE1.BSP and
' STORE2.BSP.  Each program is very similar (they display the current
' Program Slot and READ/WRITE Slot numbers and the values contained in the
' first five EEPROM locations.  Each program slot will have different data
' due to different DATA commands in each of the programs downloaded.

' {$STAMP BS2p, STORE1.BSP, STORE2.BSP}
' {$PBASIC 2.5}

#IF ($STAMP < BS2P) #THEN
  #ERROR "This program requires BS2p, BS2pe, or BS2px"
#ENDIF

idx             VAR     Word            ' index
value           VAR     Byte

LocalData       DATA    @0, 1, 2, 3, 4, 5

Main:
  GOSUB Show_Slot_Info                          ' show slot info/data
  PAUSE 2000
  STORE 1                                       ' point READ/WRITE to Slot 1
  GOSUB Show_Slot_Info
  PAUSE 2000
  RUN 1                                         ' run program in Slot 1
  END

Show_Slot_Info:
  GET 127, value
  DEBUG CR, "Pgm Slot: ", DEC value.NIB0,
        CR, "R/W Slot: ", DEC value.NIB1,
        CR, CR

  FOR idx = 0 TO 4
    READ idx, value
    DEBUG "Location: ", DEC idx, TAB,
          "Value: ", DEC3 value, CR
  NEXT
  RETURN

' STORE1.BSP

' {$STAMP BS2p}
' {$PBASIC 2.5}

idx             VAR     Word                    ' index
value           VAR     Byte

LocalData       DATA    @0, 6, 7, 8, 9, 10

Main:
  GOSUB Show_Slot_Info                          ' show slot info/data
  PAUSE 2000
  STORE 0                                       ' point READ/WRITE to Slot 0
  GOSUB Show_Slot_Info
  PAUSE 2000
  RUN 2                                         ' run program in Slot 2
  END

Show_Slot_Info:
  GET 127, value
  DEBUG CR, "Pgm Slot: ", DEC value.NIB0,
        CR, "R/W Slot: ", DEC value.NIB1,
        CR, CR

  FOR idx = 0 TO 4
    READ idx, value
    DEBUG "Location: ", DEC idx, TAB,
          "Value: ", DEC3 value, CR
  NEXT
  RETURN

' STORE2.BSP

' {$STAMP BS2p}
' {$PBASIC 2.5}

idx             VAR     Word                    ' index
value           VAR     Byte

LocalData       DATA    @0, 11, 12, 13, 14, 15

Main:
  GOSUB Show_Slot_Info                          ' show slot info/data
  PAUSE 2000
  STORE 0                                       ' point READ/WRITE to Slot 0
  GOSUB Show_Slot_Info
  END

Show_Slot_Info:
  GET 127, value
  DEBUG CR, "Pgm Slot: ", DEC value.NIB0,
        CR, "R/W Slot: ", DEC value.NIB1,
        CR, CR

  FOR idx = 0 TO 4
    READ idx, value
    DEBUG "Location: ", DEC idx, TAB,
          "Value: ", DEC3 value, CR
  NEXT
  RETURN

The next program, STOREALL.BSP, is not related to the previous three programs. STOREALL.BSP demonstrates the use of the STORE command to treat contiguous program slots as one block of memory (14 kBytes for the BS2p and BS2px, 30 kBytes for the BS2pe). This illustrates one of the most powerful uses of the STORE command.

NOTE: This is written for the BS2p and will also run on the BS2pe and BS2px. Modify the $STAMP directive (as required) before downloading to the BS2pe.

' STOREALL.BSP
' This program demonstrates the STORE command and how it can be used to
' "flatten" the EEPROM space for applications requiring a lot of storage.
' This program writes to EEPROM locations within program slots 1 though 7
' on the BS2p and BS2px, and 1 through 15 on the BS2pe, thus, has access
' to 14- or 30-kBytes of space.

' {$STAMP BS2p}
' {$PBASIC 2.5}

#SELECT $STAMP
  #CASE BS2, BS2E, BS2SX
    #ERROR "This program requires BS2p, BS2pe, or BS2px"
  #CASE BS2P, BS2PX
    HiSlot      CON     7
  #CASE BS2PE
    HiSlot      CON     15
#ENDSELECT

LoSlot          CON     1                       ' first slot for "flat" EE
MemSize         CON     HiSlot - LoSlot + 1 * 2048

eeAddr          VAR     Word                    ' address pointer
value           VAR     Word                    ' cell value
slot            VAR     Byte                    ' current R/W slot

Main:
  DEBUG "Flat Memory", CR,
        "---------------------", CR,
        "First Slot..... ", DEC LoSlot, CR,
        "Last Slot...... ", DEC HiSlot, CR,
        "Flat EE Size... ", DEC MemSize, CR, CR

  PAUSE 2000
  DEBUG "Writing to flat Memory...", CR
  PAUSE 1000
  FOR eeAddr = 0 TO (MemSize - 1) STEP 128      ' step through "flat" EE
    value = eeAddr * 2                          ' generate value
    GOSUB Write_Word                            ' write it
    GET 127, slot                               ' get R/W slot
    DEBUG "--> Location: ", DEC5 eeAddr, "   ",     ' show "flat" address
          "Value: ", DEC5 value, "   ",         ' show value
          "(", DEC slot.NIB1, ")", CR           ' show slot
  NEXT
  DEBUG CR

  DEBUG "Reading from flat Memory...", CR
  PAUSE 1000
  FOR eeAddr = 0 TO (MemSize - 1) STEP 128
    GOSUB Read_Word                             ' read value from EE
    GET 127, slot                               ' get W/R slot
    DEBUG "<-- Location: ", DEC5 eeAddr, "   ",
          "Value: ", DEC5 value, "   ",
          "(", DEC slot.NIB1, ")  "
     IF (value <> (2 * eeAddr)) THEN            ' verify location
      DEBUG "- Error"
    ENDIF
    DEBUG CR
  NEXT
  END

Write_Word:
  STORE (eeAddr >> 11) + LoSlot                 ' set slot
  WRITE eeAddr, Word value                      ' write value
  RETURN

Read_Word:
  STORE (eeAddr >> 11) + LoSlot                 ' set slot
  READ eeAddr, Word value                       ' read value
  RETURN


 TOGGLE

Example

Syntax: TOGGLE Pin

Function
Invert the state of an output pin.

  • Pin is a variable/constant/expression* (0 – 15) that specifies which I/O pin to set high. This pin will be placed into output mode.

* Note: Expressions are not allowed as arguments on the BS1. The range of the Pin argument on the BS1 is 0 - 7.

Explanation
TOGGLE sets a pin to output mode and inverts the output state of the pin, changing 0 to 1 and 1 to 0.

In some situations TOGGLE may appear to have no effect on a pin's state. For example, suppose pin 2 is in input mode and pulled to +5V by a 10 kΩ resistor. Then the following code executes:

Main:
  DIR2 = 0                              ' pin 2 in input mode
  PIN2 = 0                              ' pin 2 output driver low
  DEBUG PIN2                            ' show state of pin 2
  TOGGLE 2                              ' toggle pin 2
  DEBUG PIN2                            ' show state of pin 2
  END

Main:
  DIR2 = 0                              ' pin 2 in input mode
  OUT2 = 0                              ' pin 2 output driver low
  DEBUG ? IN2                           ' show state of pin 2
  TOGGLE 2                              ' toggle pin 2
  DEBUG ? IN2                           ' show state of pin 2
  END

The state of pin 2 doesn't change; it's high (due to the pull-up resistor) before TOGGLE, and it's high (due to the pin being output high) afterward. The point is that TOGGLE works on the OUTS register, which may not match the pin's state when the pin is initially an input. To guarantee that the state actually changes, regardless of the initial input or output mode, do this:

  PIN2 = PIN2                           ' make output driver match pin state
  TOGGLE 2                              ' then toggle

  OUT2 = IN2                            ' make output driver match pin state
  TOGGLE 2                              ' then toggle


TOGGLE Examples

Syntax

Connect four LEDs and four 470 Ω resistors as show below for the demo program.

' TOGGLE.BS1
' Connect LEDs to pins 0 through 3 as shown in the TOGGLE command descrip-
' tion in the manual and run this program. The TOGGLE command will treat
' you to a light show. You may also run the demo without LEDs. The Debug
' window will show you the states of pins 0 through 3.

' {$STAMP BS1}
' {$PBASIC 1.0}

SYMBOL  thePin          = B0            ' pin 0 - 3

Setup:
  DIRS = %1111                          ' make LEDs output, low

Main:
  FOR thePin = 0 TO 3                   ' loop through pins
    TOGGLE thePin                       ' toggle current pin
    DEBUG CLS, %PINS                    ' show on Debug
    PAUSE 100                           ' short delay
  NEXT
  GOTO Main                             ' repeat forever
  END

NOTE: This is written for the BS2 and will run on any of the BS2-family modules. Modify the $STAMP directive (as required) before downloading to the BS2e, BS2sx, BS2p, BS2pe, or BS2px.

' TOGGLE.BS2
' Connect LEDs to pins 0 through 3 as shown in the TOGGLE command descrip-
' tion in the manual and run this program. The TOGGLE command will treat
' you to a light show. You may also run the demo without LEDs. The Debug
' window will show you the states of pins 0 through 3.

' {$STAMP BS2}
' {$PBASIC 2.5}

thePin          VAR     Nib             ' pin 0 - 3

Setup:
  DIRA = %1111                          ' make LEDs output, low

Main:
  DO
    FOR thePin = 0 TO 3                 ' loop through pins
      TOGGLE thePin                     ' toggle current pin
      DEBUG HOME, BIN4 OUTA             ' show on Debug
      PAUSE 250                         ' short delay
    NEXT
  LOOP                                  ' repeat forever
  END


 WRITE

Examples

Syntax [image]: WRITE Location, DataItem
Syntax [image]: WRITE Location, {Word} DataItem {, {Word} DataItem ...}

Function
Write DataItem into Location in EEPROM. On the BS2 family, multiple DataItems may be written to consecutive locations.

  • Location is a variable/constant/expression* (0 - 255 on BS1, 0 - 2047 on all other BASIC Stamp modules) that specifies the EEPROM address to write to.
  • DataItem is a variable/constant/expression* specifying the value to be stored.

* Note: Expressions are not allowed as arguments on the BS1.

Quick Facts
 | BS1 | BS2 | BS2e and BS2sx | BS2p, BS2pe, and BS2px
Range of EEPROM locations | 0 to 255 | 0 to 2047 | 0 to 2047 | 0 to 2047 (see notes below)
Maximum number of writes per location | 10 million | 10 million | 100,000 | 100,000
Special Notes | N/A | N/A | WRITE only works with current program slot on BS2e and BS2sx. | WRITE works with any program slot as set by the STORE command.

Explanation
The EEPROM is used for both program storage (which builds downward from address 255 on BS1, 2047 on all other BASIC Stamps) and data storage (which builds upward from address 0). The WRITE instruction stores a value to any EEPROM address. Any location within the EEPROM can be written to (including your PBASIC program's locations) at run-time. This feature is mainly used to store long-term data to EEPROM; data stored in EEPROM is not lost when the power is removed.

The following WRITE command stores the value 245 at location 100:

  WRITE 100, 245

The EEPROM is organized as a sequential set of byte-sized memory locations. With the BS1, the WRITE instruction only stores byte-sized values into EEPROM. This does not mean that you can't write word-sized values, however. A word consists of two bytes, called a low-byte and a high-byte. If you wanted to write a word-sized value, you'll need to use two WRITE commands and a word-size value or variable (along with some handy modifiers). For example:

SYMBOL  value   = W1                    ' word-sized variable
SYMBOL  valLo   = B2                    ' B2 is the low-byte of W1
SYMBOL  valHi   = B3                    ' B3 is the high-byte of W1

Main:
  value = 1125

  WRITE 0, valLo
  WRITE 1, valHi
  END

value   VAR     Word

Main:
  value = 1125
  WRITE 0, value.LowByte
  WRITE 1, value.HighByte
  END

When this program runs, the two WRITE commands will store the low-byte and high-byte of the number 1125 into EEPROM.

With the BS2 family, the Word modifier can be used to write 16-bit values. The low byte of the value will be written to Location, the high byte will be written to Location + 1 ("Little Endian" ).

' {$PBASIC 2.5}

value   VAR     Word
value2  VAR     Word
addr    VAR     Word                    ' EEPROM address
test    VAR     Byte                    ' test byte read back

Main:
  value = $1125
  value2 = $2003
  WRITE 0, Word value, Word value2      ' write value at locations 0 & 1
                                        '  and value2 at locations 2 & 3

  FOR addr = 0 TO 3                     ' display "25 11 03 20"
    READ addr, test
    DEBUG HEX2 test, " "
  NEXT

  END

EEPROM differs from RAM, the memory in which variables are stored, in several respects:

  1. Writing to EEPROM takes more time than storing a value in a variable. Depending on many factors, it may take several milliseconds for the EEPROM to complete a write. RAM storage is nearly instantaneous.
  2. The EEPROM can only accept a finite number of write cycles per location before it wears out. The table above indicates the guaranteed number of writes before failure. If a program frequently writes to the same EEPROM location, it makes sense to estimate how long it might take to exceed the guaranteed maximum. For example, on the BS2, at one write per second (86,400 writes/day) it would take nearly 116 days of continuous operation to exceed 10 million.
  3. The primary function of the EEPROM is to store programs (data is stored in leftover space). If data overwrites a portion of your program, the program will most likely crash.

Check the program's memory map to determine what portion of memory your program occupies and make sure that EEPROM writes cannot stray into this area. You may also use the DATA directive on the BS2, BS2e, BS2sx, BS2p, and BS2pe to set aside EEPROM space.

On the BS1, location 255 holds the address of the last instruction in your program. Therefore, your program can use any space below the address given in location 255. For example, if location 255 holds the value 100, then your program can use locations 0-99 for data.

On other BASIC Stamps, you'll need to view the Memory Map of the program before you download it, to determine the last EEPROM location used.

On the BS2p, BS2pe and BS2px the READ and WRITE commands can affect locations in any program slot as set by the STORE command. See the STORE command for more information.

Related commands: READ, STORE ( [image] ), and PUT ( [image] )


WRITE Example

Syntax
' WRITE.BS1
' This program writes a few bytes to EEPROM and then reads them back out
' and displays them in the Debug window.

' {$STAMP BS1}
' {$PBASIC 1.0}

SYMBOL  addr            = B2            ' address
SYMBOL  value           = B3            ' value

Main:
  WRITE 0, 100                          ' write some data to locations 0 - 3
  WRITE 1, 200
  WRITE 2, 45
  WRITE 3, 28

Read_EE:
  FOR addr = 0 TO 3
    READ addr, value                    ' read value from address
    DEBUG #addr, ": ", #value, CR       ' display address and value
  NEXT
  END

NOTE: This is written for the BS2 and will run on any of the BS2-family modules. Modify the $STAMP directive (as required) before downloading to the BS2e, BS2sx, BS2p, BS2pe, or BS2px.

' WRITE.BS2
' This program writes some data to EEPROM and then reads them back out
' and displays the data in the Debug window.

' {$STAMP BS2}
' {$PBASIC 2.5}

idx             VAR     Byte            ' loop control
value           VAR     Word(3)         ' value(s)

Main:
  WRITE 0, 100                          ' single byte
  WRITE 1, Word 1250                    ' single word
  WRITE 3, 45, 90, Word 725             ' multi-value write

Read_EE:
  FOR idx = 0 TO 6                      ' show raw bytes in EE
    READ idx, value
    DEBUG DEC1 idx, " : ", DEC value, CR
  NEXT
  DEBUG CR

  ' read values as stored

  READ 0, value
  DEBUG DEC value, CR
  READ 1, Word value
  DEBUG DEC value, CR
  READ 3, value(0), value(1), Word value(2)
  FOR idx = 0 TO 2
    DEBUG DEC value(idx), CR
  NEXT
  END


 XOUT

Example

Syntax: XOUT Mpin, Zpin, [House\Command {\Cycles} {, House\Command {\Cycles}...}]

Function
Send an X-10 power-line control command (through the appropriate power-line interface).

  • Mpin is a variable/constant/expression (0 - 15) that specifies the I/O pin to output X-10 signals (modulation) to the power-line interface device. This pin will be set to output mode.
  • Zpin is a variable/constant/expression (0 - 15) that specifies the I/O pin that inputs the zero-crossing signal from the power-line interface device. This pin will be set to input mode.
  • House is a variable/constant/expression (0 - 15) that specifies the X-10 house code (values 0 - 15 representing letters A through P).
  • Command is a variable/constant/expression (0 - 30) that specifies the command to send. Values 0 - 15 correspond to unit codes 1 - 16. Other commands are shown below.
  • Cycles is an optional variable/constant/expression (1 - 255) specifying the number of times to transmit a given key or command. If no I>Cycles entry is used, XOUT defaults to two. The Cycles entry should be used only with the DIM and BRIGHT command codes.

Quick Facts
 | BS2, BS2e, BS2sx, BS2p, BS2pe, and BS2px
Compatible power-line interfaces | PL-513 and TW-523
Special Notes | The XOUT command will stop the BASIC Stamp program until it is able to send the transmission. If there is no AC power to the power-line interface, the BASIC Stamp program will halt forever.

Explanation
XOUT lets you control appliances via signals sent through household AC wiring to X-10 modules. The appliances plugged into these modules can be switched on or off; lights may also be dimmed. Each module is assigned a house code and unit code by setting dials or switches on the module. To talk to a particular module, XOUT sends the appropriate house code and unit code. The module with the corresponding code listens for its house code again followed by a command (on, off, dim, or bright).

X-10 signals are digital codes imposed on a 120 kHz carrier that is transmitted during zero crossings of the AC line. To send X-10 commands, a controller must synchronize to the AC line frequency with 50 ms precision, and transmit an 11-bit code sequence representing the command.

XOUT interfaces to the AC power-line through an approved interface device such as a PL-513 or TW-523, available from Parallax or X-10 dealers. The hookup requires a length of four-conductor phone cable and a standard modular phone-base connector (6P4C type). Connections are shown below.

Command | Value | Function
UnitOn | %10010 | Turn on the currently selected unit.
UnitOff | %11010 | Turn off the currently selected unit.
UnitsOff | %11100 | Turn off all modules in this house code.
LightsOn | %10100 | Turn on all lamp modules in this house code.
Dim | %11110 | Reduce brightness of currently selected lamp.
Bright | %10110 | Increase brightness of currently selected lamp.

Note: In most applications, it's not necessary to know the code for a given X-10 instruction. Just use the command constant (UnitOn, Dim, etc.) instead. But knowing the codes leads to some interesting possibilities. For example, XORing a UnitOn command with the value %1000 turns it into a UnitOff command, and vice-versa. This makes it possible to write the equivalent of an X-10 "toggle" instruction.

Here is an example of the XOUT instruction:

Mpin    PIN     1                       ' modulation pin
Zpin    PIN     0                       ' zero-cross input

HouseA  CON     0                       ' House code A = 0
Unit1   CON     0                       ' Unit code 1 = 0

Main:
  XOUT Mpin, Zpin, [HouseA\Unit1]       ' Get unit 1's attention..
  XOUT Mpin, Zpin, [HouseA\UnitOn]      ' ..and tell it to turn on
  END

You can combine those two XOUT instructions into one like so:

  XOUT Mpin, Zpin, [HouseA\Unit1\2, HouseA\UnitOn]

Note that to complete the attention-getting code HouseA\Unit1 we tacked on the normally optional cycles entry \2 to complete the command before beginning the next one. Always specify two cycles in multiple commands unless you're adjusting the brightness of a lamp module.

Here is an example of a lamp-dimming instruction:

Mpin    PIN     1                       ' modulation pin
Zpin    PIN     0                       ' zero-cross input

HouseA  CON     0                       ' House code A = 0
Unit1   CON     0                       ' Unit code 1 = 0

Main:
  ' Get unit 1's attention
  XOUT Mpin, Zpin, [HouseA\Unit1]
  ' Dim halfway
  XOUT Mpin, Zpin, [HouseA\UnitOff\2, HouseA\Dim\10]
  END

The dim/bright commands support 19 brightness levels. Lamp modules may also be turned on and off using the standard UnitOn and UnitOff commands. In the example instruction above, we dimmed the lamp by first turning it completely off, then sending 10 cycles of the Dim command. This may seem odd, but it follows the peculiar logic of the X-10 system.


XOUT Example

Syntax

NOTE: This is written for the BS2 and will run on any of the BS2-family modules. Modify the $STAMP directive (as required) before downloading to the BS2e, BS2sx, BS2p, BS2pe, or BS2px.

' XOUT.BS2
' This program--really two program fragments--demonstrates the syntax and
' use of the XOUT command. XOUT works like pressing the buttons on an X-10
' control box; first you press one of 16 keys to identify the unit you want
' to control, then you press the key for the action you want that unit to
' take (turn ON, OFF, Bright, or Dim). There are also two group-action keys,
' Lights ON and All OFF. Lights ON turns all lamp modules on without
' affecting appliance modules. All OFF turns off all modules, both lamp and
' appliance types.  Connect the BASIC Stamp to a power-line interface as
' shown in the XOUT command description in the manual.

' {$STAMP BS2}
' {$PBASIC 2.5}

Mpin            PIN     1               ' modulation pin
Zpin            PIN     0               ' zero-cross input

HouseA          CON     0               ' House code A = 0
Unit1           CON     0               ' Unit code 1 = 0
Unit2           CON     1               ' Unit code 2 = 1

' This first example turns a standard (appliance or non-dimmer lamp) module
' ON, then OFF. Note that once the Unit code is sent, it need not be repeated
' --subsequent instructions are understood to be addressed to that unit.

Main:
  XOUT Mpin, Zpin, [HouseA\Unit1\2]     ' select Unit1 (appliance module)
  XOUT Mpin, Zpin, [HouseA\UNITON]      ' turn it on

  PAUSE 1000                            ' wait one second

  XOUT Mpin, Zpin, [HouseA\UNITOFF]     ' then turn it off

' The next example talks to a lamp module using the dimmer feature. Dimmers
' go from full ON to dimmed OFF in 19 steps. Because dimming is relative to
' the current state of the lamp, the only guaranteed way to set a predefined
' brightness level is to turn the dimmer fully OFF, then ON, then dim to the
' desired level.

  XOUT Mpin, Zpin, [HouseA\Unit2\2]     ' select Unit2 (lamp module)

' This example shows the use of the optional Cycles argument.  Here we DIM
' for 10 cycles.

  XOUT Mpin, Zpin, [HouseA\UNITOFF\2, HouseA\DIM\10]
  STOP