Day 9 Asynchronous Communication
Once you remove the clock line from the serial interface between two devices, what you obtain is an asynchronous communication interface. Whether you want full bidirectional (duplex) communication or just half-duplex (one direction at a time), multipoint, or point-to-point communication, there are many asynchronous protocols that can make communication possible and allow for efficient use of the media. In this lesson we will review the PIC32 asynchronous serial communication interface modules, UART1 and UART2, to implement a basic RS232 interface. We will develop a console library that will be handy in future projects for interface and debugging purposes.
In addition to the usual software tools, including the MPLAB® IDE, the MPLAB C32 compiler, and the MPLAB SIM simulator, this lesson will require the use of the Explorer 16 demonstration board, your In-Circuit Debugger of choice, and a PC with an RS232 serial port (or a serial to USB adapter). You will also need a terminal emulation program. If you are using the Microsoft Windows operating system, the HyperTerminal application will suffice (Start|Programs | Accessories | Communication | HyperTerminal).
The UART interface is perhaps the oldest interface used in the embedded-control world. Some of its features were dictated by the need for compatibility with the first mechanical teletypewriters. This means that at least some of its technology has centuries’-old roots.
On the other hand, nowadays finding an asynchronous serial port on a new computer (and especially on a laptop) is becoming a challenge. The serial port has been declared a “legacy interface,” and for several years now, strong pressure has been placed on computer manufacturers to replace it with the USB interface. Despite the decline in their popularity and the clearly superior performance and characteristics of the USB interface, asynchronous serial interfaces are strenuously resisting in the world of embedded applications because of their great simplicity and extremely low cost of implementation.
Four main classes of asynchronous serial application are still being used:
The PIC32’s UART modules can support all four major application classes and packs a few more interesting features, too.
To demonstrate the basic functionality of a UART peripheral, we will use the Explorer16 demo board where the UART2 module is connected to an RS232 transceiver device and to a standard 9 poles D female connector. This can be connected to any PC serial port or, in absence of the “legacy interface” as mentioned above, to an RS232 to USB converter device. In both cases the Windows HyperTerminal program will be able to exchange data with the Explorer16 board with a basic configuration setting.
The first step is the definition of the transmission parameters. The options include:
For our demo we will choose the fast and convenient configuration:115200, 8, N, 1, CTS/RTS—that is:
Use the New Project Setup checklist to create a new project called Serial and a new source file, similarly called serial.c. We will start by adding a few useful I/O definitions to help us control the hardware handshake lines:
The hardware handshake is especially necessary in communicating with a Windows terminal application, since Windows is a multitasking operating system and its applications can sometimes experience long delays that would otherwise cause significant loss of data. We will use one I/O pin as an input (RF12 on the Explorer 16 board) to sense when the terminal is ready to receive a new character (Clear To Send), and one I/O pin as an output (RF13 on the Explorer 16 board) to advise the terminal when our application is ready to receive a character (Request To Send).
To set the baud rate, we get to play with the Baud Rate Generator (U2BREG), a 16-bit counter that feeds on the peripheral bus clock. From the device datasheet we learn that in the normal mode of operation (BREGH=0) it operates off a 1:16 divider versus a highspeed mode (BREGH=1) where its clock operates off a 1:4 divider. A simple formula, published on the datasheet, allows us to calculate the ideal setting for our configuration (see Equation 9.1).
Equation 9.1. UART Baud Rate with UxBREG = 1.
In our case, Equation 9.1 translates to the following expression:
U2BREG = (36,000,000/4/115,200) – 1 = 77.125
To decide how to best round out the result, we need a 16-bit integer after all. We will use the reverse formula to calculate the actual baud rate and determine the percentage error:
Error = ((Fpb/4/(U2BREG+1)) – baud rate)/baud rate %
Rounding up to a value of 77, we obtain an actual baud rate of 115,384 baud with an error of just 0.2 percent—well within acceptable tolerance. However, with a value of 78 we obtain 113,924 baud, a larger 1.1 percent error but still within the acceptable tolerance range for a standard RS232 port (±2 percent).
We can therefore define the constant BRATE as:
Two more constants will help us define the initialization values for the UART2 main control registers called U2MODE and U2STA (see Figure 9.2).
The initialization value for U2MODE will include the BREGH bit, the number of stop bits, and the parity bit settings.
The initialization for U2STA will enable the transmitter and clear the error flags (see Figure 9.3 ):
Using the constants defined above, let’s initialize the UART2module, the baud rate generator, and the I/O pins used for the handshake:
Sending a character to the serial port is a three-step procedure:
All of the above can be nicely packaged in one short function that we will call putU2(), respecting a rule that wants all C language I/O libraries (stdio.h) to use the put – prefix to offer a series of character output functions such as putchar(), putc(), fputc() and so on:
To receive a character from the serial port, we will follow a very similar sequence:
Again, all of the above steps can be nicely packaged in one last function:
To test our serial port control routines, we can now write a small program that will initialize the serial port, send a prompt, and let us type on the terminal keyboard while echoing each character back to the terminal screen:
Note
I recommend, for now, that you do not attempt to single-step or use breakpoints or the RunToCursor function when using the UART! See the “Tips & Tricks” section at the end of the chapter for a detailed explanation.
If HyperTerminal is already set to provide an echo for each character sent, you will see double—literally! To disable this functionality, first hit the Disconnect button on HyperTerminal. Then select File | Properties to open the Properties dialog box, and select the Settings Pane tab (see Figure 9.4). This will be a good opportunity to set a couple more options that will come in handy in the rest of the exploration.
To transform our demo project in a proper terminal console library that could become handy in future projects, we need only a couple more functions that will complete the puzzle: a function to print an entire (zero-terminated) string and a function to input a full text line. Printing a string is, as you can imagine, the simple part:
It is just a loop that keeps calling the putU2() function to send, one after the other, each character in the string to the serial port.
Reading a text string from the terminal (console) into a string buffer can be equally simple, but we have to make sure that the size of the buffer is not exceeded (should the user type a really long string), and we have to convert the carriage return character at the end of the line in a proper