Пример передачи данных по протоколу Modbus на Delphi


Для примера будем использовать контроллер ОВЕН ПЛК100. Для использования Modbus ASCII или Modbus RTU нужно подключить контроллер к компьютеру через COM порт, а для Modbus TCP по сети.

В конфигурации ПЛК добавляем компонент Modbus(slave). В группе Modbus[FIX] добавляем компонент соответствующий той связи которая соединяет компьютер с контроллером. Далее в группе Modbus(slave) добавляем регистры как показано на картинке

Компонент Modbus c набором переменных в конфигурации контроллера
Переменные Modbus
  • wdvr - двухбайтовое без знаковое
  • intvr - двухбайтовое знаковое
  • dwvr - четырех байтовое без знаковое
  • dintvr - четырех байтовое знаковое
  • fltvr - четырех байтовое с плавающей точкой
  • str - изходящая строк
  • str_ - продолжение исходящей строки
  • str2 - входящая строка

Продолжению входящей строки нет необходимости присваивать имя, так как напрямую к этой переменной обращаться не будем.

Программа контроллера будет с периодом 100мс изменять значения всех переменных, что-бы данные изменения наблюдать в программе на Delphi

Создаем VCL приложение в Delphi
Программа на Delphi для примера Modbus соединения

Добавляем на форму

  • StatusBar с одним текстовым полем
  • KRTimer, в свойствах Interval=500
  • KRCOMPortConnector, в свойствах устанавливаем необходимые настройки подключения
  • KRSpeeInfo, в свойстве Component выбираем коннектор
  • KRModbusMaster, в свойствах выбираем коннектор
  • KRModbusClient, в свойствах выбираем компонент KRModbusMaster, устанавливаем адрес устройства единицу и тип Modbus протокола mbtACSII
  • Создаем Modbus переменную, для этого в структуре объектов на компоненте KRModbusClient1 открываем контекстное меню и выбираем пункт "Add". В свойствах переменной устанавливаем Interval=500, MCVarType=MCT_WORD, Name="mb000_wdvr"
  • Создаем Modbus переменную, в свойствах устанавливаем Interval=500, MCVarType=MCT_SMALLINT, Name="mb001_intvr", RegisterIndex=1
  • Создаем Modbus переменную, в свойствах устанавливаем Interval=500, MCVarType=MCT_DWORD, Name="mb002_dwvr", RegisterIndex=2
  • Создаем Modbus переменную, в свойствах устанавливаем Interval=500, MCVarType=MCT_INT, Name="mb004_dintvr", RegisterIndex=4
  • Создаем Modbus переменную, в свойствах устанавливаем Interval=500, MCVarType=MCT_SINGLE, Name="mb006_fltvr", RegisterIndex=6
  • Создаем Modbus переменную, в свойствах устанавливаем Interval=500, MCVarType=MCT_STRING, Name="mb008_str", RegisterIndex=8
  • Создаем Modbus переменную, в свойствах устанавливаем MCVarType=MCT_STRING, Name="mb012_str2", RegisterIndex=12, UpAftWrite=true, WaitForUpdates=true

Если нужно установить соединение по Modbus RTU, то в свойствах компонента KRModbusClient установить MBType=mbtACSII

Если нужно установить связи по Modbus TCP, то вместо коннектора KRCOMPortConnector нужно использовать KRTCPConnector и в свойствах компонента KRModbusClient установить MBType=mbtTCP

Пример передачи данных с контроллера ОВЕН ПЛК100 в программу на Delphi по протоколу Modbus
 
Поделиться:
0
Андрей Савельев
14.09.2018 22:10
 
Руслан, Modbus функции 15 «Force Multiple Coils» и 16 «Preset Multiple Regs», судя по контексту, реализованы в методах WriteCoils и WriteHoldingRegisters компонента KRModbusMaster? Можно попросить Вас привести примеры их использования...
Показать полностью
5
Руслан Кандирал
15.09.2018 08:51
Андрей Савельев
 
Показать полностью
0
Андрей Юрашев
07.09.2018 14:30
 
