BASIC Stamp RS232 & modem

(c) 1998, 2002EME Systems, Berkeley CA U.S.A.
<stamp index> <home>

Contents: (updated 11/13/2010)

Baudmode table


The baudmodes is a 16 bit value that shows up after the first comma in SERIN and SEROUT commands. The low 13 bits (bit 0 to bit 12) specify the baud rate itself, while bits 13, 14 and 15 are modifiers that turn on or off certain modes of the serial operation. The values shown in the following table in the left-most column are the common baud rates. The entries in the other columns are the baudmode parameters in both HEX and Decimal to use with the BS2 and with the higher speed BS2sx and BS2p. The modifiers for other modes come after the table. There is one column for the BS2, BS2e and BS2pe, and a separate column for the BS2sx, the BS2P, which run at a faster clock rate. The chips can operate at non-standard baud rates too. The formulae relating the baudmode parameter to the baud rate is also given below.

Baudmode value required to get different baud rates on the Stamp
Baud rate
BS2, BS2e, BS2pe
BS2sx, BS2p


lowest BS2 rate





lowest BS2sx rate









highest BS2 rate









highest BS2sx rate

  • to get 7 bit, even parity
    • add $2000 (8192) for SEROUT and SERIN
    • bit 13=0 specifies 8 bit, no parity
    • bit 13=1 specifies 7 bit, even parity
  • to get inverted mode
    • add $4000 (16384) for SEROUT and SERIN
    • bit 14=0 specifies noninverted, resting high
    • bit 14=1 specifies inverted, resting low
    • The $4000 factor also affects the flow control pin, when used.

inverted mode rests low, goes high to send, and needs a pulldown resistor in open baudmode

noninverted mode rests at a high level and goes low to send, and needs a pullup resistor in open baudmode

  • to get open mode
    • add $8000 (32768) for SEROUT only
    • bit 15=0 specifies driven both high and low
    • bit 15=1 specifies resting state passive

The output from P16 (the system serial port) is unaffected by the inverting or noninverting $4000. The resting level is always low, driven high when sending data. The $4000 does however still affect the polarity of the flow control pin, when used.


BS2,BS2e, BS2pe formula



BS2sx, BS2p formula



BS2px formula

Example pattern:


$55 in binary is %01010101. RS232 transmits the LSB (least significant bit) first. The RS232 byte is preceded by a start bit, and finishes with at least one stop bit. The following diagram shows transmission of $55, then a short pause, then transmission of $00, then an 8 millisecond pause, then the $55 again, and then $ff. The time scale is about 2400 baud, where it takes about 4 milliseconds to transmit 1 byte plus the start and stop bit.

$55 $0 8 milliseconds $55 $FF etc..


RS232 is an "inverted" logic, so logical "1" is represented as a low level, and a logical "0" is a high level. The line rests at a "1" level between bytes, called "marking" (from early days when a pen stayed on the paper making a "mark", and lifted for a "space"). The start bit is a high level, followed by the least significant bit and so on up to the most significant bit, and then the stop bit. The stop bit is a low level amd it is at least one bit period long, but it may extend for any longer period. Note that the bit pattern for the $0 is %00000000 amd and is high for 9 bit periods including the stop bit. The bit patter for $FF is %11111111, and the electrical signal simply looks like a start bit standing by itself, because the stop bit and the resting level are also "1"s at the low level.

A noninverted logic will flip all of these levels over, so that logical 1 is represented by a high level, and logical 0 by a low level.


Unwanted resets from noise on the serial port ATN line


Unwanted resets can occur when there are noise sources like motors or radios near the Stamp. Also, these resets can occur when the serial programming or data cable remains connected. Noise is coupled in through the sensitive ATN signal on physical pin 3 of the Stamp, pin 4 on the DB9 connector.

I always put a 3.3kohm resistor and a 0.1uF capacitor in parallel with the ATN input. That's BS2 pin 3 to ground. found on pin 4 of the stamp. This usually cures the unwanted "reset" problem. It lowers the pin's input impedance from 20k down to 3k and filters short spikes. A capacitor in series with ATN can still be used to reset or wake up the system.

  DB9S ---||-------;------/\/\/---;
pin4 0.22 | 3.3k |
optional |------||------|
| 0.1 |
atn ground

