В мире программирования и автоматики COM-порты и ПЛК — как два старых друга, которые часто встречаются, но не всегда понимают друг друга. Кто-то мечется между байтами, пытаясь поговорить с железом, кто-то плетёт сетевые нити Ethernet, а Delphi — это магический посох для общения с этими загадочными устройствами.

В этой статье мы подробно разберём:

  • что такое COM-порт и как с ним работать на практике,
  • как настроить и использовать COM-порт в Delphi,
  • как проверить занятость порта и решить проблемы с USB-эмуляцией,
  • как общаться с ПЛК через Ethernet, используя Modbus TCP и альтернативы,
  • примеры кода и советы, чтобы не застрять в дебрях коммуникаций.

Что такое COM-порт и зачем он нужен?

COM-порт (от "Communication port") — это последовательный порт, через который компьютер общается с внешними устройствами, будь то коммутаторы, ПЛК или датчики. Представьте его как телефонный провод для разговора между железками. В современном мире физические COM-порты почти исчезли, но на сцену вышли USB, которые умеют эмулировать COM-порты — виртуальные телефонные линии для устройств.

Как открыть и настроить COM-порт в Delphi: волшебство кода

Чтобы общаться через COM-порт, нужно сначала его открыть и настроить. В Delphi для этого обычно используют API Windows. Вот как это выглядит на примере:

var
  hPort: THandle;
  FileName: string;
begin
  FileName := '\\.\COM6'; // Указываем порт через специальный путь
  hPort := CreateFile(PChar(FileName),
                      GENERIC_READ or GENERIC_WRITE,
                      0, nil, OPEN_EXISTING,
                      FILE_ATTRIBUTE_NORMAL, 0);
  if hPort = INVALID_HANDLE_VALUE then
  begin
    ShowMessage('Не удалось открыть порт');
    Exit;
  end;
  // Здесь настройка параметров порта (скорость, паритет и т.д.)
end;

Почему \\.\COM6?

Это специальный синтаксис для открытия портов с номерами выше COM9 — просто фишка Windows, чтобы не путать.

Настройка параметров порта

Используют структуру DCB (Device Control Block) и функции SetCommState и SetCommTimeouts для установки скорости передачи, битов данных, стоп-битов и таймаутов.

var
  DCB: TDCB;
  CommTimeouts: TCommTimeouts;
begin
  GetCommState(hPort, DCB);
  DCB.BaudRate := CBR_9600; // 9600 бод
  DCB.ByteSize := 8;
  DCB.Parity := NOPARITY;
  DCB.StopBits := ONESTOPBIT;
  SetCommState(hPort, DCB);

  CommTimeouts.ReadIntervalTimeout := MAXDWORD;
  CommTimeouts.ReadTotalTimeoutMultiplier := 0;
  CommTimeouts.ReadTotalTimeoutConstant := 0;
  CommTimeouts.WriteTotalTimeoutMultiplier := 0;
  CommTimeouts.WriteTotalTimeoutConstant := 0;
  SetCommTimeouts(hPort, CommTimeouts);
end;

Как отправлять данные и получать ответы с COM-порта?

После открытия и настройки можно писать и читать данные. В Delphi для этого используют WriteFile и ReadFile.

var
  BytesWritten: DWORD;
  BufferToSend: AnsiString;
begin
  BufferToSend := 'show vlan' + #13#10; // Команда с переводом строки
  if not WriteFile(hPort, BufferToSend[1], Length(BufferToSend), BytesWritten, nil) then
    ShowMessage('Ошибка отправки данных');

  // Чтение ответа
  var Buffer: array[0..255] of AnsiChar;
  var BytesRead: DWORD;
  if ReadFile(hPort, Buffer, SizeOf(Buffer), BytesRead, nil) then
    ShowMessage('Ответ: ' + string(Copy(Buffer, 0, BytesRead)))
  else
    ShowMessage('Ошибка чтения данных');
end;

Совет: используйте циклы отправки и получения, чтобы поддерживать сессию обмена с устройством.

Как проверить, занят ли COM-порт и что делать при ошибках?

Проверить занятость порта — задача не из лёгких. Просто попытка открыть порт даст ошибку и если порт:

  • занят другой программой — ошибка открытия,
  • отсутствует — ошибка открытия,
  • занят вашей же программой — тоже ошибка открытия.

Поэтому простой попытки открыть порт недостаточно.

Рекомендации по проверке:

  • Подписка на события подключения/отключения USB — помогает узнавать появление и пропажу устройств.
  • Периодическая проверка связи — отправляйте "тестовую" команду и смотрите на ответ.
  • Получение списка всех доступных COM-портов — чтобы проверить, существует ли нужный порт сейчас.
  • Использование таймаутов и обработка исключений — чтобы программа не зависала.

Пример: при отключении USB-эмулированного COM-порта устройство исчезнет из списка, а физический порт останется.

Что делать, если COM-порт не подключается через USB (виртуальный COM)?

USB-порты с драйверами, эмулирующими COM-порты, могут вести себя странно — порт есть, но устройства нет, или связь "зависает".