Руслан, а подскажите на данный момент функция 05 Force Single Coil в вашей компоненте не реализована???
Показать полностью
5
Руслан Кандирал
08.09.2018 02:56
Андрей Юрашев
 
Реализована, но только на уровне KRModbusMaster.

Пример:
Показать полностью
0
Андрей Юрашев
08.09.2018 19:26
Руслан Кандирал
 
KRModbusMaster1.WriteCoil(mbtTCP -- ругается на переменную AMBType и не принимает не mbtTCP не mbtRTU.
Еще вопрос если нужно опрашивать 2 прибора то добавляем еще один KRModbusClient2 и заводим там переменные которые нужно опросить так???
У меня не взлетело -- опрос не идет -- по логам только по первому KRModbusClient1 идет опрос. Что где надо включить?
Показать полностью
5
Руслан Кандирал
09.09.2018 12:37
Андрей Юрашев
 
mbtTCP и mbtRTU описываются в KRModbus, то бишь данный модулю нужно указать в uses.

Если устройства подключаются по разным соединениям, то нужно для каждого устройства создавать KRModbusMaster, KRModbusClient и соответствующий коннектор.

Если несколько устройств сидят на одном коннекте(например RS485 через COM порт или TCP), то достаточно для каждого устройства создавать KRModbusClient где в свойстве Addres указывать соответствующий адрес устройства и подключать общий компонент KRModbusMaster. Но в таком случае есть проблемы с которой я сам столкнулся недавно. Дело в том, что задача коннекторя отправить запрос получить ответ и если возникают при отправке/приеме возникнут проблемы отключать соединение и делать реконнект с периодом не более чем указано в свойстве ReconnectTime. То есть если например от устройства не приходит ответ несколько раз подряд (количество указывается в свойстве коннектора CountErrorsForReconnect), то соединение разрывается и затем коннектор пытается заново подключиться с периодом ReconnectTime. Это дает возможность коннектору подхватывать связь с устройством при временном ее отсутствии. Но если к одному коннектору подключено более одного устройства и с одним из них пропадает связь, то коннектор начинает периодически отключаться и в результате возникают проблемы со связью с остальными устройствами.

Что-бы обойти эту проблему я сделал следующее:

Показать полностью
0
Андрей Юрашев
04.09.2018 23:38
 
При считывании переменной типа Float получаю совершенно некорректный результат. Проанализировав возвращаемый ответ, увидел, что от прибора приходит ответ в таком виде
RECV: 10 03 04 3E CC CC CD A2 70 -- соответственно сами данные 3E CC CC CD ,в переменной типа Float получаем значение -107607648 -- т.е. перед преобразованием ответ перестраивается в такой вид CC CD 3E CC.
На самом деле мой прибор отдает значение 0.4 , данные должны идти на преобразование в том же порядке что и пришли 3E CC CC CD.
Есть ли возможность в переменной указывать порядок прихода данных -- разные производители по разному отдают этот тип данных.
Или какой способ обойти эту ситуацию.
Решение в лоб перевести переменную обратно в HEX вид, переставить как нужно и опять во Float уж очень не комильфо))))
Показать полностью
5
Руслан Кандирал
05.09.2018 08:59
Андрей Юрашев
 
Возможности поменять последовательность регистров нет. Нужно будет добавить в будущем.
Есть два варианта решить эту проблему:
1) В вашей программе. Делать тип переменной DWORD и преобразовывать в FLOAT самостоятельно. То есть тот способ который " не комильфо"
2) Внести изменение в функции MBRegsToSINGLE в файле Automation\KRModbus.pas и перекомпилировать пакет Automation. Но в таком случае последовательность регистров будет только такая как нужно вам.

Изменения которые нужно внести в файл Automation\KRModbus.pas
Показать полностью
0
Андрей Юрашев
05.09.2018 10:18
Руслан Кандирал
 
Благодарю, Руслан.
Показать полностью
0
Андрей Савельев
03.09.2018 22:52
 
