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.