Создание скрипта

<< Click to Display Table of Contents >>

Navigation:  Modbus Universal MasterOPC Server > Руководство по языку Lua 5.1 > Примеры и полезности > Чтение файлов по Modbus >

Создание скрипта

Скрипт мы расположим в устройстве – мы будем опрашивать прибор, разбирать значения и раскладывать их по тегам при помощи функции server.WriteTagByRelativeNameToHda(). Включим выполнение скрипта после чтения у устройства и откроем редактор.

Код будем создавать в функции OnBeforeReading()

primery_i_poleznosti_chtenie_fajlov_po_modbus_sozdanie_skripta

Приведем весь код, необходимый для чтения всего архива устройства, а затем разберем его.

local err,dstlen; --объявление переменных

local file={}; --объявление таблицы файлов

local rec={}; --объявление таблицы записей

local len={64}; --объявление и инициализация таблицы количества принимаемых элементов

local dstdata = {}; --объявление таблицы для принятия данных из записи 1

--маска первой таблицы (для записи 1). Тип значения Int16

local dstmsk1 = {"uint32:1:32107654","uint16:1:10","uint16:1:10","uint32:1:32107654","uint16:59:10"};

--количество элементов – 5, чередование старшим байтов вперед

local dstmsk = {dstmsk1}; --создание таблицы таблиц с масками

--цикл опроса всего архива

for i=1, 512, 1 do --цикл опроса по файлам

for j=0, 3, 1 do --цикл опроса по записям

file[1] = i; --номер файла равен номеру циклу

rec[1]=j*len[1]; --номер записи равен номеру подцикла умноженный на длину записи

--чтение архива из устройства

err,dstdata = modbus.ReadFileFunction(1,file,rec,len,dstmsk);

if err==0 then

--ошибки нет. Проверим соответствие типа записи. Тип записи должен быть равен единице

if dstdata[2]==1 then --второй элемент массива - тип записи

--тип соответствует можно записать значения в теги

local date_time=dsdata[4]; --значение времени хранится в элементе 4

local ts=time.TimeToTimeStamp(date_time,0); --преобразуем время в TimeStamp

local Frequency=dstdata[11]/100; --частота хранится в элементе 11.

local Current_A=dstdata[12]/10; --ток в фазе А

local Current_B=dstdata[13]/10; --ток в фазе B

local Current_C=dstdata[14]/10; --ток в фазе C

--записываем значения в теги

server.WriteTagByRelativeNameToHda("Частота",Frequency,OPC_QUALITY_GOOD,ts);

server.WriteTagByRelativeNameToHda("Ток фазы А",Current_A,OPC_QUALITY_GOOD,ts);

server.WriteTagByRelativeNameToHda("Ток фазы В",Current_B,OPC_QUALITY_GOOD,ts);

server.WriteTagByRelativeNameToHda("Ток фазы С",Current_C,OPC_QUALITY_GOOD,ts);

end;

end;

end;

end;

Первая часть кода в целом не требует подробного комментирования – по большей части он знаком по предыдущему примеру. В строчке:

local dstmsk1 = {"uint32:1:32107654","uint16:1:10","uint16:1:10","uint32:1:32107654","uint16:59:10"};

Мы инициализируем значение масками принимаемых элементов. Первый принимаемый элемент - номер записи в хронологии; тип – беззнаковый целый, 4 байта, то есть uint32. Второй и третий принимаемый элементы – тип записи и версия программы соответственно; тип – беззнаковый целый, 2 байта, то есть uint16, два подряд идущих элемента. Четвертый элемент – время; тип – беззнаковый целый, 4 байта, то есть uint32. Остальные элементы – все имеют тип 2 байтового беззнакового целого, таких элементов в записи 59.

При помощи двух циклов ( for i=1, 512, 1 do и for j=0, 3, 1 do) мы по очереди опрашиваем все записи в устройстве.

Отдельно стоит пояснить строчку

rec[1]=j*len[1]; --номер записи равен номеру подцикла умноженный на длину

Номер записи определяется как номер подцикла опроса записей умноженный на длину записи. Дело в том, что файл в контроллере представляет собой массив байт. В запросе мы должны указать номер байта, с которого нужно начать считывание файла. Таким образом, в первом цикле мы указываем номер регистра 0, и длину записи – количество считываемых регистров (64 регистра или 128 байт), то есть считываем байты 0 – 127. В следующем цикле мы считываем из файла байты с номерами 128 – 255, и так далее.

После этого вызывается функция:

err,dstdata = modbus.ReadFileFunction(1,file,rec,len,dstmsk);

как и в предыдущем примере вызывает запрос к устройству по функции 0x14, но в данном случае возвращаемая таблица только одна.

Затем после проверки на ошибку и на корректность записи (напомним, что нам нужна запись только с идентификатором записи равным единице), можно осуществлять запись архивного значения в тег. Сначала нам нужно получить время в формате TimeStamp, для этого используются следующие строки:

local date_time=dsdata[4]; --значение времени хранится в элементе 4

local ts=time.TimeToTimeStamp(date_time,0); --преобразуем время в TimeStamp

В первой строке мы присваиваем переменной date_time значение из четвертого элемента массива (фактически этого можно не делать, а вставить данный элемент прямо в функцию time.TimeToTimeStamp). Эту строчку мы поясним подробнее.

Прибор передает значение в формате UnixTime. Данный формат, представляет собой 4 байтовое целое число, в котором содержится количество секунд с полуночи 1 января 1970 года. В нашем OPC сервере время представлено в таком же формате, поэтому никакого дополнительного преобразования не требуется. Если в вашем приборе значение представлено в другом формате (например, как в предыдущем примере – разбито на несколько регистров, или в каком-либо другом виде), то вам может потребоваться произвести преобразования, чтобы привести время к корректному типу.

После получения времени получаются значения интересующих нас параметров – частоты, и токов в фазах (элементы 11 – 14).

local Frequency=dstdata[11]/100; --частота хранится в элементе 11.

local Current_A=dstdata[12]/10; --ток в фазе А

local Current_B=dstdata[13]/10; --ток в фазе B

local Current_C=dstdata[14]/10; --ток в фазе C

Частота делится на 100, а токи на 10 – так как эти параметры представлены в приборе как целые числа со смещением запятой.

После этого значения записываются в соответствующие теги при помощи функции server.WriteTagByRelativeNameToHda(). Первый аргумент – относительное имя тега, второй – значение, третий – признак качества, четвертый – метка времени.

Поскольку пример учебный, то он упрощен. Например, количество файлов задано статично равным 512, для реальной конфигурации лучше сделать это значение регулируемым, используя дополнительные свойства.

Не реализован случай, когда не все записи заполнены данными. Для определения количества файлов хронологии у Электон-05, есть специальная расширенная Modbus функция – 0x2B. Используя функцию OPC сервера server.SendAndReceiveDataByMask(), которую мы рассматривали ранее, можно опрашивать устройство и по данной расширенной функции.

Также может показаться не совсем корректным опрос всего архива устройства – возможно, разработчик посчитает, что лучше сохранять номер последнего считанного файла, и при следующем опросе начинать считывать с него. В этом случае потребуется сохранение номера последнего считанного файла, например, в текстовый файл на компьютере. Для работы с файлами в MasterOPC также есть специальные функции.

Условием завершения опроса устройства может стать, например, ситуация когда новая полученная метка времени имеет более ранее значение чем предыдущая – поскольку используется кольцевой буфер, то это означает что мы начали считывать старые записи. Такую проверку также несложно производить.

Примечание. Конфигурация OPC сервера с полным кодом данного примера находится по ссылке и называется Электон.mbp