📄 rs232.doc
字号:
received. Flow control effects output only. Characters can
continue to be received or written to the output buffer up to
it's capacity when output is disabled via flow control. Only
one type of flow control may be used at once.
If the remote equipment is using XON/XOFF type flow control,
rs_setflow can be used to control remote output with the
RS_FLWINS command. The control character will be sent
immediately, even if characters are already being transmitted
via the output buffer. The buffer will continue to be sent
after the control character has been transmitted.
> rs_close
> Purpose:
Closes" port prepared by rs_initport.
> Prototype:
void rs_close(void);
> Return Value:
none
> Notes:
This function should always be used when an application has
"opened" a port with rs_initport. rs_close disables interrupts
from the port and restores the previous interrupt vector.
Failure to call rs_close before exiting from the application can
very likely cause undefined behavior. The function can be
registered with the library function atexit() to insure that it
gets called. It is probably also a good idea to install a
ctrl-break handler which calls rs_close to prevent exiting the
application without closing the port:
int c_break(void)
{
rs_close();
return(0);
}
/* somewhere in application */
ctrlbrk(c_break); /* library function ctrlbrk registers
cleanup function */
If a buffer transmit is currently in progress, rs_close waits
for it to finish before closing the port unless output is
currently disabled via flow control.
> General Notes:
> Baud Rates:
Although RS232.C supports speeds up to 115.2K baud, the higher
speeds may not work on some machines due to a variety of
factors. Foremost is the speed of the CPU itself - slower
machines may not be capable of sustained input at high speeds.
Other factors may effect the maximum usable baud rate also. For
instance, even though a machine's CPU is fast enough to support
high speeds, other software running on the machine may prevent
it. (One example is a 386 CPU running an extended memory
manager which places the CPU in protected mode. This can cause
interrupt service routines to be slower.) The BIOS in some
machines may have routines which are too slow, such as the timer
interrupt service routine - this can effect time critical
routines like the serial interrupt service routine in RS232.C.
Only experimentation can determine what the highest usable speed
is on any given machine and configuration.
> Interrupts:
Because machines equipped with COM ports 3 and 4 use hardware
interrupt lines shared with ports 1 and 2, a problem can arise
with some hardware. For example, an internal modem is installed
as COM1 and you are attempting to use COM3 for some other
purpose. Because both ports use interrupt request line IRQ4, if
the modem board is "holding" IRQ4 inactive, COM3 will never be
able to signal an interrupt and thus will appear dead. Most
serial adapter boards do not behave this way and will "float"
the interrupt request line when not signaling an interrupt.
Also, the problem can only occur if software accessing the
problem board leaves interrupts enabled at the board.
(Specifically, the signal OUT2 is left active with modem control
register bit 3.)
If your application installs any of it's own interrupt routines,
they must re-enable interrupts as soon as possible after entry
to prevent loss of incoming serial characters.
RS232.C re-prioritizes hardware interrupts to give serial
interrupts the highest priority. While this will have no
noticeable effect with most applications, it should be taken
into account in those applications which make use of hardware
interrupts from other sources.
> Polled vs. interrupt driven output:
The default method of character transmission by RS232.C uses
interrupts. Each time a character is written a character is
written to the UART's transmit holding register, an interrupt is
generated by the UART when the transmit holding register becomes
available for the next character to be sent. It may be
desirable under certain circumstances to disable this feature
and use "polled transmission" instead. This requires that
software constantly poll the UART and write the next character
when the transmit holding register becomes free. The method
used is determined at compile time. If the macro RS_POLLED_XMIT
is defined, the polling method will be used. The following line
placed at the beginning of the application's source code will
accomplish this:
#DEFINE RS_POLLED_XMIT
The following describes some advantages and disadvantages to
both methods:
Interrupt driven output:
Advantages: This is the more efficient method of output. No
CPU time is wasted polling the UART. Characters may be queued
for output and the application may go on processing without
waiting for the characters to actually be sent.
Disadvantages: Some additional overhead is incurred in the
interrupt service routine. At high transmission speeds this
may cause problems on slower machines or under certain
circumstances. Interrupt driven output may not work properly
with some non-standard hardware.
Polled output:
Advantages: This method makes the interrupt service routine
slightly "leaner" and simplifies some of the code elsewhere
making the overall code size slightly smaller. This method
may prove to be more reliable on some hardware.
Disadvantages: While the application is sending characters,
it can do nothing else and no output buffer is used. This
method is less efficient for throughput.
> Flow control and handshaking:
Flow control is provided for only in respect to stopping and
starting output as requested by remote equipment. To utilize
flow control on remote equipment, the application must monitor
the conditions requiring flow control (i.e. input buffer free
space) and take the appropriate action when needed (like sending
XOFF or dropping a hardware line).
Handshaking is something that is completely arbitrary and the
only requirement is that the local and remote equipment must
agree on the protocol. RS232.C provides a function for
determining the status of and controlling hardware handshake
lines but it is up to the application to determine how it should
be used.
> Compiling:
If RS232.C can be simply included (whether by "pasting" it
directly into an applications source code or with a preprocessor
"#include" directive) no special compiler considerations are
needed. If desired, RS232.C can be split into separate header
and code files to follow more conventional 'C' conventions.
This is accomplished by splitting the file where indicated.
Programs using RS232.C can be compiled and linked from the IDE
if desired.
Borland's newer compilers have many optimization options and, so
far, none have caused problems with RS232.C. One necessity is a
must when using Turbo C 2.0 or earlier compilers: Stack checking
must be disabled. With stack checking enabled in the older
compilers, stack checking code is generated even in interrupt
functions.
Any of the memory models can be used with RS232.C - the only
drawback is the extra function call overhead and/or memory
access overhead incurred with the large models. This may
prevent an application from being able to use the higher baud
rates on some machines.
> Other Compilers:
RS232.C will compile and run with other DOS based compilers with
minor changes. The following lists types/functions/macros which
may need attention under compilers other than those produced by
Borland:
function type interrupt - must take care of saving and
restoring registers and provide IRET instruction
unsigned char inportb(int portid) /* reads a byte from
a hardware port */
void outportb(int portid,unsigned char value) /* writes a
/* byte to a port */
void far *MK_FP(unsigned seg, unsigned ofs) /* takes integer
segment and offset
arguments and returns
far pointer */
The code is C++ compatible via "#ifdef __cplusplus"
preprocessor directives. In order to use RS232.C in
a C++ program, the header file must be separated from
the main body of the code (name it RS232.H) and RS232.C
must be compiled separately (as in a project file).
> 16550 FIFO mode:
The 8250A/B and 16450 UARTs found in most machines contain only
a one byte buffer for input and output. This means that for
every byte which is received, an interrupt is generated which
invokes a routine to retrieve the incoming byte and store it.
This must take place before the next incoming byte has been
fully received to avoid loss of data. The same is true of
outgoing data - after each byte being transmitted has been
sent, an interrupt is generated to invoke a routine to write the
next byte to the transmit register. In some situations, this is
simply too much overhead or the interrupt service routines can
not be allowed to react quickly enough to keep up with the data.
The more sophisticated 16550 series of UARTs overcome this with
the inclusion of 16 byte FIFOs (first-in-first-out-registers)
for both input and output. Software must be able to recognize
and enable this feature when it's available, and software
determines how it is used. Code in RS232.C checks for the
presence of FIFO capable UARTs and automatically employs them.
Outgoing data is written to the UART at 16 bytes per interrupt
and incoming data signals generates a receive interrupt after 4
bytes have accumulated in the FIFO - though up to 16 bytes can
be received before the interrupt service routine is able to
respond, without losing any data. These defaults can be changed
by altering the corresponding constants in the function
rs_initport (see comments in RS232.C).
> Using More Than 1 COM Port Simultaneously:
While RS232.C provides no direct support for simultaneous serial
port access, it is easy enough to accomplish. The solution is
to include 2 copies of RS232.C in your source code. Because all
variable and function names in RS232.C begin with 'rs_', this
makes it easy. To allow an application to access 2 ports at
once you can do the following:
Create 2 copies of RS232.C renaming them to RS232A.C and
RS232B.C.
Using Borland's built in editor (or any editor capable of
search and replace), edit RS232A.C performing a global
search and replace of the string "rs_" with "rs1_". Do
the same for "RS_" replacing it with "RS1_".
Do the same thing with RS232B.C, replacing "rs_" with
"rs2_" and "RS_" with "RS2_".
Include both modified copies in the source code for your
application. This provides 2 complete sets of functions
(the function names now start with "rs1_" or "rs2_",
depending on which port is being accessed) allowing access
to 2 different ports and simultaneous serial port I/O.
While not the most elegant of solutions, it is workable
and RS232.C is small enough so as not to make inclusion of
2 copies a problem. (RS232.C adds about 3400 bytes to an
executable file.)
Only certain ports can be used simultaneously. Because COM1
uses the same hardware interrupt as COM3 and COM2 uses the same
interrupt as COM4, you will most likely not be able to use COM1
with COM3 or COM2 with COM4. The problem arises due to the
design of the hardware - if a UART has its OUT2 hardware line at
logic 1 (necessary to enable interrupts), another UART sharing
the same interrupt will not be able to signal an interrupt.
This is true of any serial communications software which uses
interrupts. A serial mouse driver using COM1 preventing serial
I/O on COM3 is one example of how this problem may arise even
when using only one port in an application. One way to get
around this problem (other than opening and closing the ports as
needed using rs_close) is to turn off OUT2 on the UART which is
NOT currently being utilized. OUT2 is controlled by bit 3 of
the modem control register and can be controlled using the
rs_modctrl function of RS232.C. The following is an example
which would allow interrupts to occur on a port opened with
rs1_initport and reenable interrupts on a port opened with
rs2_initport when finished:
rs2_modctrl(RS2_WRTMCR,rs2_modctrl(RS2_GETMCR) & '\xF7');
rs1_modctrl(RS1_WRTMCR,rs1_modctrl(RS1_GETMCR) | '\x08');
perform I/O with rs1...
. . . .
. . . .
. . . .
rs1_modctrl(RS1_WRTMCR,rs1_modctrl(RS1_GETMCR) & '\xF7');
rs2_modctrl(RS2_WRTMCR,rs2_modctrl(RS2_GETMCR) | '\x08');
resume I/O with rs2...
One very real drawback to this method is that no interrupts
can occur on the on the disabled port and data could be
lost. Some serial adaptor allow for the conflict
caused by shared interrupts by or'ing the interrupt request
output of the conflicting UARTs. Only testing can ascertain
if this is so. Another workaround (and only if the hardware
supports it) is to use an alternate IRQ which does not
conflict with another device. See the function description
for rs_initport for instructions on how to use an alternate
IRQ and/or base address.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -