Design Ideas: September 2, 1996
The UARTs built into most microcontrollers support a "9th-bit" communications mode. If the master sets the 9th bit of a character it transmits, the slaves then interpret that character as a slave address, not as data. The 9th-bit mode simplifies master-slave communications by using character protocols over multidrop serial lines, such as the RS-485. A PC's UART family (for example, the 8251 or 16550), however, does not support 9th-bit communications. This shortcoming is unfortunate, as the PC is an attractive alternative for many embedded applications. Also, a PC can be ideal as a laboratory tool for evaluating new slave devices. Luckily, you can trick the PC into performing 9th-bit communications. The UART's little-used and often-forgotten "mark" and "space" parity options can add the 9th bit to the UART's native 8-bit communications. The C function in Listing 1 performs the trick.
| Listing 19th-bit serial communications on a PC |
|---|
#define UART 0x2F8 // Base Address for UART (COM2)
#define LCR (UART+3) // Line Control Register I/O Address
#define LSR (UART+5) // Line Status Register I/O Address
void
sendPacket ( const char *pchPacket,
unsigned wCount
)
{ outportb ( LCR,inportb(LCR)&0xEF ); // Set Mark Parity (9th = 1)
serPut ( *pchPacket++ ); // Write Address
while (inportb(LSR) & 0x04); // Wait for Address Sent
outportb ( LCR,inportb(LCR)|0x10 ); // Set Space Parity (9th = 0)
while (--wCount) // Send Remaining Bytes
serPut ( *pchPacket++ );
}
|
The sendPacket function allows you to send a number of bytes (wCount) from a buffer (pchPacket) in a typical 9th-bit master-slave format. The first byte of a packet transmits with its 9th bit set to 1 to indicate that the character is the address of the slave for which the packet is intended. The remainder of the packet transmits with the characters' 9th bits set to 0 so the slaves won't mistake data for slave addresses and, thereby, erroneously wake slaves that have chosen to ignore the packet. The function in Listing 1 is generic and works with any serial driver on the PC. The default initialization for the PC's serial port should be 8 data bits, 1 stop bit, and space parity.
Note that for completeness, access to the needed control registers is hard-coded in this example; you may wish to access the control registers in a more elegant fashion via your serial driver. Prior to sending the slave-address byte, the routine clears bit 4 of the UART's line-control register (LCR), thereby programming the UART for mark parity. Mark parity sets the 1 in the 9th bit. The function then sends the address byte. Because PC UARTs don't queue the parity bit along with the data in their output buffers, the routine must wait until the address byte is completely sent before shifting back to space parity.
When bit 2 of the line-status register (LSR) becomes 1, the transmission of the address byte is complete. Once the address has been sent, the routine reverts to data mode (space parity) by clearing bit 4 of the LCR. You may then send the data portion of your packet, each byte of which has its 9th bit set to 0. In most protocols, slaves reply only with data bytes so you need no special handling to receive replies. (DI #1915)