Re: Чтение из COM-порта из-под DOS
От: nick_user Россия  
Дата: 04.05.06 06:00
Оценка:
Здравствуйте, _Mandor_, Вы писали:

_M_>Как сделать?

_M_>Дайте пример.
_M_>И запись тоже

Вот то, чем я пользуюсь (будет работать под DOS16 и под DOS32).
Извините за размер.
Есть еще один вариант работы с COM-портом, если нужен, могу выслать на почту (только для DOS16).

Пример работы c функциями:

InstallCom(1,115200,8,0,1); //настраиваем параметры порта
ClearCom(1); //очищаем входной буфер
//постоянно читаем данные из порта и выводим на экран
while(1)
{ 
   while(DataSizeInCom(1))
     printf("%c",ReadCom(1));
}


Заголовочный файл :

/* serial.h */
/* работа с последовательным портом для PC x86 */

#if !defined _SERIAL_H_

#define _SERIAL_H_

/* input buffer size*/
#define IN_BUF_SIZE 1024

#define __interrupt interrupt
#define __far far
#define __PARAM ...


#define NoError       0
#define ChkSumErr   -1
#define TimeOut     -2

void InstallCom1(long baud,int nbit,int parity,int stopbit);    //установка параметров порта
void RestoreCom1();                                                     //закрытие порта
int IsCom1();                                                            //проверка наличия данных в буфере порта
void ToCom1(int data);                                                 //отправка байта в порт
int ReadCom1();                                                         //чтение байта из входного буфера
void ClearCom1();                                                        //очистка входного буфера
int DataSizeInCom1();                                                 //размер данных во входном буфере
void __interrupt __far SerialISR1(__PARAM);                               //ф-ия обработки прерывания

void InstallCom2(long baud,int nbit,int parity,int stopbit);    //установка параметров порта
void RestoreCom2();                                                       //закрытие порта
int IsCom2();                                                              //проверка наличия данных в буфере порта
void ToCom2(int data);                                                   //отправка байта в порт
int ReadCom2();                                                           //чтение байта из входного буфера
void ClearCom2();                                                          //очистка входного буфера
int DataSizeInCom2();                                                   //размер данных во входном буфере
void __interrupt __far SerialISR2(__PARAM);                                //ф-ия обработки прерывания

// функции для работы с модулями 7000
int SndRcvCom1(char *cmd, char * resp,char chksum,int timeout);//отправка команды/прием ответа
int SndRcvCom2(char *cmd, char * resp,char chksum,int timeout);//отправка команды/прием ответа
// функции для ICOP-6070
void Set485DirToTransmit2();//включить порт RS485 на передачу
void Set485DirToReceive2(); //включить порт RS485 на прием

//общие функции
void InstallCom(int port, long baud, int nbit, int parity, int stopbit);
void RestoreCom(int port);
int  IsCom(int port);
void ToCom(int port, int data);
int  ReadCom(int port);
void ClearCom(int port);
int  DataSizeInCom(int port);
void ToComStr(int port, char * str);
void ToComBufn(int port, char * buf, int size);

#endif //_SERIAL


CPP-шник:

/* serial.cpp */

#include "serial.h"
#include <dos.h>
//#include <i86.h>
#include <conio.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>

/* baud */
#define BR_110 0x410
#define BR_150 0x300
#define BR_300 0x180
#define BR_600 0xC0
#define BR_1200 0x60
#define BR_2400 0x30
#define BR_4800 0x18
#define BR_9600 0xC
#define BR_19200 0x6
#define BR_38400 0x3
#define BR_57600 0x2
#define BR_115200 0x1
/* nbit */
#define bit_5 0x00
#define bit_6 0x01
#define bit_7 0x02
#define bit_8 0x03
/* parity */
#define NoParity  0x00
#define Odd       0x08
#define Even      0x18
/* stopbit */
#define OneStopBit 0x00
#define TwoStopBit 0x04


static char    InBuf1[IN_BUF_SIZE];
static int     wrcount1, rdcount1;
static char    InBuf2[IN_BUF_SIZE];
static int     wrcount2, rdcount2;
static void    __interrupt __far (* oldvectCom1)(__PARAM);
static void    __interrupt __far (* oldvectCom2)(__PARAM);

