Организация обмена с КУ ТРК через интерфейс RS-232C

+7 (383) 358-68-69; semico@mail.ru |  Контакты  |  Прайс-лист

Главная / Оборудование для АЗС / Программное обеспечение

При самостоятельной разработке систем управления АЗС или автоматизированных рабочих мест (АРМ) оператора АЗС требуется решить задачу управления оборудованием, в частности контроллерами управления (КУ) ТРК.

Обычно, прежде всего, начинаются поиски драйвера КУ ТРК. К сожалению, универсальных драйверов для этого оборудования нет. Основные причины этого следующие:

1. Из всего спектра протоколов оборудования для управления отпуском топлива на АЗС, только так называемый "Универсальный протокол..." (СКБ ВТ "Искра") является общедоступным. Все остальные нужно покупать или "доставать". Почему это так - ведомо только производителям оборудования с закрытыми протоколами обмена. Вероятно, для того, чтобы покупатели, которые однажды приобрели оборудование данной фирмы, навсегда остались к ней привязаны.

Но более-менее универсальная программа АРМ должна работать с различными типами оборудования. А программисты, потратившие деньги и время на розыск протоколов не слишком спешат поделиться ими с коллегами.

Каждый разработчик АРМ АЗС вызывает драйверы различного оборудования из своей программы своим специфическим способом. Поэтому драйверы от одной программы не подойдут к другой, даже если они выполняют одинаковые функции.

2. Интерфейс взаимодействия программы с внешним драйвером будет не проще, чем прямое обращение к своим драйверам или напрямую к оборудованию.

Многие предлагают сделать взаимодействие с КУ ТРК через файл (обычно высказываются пожелания относительно DBF формата). Но работа с оборудованием через файл резко увеличит время обращения к нему. О работе же в реальном времени в таком случае даже и мечтать не приходится. Кроме того, появляется дополнительный источник ошибок и неопределенностей. Например, значительно повышается вероятность сбоев и потери данных при внезапном пропадании питания компьютера (аварийном останове программы).

При этом сам драйвер обязан уметь работать со всеми версиями DBF напрямую, или пользоваться СУБД. В первом случае - нет гарантии, что все возможные варианты будут корректно отработаны. Второй случай еще хуже - вызовы СУБД из драйвера оборудования, работающего в реальном времени - это нонсенс.

Более грамотным решением является обмен сообщениями между программами АРМ и драйвера. Но для этого программе АРМ все равно придется организовать корректный обмен данными с другим приложением.

Причины затруднений при связи с оборудованием через последовательный порт заключены в том, что разработкой АРМ обычно занимаются программисты, которые ориентированы на работу в СУБД. Разумеется, в желании решить задачу привычным инструментом, ничего особо плохого нет, но этот подход малоэффективен.

В принципе же нет ничего сложного в работе с КУ ТРК через интерфейс последовательной связи RS-232C напрямую из программы АРМ. Далее приведен пример обмена данными с КУ ТРК через последовательный порт в операционной системе (ОС) Windows на языке C++. Пример работоспособен под всеми версиями Windows от 95 до XP. Для работы с портом используется коммуникационный API Win32, поэтому данный пример с минимальными переделками можно перенести на другие языки, позволяющие использовать WinAPI, к примеру, тот же Visual Basic.

Приведенный пример будет корректно работать и в WINE под Linux.

Для упрощения примера обмен ведется в синхронном режиме. Это значит, что выполнение основной программы прерывается на время обмена, но во многих случаях это можно допустить.

В асинхронном режиме возврат из функции происходит немедленно, сам обмен происходит в фоновом режиме, а по окончании обмена ОС сама сообщает об этом приложению. Этот режим предпочтительнее, но чуть сложнее. С небольшими изменениями приведенный пример может быть использован и для работы в асинхронном режиме.

Кроме того, в примере открытие и закрытие коммуникационного порта происходит при каждом обмене данными. Это несколько ограничивает скорость обмена. Для ускорения работы открытие и закрытие порта следует выделить в отдельные функции. При этом желательно не забывать их вызывать после запуска программы и перед выходом из нее.



Пример работы с КУ ТРК

Пример намеренно упрощен. В реальных программах, например в САУ "Лайнер", используются более сложные алгоритмы. Но этот подход позволяет получить вполне работоспособную программу.


// Начало примера

/* При создании консольного приложения этот файл может автоматически не добавиться к проекту, придется добавить вручную */

#include <afxwin.h>

/* В программе должны быть локально или глобально объявлены hPort, dcb, cto */

HANDLE hPort=NULL; /* Дескриптор порта, создается при открытии и используется для всех операций с портом */

DCB dcb; /* Device Control Block - установки, управляющие работой порта */

COMMTIMEOUTS cto; /* Структура, задающая тайм-ауты последовательного порта */

/* Класс, который будет использоваться для управления КУ ТРК */

class CPilot
{
public:
CPilot(); // конструктор класса

int kom_pilot(int, int, long, long, long); /* функция обмена данными с КУ ТРК */

int print(int); /* печать буферов команды и ответа на экран - используется в примере и может быть использована при отладке */

int com; /* номер последовательного порта 1 - COM1 и т.д. до COM9 */

private:
BYTE kbuf[256]; // буфер передаваемой команды

BYTE rbuf[256]; // буфер принимаемого ответа
};

/* Далее приведен текст функций класса CPilot: */
/////////////////////////////////////////////////////////////////
CPilot::CPilot()
{
int i;
/* Инициализация буферов, хотя этого можно и не делать */
for (i=0; i<32; i++) rbuf[i]=kbuf[i]=0;
}

int CPilot::kom_pilot(int pnum, int pkom, long pcena, long pdoza, long pkod)
{
/* Используемые при вызове переменные

pnum - номер КУ ТРК (обычно соответствует номеру ТРК или номеру отдела ККМ)

pkom - код команды, см. "Универсальный протокол"

pcena - цена за 1 л топлива в копейках, от 0 до 999999

pdoza - доза топлива в миллилитрах, от 0 до 999999

pkod - соответствует числовому значению поля Status, см. "Универсальный протокол", от 0 до 0xFFFF (то есть до 65535 в десятичном виде).


Примечание. В исходной программе на Си данные хранятся и передаются в двоичном виде.

При вызове из СУБД, вероятно, было бы проще не преобразовывать данные и передавать их в виде строк, но тогда следует внимательно следить за форматом строки и заполнять поля буфера kbuf[] слева символами "нуль" (0x30).

*/

int re=0;

/* Код возврата из функции 0 - OK, 256-выход по тайм-ауту, 257-ошибочная контрольная сумма или формат команды, 258 - последовательный порт не открыт или не обнаружен.

0x31...0x33 - ошибки, возвращаемые КУ ТРК по "Универсальному протоколу":

0x31 - "Недопустимый номер ТРК" в версии протокола 1.72 реально не используется (некому его вырабатывать). Был введен в младших версиях, в которых номер контроллера и номер ТРК передавались раздельно;

0x32 - "Недопустимая команда ТРК при данном состоянии ТРК" - подана команда, которая не может быть исполнена в текущем состоянии КУ ТРК;

0x33 - "Неправильная контрольная сумма" - в принятой КУ ТРК команде не совпала контрольная сумма.

*/

int i,j; /* Вспомогательные переменные*/

CString strPort="\\\\.\\COM"; /* Строка, используемая при открытии порта */

char ptemp[32]; /* буфер для преобразования чисел*/

DWORD d; /* переменная для подсчета реально переданных и принятых байт*/

/* Начало формирования команды в буфере kbuf[], формат команды здесь подробно не рассматривается. См. в "Универсальном протоколе" */

kbuf[0]=1; // SOH

/* формирование номера КУ ТРК */

switch (pnum)

  { case 0: kbuf[1]=0x30; kbuf[2]=0x30; break; // "00"
  case 1: kbuf[1]=0x30; kbuf[2]=0x31; break; // "01"
  case 2: kbuf[1]=0x30; kbuf[2]=0x32; break; // "02"
  case 3: kbuf[1]=0x30; kbuf[2]=0x33; break; // "03"
  case 4: kbuf[1]=0x30; kbuf[2]=0x34; break; // "04"
  case 5: kbuf[1]=0x30; kbuf[2]=0x35; break; // "05"
  case 6: kbuf[1]=0x30; kbuf[2]=0x36; break; // "06"
  case 7: kbuf[1]=0x30; kbuf[2]=0x37; break; // "07"
  case 8: kbuf[1]=0x30; kbuf[2]=0x38; break; // "08"
  case 9: kbuf[1]=0x30; kbuf[2]=0x39; break; // "09"
  case 10: kbuf[1]=0x30; kbuf[2]=0x41; break; // "0A"
  case 11: kbuf[1]=0x30; kbuf[2]=0x42; break; // "0B"
  case 12: kbuf[1]=0x30; kbuf[2]=0x43; break; // "0C"
  case 13: kbuf[1]=0x30; kbuf[2]=0x44; break; // "0D"
  case 14: kbuf[1]=0x30; kbuf[2]=0x45; break; // "0E"
  case 15: kbuf[1]=0x30; kbuf[2]=0x46; break; // "0F"
  case 16: kbuf[1]=0x31; kbuf[2]=0x30; break; // "10"
  default: kbuf[1]=0x30; kbuf[2]=0x30; /* "00" по умолчанию при некорректных входных данных */

  }

/* Перенос кода команды */

kbuf[3]=(BYTE)pkom; /* Это позволяет использовать произвольные коды команд, в том числе дополнительные команды КУ ТРК серии ПИЛОТ */

if (pnum==0) kbuf[3]=0x37; /* Для номера "00" код команды - всегда "Общий останов", впрочем, для КУ ТРК ПИЛОТ данная проверка не обязательна */

kbuf[4]=2; // STX

/* Заполнение поля "Price". Проверка цены на корректность */

if (pcena<0) pcena=0;
if (pcena>999999) pcena=999999;

ltoa(pcena,ptemp,10); /* Преобразование числа в строку по основанию системы счисления 10 */

/* Далее следует перенос в буфер kbuf[] из строки ptemp в зависимости от ее длины.
Это, разумеется, можно было сделать и короче, но гораздо менее наглядно.
Поскольку не это в примере главное, не следует отвлекаться на лишние головоломки. Пусть здесь и далее будет так.
*/

if (pcena==0)
  {
  kbuf[5]=0x30;
  kbuf[6]=0x30;
  kbuf[7]=0x30;
  kbuf[8]=0x30;
  kbuf[9]=0x30;
  kbuf[10]=0x30;
  goto jmp_doza;
  }

if (pcena<10)
  {
  kbuf[5]=0x30;
  kbuf[6]=0x30;
  kbuf[7]=0x30;
  kbuf[8]=0x30;
  kbuf[9]=0x30;
  kbuf[10]=ptemp[0];
  goto jmp_doza;
  }

if (pcena<100)
  {
  kbuf[5]=0x30;
  kbuf[6]=0x30;
  kbuf[7]=0x30;
  kbuf[8]=0x30;
  kbuf[9]=ptemp[0];
  kbuf[10]=ptemp[1];
  goto jmp_doza;
  }

if (pcena<1000)
  {
  kbuf[5]=0x30;
  kbuf[6]=0x30;
  kbuf[7]=0x30;
  kbuf[8]=ptemp[0];
  kbuf[9]=ptemp[1];
  kbuf[10]=ptemp[2];
  goto jmp_doza;
  }

if (pcena<10000)
  {
  kbuf[5]=0x30;
  kbuf[6]=0x30;
  kbuf[7]=ptemp[0];
  kbuf[8]=ptemp[1];
  kbuf[9]=ptemp[2];
  kbuf[10]=ptemp[3];
  goto jmp_doza;
  }

if (pcena<100000)
  {
  kbuf[5]=0x30;
  kbuf[6]=ptemp[0];
  kbuf[7]=ptemp[1];
  kbuf[8]=ptemp[2];
  kbuf[9]=ptemp[3];
  kbuf[10]=ptemp[4];
  goto jmp_doza;
  }

kbuf[5]=ptemp[0];
kbuf[6]=ptemp[1];
kbuf[7]=ptemp[2];
kbuf[8]=ptemp[3];
kbuf[9]=ptemp[4];
kbuf[10]=ptemp[5];

jmp_doza: /* Заполнение поля Volume. Метка для перехода из goto. Это не делает программу "структурированной" и в некоторых учебниках считается недопустимым, но зато избавляет от ненужных фигурных скобок, разобраться в которых тоже не просто. Тем более, что в откомпилированной программе все эти фигурные скобки все равно будут заменены на команды условного и безусловного перехода. */

/* Проверка дозы на корректность */

if (pdoza<0) pdoza=0;
if (pdoza>999999) pdoza=999999;

/* Перенос дозы в kbuf[]. Выполняется аналогично. */

ltoa(pdoza,ptemp,10);

if (pdoza==0)
  {
  kbuf[11]=0x30;
  kbuf[12]=0x30;
  kbuf[13]=0x30;
  kbuf[14]=0x30;
  kbuf[15]=0x30;
  kbuf[16]=0x30;
  goto jmp_kod;
  }

if (pdoza<10)
  {
  kbuf[11]=0x30;
  kbuf[12]=0x30;
  kbuf[13]=0x30;
  kbuf[14]=0x30;
  kbuf[15]=0x30;
  kbuf[16]=ptemp[0];
  goto jmp_kod;
  }

if (pdoza<100)
  {
  kbuf[11]=0x30;
  kbuf[12]=0x30;
  kbuf[13]=0x30;
  kbuf[14]=0x30;
  kbuf[15]=ptemp[0];
  kbuf[16]=ptemp[1];
  goto jmp_kod;
  }

if (pdoza<1000)
  {
  kbuf[11]=0x30;
  kbuf[12]=0x30;
  kbuf[13]=0x30;
  kbuf[14]=ptemp[0];
  kbuf[15]=ptemp[1];
  kbuf[16]=ptemp[2];
  goto jmp_kod;
  }

if (pdoza<10000)
  {
  kbuf[11]=0x30;
  kbuf[12]=0x30;
  kbuf[13]=ptemp[0];
  kbuf[14]=ptemp[1];
  kbuf[15]=ptemp[2];
  kbuf[16]=ptemp[3];
  goto jmp_kod;
  }

if (pdoza<100000)
  {
  kbuf[11]=0x30;
  kbuf[12]=ptemp[0];
  kbuf[13]=ptemp[1];
  kbuf[14]=ptemp[2];
  kbuf[15]=ptemp[3];
  kbuf[16]=ptemp[4];
  goto jmp_kod;
  }

kbuf[11]=ptemp[0];
kbuf[12]=ptemp[1];
kbuf[13]=ptemp[2];
kbuf[14]=ptemp[3];
kbuf[15]=ptemp[4];
kbuf[16]=ptemp[5];

jmp_kod: /* Заполнение поля Status. Метка для перехода по goto. */

/* Проверка поля Status */

if (pkod<0) pkod=0;

if (pkod>65535) pkod=65535; /* Поле Status - шестнадцатиричное с четырьмя цифрами. Максимальное значение 65535=0xFFFF */

ltoa(pkod,ptemp,16); /* Преобразование числа в строку по основанию 16 */

strupr(ptemp); /* Превращение цифр a-f в A-F */

/* Перенос в kbuf[] */

if (pkod==0)
  {
  kbuf[17]=0x30;
  kbuf[18]=0x30;
  kbuf[19]=0x30;
  kbuf[20]=0x30;
  goto jmp_exi;
  }

if (pkod<0x10)
  {
  kbuf[17]=0x30;
  kbuf[18]=0x30;
  kbuf[19]=0x30;
  kbuf[20]=ptemp[0];
  goto jmp_exi;
  }

if (pkod<0x100)
  {
  kbuf[17]=0x30;
  kbuf[18]=0x30;
  kbuf[19]=ptemp[0];
  kbuf[20]=ptemp[1];
  goto jmp_exi;
  }

if (pkod<0x1000)
  {
  kbuf[17]=0x30;
  kbuf[18]=ptemp[0];
  kbuf[19]=ptemp[1];
  kbuf[20]=ptemp[2];
  goto jmp_exi;
  }

kbuf[17]=ptemp[0];
kbuf[18]=ptemp[1];
kbuf[19]=ptemp[2];
kbuf[20]=ptemp[3];

jmp_exi: /* Заполнение остальных полей */

kbuf[21]=3; // ETX

/* Подсчет контрольной суммы CRC */

kbuf[22]=0;

for (i=1; i<22; i++) kbuf[22]^=kbuf[i];

/* Команда сформирована в буфере kbuf[] - далее открытие порта */

itoa(com,ptemp,10); /* Преобразование номера последовательного порта в строку */

strPort+=ptemp; /* Добавление номера к существующей строке */

/* Открытие коммуникационного порта для ввода - вывода */

hPort=::CreateFile(strPort, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,NULL);

/*
Здесь
hPort - дескриптор

strPort - строка с наименованием порта COM1...COM9 к которому при помощи кабеля связи подключены КУ ТРК. Естественно, порт с указанным номером должен физически присутствовать в компьютере. Будтье внимательны, в "современных" материнских платах может оказаться всего один COM-порт или вовсе их не быть. В таком случае следует купить и установить в компьютер специальную плату с последовательными портами.

Если вместо FILE_ATTRIBUTE_NORMAL указать FILE_FLAG_OVERLAPPED порт будет открыт в асинхронном режиме, но это выходит за рамки данного примера.
*/

/* Если порт не открывается - выход с кодом ошибки 258 */
if((hPort==INVALID_HANDLE_VALUE)||(hPort==NULL)) {re=258; goto end;}

/* Установка параметров обмена */

memset(&dcb,0,sizeof(dcb)); /* Выделение места в памяти */

dcb.DCBlength=sizeof(dcb);

dcb.BaudRate=CBR_9600; /* Скорость обмена c КУ ТРК, может быть, например CBR_19200 для КУ ТРК ПИЛОТ-11.2 */

dcb.ByteSize=8;dcb.Parity=0;dcb.StopBits=ONESTOPBIT; /* 8 бит, 1 стоп бит, без контроля четности */

dcb.fBinary=TRUE; /* Обмен двоичными числами */

dcb.fOutxCtsFlow=FALSE; /* Сигнал CTS не отслеживать */

dcb.fOutxDsrFlow=FALSE; /* Сигнал DSR не отслеживать */

dcb.fDtrControl=DTR_CONTROL_DISABLE; /* Контроль с помощью сигнала DTR запретить */

dcb.fDsrSensitivity=FALSE; /* Сигнал DSR на коммуникационный драйвер не влияет */

dcb.fOutX=FALSE; /* Управление выходным потоком символами XON/XOFF отключить */

dcb.fInX=FALSE; /* Управление входным потоком символами XON/XOFF отключить */

dcb.fErrorChar=FALSE; /* Ошибочные байты не заменять */

dcb.fNull=FALSE; /* Нулевые байты не отбрасывать */

dcb.fRtsControl=RTS_CONTROL_DISABLE; /* Запретить RTS */

dcb.fAbortOnError=FALSE; /* Не прекращать ввод-вывод при ошибках */

dcb.wReserved=0; /* Зарезервировано - должен быть 0 */

::SetCommState(hPort,&dcb); /* Установить параметры порта с дескриптором hPort из структуры dcb */

cto.ReadIntervalTimeout=40; /* Максимальное время между чтением байт, мс */

cto.ReadTotalTimeoutMultiplier=0; /* Множитель для вычисления общего времени чтения */

cto.ReadTotalTimeoutConstant=200; /* Время ожидания начала приема, мс */

cto.WriteTotalTimeoutMultiplier=10; /* Множитель для вычисления общего времени записи, мс */

cto.WriteTotalTimeoutConstant=100; /* Время ожидания начала записи, мс */

::SetCommTimeouts(hPort,&cto); /* Установить тайм-ауты из структуры cto */

::SetupComm(hPort,23,23); /* Очистить внутренние буферы порта и установить их длину 23 байта */

for (i=0; i<32; i++) rbuf[i]=0; /* Очистить входной буфер */

if(hPort!=INVALID_HANDLE_VALUE&&hPort!=NULL)
  {
  /* Если порт успешно открыт */
  /* Передать 23 байта из буфера kbuf[] */
  ::WriteFile(hPort,(LPVOID)kbuf,23,&d,NULL);

  /* Прочитать 23 байта в буфер rbuf[] */
  ::ReadFile(hPort,(LPVOID)rbuf,23,&d,NULL);

  /* Закрыть порт */
  CloseHandle(hPort);
  }

/* Проверка количества принятых байт */

if (d<23) {re=256; goto end;}

/* Проверка буфера rbuf на ненулевые значения, требуется для подтверждения выполнения операции чтения, может не выполняться */

j=0;
for (i=0; i<23; i++)
  if (rbuf[i]==0) j++;

if (j>22) {re=256; goto end;}

/* Проверка контрольной суммы принятого от КУ ТРК ответа */

j=0;
for (i=1; i<22; i++) j^=rbuf[i];
if (rbuf[22]!=(BYTE)j) {re=257; goto end;}

/* Проверка формата команды - наличие в ответе обязательных полей SOH, STX, ETX */

if ((rbuf[0]!=1)||(rbuf[4]!=2)||(rbuf[21]!=3)) {re=257; goto end;}

/* Проверка того, что на команду ответил запрошенный КУ ТРК*/

if ((rbuf[1]!=kbuf[1]) || (rbuf[2]!=kbuf[2])) {re=257; goto end;}

/* Перенос кода ошибки из поля Error в переменную re.

При подаче некоторых дополнительных команд поле Error может содержать другие данные, поэтому производится проверка на соответствие принятой команды набору команд "Универсального протокола" версии 1.72 или команде "Расширенный тест"

*/

if ((rbuf[3]==0x31) || (rbuf[3]==0x33) || (rbuf[3]==0x34) || (rbuf[3]==0x35) || (rbuf[3]==0x36) || (rbuf[3]==0x37) || (rbuf[3]==0x39) || (rbuf[3]==0x54))
  {
  /* Код команды известен и старший байт ошибки нулевой */
  if ((rbuf[17]==0x30)&&(rbuf[18]!=0x30)) re=rbuf[18];
  }

/* Выход из функции */
end: return(re);
}

