Нестандартная функция Modbus
В версии WebHMI 1.15.3620 поддерживаются типовые функции Modbus - 01..06. 99% процентов оборудования поддерживают данные функции. В случае, если необходимо работать с оборудованием, используя другие функции, можно использовать возможности пользовательских протоколов, т.е. создать еще одно соединение к устройству Modbus и написать обработку нестандартных запросов на языке lua.
В качестве примера рассмотрим работу с устройствами Dixell XR650C. В данном устройстве все данные доступны через регистры хранения (функции 03/06) , однако при необходимости управлять данным регулятором (включать, отключать, включать режим энергосбережения) используется 16-ая функция.
Шаг 1. В интерфейсе работы с регистрами необходимо добавить custom protocol:
Шаг 2. Написать протокол - исходный код протокола приведен ниже(поскольку для управления нужно только записывать регистр, функция readRegister здесь не используется, а в свойствах регистра можно установить атрибут Read On Demand):
-- Вспомогательные функции
-- вычисление контрольной суммы
function get_crc(req)
local crc = 0xffff;
local mask = 0;
-- Перебор байтов
for i=1,#req do
crc = bit.bxor(crc,req[i]);
-- перебор битов в байте
for j=1,8 do
mask = bit.band(crc,0x0001);
if mask == 0x0001 then
--если младший бит равен 1
crc = bit.rshift(crc,1); -- сдвиг
crc = bit.bxor(crc,0xA001); -- маску по XOR
else
crc = bit.rshift(crc,1);
end
end -- конец перебора бит
end -- конец перебора байтов
return crc;
end
--выделить старший байт из слова
function high_byte(b)
return bit.rshift(b,8);
end
--выделить мл. байт из слова
function low_byte(c)
return bit.band(c,0x00FF);
end
-- окончание вспомогательных функций
-- чтение не используется
function createDevices ()
-- Add your code here
addDevice({name = "PR", base = 16});
end
-- Шаблон запроса
-- №1 slave #2func #3reqister length byte count value
local request = {01, 16, 00, 01, 00, 01, 02, 00, 00, };
local full_request = request; -- сюда будет сформирован полный запрос
function readRegister ()
-- эта функция не используется
return 1; -- вернуть 1 чтобы отрабатывали функции
end
-- функция записи в регистр
function writeRegister (reg, device, unitId, newValue)
-- формируем строку запроса , addr
full_request[1] = unitId;
-- addr PDU
full_request[4] = low_byte(reg.internalAddr);
full_request[3] = high_byte(reg.internalAddr);
-- value to write
full_request[9] = low_byte(newValue);
full_request[8] = high_byte(newValue);
-- get crc
local CRC = get_crc(full_request);
table.insert(full_request,low_byte(CRC));
table.insert(full_request,high_byte(CRC));
-- отправляем запрос
local res = sendBytes(full_request);
if (res == false) then
DEBUG("Can't send bytes");
return 0;
end
-- удаляем CRC из таблицы
table.remove(full_request); table.remove(full_request);
-- принимаем ответ
local response = {};
response = readBytes(8);
if (response == false) then
DEBUG("Can't read response");
return false;
end
res_len = #response;
if (res_len ~= 8) then
DEBUG("Wrong response length");
return false;
end
if (response[1] ~= full_request[1]) then
ERROR("Wronng unit ID Got #" .. response[1].. " but expected #" .. full_request[1]);
return false;
end
return true;
end