Перейти к содержанию

Драйвер RS_TO_ECAT для модулей SPRS

Назначение

RS_TO_ECAT — библиотека, предназначенная для упрощения работы с модулями последовательных интерфейсов SA-P5-IF485/422, SA-P5-IF232.

Блок полностью скрывает особенности обмена через EtherCAT и предоставляет разработчику простой интерфейс передачи и приёма данных произвольной длины.


Почему необходим данный драйвер

Передача данных между ПЛК и модулем ввода-вывода осуществляется через PDO EtherCAT.

Размер PDO является фиксированным и не может изменяться динамически во время работы.

Использование большого буфера передачи (например, 256 байт) привело бы к тому, что весь этот объём передавался бы в каждом цикле EtherCAT независимо от количества полезных данных, значительно увеличивая загрузку сети.

Поэтому обмен в модулях реализован небольшими блоками по 8 байт.

Функциональный блок автоматически:

  • разбивает передаваемый массив на части по 8 байт;
  • отправляет их последовательно;
  • автоматически собирает принятые данные обратно в единый буфер;
  • определяет окончание приёма по времени отсутствия данных.

Пользователю больше не требуется самостоятельно управлять передачей отдельных блоков.


Установка библиотеки

  1. Откройте Tools → Library Repository и нажмите Install..., указав путь к собранному файлу библиотеки.
  2. В проекте-приложении откройте Application → Library Manager, нажмите Add library и найдите RS_TO_ECAT_Driver в списке.
  3. После добавления библиотеки блок становится доступен по полному имени RS_TO_ECAT_Driver.RS_TO_ECAT .

Интерфейс блока

Входы (VAR_INPUT)

Параметр Тип Назначение
Execute BOOL Запуск передачи по переднему фронту. Сигнал можно подавать импульсом — блок сам отслеживает фронт и не требует удержания TRUE на всё время передачи.
RecvGapTime TIME Время отсутствия новых данных на линии, после которого принятый пакет считается завершённым. По умолчанию T#40MS.
SendLength USINT Фактическая длина данных в буфере SendBuf, которые необходимо отправить (в байтах).
RS485_InData ARRAY[0..7] OF BYTE Подключается к входному PDO модуля (%IB).
RS485_InLength USINT Подключается к входному PDO модуля (%IB), показывает количество байт, доступных для считывания в RS485_InData.
FilterEcho BOOL Флаг фильтрации эха. При TRUE (по умолчанию) первые байты приёма, совпадающие по количеству с отправленным пакетом, отбрасываются. Полезно при работе с RS-485 и RS-232 .

Выходы (VAR_OUTPUT)

Параметр Тип Назначение
RS485_OutData ARRAY[0..7] OF BYTE Подключается к выходному PDO модуля (%QB).
RS485_OutLength USINT Подключается к выходному PDO модуля (%QB).
RS485_ReadFlag USINT Подключается к выходному PDO модуля (%QB), подтверждает модулю приём очередной порции данных.
Busy BOOL TRUE — идёт передача, начатая по Execute.
Done BOOL TRUE — приём пакета завершён, данные доступны в RecvBuf. Остаётся TRUE до начала приёма следующего пакета.
Error BOOL TRUE — произошла ошибка обмена.
RecvBuf ARRAY[0..63] OF BYTE Буфер с принятыми данными.
RecvLen USINT Длина принятого пакета (количество значащих байт в RecvBuf).

Входы-выходы (VAR_IN_OUT)

Параметр Тип Назначение
SendBuf ARRAY[*] OF BYTE Буфер с данными для отправки. Передаётся как открытый массив, что позволяет использовать буферы любой длины. Важно: так как стандарт IEC 61131-3 не гарантирует корректное автоматическое определение размера открытого массива внутри FB, реальное количество байт для отправки необходимо явно передавать через параметр SendLength.

Принцип работы

Передача

