📄 dupuart.doc
字号:
A Software Duplex UART for the 751/752 AN446
The following program contains routines that will allow an 8xC751 or 8xC752 to
implement a software UART that can send and receive serial data
simultaneously. Other published software UARTs only allow either transmit or
receive to occur at any one time. The demo application shown in the code
listing waits for data to be received, then echoes it and follows this with a
hexadecimal interpretation of the data plus a space. For instance, if the
program receives the character "$", it echoes back the string "$24". The
reason for echoing these additional characters is to make it easy to force the
receiver buffer to fill up in order to test the handshaking. If the program
simply echoed what was received, it would likely never use more than the very
first receiver buffer location since it can normally transmit just as fast as
it can receive.
CHIP RESOURCES
The UART routines use about 400 bytes of code space and use the timer to
provide a constant time interrupt to synchronize both transmit and receive
operations. The hardware connections require four device pins to accomplish
serial I/O with RTS/CTS handshaking. Only two pins would be needed if
handshaking is not required. Three of the four pin functions may be assigned
to any port pin. The serial input pin must be assigned as one of the external
interrupt pins. Another two pins are used in the demo application to input a
selection of one of four baud rates (1200, 2400, 4800, or 9600).
LIMITATIONS
To obtain duplex operation, a fairly large portion of the chip's time is used.
The routines were tested up to 9600 baud running on a 16 MHz 87C751. When
serial input and output were both occurring at the same time, the routines
could not support continuous operation with no pauses between characters. At
4800 baud, full speed tight reception and transmission worked flawlessly. In
other words, 4800 baud should work with all applications, while 9600 baud may
not work with all applications.
THEORY OF OPERATION
There are three possible sequences of events when serial transmit and receive
may both be operating at once: transmit and receive begin simultaneously;
transmit is requested while the receiver is busy; and receive starts while the
transmitter is busy. The first 2 cases could be handled fairly simply with
only one interrupt for each bit time. In the first case, everything is already
in synch and only one timer and one interrupt per bit is needed to do both
operations. In the second case (transmit is requested while the receiver is
busy) the program could just wait for the next bit time to start transmitting.
Unfortunately, the third case presents a problem. If the program is already
transmitting, it cannot always wait for the next bit time to start sampling
the serial data if the application is not to lose bits. Also, the timer cannot
be adjusted to the incoming data since this would distort the duration of one
of the transmitted bits.
The method used here to deal with this problem is to always divide all bit
times into 4 sub-bit times. When transmission and/or reception is in progress,
the timer runs at 4X the bit rate for the selected baud rate. The variables
TxTime and RxTime are used to count sub-bit times for the transmitter and the
receiver, respectively. Both are initialized to a negative value and count up
to simplify testing for an active sub-bit time. The maximum baud rate that can
be supported is essentially determined by the maximum amount of time that it
might take the microcontroller to do all of the operations associated with
transmitting one bit and receiving one bit . This must be done within the time
between timer interrupts.
When both transmit and receive operations are scheduled for the same timer
interrupt, priority is given to the transmitter routine. The reason for this
is that a great deal of jitter can be tolerated in the timing of the received
bit sampling, but the transmitted data must "look" good to the outside world.
The actual bit times for transmit and receive are counted by the variables
TxCnt and RxCnt, respectively. When an active sub-bit time slice occurs, these
variables tell the transmit and receive routines what to do in the current
time slice. The value 11 hex indicates a start bit, 10 hex indicates a stop
bit, and the values 8 through F hex indicate a data bit. The values were
chosen to allow quick determination of the appropriate action by the code.
The routines provide for a small amount of data buffering for both the
transmitter and the receiver. As implemented here, the transmitter buffer is
only one byte deep, allowing one data byte to be held while another is being
transmitted. The receiver buffer is larger, allowing three bytes to be held
while a fourth is being received. If the receiver buffer fills up (indicated
by the flag RxFull), the application code must retrieve one byte before a
fourth one finishes, or data will be lost. If this happens, a flag will be set
(OverrunErr) to indicate that the receiver buffer has been overrun. There is
no similar flag for the transmitter, since the transmit request routine waits
for the transmitter buffer to be available (indicated by the TxFull flag)
before taking action. It is up to the application code to check this flag in
advance if it does not want to stall execution while waiting to transmit data.
As each routine finishes a whole data byte by completing the send or receive
of a stop bit, it checks to see if there is something still happening to
warrant having the time slice interrupt running. In the case of a received
stop, the transmit activity flag (TxOn) is examined. If it is not set, the
timer is turned off. The timer will be turned back on if an interrupt from a
serial start bit is received or the main code requests data to be transmitted.
In the case of a transmitted stop, both the receiver activity flag (RxOn) and
the transmit buffer flag (TxFull) are examined. If the receiver is active or
there is more data to transmit, leave the timer is left running.
All of the status flags are in the "Flags" register. Other status flags found
there are: RxAvail, which indicates that the receiver buffer contains
unprocessed data; and FramingErr which is set when the receiver routines find
an improper start or stop bit, usually caused by mismatched baud rates.
Flow control handshaking is provided by the RTS/CTS scheme. The transmit
routine looks at the incoming CTS line before beginning each start bit
transmission, and simply exits, waiting for the next time slice, if CTS is not
asserted. The receive routine checks the buffer status whenever a start bit
interrupt occurs and de-asserts the outgoing RTS line if the buffer already
contains two bytes (i.e., it will be full when the current byte finishes). If
the device at the other end of the communication line follows the same rules
(which may very well NOT be the case) the program should be able to
communicate without buffer overflows in either direction.
Baud rates in both the send and receive routines are determined by two things:
the timer interrupt rate; and the number of time slices per bit. The method of
calculating the timer value for various baud rates is discussed in the code
listing at the BaudRate routine. This discussion has centered on there being
four time slices per bit, but if the user wants, set either the transmitter or
the receiver can be set to run at a baud rate that is a multiple of the other
by adjusting the value of the constant TxBitLen or RxBitLen. The baud rate
would be calculated as indicated for the faster channel, and TxBitLen or
RxBitLen would be changed for the slower channel. For example, the transmitter
can be set to run at half of the receiver baud rate by setting TxBitLen to -8
+ 1.
The routines shown also make provision for changing the baud rate "on the
fly", although the application code given does not implement this feature. If
the application code changes the baud rate for some reason, the change will be
effected when the next data transmission or reception begins, if both the
transmitter and receiver were already idle. This prevents the timer value from
being changed in the middle of a data byte.
THE CODE
There are a number routines in the code that the user should be aware of:
Intr0 - Called (by interrupt) when a serial start bit is received.
Timer0 - Called (by interrupt) for every sub-bit time slice.
RS232TX - Called by Timer0 when the transmitter has business to conduct in
the current time slice.
RS232RX - Called by Timer0 when the receiver has business to conduct in
the current time slice.
BaudRate - Sets the baud rate variables BaudHigh and BaudLow based on the
accumulator value.
TxSend - Called by the application code to request that a data byte be
transmitted. The data to be transmitted is in the accumulator.
GetRx - Called by the application code to request return of a received
data byte from the buffer. Data is returned in the
accumulator. This routine should not be called unless the
receiver buffer has data available.
Reset - Start of the initialization code to set up the UART.
MainLoop - Start of the mainline code of the demo application.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -