Нестандартная функция Modbus

Материал из WebHMI Wiki
Перейти к: навигация, поиск

В версии WebHMI 1.15.3620 поддерживаются типовые функции Modbus - 01..06. 99% процентов оборудования поддерживают данные функции. В случае, если необходимо работать с оборудованием, используя другие функции, можно использовать возможности пользовательских протоколов, т.е. создать еще одно соединение к устройству Modbus и написать обработку нестандартных запросов на языке lua.

В качестве примера рассмотрим работу с устройствами Dixell XR650C. В данном устройстве все данные доступны через регистры хранения (функции 03/06) , однако при необходимости управлять данным регулятором (включать, отключать, включать режим энергосбережения) используется 16-ая функция.

Шаг 1. В интерфейсе работы с регистрами необходимо добавить custom protocol:

Create 16 modbus 1.png
Шаг 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