📄 interfacing the serial - rs-232 port part 3-4.htm
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<!-- saved from url=(0045)http://www.beyondlogic.org/serial/serial1.htm -->
<HTML><HEAD><TITLE>Interfacing The Serial / RS-232 Port</TITLE>
<META content="text/html; charset=windows-1252" http-equiv=Content-Type>
<META
content="Describes interfacing the Serial (RS-232) Port in relation to both Hardware and Software. Gives Practical Examples using CDP6402 UART and Software Examples in C."
name=description>
<META
content="RS232, RS-232, Serial, CPD6402, AY-5-1015, 8250, 16450, 16550, 16650, 16750, UART, MAX-232, COMMS, COM Port, Serial Port, Terminal, Programming in C, Serial Programming, RS-232 Programming"
name=keywords>
<META content="MSHTML 5.00.3315.2870" name=GENERATOR></HEAD>
<BODY
background="Interfacing The Serial - RS-232 Port Part 3-4_files/bgyellow.gif"
leftMargin=0 topMargin=0 FACE="ARIAL" BASEFONT marginwidth="0" marginheight="0">
<STYLE type=text/css>#TITLEBLOCK {
COLOR: #ffffff; TEXT-DECORATION: none
}
TD {
FONT-FAMILY: Arial
}
P {
FONT-FAMILY: Arial
}
FONT {
FONT-FAMILY: Arial
}
A {
FONT-FAMILY: Arial
}
LI {
FONT-FAMILY: Arial
}
B {
FONT-FAMILY: Arial
}
PRE {
COLOR: #100080
}
TT {
COLOR: #100080
}
</STYLE>
<SCRIPT language=javascript
src="Interfacing The Serial - RS-232 Port Part 3-4_files/beyondmenu.js"></SCRIPT>
<CENTER><BR><BR><FONT color=green size=5>Interfacing the Serial / RS-232
Port</FONT> <BR><BR></CENTER>
<P><FONT size=+2>
<CENTER>Table of Contents</CENTER></FONT>
<P></P>
<P>
<CENTER><FONT size=+1><B>Part 1 : Hardware (PC's)</B></FONT><BR><A
href="http://www.beyondlogic.org/serial/serial.htm#1">Hardware
Properties</A><BR><A
href="http://www.beyondlogic.org/serial/serial.htm#2">Serial Pinouts (D25 and D9
connectors)<BR><A href="http://www.beyondlogic.org/serial/serial.htm#3">Pin
Functions </A><BR><A href="http://www.beyondlogic.org/serial/serial.htm#4">Null
Modems </A><BR><A href="http://www.beyondlogic.org/serial/serial.htm#5">Loopback
Plugs</A><BR><A href="http://www.beyondlogic.org/serial/serial.htm#6">DTE/DCE
Speeds</A><BR><A href="http://www.beyondlogic.org/serial/serial.htm#7">Flow
Control </A><BR><A href="http://www.beyondlogic.org/serial/serial.htm#8">The
UART (8250's and Compatibles) </A><BR><A
href="http://www.beyondlogic.org/serial/serial.htm#9">Type of UARTS (For PC's)
</A><BR><FONT size=+1><B>Part 2 : Serial Ports' Registers
(PC's)</B></FONT><BR><A
href="http://www.beyondlogic.org/serial/serial.htm#12">Port Addresses and
IRQ's</A><BR><A href="http://www.beyondlogic.org/serial/serial.htm#13">Table of
Registers</A><BR><A href="http://www.beyondlogic.org/serial/serial.htm#14">DLAB
? </A><BR><A href="http://www.beyondlogic.org/serial/serial.htm#15">Interrupt
Enable Register (IER)</A><BR><A
href="http://www.beyondlogic.org/serial/serial.htm#16">Interrupt Identification
Register (IIR)</A><BR><A
href="http://www.beyondlogic.org/serial/serial.htm#17">First In / First Out
Control Register (FCR)</A><BR><A
href="http://www.beyondlogic.org/serial/serial.htm#18">Line Control Register
(LCR)</A><BR><A href="http://www.beyondlogic.org/serial/serial.htm#19">Modem
Control Register (MCR)</A><BR><A
href="http://www.beyondlogic.org/serial/serial.htm#20">Line Status Register
(LSR)</A><BR><A href="http://www.beyondlogic.org/serial/serial.htm#21">Modem
Status Register (MSR)</A><BR><A
href="http://www.beyondlogic.org/serial/serial.htm#22">Scratch
Register</A><BR><FONT size=+1><B>Part 3 : Programming (PC's)</B></FONT><BR><A
href="http://www.beyondlogic.org/serial/serial1.htm#30">Polling or Interrupt
Driven?</A><BR><A href="http://www.beyondlogic.org/serial/termpoll.c">Source
Code - Termpoll.c (Polling Version)</A><BR><A
href="http://www.beyondlogic.org/serial/buff1024.c">Source Code - Buff1024.c
(ISR Version) </A><BR><A
href="http://www.beyondlogic.org/serial/serial1.htm#31">Interrupt
Vectors</A><BR><A
href="http://www.beyondlogic.org/serial/serial1.htm#32">Interrupt Service
Routine</A><BR><A href="http://www.beyondlogic.org/serial/serial1.htm#33">UART
Configuration</A><BR><A
href="http://www.beyondlogic.org/serial/serial1.htm#34">Main Routine
(Loop)</A><BR><A
href="http://www.beyondlogic.org/serial/serial1.htm#35">Determining the type of
UART via Software</A><BR><FONT size=+1><B>Part 4 : External Hardware -
Interfacing Methods</B></FONT><BR><A
href="http://www.beyondlogic.org/serial/serial1.htm#40">RS-232
Waveforms</A><BR><A
href="http://www.beyondlogic.org/serial/serial1.htm#41">RS-232 Level
Converters</A><BR><A
href="http://www.beyondlogic.org/serial/serial1.htm#42">Making use of the Serial
Format</A><BR><A href="http://www.beyondlogic.org/serial/serial1.htm#43">8250
and compatible UART's</A><BR><A
href="http://www.beyondlogic.org/serial/serial1.htm#44">CDP6402, AY-5-1015 /
D36402R-9 etc UARTs</A><BR><A
href="http://www.beyondlogic.org/serial/serial1.htm#46">Microcontrollers</A><BR>
<P></P></CENTER>
<CENTER>
<TABLE width="95%">
<TBODY>
<TR>
<TD>
<P><A name=Part3></A>
<HR>
</A><I><FONT size=+2>Part 3 : Programming (PC's)</FONT></I>
<HR>
<P></P>
<UL><A name=30><FONT size=+1>Polling or Interrupt Driven?</FONT><BR>
<HR>
</A>
<P>When writing a communications program you have two methods available
to you. You can poll the UART, to see if any new data is available or
you can set up an interrupt handler to remove the data from the UART
when it generates a interrupt. Polling the UART is a lot slower method,
which is very CPU intensive thus can only have a maximum speed of around
34.8 KBPS before you start losing data. Some newer Pentium Pro's may be
able to achieve better rates that this. The other option is using a
Interrupt handler, and that's what we have used here. It will very
easily support 115.2K BPS, even on low end computers. </P>
<P>
<CENTER><A
href="http://www.beyondlogic.org/serial/termpoll.c">Termpoll.c - Simple
Terminal Program using the Polling Method.</A> </CENTER>
<P></P>
<P>Polling the UART should not be dismissed totally. It's a good method
for diagnostics. If you have no idea of what address your card is at or
what IRQ you are using you can poll the UART at several different
addresses to firstly find which port your card is at and which one your
modem is attached to. Once you know this information, then you can set
up the Interrupt routines for the common IRQs and by enabling one IRQ at
a time using the Programmable Interrupt Controller you can find out your
IRQ, You don't even need a screw driver! </P>
<P>
<CENTER><A
href="http://www.beyondlogic.org/serial/buff1024.c">Buff1024.c - Simple
Terminal Program using Interrupt Requests.</A> </CENTER>
<P></P>
<P>
<CENTER>
<TABLE width="90%">
<TBODY>
<TR>
<TD vAlign=top>Note:</TD>
<TD><I>The source code above is not a really good example on how
to program but is rather cut down to size giving quick results,
and making it easier to understand. Upon executing your
communications program, it would be wise to store the status of
the UART registers, so that they all can be restored before you
quit the program. This is to cause the least upset to other
programs which may also be trying to use the communications ports.
</I></TD></TR></TBODY></TABLE></CENTER>
<P>The first step to using interrupts is to work out which interrupt
services your serial card. Table 13 shows the base addresses and IRQ's
of some standard ports. IRQ's 3 and 4 are the two most commonly used.
IRQ 5 and 7 are sometimes used. </P><A name=31><FONT size=+1>Interrupt
Vectors</FONT><BR>
<HR>
</A>
<P>Once we know the IRQ the next step is to find it's interrupt vector
or software interrupt as some people may call it. Basically any 8086
processor has a set of 256 interrupt vectors numbered 0 to 255. Each of
these vectors contains a 4 byte code which is an address of the
Interrupt Service Routine (ISR). Fortunately C being a high level
language, takes care of the addresses for us. All we have to know is the
actual interrupt vector. </P>
<CENTER>
<TABLE border=1 width="80%">
<TBODY>
<TR>
<TD>
<CENTER><B>INT (Hex)</B></CENTER></TD>
<TD><B>
<CENTER>IRQ</CENTER></B></TD>
<TD><B>Common Uses</B></TD></TR>
<TR>
<TD>
<CENTER>08</CENTER></TD>
<TD>
<CENTER>0</CENTER></TD>
<TD>System Timer</TD></TR>
<TR>
<TD>
<CENTER>09</CENTER></TD>
<TD>
<CENTER>1</CENTER></TD>
<TD>Keyboard</TD></TR>
<TR>
<TD>
<CENTER>0A</CENTER></TD>
<TD>
<CENTER>2</CENTER></TD>
<TD>Redirected</TD></TR>
<TR>
<TD>
<CENTER>0B</CENTER></TD>
<TD>
<CENTER>3</CENTER></TD>
<TD>Serial Comms. COM2/COM4</TD></TR>
<TR>
<TD>
<CENTER>0C</CENTER></TD>
<TD>
<CENTER>4</CENTER></TD>
<TD>Serial Comms. COM1/COM3 </TD></TR>
<TR>
<TD>
<CENTER>0D</CENTER></TD>
<TD>
<CENTER>5</CENTER></TD>
<TD>Reserved/Sound Card </TD></TR>
<TR>
<TD>
<CENTER>0E</CENTER></TD>
<TD>
<CENTER>6</CENTER></TD>
<TD>Floppy Disk Controller </TD></TR>
<TR>
<TD>
<CENTER>0F</CENTER></TD>
<TD>
<CENTER>7</CENTER></TD>
<TD>Parallel Comms. </TD></TR>
<TR>
<TD>
<CENTER>70</CENTER></TD>
<TD>
<CENTER>8</CENTER></TD>
<TD>Real Time Clock</TD></TR>
<TR>
<TD>
<CENTER>71</CENTER></TD>
<TD>
<CENTER>9</CENTER></TD>
<TD>Reserved</TD></TR>
<TR>
<TD>
<CENTER>72</CENTER></TD>
<TD>
<CENTER>10</CENTER></TD>
<TD>Reserved</TD></TR>
<TR>
<TD>
<CENTER>73</CENTER></TD>
<TD>
<CENTER>11</CENTER></TD>
<TD>Reserved</TD></TR>
<TR>
<TD>
<CENTER>74</CENTER></TD>
<TD>
<CENTER>12</CENTER></TD>
<TD>PS/2 Mouse</TD></TR>
<TR>
<TD>
<CENTER>75</CENTER></TD>
<TD>
<CENTER>13</CENTER></TD>
<TD>Maths Co-Processor</TD></TR>
<TR>
<TD>
<CENTER>76</CENTER></TD>
<TD>
<CENTER>14</CENTER></TD>
<TD>Hard Disk Drive</TD></TR>
<TR>
<TD>
<CENTER>77</CENTER></TD>
<TD>
<CENTER>15</CENTER></TD>
<TD>Reserved </TD></TR></TBODY></TABLE><FONT size=-1>Table 14 :
Interrupt Vectors (Hardware Only) </FONT></CENTER>
<P>The above table shows only the interrupts which are associated with
IRQ's. The other 240 are of no interest to us when programming RS-232
type communications. </P>
<P>For example if we were using COM3 which has a IRQ of 4, then the
interrupt vector would be 0C in hex. Using C we would set up the vector
using the instruction <FONT color=#400080><TT>setvect(0x0C,
PORT1INT);</TT></FONT> where PORT1INT would lead us to a set of
instructions which would service the interrupt. </P>
<P>However before we proceed with that I should say that it is wise to
record the old vectors address and then restore that address once the
program is finished. This is done using <FONT
color=#400080><TT>oldport1isr = getvect(INTVECT);</TT></FONT> where
oldport1isr is defined using <FONT color=#400080><TT>void interrupt
(*oldport1isr)(); </TT></FONT></P>
<P>Not only should you store the old vector addresses, but also the
configuration the UART was in. Why you Ask? Well it's simple, I wrote a
communications program which was fully featured in the chat side of
things. It had line buffering, so no body could see my spelling mistakes
or how slowly I typed. It included anti-bombing routines and the list
goes on. However I couldn't be bothered to program any file transfer
protocols such as Zmodem etc into my communications program. Therefore I
either had to run my communications program in the background of
Telemate using my communications program for chat and everything else it
was designed for and using Telemate to download files. Another method
was to run, say Smodem as a external protocol to my communications
program. </P>
<P>Doing this however would mean that my communications program would
override the original speed, parity etc and then when I returned to the
original communications program, everything stopped. Therefore by saving
the old configuration, you can revert back to it before you hand the
UART back over to the other program. Makes sense? However if you don't
have any of these programs you can save yourself a few lines of code.
This is what we have done here. </P><A name=32><FONT size=+1>Interrupt
Service Routine (ISR)</FONT><BR>
<HR>
</A>
<P>Now, could we be off track just a little? Yes that's right, PORT1INT
is the label to our interrupt handler called a Interrupt Service Routine
(ISR). You can put just about anything in here you want. However calling
some DOS routines can be a problem. </P><FONT color=#400080><PRE>void interrupt PORT1INT()
{
int c;
do { c = inportb(PORT1 + 5);
if (c & 1) {
buffer[bufferin] = inportb(PORT1);
bufferin++;
if (bufferin == 1024) bufferin = 0;
}
} while (c & 1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -