Содержание
Сервер &ModbusSrv - универсальный сервер шины для обслуживания запросов по протоколу MODBUS.
Сервер ModbusSrv:
реализует протокол MODBUS (сервер,ведомый),
в соответствии со спецификациями
"MODBUS application protocol specification V1.1b",
"MODBUS messaging on TCP/IP implementation guide V1.0b" и
"MODBUS over serial line specification and implementation guide V1.02".
поддерживает функции MODBUS номер 1, 2, 3, 4, 5, 6, 15, 16.
поддерживает протоколы MODBUS-TCP/IP, MODBUS-RTU, MODBUS-ASCII.
поддерживает (в текущей версии) до 16 логических портов, каждый из которых может иметь множество клиенских подключений, до 64 логических устройств, каждое из которых содержит адресное пространство по 1000 регистров и статусов ввода и вывода.
данные хранятся в тегах и кривых, которые подключаются к серверу.
Таким образом, один сервер "закрывает" сразу большой спектр задач.
Одним из главных применений сервера &ModbusSrv является связь с внешними системами SCADA и HMI. При всех своих недостатках, протокол MODBUS является промышленным стандартом, поддерживается большим числом программ и позволяет организовывать "гибридные" системы, работающие на базе нескольких пакетов.
Имеется работающий пример demo_mdbs.
Стандартное описание сервера ModbusSrv (кроме обычного подключения кривых) имеет примерно такой вид:
[DeviceList]
&ModbusSrv = device software program
[&ModbusSrv]
Comment = MODBUS SERVER (SLAVE).
InquiryPeriod = 0
DevicePolling = 1, tpTimeCritical
ProgramSource = ~~\resource\daqsite\modbusserver\modbussrv.pas
DebugFlags = 3
OpenConsole = 2
StdInFifo = 512
StdOutFifo = 512
StartupScript = [&ModbusSrv.StartupScript]
FinallyScript = [&ModbusSrv.FinallyScript]
[]
либо подключение стандартного библиотечного модуля
[ConfigFileList]
ConfigFile = ~~\resource\daqsite\default\modbussrv.cfg
[]
при этом
- в секцию [&ModbusSrv] надо поместить описание подключений (кривых),
данные которые которых будут передаваться и приниматься сервером
- в секцию [&ModbusSrv.StartupScript] надо поместить описание портов,
узлов (устройств MODBUS), а также таблицы адресов регистров MODBUSТаблица параметров и адресов MODBUS задается в секции StartupScript через консольные команды, описанные ниже. Поэтому эта секция обязательно должна быть описана. Хотя, строго говоря, все описание может генерироваться и динамически, через посылку сообщений. При этом размер буфера StdInFifo должен быть достаточным для размещения таблиц из секции StartupScript.
Команда @Reset очищает все таблицы и приводит сервер в исходное состояние.
С этой команды рекомендуется начинать описание таблиц данных сервера.
Команда @ZeroPortCounters очищает все теги со счетчиками ошибок.
Эту команду можно дать при старте, после инициализации всех таблиц портов.
Для описания сервера в секции StartupScript должны быть заданы следующие таблицы:
@port 1 IP tcp port 502 server 16
- логический порт №1 работает по протоколу IP, использует TCP порт №502 (это стандартный порт MODBUS)
- сервер поддерживает подключение до 16 клиентов.
@port 2 RTU com port 4 baudrate 9600 parity even databits 8 stopbits 1
- логический порт №2 работает по протоколу RTU, использует COM порт №4, скорость 9600 бит/сек,
- контроль четности EVEN, 8 бит данных, 1 стоповый бит.Командой @PortErrorCounters port Rx Tx Ex можно задать теги счетчиков ошибок данного порта.
Командой @PortErrorRates port Rx Tx Ex можно задать теги скорости счета ошибок данного порта.
Здесь
port - номер порта.
Rx - имя тега для счетчика ошибок приемника, когда приходят запросы с неверным адресом устройства, неверной контрольной суммой и т.д.
Tx - имя тега для счетчика ошибок передатчика, когда не удается отправить ответ на запрос.
Ex - имя тега для счетчика ошибок - исключений MODBUS, когда в запросе указан неверный адрес статусного или регистрового входа-выхода.
Аналогично задаются теги для подсчета трафика:
Командой @PortPollCounters port Rx Tx можно задать теги счетчиков запросов данного порта.
Командой @PortPollRates port Rx Tx можно задать теги скорости поступления запросов данного порта.
Командой @PortByteCounters port Rx Tx можно задать теги счетчиков потока байтов данного порта.
Командой @PortByteRates port Rx Tx можно задать теги скорости счета потока байтов данного порта.
Теги счетчиков могут иметь тип Integer или Real (лучше Real). При необходимости общего счетчика допустимо многократно ссылаться на один и тот же тег, в этом случае счета из разных источников будут складываться.
В случае, если теги ошибок не указаны, будут инкрементироваться стандартные счетчики ошибок, общие для всех портов. Эти стандартные ошибки влияют на статус DAQ-системы (улыбающийся человечек пожелтеет и покраснеет). В случае, когда теги ошибок указаны, они будут инкрементироваться при ошибках на данном порте, но при этом стандартные счетчики задействованы не будут (поэтому статус DAQ системы при ошибках не изменится). Это позволяет делать индивидуальную обработку ошибок, по выбору прикладного программиста.
Команда @View node служит для отображения (в консоли) таблицы адресов узла node. Если узел не указан, то в консоли отображается таблица портов и узлов. Эта команда применяется для контроля задания таблиц при отладке.
Команды @ModbusPoll, @ModScan32, @ModbusHelp служат для отладочных и справочных целей.
Таблицы адресов статусов и регистров должна быть непрерывны и не должна содержать пересечений, то есть данные, хранящиеся в таблицах, должны занимать непрерывную область адресов, а элементы данных не должны "налезать" друг на друга. Если это условие не выполнено, при чтении данных будет возвращена ошибка (исключение MODBUS - ILLEGAL ADDRESS или ILLEGAL DATA). При запросах на чтение и запись надо указывать существующие адреса в таблице и такой размер данных, чтобы происходила передача полных (без усечения) элементов данных. Операции чтения и записи совершенно независимы, а это значит, что о логике связи читаемых и записываемых по одному адресу данных должна заботиться прикладная программа (кроме случая чтения и записи в один и тот же тег или кривую).
Краткое описание команд MODBUS в секции StartupScript:
@Reset
@View
@View node
@Port port prot decl
@Node node port neta
@PortErrorRates port Rx Tx Ex
@PortErrorCounters port Rx Tx Ex
@PortPollRates port Rx Tx
@PortPollCounters port Rx Tx
@PortByteRates port Rx Tx
@PortByteCounters port Rx Tx
@CoilStatusBase node base
@InputStatusBase node base
@InputRegisterBase node base
@HoldingRegisterBase node base
@CoilStatus node addr bit src ref dst out
@InputStatus node addr bit src ref
@InputRegister node addr typ src ref
@HoldingRegister node addr typ src ref dst out
где
port - логический порт, 1..16
prot - протокол IP,RTU,ASCII
decl - описание порта: (tcp port 502 server 16),(com port 1 baudrate 9600 parity even databits 8 stopbits 1)
node - логический узел, 1..228
neta - сетевой адрес, 1..247
base - базовый адрес в таблице данного узла
addr - адрес элемента данных, начиная с base
typ - тип элемента данных: int16,int32,float,double
bit - бит статуса: bit0,bit1,bit3,..,bit31
src - тип источника данных: AnalogInput,DigitalInput,Tag
ref - индекс источника данных: номер AI,DI или имя тега
dst - тип приемника данных: AnalogOutput,DigitalOutput,Tag
out - индекс приемника данных: номер AO,DO или имя тега
Rx - имя тега (integer,real) для накопления ошибок приемника
Tx - имя тега (integer,real) для накопления ошибок передатчика
Ex - имя тега (integer,real) для накопления ошибок - исключений
типы данных:
int16 - 1 регистр, 2 байта
int32 - 2 регистра, 4 байта
float - 2 регистра, 4 байта
double - 4 регистра, 8 байт
bit0..bit31 - для статусных 1-битных данных
Например:
[&ModbusSrv.StartupScript]
;--- Задание таблицы портов (порт,протокол,описание)
;--- Задание счетчиков приема/передачи/ошибок
;--- Логический порт 1
@Port 1 ip tcp port 502 server 16
@PortByteCounters 1 BYTECOUNT.RX BYTECOUNT.TX
@PortPollCounters 1 POLLCOUNT.RX POLLCOUNT.TX
@PortErrorCounters 1 BUGSCOUNT.RX BUGSCOUNT.TX BUGSCOUNT.EX
@PortByteRates 1 BYTERATE.RX BYTERATE.TX
@PortPollRates 1 POLLRATE.RX POLLRATE.TX
@PortErrorRates 1 BUGSRATE.RX BUGSRATE.TX BUGSRATE.EX
;--- Логический порт 2
@Port 2 rtu com port 4 baudrate 9600 parity even databits 8 stopbits 1
@PortByteCounters 2 BYTECOUNT.RX BYTECOUNT.TX
@PortPollCounters 2 POLLCOUNT.RX POLLCOUNT.TX
@PortErrorCounters 2 BUGSCOUNT.RX BUGSCOUNT.TX BUGSCOUNT.EX
@PortByteRates 2 BYTERATE.RX BYTERATE.TX
@PortPollRates 2 POLLRATE.RX POLLRATE.TX
@PortErrorRates 2 BUGSRATE.RX BUGSRATE.TX BUGSRATE.EX
;--- Очистка счетчиков ошибок
@ZeroPortCounters
;--- Задание таблицы узлов (узел,порт,сетевой адрес)
@Node 1 1 1
@Node 2 1 2
;---Задание базовых адресов узла 1 (указаны стандартные значения)
@CoilStatusBase 1 1
@InputStatusBase 1 10001
@InputRegisterBase 1 30001
@HoldingRegisterBase 1 40001
;---Регистры Holding узла 1, только чтение
@HoldingRegister 1 40001 int16 DigitalInput 0
@HoldingRegister 1 40002 int32 DigitalInput 1
@HoldingRegister 1 40004 float AnalogInput 0
@HoldingRegister 1 40006 double AnalogInput 1
@HoldingRegister 1 40010 int16 tag demo_test_1
;---Регистры Holding узла 2, чтение и запись
@HoldingRegister 2 40001 int16 DigitalInput 0 DigitalOutput 0
@HoldingRegister 2 40002 int32 tag TEST.L1 tag TEST.L1
@HoldingRegister 2 40004 float tag TEST.F2 tag TEST.F2
@HoldingRegister 2 40006 double tag TEST.D2 tag TEST.D2
;---Регистры Input узла 1, только чтение
@InputRegister 1 30001 int16 DigitalInput 0
@InputRegister 1 30002 int32 DigitalInput 1
@InputRegister 1 30004 float AnalogInput 0
@InputRegister 1 30006 double tag demo_test_2
;---Статусы Coil узла 1, только чтение
@CoilStatus 1 1 bit0 DigitalInput 0
@CoilStatus 1 2 bit1 DigitalInput 0
;---Статусы Coil узла 2, чтение и запись
@CoilStatus 2 3 bit0 tag TEST.W1 tag TEST.W1
@CoilStatus 2 4 bit1 tag TEST.W1 tag TEST.W1
@CoilStatus 2 5 bit2 tag TEST.W1 tag TEST.W1
;---Статусы Input узла 1, только чтение
@InputStatus 1 10001 bit0 DigitalInput 0
@InputStatus 1 10002 bit1 DigitalInput 0
[]При задании таблиц данных указывается узел, адрес, тип данных (int16, int32, float, double) для регистров или номер бита bit0..bit31 для статусов, тип источника (цифровой или аналоговый вход или тег), индекс источника (номер входа или имя тега). Для перезаписываемых данных (CoilStatus,HoldingRegister) также указывается тип приемника (цифровой или аналоговый выход или тег) и индекс приемника (номер выхода или имя тега). Эти данные связывают адрес таблицы MODBUS с базой данных (кривых и тегов), чтобы сервер знал, где и какого типа данные ему использовать.
Работа сервера происходит в пассивном режиме опроса со стороны клиентов. Это значит, что сервер передает данные только по инициативе подключенных клиентов, по их запросам. Частота опроса также определяется клиентами. Этот факт ограничивает область применения сервера. Потокол MODBUS нельзя применять, если система требует запросов на обслуживание или обновления данных по инициативе сервера (а не клиентов). Это свойство не является особенностью данного сервера - оно присуще самой логике протокола MODBUS.
Ограниченный спецификацией MODBUS размер пакета данных, передаваемого за одну транзакцию (запрос-ответ) в 250 байт ограничивает траффик данных величиной примерно 125 килобайт в секунду (исходя из реалистичной цифры - 500 транзакций в секунду). Это ограничение также не является особенностью данного сервера - оно присуще самой логике протокола MODBUS. Поэтому сервер предназначен для передачи сравнительно небольших пакетов данных в псевдо-реальном времени. Для увеличения траффика запросы можно (и нужно) делать в несколько потоков, так как в одном потоке сложно получить более 100 транзакций в секунду. При этом среднее время транзакции (запрос-ответ) в каждом потоке составляет порядка 4 мс.
В выражении @CoilStatus node addr bitN tag S tag T данные по адресу addr будут считываться из бита N тега S, а записываться в бит N тега T. Если имена S и T совпадают, то читаться - записываться будет тот же самый тег. Если имена не совпадают, то логическая связка читаемого и записываемого значения должна выполняться программно. Это позволяет делать запись в тег после проверки тех или иных условий.
В выражении @CoilStatus node addr bitN DigitalInput S DigitalOutput T данные по адресу addr будут считываться из бита N цифрового входа S, однако записываться будут в бит 0 цифрового выхода T. Это связано с тем, что в случае кривых из-за буферизации нельзя менять отдельные биты данных. Поэтому под запись каждого статуса надо отводить отдельную кривую, в которой будет занят только один нулевой бит.
В текущей версии сервера используются статические таблицы адресов, занимающие довольно много места (около 10 МБ). Это надо учитывать при работе на малоресурсных компьютерах.
Желаем успешного использования &ModbusSrv.
CRW-DAQ Copyright (c) 2001-2024 Alexey Kuryakin daqgroup@mail.ru.