• No results found

TABLE 5-3 Baud rate summary

5.5.4 9-Bit UART with Variable Baud Rate (Mode 3)

TABLE 5-3 Baud rate summary

TH1 Reload Actual Baud

Baud Rate Crystal Frequency SMOD Value Rate Error

9600 12.000 MHz 1 -7 (0F9H) 8923 7%

2400 12.000 MHz 0 -13 (0F3H) 2404 0.16%

1200 12.000 MHz 0 -26 (0E6H) 1202 0.16%

19200 11.059 MHz 1 -3 (0FDH) 19200 0

9600 11.059 MHz 0 -3 (0FDH) 9600 0

2400 11.059 MHz 0 -12 (0F4H) 2400 0

1200 11.059 MHz 0 -24 (0E8H) 1200 0

EXAMPLE Initializing the Serial Port

5.1 Write an instruction sequence to initialize the serial port to operate as an 8-bit UART at 2400 baud. Use Timer 1 to provide the baud rate clock.

Solution

For this example, four registers must be initialized: SMOD, TMOD, TCON, and TH1.

The required values are summarized below.

Setting SM0/SM1 = 0/1 puts the serial port into 8-bit UART mode. REN = 1 enables the serial port to receive characters. Setting TI = 1 allows transmission of the first character by indicating that the transmit buffer is empty. For TMOD, setting M1/M0 = 1/0 puts Timer 1 into 8-bit auto-reload mode. Setting TR1 = 1 in TCON turns on Timer 1. The other bits are shown as 0s, since they control features or modes not used in this example.

Discussion

The required TH1 value is that which provides overflows at the rate of 2400 x 32 = 76.8 kHz. Assuming the 8051 is clocked from a 12 MHz crystal, Timer 1 is clocked at a rate of 1 MHz or 1000 kHz, and the number of clocks for each overflow is 1000 76.8 = 13.02.

(Round to 13.) The reload value is -13 or 0F3H.

The initialization instruction sequence is shown below.

EXAMPLE Output Character Subroutine

5.2 Write a subroutine called OUTCHR to transmit the 7-bit ASCII code in the accumulator out the 8051 serial port, with odd parity added as the eighth bit. Return from the subrou-tine with the accumulator intact, i.e., containing the same value as before the subrousubrou-tine was called.

Solution

This example and the next illustrate two of the most common subroutines on microcom-puter systems with an attached RS232 terminal: output character (OUTCHR) and input character (INCHAR).

8100 5 ORG 8100H

8100 A2D0 6 OUTCHR: MOV C.P ;put parity bit in C flag

8102 B3 7 CPL C ;change to odd parity

8103 92E7 8 MOV ACC.7.C ;add to character code 8105 3099FD 9 AGAIN: JNB TI.AGAIN ;Tx empty? no:check again

8108 C299 10 CLR TI ;yes: clear flag and

810A F599 11 MOV SBUF.A ;send character

810C C2E7 12 CLR ACC.7 ;strip off parity bit and

810E 22 13 RET ; return

14 END

Discussion

The first three instructions place odd parity in the accumulator bit 7. Since the P bit in the PSW establishes even parity with the accumulator, it is complemented before being placed in ACC.7. The JNB instruction creates a "wait loop," repeatedly testing the transmit inter-rupt flag (TI) until it is set. When TI is set (because the previous character transmission is finished), it is cleared and then the character in the accumulator is written into the serial port buffer (SBUF). Transmission begins on the next rollover of the divide-by-l6 counter that clocks the serial port. (See Figure 5-5.) Finally, ACC.7 is cleared so that the return value is the same as the 7-bit code passed to the subroutine.

The OUTCHR subroutine is a building block and is of little use by itself. At a

"higher level" this subroutine is called to transmit a single character or a string of characters. For example, the following instructions transmit the ASCII code for the letter

"Z" to the serial device attached to the 8051's serial port:

MOV A.#'Z' CALL OUTCHR (continue)

As a natural extension to this idea, Problem 1 at the end of this chapter uses OUTCHR as a building block in an OUTSTR (output string) subroutine that transmits a sequence of ASCII codes (terminated by a NULL byte, 00H) to the serial device attached to the 8051's serial port.

EXAMPLE Input Character Subroutine

5.3 Write a subroutine called INCHAR to input a character from the 8051's serial port and turn with the 7-bit ASCII code in the accumulator. Expect odd parity in the eighth bit re-ceived and set the carry flag if there is a parity error.

Solution

Discussion

This subroutine begins by waiting for the receive interrupt flag (RI) to be set, indicating that a character is waiting in SBUF to be read. When RI is set, the JNB instruction falls through to the next instruction. RI is cleared and the code in SBUF is read into the accu-mulator. The P bit in the PSW establishes even parity with the accumulator, so it should be set if the accumulator, on its own, correctly contains odd parity in bit 7. Moving the P bit into the carry flag and complementing it leaves CY = 0 if there is no error. On the other hand, if the accumulator contains a parity error, then CY = 1, correctly indicating