SERIN and SEROUT, flow control and timing.


The SERIN and SEROUT commands on the BASIC Stamp 2 are without a doubt the most involved commands available in the instruction set. This note deals with several issues that arise in implementing the serial port. A lot of this material is not explained at all in the Stamp manuals, especially the timing issues. Difficulties with timing on the serial ports can be one of the most frustrating aspects of developing stamp applications. It usually comes down to quantitative questions of how fast data can be received, recognized, processed and transmitted.

The BASIC Stamp II allows you to choose from a wide range of standard and non-standard baud rates.

BS2 minimum 122 baud at baudmode=8191 ($1fff)
BS2SX minimum 304 baud
BS2 maximum 50 kbaud at baudmode=0 ($0000)
BS2SX maximum 125 kbaud

BS2 formula baudmode = 1000000/baud - 20
BS2SX formula baudmode = 2500000/baud - 20

• add $2000 for 7 bits even parity
• add $4000 for inverted data
• add $8000 for open (needs pullup or pulldown) (SEROUT only)

The BS2SX formula was incorrect in some of the early documentation.

Use of flow control top

The SEROUT and SERIN commands have an option to assign a pin for flow control.. Flow control is useful when two BS2 stamps have to talk to one another, so that one talks only when the other is ready to listen. This flow control can be combined with timeouts to implement a system where both stamps can be busy doing something else most of the time. Those stamps can then communicate, despite the stamp's lack of interrupts or a serial port buffer. The interface takes an extra wire for the flow control, but the code requirements on the stamp end are minimal. The flow control is also useful when the stamp has to send data to a desktop PC or peripheral. RST/CTS or DTR/DSR Hardware flow control can prevent data loss.

SEROUT flow control <top>


serout 15\14,$4054,["AB"]

P15 is an output, resting at a low level. P14 is an input. So long as p14 is low, the serout command pauses and does not send anything. But when p14 goes high, then the serout command sends data letter A. It first sends the start bit, a high level, and the bits of the ascii code 65, lsb first, and then a level low stop bit. If p14 is still high, the serout command immediately sends the letter B. If p14 is low, it waits until p14 goes high again to send the letter B. The delay from the time p14 goes high to the leading edge of the start bit is about 10 microseconds. Once the start bit is sent, the serout command is committed to send the entire byte, regardless of the status of pin 14. Variations:

serout 15\14,$54,["AB"]

This differs from the above because the polarity is reversed. The data pin (p15) rests at a high level, and the flow is paused so long as the level on flow pin (p14) is also high. But when p14 goes low, the byte transmission starts about 10 microseconds later. Another variation:

serout 15\14,$54,6000,bailout,["A"]

rests with p15 at a high level, and waits until p14 goes low to send the data. But if p14 does not go low within 6 seconds, the command times out and branches to the label "bailout".

Here is another variation, this time using the system serial port on physical pins 1 and 2, addressed as p16:

serout 16\14,$4054,60000,bailout,["A"]

The system serial port has a built-in inverter and rests at a low (-5 volts) level. It waits until input p14 goes high before sending the data, "A". Data flow is enabled so long as p14 is high and it it inhibited if p14 is low. If p14 does not go high within one minute, the command times out and branches to the label "bailout". If baudmode=$54 instead of $4054 as shown, then the resting state of pin 1 is not affected, but the sense of the flow control pin is inverted so that data flow is enabled when low and inhibited when high. On regular pins, the baudmode affects the sense of both the flow control pin and the data pin; on the system port p16 only the sense of the flow control is affected.

Serout flow control and hardware handshaking with a PC <top>

The HP200LX is a palmtop computer that can use RTS-CTS handshaking. The RTS line (Request to Send) is an output from the HP200LX, and it can be connected BS2 p14 (for example) for flow control. RTS-CTS handshaking has to be enabled in the telecomm program. The RTS output from the HP200LX is normally high (+5 volts) when the HP is ready to receive data, but it goes low (-5 volts) when the HP temporarily cannot accept more data. The connection of RTS to p14 (via a protection resistor) prevents overflow of the HP200LX input buffer when transferring large amounts of data. This is more of a concern when using the BS2SX with its much faster processor. With a direct connection (via a resistor) use the $4054 form of the baudmode.

SERIN flow control <top>