Подскажите пожалуйста, я работаю с контроллерами ЭЛМЕТРО-МВВ. Возможно ли обращение к регистрам контроллера через переменные компонента KRModbusClient?
Не совсем понятно, как сопоставлять адресацию регистров контроллера с адресацией переменных компонента, ведь существуют два вида ригистров: входные и хранения с независимыми арресациями для каждого вида, но адресация у переменных компонента как-будто бы сквозная...
Показать полностью
5
Руслан Кандирал
03.09.2018 23:01
Андрей Савельев
 
У регистров (TKRMBRegister) есть свойство ReadFunction. Для входящих регистров выбирайте mbrfReadInputRegisters, а для регистров хранения соответственно mbrfReadHoldingRegisters. Адрес в обоих случаях указывается в свойстве RegisterIndex
Показать полностью
0
Андрей Савельев
28.08.2018 19:13
 
Руслан, подскажите пожалуйста, куда сбрасывается результат работы метода ReadDiscretInputs компонента KRModbusMaster? Я поначалу считал, что он возвращатся в переменной AData CallBack метода, но покопавшись в исходника, вижу, что в переменной всегда возвращается nil.
Показать полностью
5
Руслан Кандирал
28.08.2018 19:39
Андрей Савельев
 
Результат передается в callback функцию.

Пример:

Показать полностью
0
Андрей Савельев
28.08.2018 22:05
Руслан Кандирал
 
Благодарю.
Показать полностью
0
Oleksiy Tokarchuk
22.04.2018 20:52
 
Использовал данный пример для чтения переменных с ПЛК Click.
На первой машине все работало нормально.
На второй машине установил все компоненты Kandiral, скомпилировал - запустилось.
Вернулся на первую машину с заведомо рабочим кодом - скомпилировал - error no connetcion на ком порту (другие программы к порту коннектятся)
Не подскажите, где искать причину?
Показать полностью
5
Руслан Кандирал
23.04.2018 05:23
Oleksiy Tokarchuk
 
Удачный коннект считается тогда, когда от устройства приходит ответ. То есть, возможно программа подключается к COM порту, но устройство не отвечает на запросы. С помощью событий коннектора OnSendAsync и OnRecvAsync вы можете определить идет отправка данных или нет и приходит ли ответ от устройства.
Показать полностью
0
Oleksiy Tokarchuk
23.04.2018 22:02
Руслан Кандирал
 
Спасибо. Помогло. Причину нашел. Дело было в неправильной настройке коннектора.
Еще небольшой вопрос.
У меня на KRCOMPortSets1.Init ругается undeclared identifier Init
Лень самому искать причину)
Подскажите в чем она?
Показать полностью
5
Руслан Кандирал
24.04.2018 13:31
Oleksiy Tokarchuk
 
При компиляции примера использовалась более новая версия компонентов. Я ее еще не выкладывал так как нужно сделать тесты под разные версии delphi. Вот я давал в комментариях более новую версию
https://kandiral.ru/o_sajte.html#comment...
Показать полностью

Новости сайта

06.02.2018 15:53
Добавлена программа SimpleADB
Программа SimpleADB разработана в среде Delphi XE для отладки Android устройств через утилиту adb
07.10.2017 23:57
Оптимизация библиотек Modbus для контроллеров Arduino
Сделал оптимизированный вариант библиотек Modbus под Arduino, с целью снизить размер занимаемой памяти для скетча
28.03.2017 23:51
Modbus Slave RTU/ASCII для микроконтроллеров Arduino
Реализация клиентской части протокола Modbus RTU и Modbus ASCII для контроллеров Arduino и пример использования с видео обзором

Популярные статьи

Пример передачи данных по протоколу Modbus на Delphi
Пример передачи данных с контроллера ОВЕН ПЛК100 в программу на Delphi по протоколу Modbus
Modbus Slave на Arduino
Реализация клиентской части протокола Modbus RTU и Modbus ASCII для контроллеров Arduino
Набор компонентов для Delphi
Набор компонентов для Delphi включает в себя компонент для работы с файловой системой, сетью, автоматизацией и другие.