/*
Приведенная ниже функция требуется для печати содержимого буферов на экран.
Может использоваться при отладке программы.
*/

int CPilot::print(int err)
{
int i;

if (err==0)
  {
  /* Если нет ошибок - распечатать буферы в шестнадцатиричном виде (HEX) */
  for (i=0; i<23; i++)
    {
    if (i!=0) printf(",");
      else printf("> ");
    if (kbuf[i]<16) printf("0");
    printf("%X",kbuf[i]);
    }

  printf("\r\n");
  for (i=0; i<23; i++)
    {
    if (i!=0) printf(",");
      else printf("< ");
    if (rbuf[i]<16) printf("0");
    printf("%X",rbuf[i]);
    }

  printf("\r\n\n");
  }
  else
  /* Если есть код ошибки - напечатать сообщение */
  printf ("Error %d \r\n\n",err);

return 0;
}

/*
Эта функция - главная. Из нее происходит обращение к подпрограмме обмена с КУ ТРК
*/
int main(int argc, char* argv[])
{
int i; /* вспомогательная переменная */
int n; /* Здесь хранится номер КУ ТРК */
CPilot Pilot; /* Объект класса CPilot */

SetConsoleTitle("Проверка КУ ТРК"); /* Заголовок окна */

Pilot.com=1; /* Использовать порт COM1 */
n=1; /* КУ ТРК номер 1 */
/* Далее передаются команды "Универсального протокола" */
i=Pilot.kom_pilot(n,0x37,0,0,0); /* Сброс */
Pilot.print(i); /* Распечатка буферов или кода ошибки */
Sleep(200); /* Задержка 0,2 с */

i=Pilot.kom_pilot(n,0x31,1500,100000,0); /* Задать дозу 100 л по цене 15 руб/литр */
Pilot.print(i);
Sleep(200);

i=Pilot.kom_pilot(n,0x35,0,0,0); /* Пуск */
Pilot.print(i);
Sleep(200);

i=Pilot.kom_pilot(n,0x34,0,0,0); /* Тест */
Pilot.print(i);
Sleep(200);

i=Pilot.kom_pilot(n,0x36,0,0,0); /* Останов */
Pilot.print(i);
Sleep(200);

i=Pilot.kom_pilot(n,0x37,0,0,0); /* Сброс */
Pilot.print(i);

return 0;
}