#define PORT1       0x3F8
#define INTVECT1    0xC
#define PORT2       0x2F8
#define INTVECT2    0xB

void __interrupt __far SerialISR1(__PARAM)
{// получено прерывание от порта
    while( inp(PORT1+5) & 0x01 )
    {
      if( wrcount1 >= IN_BUF_SIZE )
      {
         wrcount1 = 0;
         rdcount1 = 0;
      }
      InBuf1[wrcount1++] = (char)inp(PORT1);
    }
    outp(0x20,0x20);
};

void InstallCom1(long baud,int nbit,int parity,int stopbit)
{
   outp(PORT1+1,0);                       //запрещаем прерывания от UART
   oldvectCom1 = _dos_getvect(INTVECT1);  //получаем старый вектор прерывания
   _dos_setvect(INTVECT1,SerialISR1);     //устанавливаем новый вектор прерывания
   outp(PORT1+3,0x80);                    //устанавливаем режим загрузки делителя
   //скорость передачи
   switch( baud )
   {
   case 110L:    baud = BR_110; break;
   case 150L:    baud = BR_150; break;
   case 300L:    baud = BR_300; break;
   case 600L:    baud = BR_600; break;
   case 1200L:   baud = BR_1200; break;
   case 2400L:   baud = BR_2400; break;
   case 4800L:   baud = BR_4800; break;
   case 9600L:   baud = BR_9600; break;
   case 19200L:  baud = BR_19200; break;
   case 38400L:  baud = BR_38400; break;
   case 57600L:  baud = BR_57600; break;
   case 115200L: baud = BR_115200; break;
   default:      baud = BR_9600;
   }
   outp(PORT1+0, baud & 0xFF );           //загружаем младший байт делителя
   outp(PORT1+1,baud>>8);                 //загружаем старший байт делителя
   //кол-во бит
   switch( nbit )
   {
   case 5: nbit = bit_5; break;
   case 6: nbit = bit_6; break;
   case 7: nbit = bit_7; break;
   case 8: nbit = bit_8; break;
   default: nbit = bit_8;
   };
   //четность
   switch( parity )
   {
   case 0:  parity = NoParity; break;
   case 1:  parity = Odd;      break;
   case 2:  parity = Even;     break;
   default: parity = NoParity;
   };
   //стоп-биты
   switch( stopbit )
   {
   case 1: stopbit = OneStopBit; break;
   case 2: stopbit = TwoStopBit; break;
   default: stopbit = OneStopBit;
   };
   outp(PORT1+3,nbit|parity|stopbit);     //настраиваем формат передачи: кол-во бит/паритет/стоп-бит
   outp(PORT1+2,0x07);                    //буфер FIFO - 1 байт, включаем буфер
   outp(PORT1+4,0x0B);                    //устанавливаем линии RTS, DTR, OUT1
   outp(0x21,inp(0x21)&0xEF);             //настраиваем регистр маски прерываний контроллера прер-й
   outp(PORT1+1,0x01);                    //разрешаем контроллеру UART прерывание по приему байта
};

void RestoreCom1()
{
   outp(PORT1+1,0);                        //запрещаем прерывания от UART*/
   outp(0x21,(inp(0x21)|0x10));            //маскируем линию запроса прерывания
   if( oldvectCom1 )
      _dos_setvect(INTVECT1, oldvectCom1); //возвращаем старый вектор прерывания
};

int IsCom1()
{
   return ( wrcount1 > rdcount1 );
};

int ReadCom1()
{
   if( wrcount1 > rdcount1 )
      return InBuf1[rdcount1++];
   return -1;
};

void ToCom1(int data)
{
   while( !(inp(PORT1+5) & 0x20) );//ждем отправки байта
   outp(PORT1+0,data);//отправляем байт
};

void ClearCom1()
{
   wrcount1 = rdcount1 = 0;
};

int DataSizeInCom1()
{
   return (wrcount1 - rdcount1);
};

void __interrupt __far SerialISR2(__PARAM)
{//получено прерывание от порта
   while( inp(PORT2+5) & 0x01 )
   {
      if( wrcount2 >= IN_BUF_SIZE )
      {
         wrcount2 = 0;
         rdcount2 = 0;
      }
      InBuf2[wrcount2++] = (char)inp(PORT2);
   }
   outp(0x20,0x20);
};

