[comp.lang.pascal] Setting up the COMMS ports using Turbo Pascal

cfraser@gara.une.oz.au (Colin Fraser BEST) (11/28/90)

I would like to set up the comms port on my AT-compatible using
TP. The manual indicates how to do this for baud rates up to
and including 9600. However, I'd like to use a baud rate of
19200, and so I can't use the interrupts as in the example.

Has anyone done this, and if so, could you please help?

phys169@csc.canterbury.ac.nz (12/05/90)

In article <4805@gara.une.oz.au>, cfraser@gara.une.oz.au (Colin Fraser BEST) writes:
> I would like to set up the comms port on my AT-compatible using
> TP. The manual indicates how to do this for baud rates up to
> and including 9600. However, I'd like to use a baud rate of
> 19200, and so I can't use the interrupts as in the example.
> 
You have to program the registers yourself, but be warned: high baud rates can
result in data loss on input, unless you go to the effort of installing an
interrupt service routine to buffer incoming bytes. The following program
probably does a bit more than you need...

---snip---BAUDRATE.PAS-----(C)1990 M.Aitchison@canterbury.ac.nz---E&OE---
program BaudRate; {show/set baudrate of a coms posrt (default is COM1)}
uses DOS;

const ClockRate = 1843200.0/16.0; {PCjr is 1.7895e6/16}
      PortAddr : array[0..7] of word = 
        ($3F8,$2F8,$3E8,$3E0,$2F0,$2E8,$2E0,$260); {some have COM4 at $2E8}
      ProgramName = 'BAUDRATE';
      Version     = ' 1.0alpha (May have bugs; caveat emptor and all that)';
      CommandSyntax=' [baudrate]';
      ValidOptions= 'one of: /COM1 /COM2 /COM3 /COM4 /COM5 /COM6 /COM7 /COM8';
      Author      = 'M.Aitchison@canterbury.ac.nz';
      Copyright   = '(C)1990 by '+Author;
   
var BaudRate : real;
    Divisor  : word;
    ComsPort : integer; {0=COM1, 1=COM2, ... 3=COM4}
    BaseAddr : word;
    BiosPort : array[0..3] of word absolute $40:0; {port addresses known to BIOS}
    st       : string;
    i,err    : integer;

begin
ComsPort:=0;
BaudRate:=0;
for i:=1 to paramcount do
    begin
    st:=paramstr(i);
    if st[1] in ['/','-'] 
       then begin
            if upcase(st[2])='C' then ComsPort:=ord(st[length(st)])-ord('1');
            if st[2]='?' then 
                begin 
                writeln(ProgramName,Version,^M^J,Copyright:78,^M^J,
                 '(you are free to use/distribute this unmodified/non-commercially)',
                 ^M^J'Syntax:  ',ProgramName,' [options] '+CommandSyntax,
                 ^M^J'Options: ',ValidOptions,^M^J,
                 ^M^J'What It Does:'^M^J,
                 'Set or show the baud rate of a coms port (default is COM1), e.g.',
                 ^M^J'  BAUDRATE/COM2 134.5  {sets COM2 to 134.5 baud}');
                halt(0);
                end;
            end
       else val(st,BaudRate,err);
    end;
if (not ComsPort in [0..7]) 
   then begin writeln('Invalid Comms port!;); halt(1);end;
if (ComsPort>3) or (PortAddr[ComsPort]=0)
   then begin
        writeln('Warning: COM'+ComsPort+1,' not found in BIOS table.');
        BaseAddr:=PortAddr[ComsPort]; {a old BIOS that didn't detect COM3..?}
        end
   else BaseAddr:=BiosPort[ComsPort];
if BaudRate=0.0
   then begin {display present baud rate}
        i:=Port[BaseAddr+3]; {get present Line Control Register}
        Port[BaseAddr+3]:=i or $80; {enable baud rate divisor}
        Divisor:=port[BaseAddr]+256*port[BaseAddr+1];
        Port[BaseAddr+3]:=i;  {return to previous state. Should've used CLI/STI}
        if (Divisor=0 ) or (Divisor=$FFFF)
           then writeln('INVALID')
           else writeln(ClockRate/Divisor:7:1,' baud on COM'+ComsPort+1);
        end
   else begin {change baud rate}
        if BaudRate<50 then Divisor:=$FFFF
                       else Divisor:=round(ClockRate/BaudRate);
        i:=Port[BaseAddr+3]; {get present Line Control Register}
        Port[BaseAddr+3]:=i or $80; {enable baud rate divisor}
        Port[BaseAddr+0]:=lo(Divisor);
        Port[BaseAddr+1]:=hi(Divisor);
        Port[BaseAddr+3]:=i;  {return to previous state. Should've used CLI/STI}
        end;
end.

Mark Aitchison, Physics, University of Canterbury, New Zealand.
email address: PHYS169@Canterbury.ac.nz (or msa@phys.canterbury.ac.nz)

bb16@prism.gatech.EDU (Scott Bostater) (12/05/90)

In article <1990Dec5.121609.10113@csc.canterbury.ac.nz> phys169@csc.canterbury.ac.nz writes:
>In article <4805@gara.une.oz.au>, cfraser@gara.une.oz.au (Colin Fraser BEST) writes:
>> I would like to set up the comms port on my AT-compatible using
>> TP. The manual indicates how to do this for baud rates up to
>> and including 9600. However, I'd like to use a baud rate of
>> 19200, and so I can't use the interrupts as in the example.
>> 
>You have to program the registers yourself, but be warned: high baud rates can
>result in data loss on input, unless you go to the effort of installing an
>interrupt service routine to buffer incoming bytes. The following program
>probably does a bit more than you need...

[program code deleted]

If you want high data rates, I'd suggest using a FOSSIL driver (a device 
driver) to handle the interrupt service routines.  You can then perform simple
interrupt calls (almost identical to the BIOS calls) to do the serial I/O and
not have to worry about losing data.  Fossil supports data rates up to 38400
baud.

If you're interested, I've already written a FOSSIL unit to handle the 
interface from TP to the device driver.  I'll be happy to e-mail you a copy.


-- 
Scott Bostater      Georgia Tech Research Institute - Radar Systems Analysis
"My soul finds rest in God alone; my salvation comes from Him"  -Ps 62.1
uucp:     ...!{allegra,amd,hplabs,ut-ngp}!gatech!prism!bb16
Internet: bb16@prism.gatech.edu