I should point out that I haven't done a lot of COM port programming,
especially by directly accessing them with OUT and INP.  However, I have
some books that describe how COM ports work, at least in regard to
programming them, so I'll give you what should be the important
information and hope you can take it from there.  (I *have* written simple
routines to read/write individual bytes from/to the UART.  But for
anything more sophisticated, I haven't gone farther than just letting QB's
OPEN COMn statement handle things.)

First, QB's syntaxes for OUT and INP are

OUT port#, byte

and

byte = INP(port#)

(OUT writes a byte of data to port# and INP reads a byte of data from
port#.)  The trick is knowing the port number and knowing what byte to
write with OUT.  You have to do more than OUT your data to the COM port.
You also have to initialize the port and possibly read various status
information to make sure the data is flowing properly.  You could use
DOS' MODE command for the initialization, but I presume you'd probably
rather have QB handle everything.

COM ports have at least 7 registers.  (Newer ones have 8, but you only
need to worry about the first 7.)  These registers are numbered from 0 to
6 (or 7).  The port number (port#) that you have to work with is obtained
by adding the register number to the COM port's base address.

The base address for COM ports can usually be obtained by reading your
"ROM bios data area:"

DEF SEG = 0
BASEADD = PEEK(&H400) + 256& * PEEK(&H401)    'For COM1
BASEADD = PEEK(&H402) + 256& * PEEK(&H403)    'For COM2
BASEADD = PEEK(&H404) + 256& * PEEK(&H405)    'For COM3
BASEADD = PEEK(&H406) + 256& * PEEK(&H407)    'For COM4

(If you get zero for BASEADD when using the above, that's probably a good
indication that you don't have that COM port--unless you or some program
you've run explicitly "gimmicked" your computer to change memory values
from what the boot-up process put there.)

Okay, here's what the registers are for.  (And most of these registers
need to be accessed at the bit level, i.e., before writing to them, you'll
likely need to use QB's logical bit operators to create the byte, and
after reading from them, you may need to use those logical operators to
extract bits from the byte.)


Register 0:

Either the data byte you read with INP is in this register or the data
byte you write with OUT goes to this register.  (It's called the "receiver
buffer" if you're reading or the "transmit buffer" if you're writing.)

This assumes something called the Divisor Latch Access Bit (DLAB) is zero.
This bit is set by what's stored in register 3.  (I'll get there
eventually.)  If DLAB = 1, this register is used for something else.  In
this situation, register 0 and register 1 are used to specify the baud you
want to use.  You would write the least significant byte of the "Divisor
Latch" to register 0 and its most significant byte to register 1.  What is
this Divisor latch?  It's 115,200 divided by the baud you want to use.
Call this quotient DL (for divisor latch).  The least significant byte is

LSB = DL AND &HFF

and the most significant byte is

MSB = (DL and &HFF00&) / 256.

(Use an INTEGER or LONG variable for DL to make the AND operator work
right.  Note that you don't have to set the baud every time you access
this register for the purpose of writing or reading data.  Like other port
initializations, you only need to do it once.)


Register 1:

I've already mentioned what to do with this register if DLAB = 1.  So this
assumes DLAB = 0.  In that situation, this is the "interrupt enable"
register.  This is something you would write to (if you want to) and you
have to manipulate the bits in whatever you write.  Just to make sure we
understand the terminology, there are 8 bits in a byte.  They are numbered
from 0 to 7.  Bit 0 is the rightmost bit and bit 7 is the one on the left.
(And a bit is either 0 or 1--ignore the parts of any of this that insult
your intelligence.)  Bits 6 and 7 are not used here.  Bits 4 and 5 are
only used if you have a 82510 UART.  (A "UART" is the chip on your serial
board that makes it work.)  Now, what do these bits do?  Setting a
particular bit to 1 enables a particular interrupt.  Here's a table
showing which interrupt is enabled by setting which bit to 1.  (A bit = 0
means that the interrupt is disabled.  All bits are set to zero after a
hardware reset.)


bit 5 = 1:  Enable timer interrupt on 82510 UART

bit 4 = 1:  Enable transmit machine interrupt on 82510 interrupt

bit 3 = 1:  Enable modem status interrupt

bit 2 = 1:  Enable receiver line status interrupt

bit 1 = 1:  Enable transmit holding register empty interrupt

bit 0 = 1:  Enable received data available interrupt


(On a 16550 UART, bit 0 also enables the timeout interrupt when in FIFO
mode.  However, when I get to register 2, I'm going to suggest that you
ignore FIFO mode.  :)  )  I should also add that if you have any sort of
detailed questions about these interrupts, and this applies to register 2
as well, all I can say is that, although I think it relates to "hand-
shaking," i.e., not sending or receiving data until everything involved is
ready for those things to happen, I don't have the answers.  Hopefully,
this will all at least give you something to start with.


Register 2:

If you have a 16552 UART, use of this register is also determined by
whether or not DLAB = 1.  However, what my book says about this register
when DLAB = 1 doesn't look particularly worth worrying about, so let's
just assume that you don't have a 16552 UART, or if you do, that you've
set DLAB to 0.  (Basically, if it didn't become clear already, registers 0
and 1, and maybe 2, constitute a different set of registers depending on
whether DLAB = 0 or 1.  And if you have a 16552 UART and you're really
interested in the DLAB = 1/register 2 case, let me know and I'll quote
from my book for you.  :)  )

