Чтение из COM-порта из-под DOS
От: _Mandor_  
Дата: 02.05.06 15:12
Оценка:
Как сделать?
Дайте пример.
И запись тоже

03.05.06 11:20: Перенесено из 'C/C++'
Re: Чтение из COM-порта из-под DOS
От: programmater  
Дата: 02.05.06 15:40
Оценка: 1 (1)
Здравствуйте, _Mandor_, Вы писали:

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

_M_>Дайте пример.
_M_>И запись тоже
Ууу. Это сложно будет. Читай про регистры устройства (3F8-3FF). DOS-ом (точнее BIOS-ом) поддерживаются скорости только до 9600 бод, что на сегодняшний день явно мало. А все остальное в DOS-е только ручками прямой записью значений в порты этой микросхемы (Motorola 16550 если я не ошибаюсь). Да еще и на прерывания неплохо было бы повеситься, чтобы вовремя ловить момент прихода байта. Пример не дам — слишком длинно и без теоретической базы (понимания принципов работы аппаратуры последовательного адаптера) не разберешься. Так как в виндах (CreateFile()->SetCommState()->ReadFile()/WriteFile()->CloseHandle()) не получится — в DOS-е это _намного_ сложнее. Зато интереснее и свободы больше. В этом есть свои плюсы .
Re[2]: Чтение из COM-порта из-под DOS
От: rg45 СССР  
Дата: 02.05.06 16:06
Оценка:
"programmater" <34509@users.rsdn.ru> wrote in message news:1876857@news.rsdn.ru...
> Здравствуйте, _Mandor_, Вы писали:
>
> _M_>Как сделать?
> _M_>Дайте пример.
> _M_>И запись тоже
> Ууу. Это сложно будет. Читай про регистры устройства (3F8-3FF). DOS-ом (точнее BIOS-ом) поддерживаются скорости только до 9600 бод, что на сегодняшний день явно мало. А все остальное в DOS-е только ручками прямой записью значений в порты этой микросхемы (Motorola 16550 если я не ошибаюсь). Да еще и на прерывания неплохо было бы повеситься, чтобы вовремя ловить момент прихода байта. Пример не дам — слишком длинно и без теоретической базы (понимания принципов работы аппаратуры последовательного адаптера) не разберешься. Так как в виндах (CreateFile()->SetCommState()->ReadFile()/WriteFile()->CloseHandle()) не получится — в DOS-е это _намного_ сложнее. Зато интереснее и свободы больше. В этом есть свои плюсы .

Можно также использовать прерывание BIOS 14h
Posted via RSDN NNTP Server 2.0
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[2]: Чтение из COM-порта из-под DOS
От: _Mandor_  
Дата: 03.05.06 03:12
Оценка:
Здравствуйте, programmater, Вы писали:

P>Ууу. Это сложно будет. Читай про регистры устройства (3F8-3FF). DOS-ом (точнее BIOS-ом) поддерживаются скорости только до 9600 бод, что на сегодняшний день явно мало. А все остальное в DOS-е только ручками прямой записью значений в порты этой микросхемы (Motorola 16550 если я не ошибаюсь). Да еще и на прерывания неплохо было бы повеситься, чтобы вовремя ловить момент прихода байта. Пример не дам — слишком длинно и без теоретической базы (понимания принципов работы аппаратуры последовательного адаптера) не разберешься.


Вообщето именно 9600 и нужно т.к. больше сама железяка не умеет.
Может все же разродитесь примером? ИМХО разберемся...
Re[3]: Чтение из COM-порта из-под DOS
От: _Mandor_  
Дата: 03.05.06 03:13
Оценка:
Здравствуйте, rg45, Вы писали:

R>Можно также использовать прерывание BIOS 14h


Пример есть?
Re[3]: Чтение из COM-порта из-под DOS
От: Figaro Россия  
Дата: 03.05.06 04:53
Оценка:
Здравствуйте, _Mandor_, Вы писали:

_M_>Здравствуйте, programmater, Вы писали:


P>>Ууу. Это сложно будет. Читай про регистры устройства (3F8-3FF). DOS-ом (точнее BIOS-ом) поддерживаются скорости только до 9600 бод, что на сегодняшний день явно мало. А все остальное в DOS-е только ручками прямой записью значений в порты этой микросхемы (Motorola 16550 если я не ошибаюсь). Да еще и на прерывания неплохо было бы повеситься, чтобы вовремя ловить момент прихода байта. Пример не дам — слишком длинно и без теоретической базы (понимания принципов работы аппаратуры последовательного адаптера) не разберешься.