При появлении переднего фронта на Execute блок считывает длину пакета из параметра SendLength и начинает цикл из трёх состояний:

  1. Копирует очередную порцию (до 8 байт) из SendBuf в RS485_OutData, выставляет RS485_OutLength.
  2. На следующем цикле сбрасывает RS485_OutLength в 0 — это обязательный шаг квитирования, без которого модуль не примет следующую порцию.
  3. Проверяет, остались ли неотправленные байты. Если да — возвращается к шагу 1 с новой порцией. Если нет — завершает передачу, сбрасывает Busy в FALSE.

Все три шага выполняются автоматически, без участия прикладной программы — пользователю достаточно один раз подать импульс на Execute.

Приём

Приём построен симметрично передаче и проходит через три состояния:

  1. Как только RS485_InLength становится не равным 0, блок копирует данные из RS485_InData в RecvBuf и устанавливает RS485_ReadFlag := 1, подтверждая модулю получение порции.
  2. На следующем цикле RS485_ReadFlag сбрасывается в 0.
  3. Блок проверяет RS485_InLength: если в нём снова появились данные — переходит к шагу 1 за новой порцией. Если данных нет — запускает таймер на время RecvGapTime; если в течение этого времени новых данных не появляется, пакет считается завершённым: фиксируется длина в RecvLen, выставляется Done := TRUE.

Если за время ожидания (RecvGapTime) появляются новые данные, таймер сбрасывается, и приём продолжается — это защищает от обрыва пакета на естественных микропаузах при передаче по медленным линиям RS485.


Рекомендации по архитектуре и циклам задач

Важно

Для стабильной работы драйвера и корректного обмена данными через PDO крайне не рекомендуется запускать задачу (Task), в которой вызывается данный FB, с тем же циклом, что и шина EtherCAT, или быстрее неё.

Правило: цикл задачи опроса должен быть медленнее (длиннее) цикла шины EtherCAT минимум в 2–4 раза.

Пример использования

PROGRAM PLC_PRG
VAR
    fbRS485      : RS_TO_ECAT_Driver.RS_TO_ECAT;

    // Буфер запроса. Может быть любой длины (в примере 8 байт)
    SendData8    : ARRAY[0..7] OF BYTE := [16#01, 16#02, 16#03, 16#04,
                                           16#05, 16#06, 16#07, 16#08];
    SendLength   : USINT;               // Переменная для хранения длины буфера

    bStart       : BOOL;

    MyAnswer     : ARRAY[0..63] OF BYTE;  // куда забираем готовый ответ
    MyAnswerLen  : USINT;
    bAnswerReady : BOOL;                  // флаг "новый ответ получен"
    bDoneLast    : BOOL;
    i            : USINT;

    // Привязка к PDO модуля
    RS485_OutData    AT %QB10 : ARRAY[0..7] OF BYTE;
    RS485_OutLength  AT %QB18 : USINT;
    RS485_ReadFlag   AT %QB19 : USINT;
    RS485_InData     AT %IB9  : ARRAY[0..7] OF BYTE;
    RS485_InLength   AT %IB17 : USINT;
END_VAR

// 1. Вычисляем длину массива для отправки.

SendLength := USINT(SIZEOF(SendData8));

// 2. Вызов драйвера каждый цикл
fbRS485(
    Execute         := bStart,
    SendBuf         := SendData8,
    SendLength      := SendLength,       // Явно передаем длину
    RecvGapTime     := T#40MS,
    FilterEcho      := TRUE,
    RS485_InData    := RS485_InData,
    RS485_InLength  := RS485_InLength,
    RS485_OutData   => RS485_OutData,
    RS485_OutLength => RS485_OutLength,
    RS485_ReadFlag  => RS485_ReadFlag
);

// bStart - однократный импульс, сбрасываем сами после подачи
IF bStart THEN
    bStart := FALSE;
END_IF;

// Забираем ответ в обычную переменную по переднему фронту Done
IF fbRS485.Done AND NOT bDoneLast THEN
    MyAnswerLen := fbRS485.RecvLen;
    FOR i := 0 TO MyAnswerLen - 1 DO
        MyAnswer[i] := fbRS485.RecvBuf[i];
    END_FOR;
    bAnswerReady := TRUE;
END_IF;
bDoneLast := fbRS485.Done;