Even with DLAB = 0, this register's function depends on whether you're
reading it (INP) or writing to it (OUT).  The writing mode seems simplest,
especially given what I'm going to suggest, so I'll get it over with
first.  In write mode, and ONLY for the 16550 series UART chips, this is
the "FIFO control" register.  FIFO mode is apparently another way of
transferring data over the serial port.  I don't see much information in
my book about what to do if you wanted to use this mode, so I'm going to
suggest not using this mode.  (FIFO mode off is the default state after a
hardware reset.)  You do this by setting bit 0 to 0 in register 2.  The
easiest way to do this is to just OUT a 0 or any other even byte to the
register.  (Since other uses of this register, i.e., for input purposes,
may cause bit 0 to be set because of what your peripheral device does, you
may need to write this even byte previous to every time you write data to
register 0.  I'm not real sure about that, however.  FIFO mode may only
get set when *you* set bit 0 to 1, not when your peripheral device does
it.)

In read mode, this is called the "interrupt identification" register.  It
appears to relate to those interrupts you may have enabled using register
1.  From what I understand, you only need to worry about this register
(unless you're using FIFO mode, when it also has a use with INP) if you
enabled interrupts with register 1, and you only have to worry about the
bits in register 2 that correspond to the bits you set to one in register
1.  Since you aren't using FIFO mode (right? :)  ), only the first four
bits of register 2 are of interest to you.  (These are the four bits on
the right, bits 0 - 3.)  Here's how you interpret the bits (on the
assumption that the corresponding interrupts were enabled in register 1).
(In this table (bit 3 is the one on the left and bit 0 is on the right.)


0000:  modem status changed
0001:  no interrupt pending
0010:  transmit holding register empty interrupt triggered
0100:  received data available interrupt triggered
0110:  receiver line status interrupt triggered
1000:  transmit machine interrupt only (82510 UART only)
1010:  timer interrupt triggered (82510 UART only)
1100:  character time-out interrupt triggered (16550 series UARTs only)


(This is the only reference I saw to the character time-out interrupt.
The book's discussion for register 1 didn't say anything about enabling
or disabling it.)


Register 3:

In addition to the baud you want to use, which was already discussed,
there are other communication parameters you need to initialize your COM
port with.  You use register 3 (and OUT) to do that.  (You can also of
course read the byte with INP if you want to see what things are already
set to.)  This is the "line control" register.  These communication
parameters include things like parity, the number of stop bits, and the
number of data bits (or the "character word length").  There are a few
other things too.  Let's do those other things first.

One such other parameter is the DLAB bit.  It's bit 7 and has already been
otherwise discussed.  (You need to set it to 0 or 1, depending on what
you're currently doing with registers 0 - 2.)

Bit 6 is the "break control bit."  Make things easy on yourself, and set
this bit to 0 (the "normal setting," according to my book).

Now we get to the communication parameters.  The parity is set using bits
3 - 5.  I have two different books that discuss this and I noticed some
time ago that they disagree as to what these bits should be set to (and
neither seems to be totally right).  Between comparing the two books and
doing some experimenting, I came up with the following table as to what
you should do with these bits.


bits 5 4 3     parity
     0 0 0     IGNORE (NONE)
     0 0 1      ODD
     0 1 0      EVEN  ?
     0 1 1      EVEN
     1 0 0      ODD
     1 0 1      MARK
     1 1 0      EVEN
     1 1 1     SPACE


Bit 2 specifies the number of stop bits.  Set it to zero to use one stop
bit.  Set it to one for two stop bits--unless you're going to use 5 data
bits (bits 0 and 1).  If you use 5 data bits, setting bit 2 to one means
to use 1.5 stop bits.  (I have no idea what half a bit means, but this
isn't the first time I've seen reference to the concept--in regard to
communication parameters.)

And as I've already implied, you use bits 0 and 1 to specify the number of
data bits you want to use.  Here's a table showing the settings.


bits 1 0   data bits
     0 0       5
     0 1       6
     1 0       7
     1 1       8


Register 4:

This is the "modem control" register.  It relates to setting the state of
the pins on your COM port connector.  The information in my book seems
somewhat "archane" and I can't pretend to understand much about what it
says, so I'll just pretty much quote (or closely paraphrase) what I'm
reading (like I haven't pretty much been doing that all along).  The bit
interpretations again depend on what type of UART you have.  Most of the
bits you can either read or write (and some of them you would definitely
need to write).  In the following tables, "r" means you can read the bit,
"w" means you can write the bit, and "x" means a value of 0 or 1, depend-
ing on what you want to do.

For non-16C1450/1550 series UARTs, here's the table.


bit 7 (r) = 0:  unused
bit 6 (r) = 0:  unused
bit 5 (r/w) = x:  unused or -OUT0 line on 82510
bit 4 (r/w) = 1:  loopback between transmit and receive is enabled.
bit 3 (r/w) = 1:  -OUT2 line, used to enable interrupt requests (IRQ).
bit 2 (r/w) = x:  -OUT1 line, unconnected and unused.
bit 1 (r/w) = x:  set the state of the Request to Send (RTS) line on the
                  connector.
bit 0 (r/w) = x:  set the state of the Data Set Ready (DTR) line on the
                  connector.


Here's the table for 16C1450 and 16C1550 series UARTs.


bit 7 (r/w) = 0:  power on, normal operation
            = 1:  power savings mode
bit 6 (r) = 0:  unused
bit 5 (r) = 0:  unused
bit 4 (r/w) = 1:  loopback between transmit and receive is enabled.
bit 3 (r/w) = 1:  enable interrupt requests (IRQ).
bit 2 (r/w) = 0:  normal operation
            = 1:  reset UART (like a hardware reset)
bit 1 (r/w) = x:  set the state of the Request to Send (RTS) line on the
                  connector.
bit 0 (r/w) = x:  set the state of the Data Set Ready (DTR) line on the
                  connector.


Simply quoting:  "A power down mode allows the system to save power.
During power down, all registers are retained, but the oscillators are
turned off."  This capability is, according to the book, what allows these
types of UARTs to have bit 2 being set to cause a reset.


Register 5:

This is the "line status" register.  It's something you would read.  There
are no bits to be set by using OUT to write a properly configured byte.
Here's the rundown on what the bits mean.

Bit 7 is unused except for 16550 series UARTs.  On these UARTs, bit 7 = 0
means that the UART is not in FIFO mode.  (Again, *you* don't put the
UART in FIFO mode by setting this bit to 1.  That's what bit 0 of register
2 is for.)  Again only for 16550 series UARTs, if bit 7 is 1 *and* FIFO
mode is being used, the indication is that some sort of error occurred.
(If such UARTs aren't using FIFO mode, this bit essentially isn't used by
them either.)

Bit 6 = 0:  The transmit holding register or transmit shift register has a
            byte.

Bit 6 = 1:  The transmit holding register and the transmit shift register
            are both empty.  (In case you're using FIFO mode, somehow, the
            "transmit FIFO" must also be empty for bit 6 to be one.)

Bit 5 = 0:  The transmit holding register has a byte.  (This state is set
            whenever the CPU loads a byte for sending.)

Bit 5 = 1:  The transmit holding register is empty and is ready to accept
            a new byte for transmission.  If the transmit holding
            interrupt is enabled, an interrupt request is made when this
            bit = 1.  (In FIFO mode, this bit is set to 1 only when the
            transmit FIFO is empty.)

Bit 4 = 0:  This is the "normal" condition.  It means no break was
            detected.

Bit 4 = 1:  This means a break was received.  (A break is signalled when
            an incoming signal remains "high" for longer than a full
            "serial frame," whatever that is.  Oh, wow.  The book actually
            explains what all this means.  It means that the received
            start bits, data bits, and parity are all high (i.e., all
            equal 1) but no stop bit is received.)  Reading this register
            clears this bit.  (Clearing a bit means to set it to zero.))

Bit 3 = 1:  A framing error occurred.  This means that, while receiving
            data, the stop bit was detected as high (i.e., it was 1).
            (The stop bit is always, according to the book, supposed to be
            a low signal (0 bit).)  This usually means that your signal is
            noisy or otherwise of poor quality.  This bit is also cleared
            upon reading the register.

Bit 2 = 1:  This means a parity error occurred and this bit is again
            cleared if you read the register.

Bit 1 = 1:  An overrun error occurred.  This means that a second byte was
            received before the CPU read the prior received byte from the
            buffer (register 0, I would think).  In FIFO mode, this error
            only occurs if the received FIFO buffer is full.  (This bit is
            also cleared when you read the register.)

Bit 0 = 0:  This means no data is available.  (In FIFO mode, the received
            FIFO is empty.)

Bit 0 = 1:  This is the "data ready indicator."  (A received byte is
            available to be read by the CPU.)


Register 6:

This is the "modem status" register.  It holds modem status flags (bits).
All bits may be read or written.  They all refer to pins on your serial
connector and show the current control line's state.  They indicate
whether the line has changed since this register was last read.  Bits 0 to
3 are the "changed state" bits.  If any of these bits gets set (because of
whatever happens in the process of transferring data through the COM
port) *and* the modem status interrupt is enabled (see register 1/DLAB =
0, bit 3), an interrupt is generated.  These bits are set to zero after a
hardware reset or this register is read.  (So, if you didn't enable the
modem status interrupt, you can ignore this register.)

My book indicates that bits 4 - 7 aren't used unless you're in "loopback
mode."  However, it doesn't seem to give much information on what that
mode really is, so I don't see any point in showing a table of information
that won't likely mean anything to you and that I can't make mean
anything.


Register 7:

This register isn't available in the original 8250 UART, and it may not be
in others either.  Even the UARTs that have it (and most, if not all, of
the newer ones do, I think) don't use it for *anything*.  You can just
skip the rest of this if you want to.

This register is readable and writable.  You can use it, for whatever
reason you would want to, to store one byte's worth of data.  However, you
might want to be careful doing that because other programs may also use
this register as a temporary one-byte data space.  As with my reference,
I only mention this register for this reason and the fact that it has a
rather neat attribute:  whatever's in this register doesn't get changed if
you do a hardware reset.  If you, for example, wanted to reboot your
computer and have your autoexec automatically do something based on a
previous condition that existed before you rebooted--and you can represent
that condition by a number between 0 and 255, you could put that number in
this register, reboot, and then have some program run by your autoexec
read this register and act accordingly.


    Source: geocities.com/gstumpff