void InstallCom2(long baud,int nbit,int parity,int stopbit)
{
   outp(PORT2+1,0);                     //запрещаем прерывания от UART
   oldvectCom2 = _dos_getvect(INTVECT2);//получаем старый вектор прерывания
   _dos_setvect(INTVECT2,SerialISR2);   //устанавливаем новый вектор прерывания
   outp(PORT2+3,0x80);                  //устанавливаем режим загрузки делителя
   //скорость передачи
   switch( baud )
   {
   case 110L:    baud = BR_110; break;
   case 150L:    baud = BR_150; break;
   case 300L:    baud = BR_300; break;
   case 600L:    baud = BR_600; break;
   case 1200L:   baud = BR_1200; break;
   case 2400L:   baud = BR_2400; break;
   case 4800L:   baud = BR_4800; break;
   case 9600L:   baud = BR_9600; break;
   case 19200L:  baud = BR_19200; break;
   case 38400L:  baud = BR_38400; break;
   case 57600L:  baud = BR_57600; break;
   case 115200L: baud = BR_115200; break;
   default:      baud = BR_9600;
   }
   outp(PORT2+0, baud & 0xFF );         //загружаем младший байт делителя
   outp(PORT2+1,baud>>8);               //загружаем старший байт делителя
   //кол-во бит
   switch( nbit )
   {
   case 5: nbit = bit_5; break;
   case 6: nbit = bit_6; break;
   case 7: nbit = bit_7; break;
   case 8: nbit = bit_8; break;
   default: nbit = bit_8;
   };
   //четность
   switch( parity )
   {
   case 0:  parity = NoParity; break;
   case 1:  parity = Odd;      break;
   case 2:  parity = Even;     break;
   default: parity = NoParity;
   };
   //стоп-биты
   switch( stopbit )
   {
   case 1: stopbit = OneStopBit; break;
   case 2: stopbit = TwoStopBit; break;
   default: stopbit = OneStopBit;
   };
   outp(PORT2+3,nbit|parity|stopbit);   //настраиваем формат передачи: бит/паритет/стоп-бит
   outp(PORT2+2,0x7);                   //буфер FIFO - 1 байт, включаем буфер
   outp(PORT2+4,0x0B);                  //устанавливаем линии RTS, DTR, OUT1
   outp(0x21,inp(0x21)&0xF7);           //настраиваем регистр маски прерываний контроллера прер-й
   outp(PORT2+1,0x01);                  //разрешаем контроллеру UART прерывание по приему байта
};

void RestoreCom2()
{
   outp(PORT2+1,0);//запрещаем прерывания от UART*/
   outp(0x21,(inp(0x21)|0x10));//маскируем линию запроса прерывания
   if( oldvectCom2 )
      _dos_setvect(INTVECT2, oldvectCom2);//возвращаем старый вектор прерывания
};

int IsCom2()
{
   return ( wrcount2 > rdcount2 );
};

int ReadCom2()
{
   if( wrcount2 > rdcount2 )
       return InBuf2[rdcount2++];
   return -1;
};

void ToCom2(int data)
{
   while( !(inp(PORT2+5) & 0x20) );
   outp(PORT2+0,data);
};

void ClearCom2()
{
   wrcount2 = rdcount2 = 0;
};

int DataSizeInCom2()
{
   return (wrcount2 - rdcount2);
};

void Set485DirToTransmit2()
{
   outp( PORT2+4, inp(PORT2+4) | 0x02 );//устанавливаем линию RTS
}

void Set485DirToReceive2()
{
   outp( PORT2+4, inp(PORT2+4) & 0xFD );//сбрасываем линию RTS
}