On the other hand, with the SERIN command, the flow control pin is an output. When the BS2 encounters a serin instruction, it sets the level on fpin to "ready". As soon as it detects an incoming character, it sets fpin back to "not ready", so that the device that is sending data will not pile up characters end to end. If the one serin instruction has to receive several bytes, you will see the fpin blip back and forth several times. When the serin instruction is finished execution, the fpin is left in the "not ready" state. Thus further data transmission is quenched until another serin instruction is ready for it. Your program can go off and do something with the data and then come back to get more without danger of losing characters. Examples:

serin 15\14,$54,[zork]

P15 is an input, which should be resting at a high (+5 volts) level provided by an external source. When the program hits this command, p14 is set low automatically by the BS2 to signal to the external device that the command is ready to receive data. The external device should then send the start bit (a low level) followed by the data that is put into the variable zork. P14 goes back high about halfway through the first data bit. After the byte is received, p14 remains high until the next time this instruction is encountered. There may be additional SERIN instructions that use this same dpin/fpin. Note that it is possible for other instructions in the program to change the state of p14 and p15 , and this may have undesired effects--it is up to the programmer to know what is being done. Variation:

serin 15\14,$54,[zork,zark]

Here, there are two units of data. After serin has received the first one, zork, and stored it, p14 goes low again briefly to signal to the external device to send the next byte, zark. Another variation:

serin 15\14,$4054,[zork]

The polarities are reversed, due to the $4054 in place of $54. The input on p15 should be resting at a low level, and p14 will be a low output from the stamp to signal to the external circuit that the Stamp is not ready to receive data. When this Serin is executed, p14 goes high to signal "ready".

Here is another variation, where the system serial port on physical pin 2 of the BS2 chip are used as the input. The port is addressed as p16 in the SERIN command. It has a couple of considerations that distinguish it perform from the standard BS2 pins, p0 to p15.

serin 16\14,$4054,6000,bailout,[zork]

This differs because of the reference to system port p16. The input marks time at a low (-5 volt) level. p14 is an output, and rests at a low level to signal that the command is not ready to accept data. When the command is executed, it sets p14 high to signal to the external system that it is ready to accept data. In this example, the command waits 6 seconds to receive "zork" before jumping to bailout.

If the baudmode in this last example is changed to $54, then the sense of physical pin 2 is not affected, but the sense of p14 is inverted. It rests high to signal "not ready" and goes low to signal "ready".

In RS232 sttandards, a high level on a handshaking pin usually signals the "ready" state.

The BS2 does this handshaking on a byte by byte basis. Some external computers may send several bytes before they even check the status of their handshaking lines. Such devices will overwhelm the BS2 with too much data. One solution to that is to use an external buffer such as the MAX3100.

Master-Slave scenarios <top>

Stamp to stamp communication, and communication between a stamp and a custom-designed peripheral PIC, are the areas where this form of handshaking shines.

  serout 15\14,$54,60,bailout,["A"]      ' code on first BS2, sends data
| ^
| | signal directions
v |
serin 15\14,$54,2,nodata,[zork] ' code on second BS2, receives data

Here are a couple of scenarios in which this connection might be used. One BS2 is a master, and the second BS2 is a slave. The master commands, the slave responds. Between commands, the slave goes about other business, such as counting events or doing things. But frequently it must check to see if the master wants to talk. The master signals that it wants to talk by raising a flow control flag.

Master/slave scenario #1

A simple form of this exchange can occur if there is only one command from the master, a trigger really, which means effectively, "send me data now". Here is code for the master:

' master code fragment
high 14 ' to inhibit transmissions from the slave
' do stuff
' now request data from the slave
serin 15\14,$54,100,notalk,[datas]
' now have data, do something
goto loop ' repeat

' come here if the slave did not respond
' usually an error condition
goto loop '------

and on the slave:

' slave code fragment
' do stuff
' now check if master wants to talk
serout 15\14,$54,2,loop,[datas]
' come here when datas have been sent
' reinitialize accumulators
goto loop

In the above the flow control output serves as the sole command from the master to the slave. When p14 goes low, that means, "send data now"