"parity error." Finally, ACC.7 is cleared to ensure that only a 7-bit code is returned to the calling program.

EXAMPLE Full Duplex Operation

5.4 Write a program that continually transmits characters from a transmit buffer (internal RAM 30H to 4FH). If incoming characters are detected on the serial port, store them in the receive buffer starting at internal RAM location 50H. Assume that the 8051 serial port has already been initialized in mode H.

Solution

This example shows how the serial port can be used in full duplex operation, i.e., trans-mission and reception are done simultaneously.

Discussion

This program first uses the two registers R0 and R1 to point to the transmit and receive buffers respectively. It then checks to see if a character has been received or if the previous character to be transmitted has already been sent out. Notice that reception is processed first. This is because reception is more critical since the 8051 is depending on an external device for an incoming character, which must be processed and stored as soon as possible else it might be overwritten by subsequent incoming characters. Recall that the serial port can hold at most one character in its buffer while a second is being received. If an incoming character has been fully received, it is read from SBUF and checked for parity before being stored into the receive buffer whose current empty location is pointed to by R1. R1 is next incremented to point to the next available location and the program goes back to checking. When the previous transmission is finished, the program first gets the character to be transmitted from the transmit buffer. R0 is used as the pointer to the next character in the transmit buffer. The odd parity is then placed in bit 7 of the code before it is sent to the SBUF for transmission. R1 is then incremented to point to the next character. The program also checks for the end of the transmit buffer, upon which it would recycle back to the beginning of the buffer. Finally, the program goes back to checking for further receptions or transmission.

EXAMPLE Compensating for the Round-off Errors

5.5 Calculate the round-off error for the baud rate of the serial port in Example 5.1. Assuming the same Timer 1 reload value of -13 or 0F3H is to be used, calculate the value of the crystal frequency for an exact baud rate of 2400 baud.

Solution

The round-off error for the baud rate is:

Discussion

The desired baud rate is 2400 baud. The rounded-off Timer 1 reload value is -13 for 13 µs, causing an overflow rate of 76.9kHz, which in turn causes a baud rate of 76.9 kHz 32 = 2403.8 baud.

In the calculation of the desired crystal frequency to produce an exact baud rate of 2400, we can use the ratio technique, as shown in the solution above. Let's check if causes an exact 2400 baud rate. A crystal frequency of 11.98MHz means that Timer 1 increments at a rate of 11.98 MHz12 = 0.998 MHz so the duration of one count is

1/0.998 MHz =1.002 µs. The reload value for Timer 1 is -13 so it overflows every 13 x 1.002 µS =1.3026 µS, hence the overflow rate is 1/1.3026 µs = 76.77 kHz. This causes a baud rate of 76.77 kHz 32 = 2399 baud 2400 baud.

A more commonly used crystal frequency is 11.059 MHz rather than 11.98MHz. In this case, the Timer 1 reload value would have to be -12 instead of -13. To check that it results in an exact baud rate of 2400, note that Timer 1 increments at a rate of 11.059 MHz12 = 0.9216 MHz so the duration of one count is 1/0.9216 MHz = 1.085 µs. The reload value for Timer 1 is -12 so it overflows every 12 x 1.085 µs = 13.02 µs, hence the overflow rate is 1/13.02 µs= 76.8 kHz. This causes a baud rate of 76.8 kHz / 32 = 2400 baud.

It is clear then that the crystal frequency to eliminate round-off errors in the baud rate would vary depending on the Timer 1 reload value used.

SUMMARY

This chapter has presented the major details required to program the 8051 serial port. A passing mention has been made in this chapter and in the last chapter of the use of interrupts. Indeed,

advanced applications using the 8051 timers or serial ports generally require input/output operations to be synchronized by interrupts. This is the topic of the next chapter.

PROBLEMS

The following problems are typical of the software routines for interfacing terminals (or other serial devices) to a microcomputer. Assume the 8051 serial port is initialized in 8-bit UART mode and the baud rate is provided by Timer 1.

5.1 Write a subroutine called OUTSTR that sends a null-terminated string of ASCII codes to the device (perhaps a VDT) connected to the 8051 serial port. Assume the string of ASCII codes is in external code memory and the calling program puts the address of the string in the data pointer before calling OUTSTR. A null-terminated string is a series of ASCII bytes terminated with a 00H byte.

5.2 Write a subroutine called INLINE that inputs a line of ASCII codes from the device connected to the 8051 serial port and places it in internal data memory beginning at address 50H. Assume the line is terminated with a carriage return code. Place the carriage return code in the line buffer along with the other codes, and then terminate the line buffer with a null byte (00H).

5.3 Write a program that continually sends the alphabet (lowercase) to the device at-tached to the 8051 serial port. Use the OUTCHR subroutine written earlier.

5.4 Assuming the availability of the OUTCHR subroutine, write a program that contin-ually sends the displayable ASCII set (codes 20H to 7EH) to the device attached to the 8051 serial port.