// Конец примера

Для компиляции программы следует создать консольное приложение (Win32 Console Application) с именем, например, Test1. Для упрощения работы следует создать заготовку приложения (A simple application). Затем скопировать в файл test1.cpp приведенный выше текст и откомпилировать его. Если все сделано правильно - получится файл test1.exe.

Консольное приложение - Проверка КУ ТРК

Для записи результатов в файл перенаправьте вывод программы, для этого наберите в командной строке: "test1.exe > test1.txt". После запуска с подключенным к порту COM1 КУ ТРК с номером 1 в каталоге программы появится файл test1.txt. В него будут записаны команды и ответы:

Начало файла
> 01,30,31,37,02,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,03,37
< 01,30,31,37,02,30,30,31,35,30,30,30,30,30,30,30,30,30,30,30,35,03,36

> 01,30,31,31,02,30,30,31,35,30,30,31,30,30,30,30,30,30,30,30,30,03,34
< 01,30,31,31,02,30,30,31,35,30,30,31,30,30,30,30,30,30,30,30,31,03,35

> 01,30,31,35,02,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,03,35
< 01,30,31,35,02,30,30,31,35,30,30,31,30,30,30,30,30,30,30,30,33,03,33

> 01,30,31,34,02,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,03,34
< 01,30,31,34,02,30,30,31,35,30,30,31,30,30,30,30,30,30,30,30,33,03,32

> 01,30,31,36,02,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,03,36
< 01,30,31,36,02,30,30,31,35,30,30,31,30,30,30,30,30,30,30,30,31,03,32

> 01,30,31,37,02,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,03,37
< 01,30,31,37,02,30,30,31,35,30,30,30,30,30,30,30,30,30,30,30,35,03,36

Конец файла



Здесь рассмотрена организация обмена на уровне работы с последовательным портом. Организация обмена с КУ ТРК на уровне команд протокола описана на странице: "Особенности использования Универсального протокола".


НПП "СЕМИКО" (383) 271-01-25 (многоканальный)