Как определить скорость передачи данных контроллера последовательного порта в MS-DOS с помощью C

Как можно определить текущую скорость передачи последовательного порта на контроллере UART 16550A в MS-DOS?


person Malcolm McCaffery    schedule 01.12.2020    source источник


Ответы (1)


Скорость передачи данных можно рассчитать, получив делитель. Это делается путем установки флага делителя путем отправки 0x80 на порт базовый адрес+3. Затем делитель извлекается путем считывания 16-битного значения из порта базовый адрес, который может определить скорость передачи на основе частоты кристалла на микросхеме UART. Различные таблицы зависимости частоты от скорости передачи данных можно найти в Книге данных по элементам микросвязи< /а>

Пример. Запустите это без параметров командной строки, чтобы получить список всех последовательных портов, установленных с COM1-COM4, ​​их базовый адрес и скорость передачи данных.

#include <dos.h>
#include <stdio.h>
#include <stdlib.h>

int detect_UART(unsigned baseaddr)
{
    // This function returns
    // -1 if no UART is installed
    // 0 - 8250
    // 1 - 16450
    // 2 - 16550 w/o SCR
    // 3 - 16550
    // 4 - 16550A w/o SCR
    // 5 - 16550A
    unsigned char x, scr=1;

    // First step: see if the LCR is there
    outp(baseaddr+3, 0x1B);
    if (inp(baseaddr+3) != 0x1B) return -1;
    outp(baseaddr+3,0x03);
    if (inp(baseaddr+3) != 0x03) return -1;
    // next thing to do is look for the scratch register
    outp(baseaddr+7,0x55);
    if (inp(baseaddr+7) != 0x55) scr=0;
    outp(baseaddr+7,0xAA);
    if (inp(baseaddr+7) != 0xAA) scr=0;
    // then check if there's a FIFO
    outp(baseaddr+2,0x01);
    x=inp(baseaddr+2);
    outp(baseaddr+2,0x00); // some old fashioned software relies on this
    if (!(x&0x80)) return scr;
    if (!(x&0x40)) return 2+scr;
    return 4+scr;
}

void check_type(unsigned baseaddr)
{
  char *uart[]={"COM1","COM2","COM3","COM4","UART"};
  char *type[]={"not installed",
        "8250","16450",
        "16550 w/o SCR","16550",
        "16550A w/o SCR","16550A"};

  int i;
  for (i=0;i<4;i++)
  {
    if ((unsigned)peek(0x40,2*i)==baseaddr) break;
  }

  if (baseaddr==0) i=4;
  printf(" %s with base address %03X is %-14s\n",
    uart[i], baseaddr, type[1+detect_UART(baseaddr)]);
}

void main(int argc,char *argv[])
{
    int i,divisor;
    printf("UARTs detect routine\n");
    if (argc<2)
    {
        for(i=0;i<4;i++)
        {
            register baseaddr=peek(0x40,2*i);
            if (baseaddr!=0)
            {
                check_type((unsigned)baseaddr);
                outp(baseaddr+3,0x80);
                divisor = inpw(baseaddr);
                printf("Divisor = %i\n",divisor);
                // assumes 1.8432 MHz crystal
                switch (divisor)
                {
                    case 2304:
                        printf("Baud Rate = 50\n");
                        break;
                    case 1536:
                        printf("Baud Rate = 75\n");
                        break;
                    case 1047:
                        printf("Baud Rate = 110 +/- 0.026 percent\n");
                        break;
                    case 857:
                        printf("Baud Rate = 134.5 +/- 0.058 percent\n");
                        break;
                    case 768:
                        printf("Baud Rate = 150\n");
                        break;
                    case 384:
                        printf("Baud Rate = 300\n");
                        break;
                    case 192:
                        printf("Baud Rate = 600\n");
                        break;
                    case 96:
                        printf("Baud Rate = 1200\n");
                        break;
                    case 64:
                        printf("Baud Rate = 1800\n");
                        break;
                    case 58:
                        printf("Baud Rate = 2000 +/- 0.69 percent\n");
                        break;
                    case 48:
                        printf("Baud Rate = 2400\n");
                        break;
                    case 32:
                        printf("Baud Rate = 3600\n");
                        break;
                    case 24:
                        printf("Baud Rate = 4800\n");
                        break;
                    case 16:
                        printf("Baud Rate = 7200\n");
                        break;
                    case 12:
                        printf("Baud Rate = 9600\n");
                        break;
                    case 6:
                        printf("Baud Rate = 19200\n");
                        break;
                    case 3:
                        printf("Baud Rate = 38400\n");
                        break;
                    case 2:
                        printf("Baud Rate = 56000 +/- 2.86 percent\n");
                        break;

                }
                outp(baseaddr+3,0x0);
            }
        }
    }
    else
    {
        for (i=1;i<argc;i++)
        {
            char *end;
            check_type((unsigned)strtol(argv[i],&end,16));
        }
    }
    printf("\n");
}
person Malcolm McCaffery    schedule 01.12.2020