When the master executes the SERIN command, p14 goes low to signal that the master is ready to receive data. That is the trigger for the slave to send its data from the SEROUT command. Notice that the slave hits the SEROUT command often as part of its main loop, even when the master does not want any data. And mostly it just times out, without sending any data, and continues with its main loop. The timeout is very short, 1 millisecond, so the slave does not waste much time waiting for the master. But it executes the SEROUT command often enough so as not to keep the master waiting for too long.

The master can wait for the slave for up to a tenth of a second in the above. This delay has to be set longer than the time it takes for the slave to finish the loop. The timeout assures that the master program will keep running even if the slave is disconnected for some reason. It is always a good idea in programming to leave an out when things get disconnected.

Note: the delay parameter is set to 2 in the above slave program, and yet I say that the delay is one millisecond. This is a quirk in the BS2 timing.

Master/slave scenario #2

Here is a more complicated situation. The command is now more complicated than just "send data now". Now the master needs to transmit one or more command bytes, and the slave has to decode the command and respond accordingly. The two stages of the exchange, the command and the response, are regulated by flow control flags. Here is a fragment of the program on the master:

' master program fragment
' initialize
high 15 ' set data line to high level
' do stuff ...
' now time to talk to slave
serout 15\14,$54,6000,noslave,[commands]
serin 14\15,$54,6000,noslave,[datas]
' now have data returned by the slave
' do something with it
goto loop:

' come here if the slave did not respond
' usually an error condition

And here is the fragment of the program on the slave:

' slave program to go with the above master program fragment
' initialize
high 14 ' to inhibit transmissions from the master
' do waiting loop stuff
' now listen to see if master wants to talk
serin 15\14,$54,2,loop,[commands]
' come here if there is talk
' decode commands and do stuff and get datas
serout 14\15,$54,6000,notalk,[datas]
' do more stuff to reset for next round
goto loop

' come here if the master did not respond
' usually an error condition
goto loop

When the master executes its SEROUT command, it has to wait for the slave to get around to its SERIN command. When the slave hits its SERIN, it sets its p14 low to signal that it is ready for data, and that low level is transmitted to the SEROUT command waiting on the master and is interpreted as a "ready" amd causes the master to send the commands. After the master sends the commands, p15 is left in a high state. Now on to the SERIN command on the master and the SEROUT command on the slave. The master executes the SERIN command, which causes p15 to go low to signal that the master is ready to receive data. When the slave executes its SEROUT command, it will either find that the master is ready to receive immediately, or else the slave will have to wait around briefly for the master to be ready. After the datas are sent, the two stamps go back to their main loops. The p14 is left in a high state which inhibits transmission of further commands from the master, until the slave is ready to receive them. The time-outs are arranged to be longer than the delays in the loops and processing.

SEROUT setup and execution times <top>

It takes a certain amount of time for the BS2 to read in a SEROUT command and interpret it, before it starts actually sending any data. If the SEROUT statement includes several bytes to be transmitted, there are further delays between the individual bytes, beyond the usual 1 minimal stop bit. Similarly, for the SERIN command, there is a delay after the program hits the commnand, before it is actually ready to receive data. And if the SERIN includes modifiers like SKIP and WAIT and a sequence of variables, then there are interbyte delays when the BS2 is not ready to receive. Data arriving during these intervals will will misframe and produce garbage data, or fail all together. This reception problem is acute at 4800 baud and above. These shortcomings can cause a huge amount of frustration in developing applications for the BS2. It sometimes helps to know the exact timing and tradeoffs.

If you control both ends of the communication, then you can probably adjust the timing to achieve reliable communication. But sometimes data comes from intruments like GPS receivers or scientific instruments or from a third-party program running on a PC, and you must take the data as it comes. If the instrument will accept hardware handshaking (flow control), this may resolve the problem. Or you may have an option to reduce the baud rate on the other end, or to pace the transmission of bytes, say by specifying two stop bits instead of one. The BS2SX running at 50mhz is generally 2.5 times faster than the BS2 in all these timings. If you run up against the proverbial brick wall and cannot use one of the tricks described here, then you may have to resort to an external UART. The MAX3100 from Maxim is a UART that is specifically designed to buffer asynchronous serial data for microprocessors like the BASIC Stamp.

This difficulty is seen for example when you want to send a command to an external instrument, and then receive back a response. It takes about 500 microseconds from the end the SEROUT stop bit up to the point where the SERIN command is ready to accept data. For example,