Советы:

  • Используйте путь \\.\COMn для открытия.
  • Уточните, какой именно чип использует устройство (например, Silicon Labs CP210x).
  • Проверьте драйверы и их состояние.
  • В некоторых случаях помогает перезапуск драйвера или переустановка.
  • Отправляйте в порт тестовые запросы, чтобы проверить реакцию.
  • Если используете OLE-менеджер, проверяйте связь на более высоком уровне.
  • Логируйте ошибки и состояния для диагностики.

Какие компоненты для работы с COM-портами в Delphi существуют?

Чтобы не изобретать велосипед, используют готовые компоненты, например:

Название Особенности Лицензия
BComPort Бесплатный, стабильно работает с COM-портами Free
TComPort Класс с методами и свойствами для управления Встроенный
Serial Communications Library Коммерческий, с поддержкой Delphi Платный

Использование компонентов упрощает открытие, настройку, чтение и запись, а также обработку ошибок.

ПЛК и связь через Ethernet: встречаем Modbus TCP

ПЛК — программируемые логические контроллеры, "мозги" автоматизации. Для связи с ними по сети чаще всего используют протокол Modbus TCP.

Как это работает?

  • Ваш ПК с программой на Delphi — мастер сети (клиент).
  • ПЛК — слейв-устройство, отвечающее на запросы.
  • Коммуникация происходит по IP и порту (обычно 502).

Настройка ПЛК

  • В CoDeSys добавляем устройство Modbus slave.
  • Настраиваем тип связи — TCP.
  • Каждому ПЛК присваиваем уникальный адрес (1–255).
  • Важно: настроить IP и сеть правильно, чтобы не было конфликтов.

Работа с Delphi

  • Используйте бесплатные компоненты, например с SourceForge: delphimodbus.
  • Настройте соединение, отправляйте запросы чтения/записи регистров.
  • Для отладки можно использовать SCADA-системы или утилиты modpoll.

Альтернативы Modbus TCP: OPC и UDP

Если Modbus кажется слишком сложным, рассмотрите альтернативы:

Протокол Описание Особенности
OPC Стандарт обмена данными для промышленных систем Требует OPC-сервер, сложнее
UDP Протокол без установки соединения, проще для простых задач Менее надежен, требует контроля

В Delphi есть компоненты для OPC (например, iocomp) и для работы с сокетами UDP.

Пример: подключение по UDP в C

Для простоты можно использовать UDP-сокеты, как в примере ниже:

Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
IPEndPoint localEP = new IPEndPoint(IPAddress.Any, 1221);
sock.Bind(localEP);

byte[] buffer = new byte[1024];
EndPoint remoteEP = new IPEndPoint(IPAddress.Any, 0);
int received = sock.ReceiveFrom(buffer, ref remoteEP);
string message = Encoding.ASCII.GetString(buffer, 0, received);
Console.WriteLine($"Получено: {message}");

С этим можно легко связываться с ПЛК, настроенными на приём UDP-пакетов.

Как поддерживать связь с устройством через COM-порт при авариях и эмуляции?

Если устройство может внезапно отключиться, а порт при этом не исчезает (виртуальный COM), то стоит:

  • Периодически посылать контрольные команды.
  • Ловить таймауты и ошибки при чтении/записи.
  • При потере связи пытаться переподключиться.
  • Использовать логи для диагностики.
  • Для разных типов портов (физический/виртуальный) анализировать описание устройства.

Кратко: советы и чек-лист по работе с COM-портами и ПЛК

Шаг Совет
Открытие порта Используйте \\.\COMn, проверяйте ошибки
Настройка параметров Установите скорость, паритет, таймауты
Отправка/чтение данных Используйте WriteFile/ReadFile
Проверка занятости порта Подписывайтесь на события USB, проверяйте список портов
Работа с USB-эмуляцией Анализируйте драйверы и отправляйте тестовые запросы
Связь с ПЛК через Ethernet Используйте Modbus TCP или OPC, настраивайте IP и адреса
Обработка ошибок Ловите исключения, логируйте, переподключайтесь
Использование компонентов Применяйте готовые библиотеки для упрощения
Отладка Пробуйте SCADA и утилиты, снифферы, читайте документацию

FAQ

В: Что делать, если порт всегда занят, но устройство отключено?
О: Проверьте, не "повис" ли порт в системе. Попробуйте закрыть программы, использующие порт, или перезагрузите драйвер.

В: Как понять, что порт виртуальный?
О: Через описание порта в системе, часто драйвер указывает производителя (например, Silicon Labs).

В: Можно ли работать с несколькими ПЛК одновременно?
О: Да, для каждого ПЛК нужен уникальный адрес и IP. Программа на Delphi должна поддерживать мультипортовую работу.

В: Как проверить, отвечает ли устройство, если протокол неизвестен?
О: Отправьте тестовую команду, ожидайте ответа. Если нет реакции — значит связь потеряна.


Знание — сила, особенно когда речь о железе и Delphi. Теперь у вас есть карта сокровищ, чтобы уверенно общаться с COM-портами, эмулировать их, работать с ПЛК по Ethernet и даже шутить с командными строками коммутаторов. Не бойтесь экспериментировать, ведь даже самый сложный порт можно открыть... главное, чтобы он не был занят!