_M_>Вообщето именно 9600 и нужно т.к. больше сама железяка не умеет.

_M_>Может все же разродитесь примером? ИМХО разберемся...

Любая BBS'ка под дос... Масса в инете. Например:

http://bib.com.ua/info101.html
... << RSDN@Home 1.2.0 alpha rev. 0>>
Re: Чтение из COM-порта из-под DOS
От: _Mandor_  
Дата: 03.05.06 07:34
Оценка:
А почему перенесли? Мне же пример на C++ надо...
Re[2]: Чтение из COM-порта из-под DOS
От: programmater  
Дата: 03.05.06 08:07
Оценка:
Здравствуйте, _Mandor_, Вы писали:

_M_>А почему перенесли? Мне же пример на C++ надо...

Потому что работа с прерываниями на C++ делается сложнее, чем на ассемблере, а в DOS-е подобные вещи прерываниями делаются (это в случае 9600 и меньше) или вообще не делаются, только ручками прямой записью в порты (если выше 9600). Так что к сям придется ассемблерный переходник писать (типа функции WriteToPort(const char* Buf, unsigned short int BufLng)) и на сях использовать уже эту функцию. А тело самой этой функции лучше писать на асме. Так что переместили правильно.
Сейчас к сожалению доки по прерываниям BIOS нет, так что с ходу пример дать не могу. Как докопаюсь — дам.
Re[3]: Чтение из COM-порта из-под DOS
От: _Mandor_  
Дата: 03.05.06 08:11
Оценка:
Здравствуйте, programmater, Вы писали:

P>Сейчас к сожалению доки по прерываниям BIOS нет, так что с ходу пример дать не могу. Как докопаюсь — дам.


Спасибо, буду ждать...
Re: Чтение из COM-порта из-под DOS
От: DOOM Россия  
Дата: 03.05.06 08:19
Оценка:
Здравствуйте, _Mandor_, Вы писали:

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

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

Сам в свое время по Журдену осваивал.
P.S. Кодировка cp866 если что...
Re[2]: Чтение из COM-порта из-под DOS
От: programmater  
Дата: 03.05.06 10:38
Оценка:
Здравствуйте, DOOM, Вы писали:

DOO>Здравствуйте, _Mandor_, Вы писали:


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

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

DOO>Сам в свое время по Журдену осваивал.

DOO>P.S. Кодировка cp866 если что...
Кстати да, очень рекомендую для начала изучить то, что он пишет. Он правда пропустил прием и передачу данных через "средний уровень" (видимо оставил в качестве упражнения читателю ), а он явно проще "низкого уровня", который проводит Джордейн. Но средний уровень обладает очень серьезным недостатком: при приеме программа можент навечно зависнуть в ожидании байта, который (возможно) ей никогда не придет. И нет способа вывести программу из этого состояния, кроме как перезагрузить машину . В серьезных программах такое недопустимо, но для начала (для изучения работы DOS и последовательного адаптера) вполне сойдет. Я правда изучал все это по другим книгам и писал свои собственные функции, но то что за то, пишет Джордейн, ручаться не могу, но очень похоже на правду. Сейчас сочиню процедуры "среднего уровня" для работы с портом. Предупреждаю, tasm-а и turbo Debuger-а под рукой нет, так что возможно не будет компилироваться и не совсем правильно работать (ну давно я использовал все эти локальные переменные и передачу параметров из сей в ассемблер, так что могу со стеком намудрить). Я хочу показать идею, принцип. С конкретикой надеюсь _Mandor_ разберется. Поехали :
// Объявления в h файле.

typedef enum {BR110 = 0 , BR150 = 32 , BR300 = 64 , BR600 = 96 ,
                       BR1200 = 128 , BR2400 = 160 , BR4800 = 192 , BR 9600 = 224} BRCode;
typedef enum {ONE_STOP_BIT = 0 , TWO_STOP_BITS = 4} STBCode;
typedef enum {NO_PARITY = 0, ODD_PARITY = 8, EVEN_PARITY = 24} PARCode;
extern "C" void InitPort(unsigned short PortNum , BRCode BaudRate, STBCode StopBits, PARCode Parity);
extern "C" int ReadByteFromCOM(unsigned short PortNum);
extern "C" void WriteByteToCOM(unsigned short PortNum, unsigned char ByteToSend);