serout 5,84,["T"]
serin 6,84,1000,nodata,[temp]

The serout transmits the letter "T", but after that, it takes 500 microseconds before the serin command is ready to receive a response. If the response comes sooner than that, you are out of luck. The same command running on the BS2SX at 50mhz requires 200 microseconds for the same setup. The delay is longer if the input list is more complicated. For example, the setup time is 600 microseconds before the serin is ready to receive a string

serout 5,84,["T"]
serin 6,84,1000,nodata,[str zoom\6]

This format, using "str zoom\6" is faster in other respects, for example it can easily receive the 6 bytes at 9600 baud flat out.

The opposite problem occurs when the BS2 has to receive a command and then send back a response:

serin 5,84,[x]
serout 6,84,[x]

After the serin command receives the value of x, it takes 950 microseconds before the serout command starts transmitting its response. The device on the other end may not be willing to wait so long.

Here are some SEROUT timings obtained from variations on the following program. The signals from P13 and P14 were observed on an oscilloscope to determine the times. The results are approximate, determined "by eyeball":

pulsout 13,4 ' P13 to 'scope trigger
serout 14\15,$54,1,loop,[x] ' P14 to 'scope channel A
goto loop

Here are the forms of the serout command with the associated delay.

serout 14,$54,[x]             ' 920 microseconds
serout 14,$54,0,[x] ' 980 microseconds (pacing)
serout 14\15,$54,[x] ' 480 microseconds (flow)
serout 14\15,$54,2,loop,[x] ' 650 microseconds (flow & timeout)

The most suprising result above is that the use of the flow control pin interprets faster than the form without flow control. The times with a constant in place of the variable are marginally faster, by about 10 microseconds. The setup time is the same if there are additional items in the list to transmit:

serout 14\15,$54,[x,y]        ' 480 microseconds (more data)

The numerical modifiers really slow things down, to get out the first byte:

serout 14\15,$54,[hex1 x]    ' 900 microseconds  (modifier)
serout 14\15,$54,[hex2 x] ' 1000 microseconds (modifier)
serout 14\15,$54,[hex3 x] ' 1100 microseconds (modifier)
serout 14\15,$54,[hex4 x] ' 1200 microseconds (modifier)
serout 14\15,$54,[hex x] ' 2500 microseconds (modifier)
serout 14\15,$54,[dec x] ' 3500 microseconds (modifier)

serout 14,$54,[hex2 x] ' 1500 microseconds (modifier, no flow)

The suprise in the above is how much time it takes to format the data, which evidently occurs before anything is transmitted. The forms that do not specify a number of digits take especially long. The forms with flow control take 500 microseconds less than the forms without flow control.

The fastest way to send a string of bytes is through an array. As above, this is the interpretation and processing time, up to the first start bit.

serout 14\15,$54,[str x\3]      ' 510 microseconds (string array)
serout 14,$54,[str x\3] ' 950 microseconds (string array)

The equivalent times for the BS2SX operating at 50 mhz are about 2.5 x faster based on direct oscilloscope operation:

serout 14,$54,[x]             ' 375 microseconds  BS2SX
serout 14\15,$54,[x] ' 190 microseconds (flow) BS2SX
serout 14\15,$54,2,loop,[x] ' 260 microseconds (flow & timeout) BS2SX


The above discussion had to do with the delays before the SEROUT starts to send data. It also happens that there are short delays between the individual bytes that are sent. In the SEROUT command, the BS2 does not send the characters as fast as possible. There is a slight pause between the characters that amounts to extra stop bits. The extra delay allows one stamp to receive data perfectly from another stamp even at high baud rates. Stamps may have trouble receiving high speed data from other computers and instruments that transmit the data with the bytes "head to tail" without any delays. The following illustrates some of the interbyte timings I've seen on the oscilloscope screen: The times given are the extra, from the end of the stop bit on one byte to the beginning of the start bit on the next byte.

x var byte(6)
y var word
y0 var y.byte0
a var byte
b var byte
serout 5,84,[str x\6] '150 microseconds
serout 5,84,[str y0\2] '150 microseconds
serout 5,84,[a,b] '250 microseconds
serout 5,84,[hex4 y] '180 microseconds
serout 5,84,[x(0),x(1),x(2)] '350 microseconds