//функции для работы с модулями 7000
//отправка команды/прием ответа
int SndRcvCom1(char *cmd, char * resp,char chksum,int timeout)
{
        unsigned char sum = 0;
        char sumstr[2];
        if( chksum )
        {
                for( int i = 0; i < strlen(cmd); i++ )
                        sum += cmd[i];
                sprintf(sumstr,"%02X",sum);
        }
        //отправка команды
        for( int byte = 0; byte < strlen(cmd); byte++ )
                ToCom1(cmd[byte]);
        if( chksum )
        {
                ToCom1(sumstr[0]);
                ToCom1(sumstr[1]);
        }
        ToCom1('\r');
        //
        clock_t start_time = clock(), end_time;
        //ждем появления данных
        int counter = 0;
        char ch;
        do
        {
                while( !IsCom1() )
                {
                        end_time = clock();
                        if( (end_time - start_time) >= timeout ) return TimeOut;
                }
                ch = (char)ReadCom1();
                resp[counter++] = ch;
        }
        while( ch != '\r' );

        if( counter )
        {
           counter--;
           resp[counter] = 0;
        }

        if( chksum )
        {
            if( strlen(resp) < 2 ) return ChkSumErr;
                sum = 0;
                for( int i = 0; i < strlen(resp)-2; i++ )
                        sum += resp[i];
                if( sum == (unsigned char)strtoul(resp+strlen(resp)-2,0,16) )
                {
                        resp[strlen(resp)-2] = 0;
                        return NoError;
                }
                else
                {
                        return ChkSumErr;
                }
        }
        return NoError;
}

/* отправка команды/прием ответа */

int SndRcvCom2(char *cmd, char * resp,char chksum,int timeout)
{
        unsigned char sum = 0;
        char sumstr[3];
        if( chksum )
        {
                for( int i = 0; i < strlen(cmd); i++ )
                        sum += cmd[i];
                sprintf(sumstr,"%02X",sum);
        }
        //отправка команды
        for( int byte = 0; byte < strlen(cmd); byte++ )
                ToCom2(cmd[byte]);
        if( chksum )
        {
                ToCom2(sumstr[0]);
                ToCom2(sumstr[1]);
        }
        ToCom2('\r');
        //
        clock_t start_time = clock(), end_time;
        //ждем появления данных
        int counter = 0;
        char ch;
        do
        {
                while( !IsCom2() )
                {
                        end_time = clock();
                        if( (end_time - start_time) >= timeout ) return TimeOut;
                }
                ch = (char)ReadCom2();
                if( resp )
                   resp[counter++] = ch;
        }
        while( ch != '\r' );

        if( counter )
        {
           counter--;
           resp[counter] = 0;
        }

        if( chksum )
        {
           if( strlen(resp) < 2 ) return ChkSumErr;
                sum = 0;
                for( int i = 0; i < strlen(resp)-2; i++ )
                        sum += resp[i];
                if( sum == (unsigned char)strtoul(resp+strlen(resp)-2,0,16) )
                {
                        resp[strlen(resp)-2] = 0;
                        return NoError;
                }
                else
                {
                        return ChkSumErr;
                }
        }
        return NoError;
}

void InstallCom(int port, long baud, int nbit, int parity, int stopbit)
{
   switch( port )
   {
   case 1: InstallCom1(baud, nbit, parity, stopbit);break;
   case 2: InstallCom2(baud, nbit, parity, stopbit);break;
   default: InstallCom1(baud, nbit, parity, stopbit);break;
   }
};
void RestoreCom(int port)
{
   switch( port )
   {
   case 1: RestoreCom1();break;
   case 2: RestoreCom2();break;
   default: RestoreCom1();break;
   }
};
int  IsCom(int port)
{
   switch( port )
   {
   case 1: return IsCom1();
   case 2: return IsCom2();
   default: return IsCom1();
   }
};
void ToCom(int port, int data )
{
   switch( port )
   {
   case 1: ToCom1(data); break;
   case 2: ToCom2(data); break;
   default: ToCom1(data); break;
   }
};
int  ReadCom(int port)
{
   switch( port )
   {
   case 1: return ReadCom1();
   case 2: return ReadCom2();
   default: return ReadCom1();
   }
};
void ClearCom(int port)
{
   switch( port )
   {
   case 1: ClearCom1();  break;
   case 2: ClearCom2();  break;
   default: ClearCom1();  break;
   }
};
int  DataSizeInCom(int port)
{
   switch( port )
   {
   case 1: return DataSizeInCom1();
   case 2: return DataSizeInCom2();
   default: return DataSizeInCom1();
   }
};
void ToComStr(int port, char * str)
{
   for( int i = 0; i < strlen(str); i++)
      ToCom(port,str[i]);
};
void ToComBufn(int port, char * buf, int size)
{
   for( int i = 0; i < size; i++)
      ToCom(port,buf[i]);
};
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.