5.5 Modify the solution to the above problem to suspend and resume output to the screen, using XOFF and XON codes entered on the keyboard. All other codes received should be ignored. (Note: XOFF = CONTROL-S = 13H, XON = CONTROL-Q = 11H)

5.6 Assume the availability of the INCHAR and OUTCHR subroutines and write a program that inputs characters from the keyboard and echoes them back to the screen, converting lowercase characters to uppercase.

5.7 Assume the availability of the INCHAR and OUTCHR subroutines and write a program that inputs characters from the device attached to the 8051 serial port and echoes them back substituting period (.) for any control characters (ASCII codes 00H to 1FH, and 7FH).

5.8 Assume the availability of the OUTCHR subroutine, and write a program that clears the screen on the VDT attached to the 8051 serial port and then sends your name to the VDT 10 times on 10 separate lines. The clear screen function on VDTs is accomplished by transmitting a CONTROL-Z on many terminals or <ESC> [2 J on terminals that support ANSI (American National Standards Institute) escape sequences. Use either method in your solution.

5.9 Figure 5-4 illustrates a technique for expanding the output capability of the 8051.

Assuming such a configuration, write a program that initializes the 8051 serial port

for shift register mode and then maps the contents of internal memory location 20H to the eight extra outputs, 10 times per second.

5.10 Which type of serial communication does the 8051's serial port support? Simplex, half- or full duplex? Why? Explain the components within the serial port and how they support this type of serial communication.

5.11 Explain how the 8051's input/output (I/O) capability can be expanded by using the serial port.

What is the disadvantage of such a method?

5.12 Write a subroutine called OUTCHR9 to transmit a 9-bit code (C8C7C6C5C4C3- C2C1C0) out the 8051 serial port. Note that C8 is in the LSB of B register while C7C6C5C4C3C2C1C0 are in the accumulator. Return from the subroutine with all registers intact.

5.13 Write a subroutine called INCHAR8 to input an 8-bit extended ASCII character from the 8051's serial port and return with the 8-bit code in the accumulator. Expect odd parity in the ninth bit received and set the carry flag if there is a parity error.

5.14 Write a subroutine called OUTCHR8 to transmit the 8-bit extended ASCII code in the accumulator out the 8051 serial port, with odd parity added as the ninth bit. Return from the subroutine with the accumulator intact.

5.15 a. Write an instruction sequence to initialize the serial port to operate as a 9-bit UART at 9600 baud. Use Timer 1 to provide the baud rate clock, assuming that the crystal oscillator frequency, fosc= 12 MHz.

b. Is the resulting baud rate exactly 9600 baud? If not, what is the percentage error (% error)?

Hence, calculate the value of fosc to achieve an exact baud rate of 9600 baud.

Interrupts

6.1 INTRODUCTION

An interrupt is the occurrence of a condition—an event—that causes a temporary suspen-sion of a program while the condition is serviced by another program. Interrupts play an important role in the design and implementation of microcontroller applications. They allow a system to respond asynchronously to an event and deal with the event while another program is executing. An interrupt-driven system gives the illusion of doing many things simultaneously. Of course, the CPU cannot execute more than one instruction at a time; but it can temporarily suspend execution of one program, execute another, then return to the first program. In a way, this is like a subroutine. The CPU executes another program—the subroutine—and then returns to the original program. The difference is that in an interrupt-driven system, the interruption is a response to an "event" that occurs asynchronously with the main program. It is not known when the main program will be interrupted.

The program that deals with an interrupt is called an interrupt service routine (ISR) or interrupt handler. The ISR executes in response to the interrupt and generally performs an input or output operation to a device. When an interrupt occurs, the main program tem-porarily suspends execution and branches to the ISR; the ISR executes, performs the opera-tion, and terminates with a "return from interrupt" instruction; the main program continues where it left off. It is common to refer to the main program as executing at base-level and the ISRs as executing at interrupt-level. The terms foreground (base-level) and back-ground (interrupt-level) are also used. This brief view of interrupts is depicted in Figure 6-1, showing (a) the execution of a program without interrupts and (b) execution at base-level with occasional interrupts and ISRs executing at interrupt-level.

A typical example of interrupts is manual input, using a keyboard. Consider an appli-cation for a microwave oven. The main program (foreground) might control a microwave power element for cooking; yet, during cooking, the system must respond to manual input

131

FIGURE 6-1

Program execution with and without interrupts (a) Without interrupts (b) With interrupts

on the oven's door, such as a request to shorten or lengthen the cooking time. When the user depresses a key, an interrupt is generated (a signal goes from high to low, perhaps) and the main program is interrupted. The ISR takes over in the background, reads the keyboard code(s) and changes the cooking conditions accordingly, and finishes by passing control back to the main program. The main program carries on where it left off. The important point in this example is that manual input occurs "asynchronously"; that is, it occurs at intervals not predictable or controlled by the software running in the system. This is an interrupt.