функции записи буфера и приема серии байт писать на асме в лом. Хотя если переходить на схему с прерываниями от COM порта (а не прерыванем BIOS!), то писать надо будет именно такие функции. Но это уже следующий уровень. В одном посте не ответишь. Да и отлаживать долго. Так что сейчас всю "пакетность" пиши на сях.
Перед тем, как давать реализацию вышезадекларированных функций на асме приведу отрывок документации на прерывание BIOS 14h, которое используется при работе с последовательным портом.


15. INT 14H — функции асинхроннной связи

Следующие функции INT 14H поддерживают протокол RS-232-C:
(AH) = 0 — инициализация порта асинхронной связи;
1 — передача байта;
2 — прием байта;
3 — получить состояние;
4 — расширенная инициализация;
5 — расширенное управление портом связи.
Последние две функции применяются только в System/2.
Сохраняются значения всех регистров, кроме AX. Базовые адреса портов
адаптеров связи и значения таймаутов устанавливаются при инициализации БСВВ.

15.1. Инициализация порта асинхронной связи.

Параметры: (AH) = 0;
(DX) — номер канала (0 — 3) в соответствии с базовым
адресом портов в таблице БСВВ по адресу 40:0;
(AL) — параметры инициализации:
биты 1,0 = 00 — 5-ти битный код,
= 01 — 6-ти битный код,
= 10 — 7-ми битный код,
= 11 — 8-ми битный код;
бит 2 = 0 — 1 стоп-бит,
1 — 2 стоп-бита для 6-8-ми битного кода,
1,5 стоп-бита для 5-ти битного кода;
бит 3 = 0 — нет контроля по паритету,
= 1 — есть контроль по паритету;
бит 4 = 0 — контроль по нечетности,
= 1 — контроль по четности;
биты 7-5 — скорость обмена (бод):
= 000 — 110
= 100 — 150
= 010 — 300
= 110 — 600
= 001 — 1200
= 101 — 2400
= 011 — 4800
= 111 — 9600
Результаты: (AH) — состояние линии управления,
(AL) — состояние модема (см. 15.4).

15.2. Передача байта

Параметры: (AH) = 1;
(DX) — номер канала (0 — 3) в соответствии с базовым
адресом портов в таблице БСВВ по адресу 40:0;
(AL) — байт данных для передачи.
Результаты: (AH) — состояние линии управления (см. 15.4),
(AL) — сохраняется.
Если бит 7 состояния линии устанавливается в 1, то остальные биты
состояния непредсказуемы. Байт в этом случае не передан.

15.3. Прием байта

Параметры: (AH) = 2;
(DX) — номер канала (0 — 3) в соответствии с базовым
адресом портов в таблице БСВВ по адресу 40:0;
(AL) — байт данных для передачи.
Результаты: (AH) — состояние линии управления (см. 15.4),
(AL) — принятый байт данных.
Модуль БСВВ ожидает приема байта.

15.4. Получить состояние канала.

Параметры: (AH) = 3;
(DX) — номер канала (0 — 3) в соответствии с базовым
адресом портов в таблице БСВВ по адресу 40:0;
Результаты: (AH) — состояние линии управления:
бит 7 — таймаут
6 — конец передачи (КПД)
5 — готов к передаче (ГПД)
4 — обрыв канала (авария)
3 — ошибка по стоп-биту
2 — ошибка по паритету
1 — переполнение
0 — готов к приему (ГПР)
(AL) — состояние модема:
бит 7 — детектор принимаемого линейного
сигнала канала данных (цепь 109),
6 — индикатор вызова (цепь 125),
5 — аппаратура готова (цепь 107),
4 — готов к передаче (цепь 106).

Документация какая-то древняя, но другой все равно под рукой нет, так что пишу отталкиваясь от того, что имею. Итак, используя сведения из этой доки, пишем реализацию функций на ассемблере:

InitPort PROC NEAR
         ARG PortNum:WORD , BaudRateCode:WORD , StopBitsCode:WORD , ParityCode:WORD
         push bp      ; стандартная конвенция входа в процедуру с использованием
         mov bp,sp    ; параметров и локальных переменных (в следующих функциях называется "пролог")
                      ; возможно этот кусок кода будет сгенерирован ассемблером,
                      ; но надо смотреть (из документации не ясно, а я сам уже забыл)
         push dx ax
         mov ax , BaudRateCode ; опять не помню как правильно: так
         ;mov ax , [BaudRateCode] или так.

         or ax , StopBitsCode  ; и далее обращения к локальным переменным. Если что, проставишь скобочки :)
         or ax , ParityCode
         or al , 3    ;8-ми битное слово. Сейчас других уже не бывает.
         mov dx , PortNum ; вот здеть не проверяем на корректность. Передавай правильные значения (0 - COM1 и т.д.)
         int 14h    ;вызов прерывания BIOS для инициализации порта.
 
         pop ax dx
         pop bp     ; тож может быть сгенерировано ассемблером вместе с кодом входа в процедуру (см.выше)
                    ; далее "эпилог"
         ret
InitPort Endp

ReadByteFromCOM proc NEAR
         ARG PortNum:WORD
;--------------пролог---------------------------
         push bp
         mov bp,sp
;------------------------------------------------
         push dx
         mov dx,PortNum
         mov ah,2
         int 14h    ; Вот тут можем повиснуть надолго (если ожидаемый нами байт не придет)
                    ; это главный недостаток приема данных используя прерывания BIOS
                    ; чтобы этого не было, нужно организовывать опрос (т.н. полинг)
                    ; или работать по аппаратному прерыванию от COM порта.
                    ; Но это уже ближе к Джордейну и его "низкому уровню"
         mov ah,0
         pop dx
         pop bp     ;------Эпилог-----------------
         ret
ReadByteFromCOM endp

WriteByteToCOM proc NEAR
         ARG PortNum:WORD , ByteToSend:WORD
;--------------пролог---------------------------
         push bp
         mov bp,sp
;------------------------------------------------
         push ax dx
;в передаче данных есть одна тонкость: нужно убедиться, что передатчик готов
;т.е. передача предыдущего байта уже завершена. Теоретически здесь тоже можно
;зависнуть, так что если не в лом, потом сможешь сам организовать выход по таймауту.

;-------проверим готовность передатчика
;-------для этого прочитаем состояние линии (функция 3 прерывания 14h)
@@WAIT_COMM_TRANSMITTER_READY_LOP:
         mov ah,3
         mov dx,PortNum
         int 14h
         ; теперь имеем в ah байт состояния линии. Проверим бит готовности передатчика
         test ah , 32
         jnz @@WAIT_COMM_TRANSMITTER_READY_LOP  ; Если передатчик не готов, то переходим 
                                                ; на опрос состояния линии.
                                                ; здесь вместо сразу перехода на опрос линии можно
                                                ; вставить еще и проверку таймаута (оставлю для упражнения)
         ; передатчик готов, можно передавать байт
         mov ax , ByteToSend
         mov ah , 1
         mov dx PortNum  ; по идее должен был сохраниться с предыдущего обращения к прерыванию. 
                         ; Но на всякий случай пишу (вот так и разрастаются программы :)  )
                         ; если хочешь, эту команду можно выбросить.
         int 14h

         pop dx ax
         pop bp     ;------Эпилог-----------------
         ret
WriteByteToCOM endp

Теоретически функцию проверки состояния линии можно было оформить как отдельную сишную функцию и организовать работу по опросу (при этом теоретически можно было проверять и бит готовности приемника), т.е. никогда не зависнуть, всегда быть способным среагировать на действия юзера и т.д. Но я этого никогда не делал (в смысле через прерывания BIOS, я делал так, но только через чтение/запись портов контроллера, а прерывания от контроллера запрещал, но это к делу не относится), поэтому приводить код не стал — слишком большая вероятность, что что-то напутаю. Поэтому рекомендую поэкспериментировать с этой функцией, посмотреть, что она возвращает в разных ситуациях. Возможно это как-то использовать. Ну, вроде все. Направление я дал, а дальше копай. Удачи.
Re[3]: Чтение из COM-порта из-под DOS
От: DOOM Россия  
Дата: 04.05.06 04:23
Оценка:
Здравствуйте, programmater, Вы писали:

[skipped]

Одна поправка... Jourdain надо читать не по-английски, а по-французски. Т.е. все-таки Жу(ю)рден. А то получается как у Акунина в Алтын-Толобасе "...усиленно называл меня мистер Фандорайн...."
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...
Пока на собственное сообщение не было ответов, его можно удалить.