This is a reprint from the Stamp Project of the Month, June 2000. Check out this month's project. Also, check out our full line of peripheral chips for microcontrollers -- floating point, I/O expansion, PS/2 keyboard interface, PWM, and more. If you want a handy way to connect RS-232 to a breadboard, have a look at http://www.al-williams.com/awce/rs1.htm.
Many Stamp projects require RS-232 connections to external devices, instruments, or a PC. The Stamp has several ways to handle RS-232. You can use any pin as a TTL RS-232 input or output. You can also use the programming port as a half-duplex RS-232 port that has level shifting to the RS-232 specification.
The real missing link, however, is buffering. While the Stamp is working, it can't listen to the RS-232 port. If data arrives and you aren't ready, it is lost. Another problem is that only one port has level shifting. If you want to do true RS-232 on another port, you'll have to use a MAX232, a MAX233, or a 1488/1489 combo to get true RS-232 levels.
If you have the tools to program an SX chip (which could be an inexpensive SX-Blitz from Parallax), you can build an SSIB that provides two buffered input channels for the Stamp. You can find the details of the SSIB in my SX course that Parallax produces (download the PDF). Of course, this provides two channels of input buffer, but it doesn't provide level shifting.
Maxim makes a serial UART (the MAX3110E) that uses SPI to communicate with the Stamp. The output is RS-232. In addition to the UART, the chip contains an eight byte buffer and a level shifter similar to a MAX233. The level shifter is independent of the UART and requires no capacitors. There are four shifters, two for the RS232 and two for the RTS and CTS signals from the UART. Maxim will send you free samples of most of their ICs, so you can actually get one or two of the chips to experiment with at no charge.
The MAX3110E requires a crystal, along with two capacitors for the crystal (although you may be able to omit the capacitors if you use a breadboard). Maxim recommends a 1.8432MHz (300 baud to 115.2Kbaud) or 3.6864MHz (600 baud to 230.4Kbaud) crystal. The chip has 28 pins like the Stamp II. Unlike the Stamp II, the MAX3110E is in a .3" package.
You need at least 4 pins to interface to the UART. You can also gain some efficiency if you use a fifth pin, but it is not strictly necessary.
Usually, with an SPI device you can use ShiftIn and ShiftOut to communicate with it. However, the Maxim UART is a bit different. When you send characters to it, it also simultaneously sends a received character (if available). This helps the host computer keep up, but complicates the programming. Each operation requires 16 bits. You can read and write the configuration register (mainly to set the baud rate), read characters, or write characters. When you write a character, you also read a character, if it is available.
The UART is set up to generate an interrupt when it requires attention. The Stamp doesn't easily support interrupts, so my code can work two different ways. First, with a four-wire interface, it can simply poll to see if characters are available. Second, you can use five wires and poll the IRQ pin instead of sending 16 bits just to check for a character. This is faster, but requires an extra Stamp pin.
The library contains only a few functions:
sendchar - Sends the byte in sbyte via RS232
rcvidle - Polls the UART for input characters (see below)
uartinit - Initialize the UART using the baudrate constant.
Because the UART can send a character at the same time you are sending a character, your program must be prepared to handle characters at any time. My library requires you to provide a function named rcvchar. This function receives a character in the sbyte variable. If you call sendchar, be careful -- it may cause a recursive call to rcvchar.
In addition to sbyte, the library also uses three bit variables: rts, cts, and err. These reflect the status of RTS, CTS, and if an error is detected.
Keep in mind that the buffer is only 8 characters deep. If you let it fill up, you'll lose characters and there is no error indication that I could find.
Here is a table showing the connections to the MAX3110E:
|Pin #||Name||Connection||Pin #||Name||Connection|
|4||T1IN||Pin 14||18||CS||Stamp P4|
|5||R1OUT||Pin 13||19||IRQ||Stamp P3|
Pin 6 is the RS-232 RX pin. If you are connecting to a PC or other DTE device, you'll need to connect this to the TX pin. Pin 7 is the TX pin (which would connect to a DTE's RX pin). The exact connection will depend on the device you are connecting to.
You probably need capacitors from pin 9 and 10 to ground. The value of the capacitors should match the load capacitance of the crystal in use. So a 20pF crystal would use two 20pF capacitors. One would connect to pin 9 and ground. The other would connect between pin 10 and ground.
If you are breadboarding the circuit, you probably don't need the capacitors. Also, if you are breadboarding, an ASP-II is ideal for making the connections to the DB9. However you connect, don't forget to connect the ground on the DB connector (pin 5 on a DB9) to your circuit ground.
' MAX3110E Driver for Basic Stamp
baudrate con $A ' 9600, 8, N, 1 -- no interrupts din con 7 dout con 6 indout var in6 clk con 5 cs con 4
' you can gain a little speed by ' connecting the IRQ line irq var in3
uartcfg con $C400 ' use $C400 if using IRQ; $C000 if not
ioword var word uartin var word uarti var nib
rts var bit cts var bit err var bit sbyte var byte ' input byte
sbyte="?" gosub sendchar idle: gosub rcvidle goto idle
rcvchar: ' do what you want with sbyte here ' but be careful... sendchar may reenter if sbyte<"a" or sbyte>"z" then s2 sbyte=sbyte & $DF s2: if sbyte=13 then crlf goto sendchar
crlf: gosub sendchar sbyte=10 goto sendchar
' Driver code from here down
sendchar: ioword=$8000 + sbyte + (rts*$200) ucheck: gosub uart cts = uartin >> 9 if uartin & $200 <> 0 then unoerr sbyte="~" err=1 return
unoerr: if uartin & $8000 = 0 then ret sbyte=uartin & $FF goto rcvchar
rcvidle: ' remove next line if not using IRQ if irq=1 then ret ioword=0 goto ucheck
uartinit: err=0 high cs ' let chip see edge low din input dout low clk ioword=uartcfg + baudrate uart: uarti=15 uartin=0 uloop: low din if (ioword & (1<<uarti)) = 0 then unoset high din unoset: low cs ' really only need this once high clk if indout=0 then uno1in uartin=uartin + (1<<uarti) uno1in: low clk uarti=uarti-1 if uarti<>15 then uloop high cs ret: return
This article is copyright 1999, 2000 by AWC. All Rights Reserved.