The form using the array is fastest in this respect, sending bytes rapidly after one another. The other forms seem to incur small processing delays. At 9600 baud, one stop bit is about 100 microseconds. The above additional delays amount to an extra 1.5 to 3.5 stop bits. The addititional delays amount to 7 to 18 stop bits at 50 kbaud. The delays are insignificant at lower baud rates.

One form of the SEROUT command allows pacing, extra time inserted deliberately between bytes transmitted so that a slow process on the other end can receive them without choking on too rapid delivery.

serout 14,$54,2,[x\6]           ' adds 2 millisecond pacing

The pacing delay is inserted before the first character is sent, and then between subsequent characters. E.g., the delay before the first character is transmitted here is 2980 microseconds, and then 2 milliseconds between subsequent bytes. The BS2SX also interprets the pacing delay properly as 2 milliseconds, but the setup delay is shorter, so it is 2380 microseconds to the first byte out, and 2000 microseconds between subsequent bytes.

The timeout parameter is in units of milliseconds on the vanilla BS2, but in units of 0.4 milliseconds on the BS2SX:

serout 14\15,$54,td,err,[x\6] ' timeout
' td millisecond on the BS2
' td*0.4 millisecond on the BS2SX
' see mote on timeout bug, below

SERIN setup and execution times <top>

Bad reception of serial data at 9600 baud and above <top>

When one stamp sends data at 9600 baud, say,

serout 5,84,["hello",0]       ' sends hello and byte 0

there is a slight delay between the bytes of the string, amounting to two and one half stop bits, as detailed above in connection with the serout command. Another stamp can receive that data using,

serin 6,84,[str zoom\5,x]      ' receives hello and also x


serin 6,84,[wait ("hello"),x]  ' waits to receive hello, then x


serin 6,84,[skip 5,x]          ' skips hello then receives byte x

There is no trouble when sending from stamp to stamp, because of the extra padding on the serout end. But when serin has to receive the data at 9600 or above from a device that sends the 9600 full tilt, with only one stop bit and no extra, the data may come out jumbled, or the instruction may lock up. The way to get around this are to lower the baud rate or add pacing on the transmitter end (not always possible). Or add a hardware buffer to the stamp input (not often practical). Or rethink the problem. The fastest way for the stamp to receive a string of data is, for example, via the [str zoom\5] syntax. The stamp can receive even at full tilt 9600 baud with that simple syntax. That will be a lot faster than [a,b,c,d,e], received as separate bytes. The serin command will choke on full-tilt 9600 or faster baud if qualifiers such as WAIT or SKIP are added to the mix.

The timing data for the serin command comes from variations on the following program:

pulsout 13,4 ' P13 to 'scope trigger
serin 15\14,$54,2,loop,[x] ' P14 to channel A
goto loop

When P15 is held low, P14 goes high when SERIN is ready to receive input data. The command times out and the loop repeats. Data can be input to the command to test interbyte intervals. P14 goes high between bytes to indicate the not-ready condition. The effect of removing flow control can be measured indirectly by monitoring the total loop time.

' setup time, before ready to receive data
serin 15\14,$54,2,loop,[x] ' with flow
' 560 microseconds for BS2
' 225 microseconds for BS2SX

serin 15,$54,2,loop,[x] ' (without flow)
' 480 microseconds for BS2
' 190 microseconds for BS2SX

serin 6,84,1000,nodata,[str zoom\6] ' 600 microseconds for BS2
' 240 BS2SX
Bug in the serial timeout parameter <top>

I stumbled :-( on an interesting anomoly in the SERIN timeout parameter. Consider the time-out parameter, td:

serin 6\7,84,td,nodata,[temp] 

I once thought, based on the BS2 manual, that the timeout delay, td, is given directly in milliseconds. But if you look at it on a scope, you find that the timeout delay is actually equal to (td-1) milliseconds. E.g. to get a 1 millisecond delay, you should use td=2. Strange things happen when td=1 and when td=0.

if td=1, then the flow control pin, p7, is always high (not ready), but the SERIN command instantly times out, without waiting for data.

If td=0. then the flow control pin, p7, is always low (ready), but the SERIN command instantly times out, without waiting for data.

<top> <index> <home> logo<>