Просмотр полной версии : ПЛК63 + МВ110-8АС + МУ110-8И + МК110-8ДН-4Р опрос по modbus
Егор_Егор
25.07.2018, 15:34
Здравствуйте! Прошу помощи в опросе МВ110-8АС с ПЛК63 по модбус. Связь с модулями есть - лампочки RS-485 мигают. из кучи примеров найденных на форуме слепил это, но никак не могу разобраться с указателями и буфером МВ110-8АС и МУ110-8И. С дискретными входами/выходами МК110 разобрался - все работает, но никак не удается получить значения с аналоговых входов.
VAR
get1_modbus: MB_RD_HOLD_REGS; (*МВ110.8АС*) (*функция 04 - чтение параметров float*)
send2_modbus: MB_WR_REGS; (*МУ110.8И*) (*функция 16 - запись параметров float*)
get3_modbus: MB_RD_HOLD_REGS; (*МК110.8ДН.4Р*) (*функция 04 - чтение параметров типа int*)
send4_modbus: MB_WR_REGS; (*МК110.8ДН.4Р*) (*функция 16 - запись параметров int*)
Buffer: ARRAY[0..255] OF BYTE; (* байтовый буфер данных *)
cmpl: BOOL;
port_opened: BYTE := 0;
Init: BOOL; (* признак инициализации пользовательской программы *)
Settings:COMSETTINGS; (* настройки последовательного порта *)
com_num: PORTS:=0; (*0 - RS-485, 1 - RS-232*)
enabl: BOOL; (*состояние работы блока*)
err: INT; (*номер ошибки*)
TimeOut: TIME:=T#50ms; (*таймаут*)
Exception: BYTE;
DataSize: WORD;
master1: BYTE:= 1;
COM_SERVICE1: COM_SERVICE;
ptr_D:POINTER TO BYTE;
(* Каналы модуля МВ110 8АС *)
i : BYTE;
pAI : POINTER TO BYTE;
pDiag : POINTER TO BYTE;
x: ARRAY[1..8] OF REAL;
ReciveBuffer : ARRAY[0..255] OF BYTE; (* Буфер ответов*)
SendBuffer : ARRAY[0..255] OF BYTE; (* Буфер посылок *)
AI : ARRAY[1..8] OF INT; (* Данные с каналов модуля*)
Diag : ARRAY[1..8] OF INT; (* Диагностические данные с каналов модуля*)
(* Каналы модуля МУ110 8И *)
pAO : POINTER TO BYTE;
y: ARRAY[1..8] OF REAL;
(* Каналы модуля МК110.8ДН.4Р *)
dwDI : WORD; (* Данные с входов модуля в формате word*)
DI : ARRAY[1..8] OF BOOL; (* Данные с входов модуля*)
DICntr : ARRAY[1..16] OF WORD; (* Счетчики входов модуля *)
pData : POINTER TO BYTE;
END_VAR
(*Устанавливаем настройки COM-порта*)
IF port_opened=0 THEN
Settings.Port:=com_num; (*номер COM-порта*)
Settings.dwBaudRate:=115200; (*скорость*)
Settings.byParity:=0;
Settings.dwTimeout:=0;
Settings.byStopBits:=0;
Settings.dwBufferSize:=0;
Settings.dwScan:=0;
END_IF
COM_SERVICE1(Enable:=(port_opened=0) , Settings:=Settings , Task:=OPEN_TSK );
(*Если COM-порт открыт, то переходим к приему и передачи данных *)
IF COM_SERVICE1.ready THEN
port_opened:=2;
END_IF
IF port_opened=2 THEN (*Удачно проинициализировали*)
CASE master1 OF
0:
get1_modbus(
Enable:=enabl , (* разрешение работы блока *)
Mode:=MB_RTU , (*режим передачи*)
DevAddr:=adr1 , (*адрес*)
FirstAddr:=100 , (*номер регистра*)
Quantity:=1, (*количество регистров*)
ComHandle:=Settings.Port ,(*номер COM-порта*)
TimeOut:=TimeOut , (*Таймаут T#50ms*)
Buffer:=Buffer , (* буфер данных *)
Complete=>cmpl , (* скопировать признак завершения операции *)
Exception=>err , (* скопировать регистр ошибок *)
ByteCnt=>DataSize ); (*кол-во считанных байтов *)
(*если установлен признак завершения операции, то *)
IF cmpl THEN
master1:=1;(*переходим к выполнению следующего ФБ*)
IF err=0 THEN (*Если нет ошибок, то получаем данные из буфера типа FLOAT*)
FOR i := 1 TO 8 DO
pAI := ADR(AI[i]);
pAI^ := Buffer[(i-1)*4 + 1];
pAI := pAI + 1;
pAI^ := Buffer[(i-1)*4];
pDiag := ADR(Diag[i]);
pDiag^ := ReciveBuffer[(i-1)*2 + 33];
pDiag := pDiag + 1;
pDiag^ := ReciveBuffer[(i-1)*2 + 32];
END_FOR;
END_IF
END_IF
1:
(*запись в буффер параметра типа Float*)
pAO:=ADR(y);
buffer[5] := pAO^;
pAO:=pAO+1;
buffer[4] := pAO^;
pAO:=pAO+1;
buffer[7] := pAO^;
pAO:=pAO+1;
buffer[6] := pAO^;
send2_modbus(
Enable:= enabl, (* разрешение работы блока *)
Mode:=MB_RTU , (*режим передачи*)
DevAddr:=adr2 , (*адрес*)
FirstAddr:= 0, (*номер регистра*)
Quantity:= 6, (*количество записываемых регистров*)
ComHandle:=Settings.Port ,(*номер сом-порта*)
TimeOut:=TimeOut , (*таймаут T#50ms*)
Buffer:=Buffer , (* буфер данных *)
Complete=>cmpl , (* скопировать признак завершения операции *)
Exception=>err , (* скопировать регистр ошибок *)
RegCnt=> DataSize); (*кол-во считанных байтов *)
(*если установлен признак завершения операции, то *)
IF cmpl THEN
master1:=2;(*переходим к выполнению следующего блока*)
END_IF
2:
get3_modbus(
Enable:= enabl, (* разрешение работы блока *)
Mode:=MB_RTU , (*режим передачи*)
DevAddr:=adr3 , (*адрес*)
FirstAddr:=51 , (*номер регистра*)
Quantity:=1 , (*количество регистров*)
ComHandle:= Settings.Port,(*номер COM-порта*)
TimeOut:=TimeOut , (*Таймаут T#50ms*)
Buffer:=Buffer , (* буфер данных *)
Complete=>cmpl , (* скопировать признак завершения операции *)
Exception=>err , (* скопировать регистр ошибок *)
ByteCnt=> DataSize); (*кол-во считанных байтов *)
(*если установлен признак завершения операции, то *)
IF cmpl THEN
IF err=0 THEN (*Если нет ошибок, то получаем данные из буфера типа INT*)
dwDI:=BYTE_TO_WORD(BUFFER[1]) OR SHL(BYTE_TO_WORD(BUFFER[0]),8);
END_IF
master1:=3;
END_IF
3:
(*Пишем в буфер отправки битовую маску*)
ptr_D:=ADR(mk_mask_in);
Buffer[1]:=ptr_D^;
ptr_D:=ptr_D+1;
Buffer[0]:=ptr_D^;
(*Выполняем отправку*)
send4_modbus(
Enable:= enabl, (* разрешение работы блока *)
Mode:=MB_RTU , (*режим передачи*)
DevAddr:=adr3 , (*адрес*)
FirstAddr:=50 , (*номер регистра*)
Quantity:=1 , (*количество регистров*)
ComHandle:= Settings.Port,(*номер COM-порта*)
TimeOut:=TimeOut , (*Таймаут T#50ms*)
Buffer:=Buffer , (* буфер данных *)
Complete=>cmpl , (* скопировать признак завершения операции *)
Exception=>err , (* скопировать регистр ошибок *)
RegCnt=> DataSize); (*кол-во считанных байтов *)
(*если установлен признак завершения операции, то *)
IF cmpl THEN
master1:=0;(*переходим к выполнению следующего блока*)
END_IF
END_CASE
IF enabl = FALSE THEN
enabl := TRUE;
END_IF
IF err <> 0 THEN
enabl := FALSE;
END_IF
(*Разбираем битовую маску входов МК110.8ДН.4Р*)
A4_in1:=dwDI.0;
A4_in2:=dwDI.1;
A4_in3:=dwDI.2;
A4_in4:=dwDI.3;
A4_in5:=dwDI.4;
A4_in6:=dwDI.5;
A4_in7:=dwDI.6;
A4_in8:=dwDI.7;
END_IF
Трофимов Артем
25.07.2018, 16:13
(* Каналы модуля МУ110 8И *)
pAO : POINTER TO BYTE;
y: ARRAY[1..8] OF REAL;
зачем это? у модуля 8И регистры типа WORD
сделайте y: ARRAY[1..8] OF WORD; подайте значение от 0 до 1000 (0,0.. 100.0%)
Quantity:= 8 (8 же каналов а не 6), (*количество записываемых регистров*)
Buffer:=ADR(y) ,
и будете записывать. не представляю что Вы в модуль записываете. у Вас скорей всего err не равен 0 , т.е. ошибка какая то происходит.
cml выставится и при наличии ошибки
Егор_Егор
27.07.2018, 10:01
Спасибо, с записью вроде понял, но проверить сейчас нет возможности. А как быть с чтением с МВ1108АС? в примерах есть опрос одного регистра, но мне надо считывать значения со всех 8 входов.
Трофимов Артем
27.07.2018, 10:26
сразу и не заметил. у Вас ошибка в адресе регистра 8АС. в РЭ стоит 0х100 , а у Вас просто 100...
приставка 0х говорит о том , что число в шестнадцатеричной системе исчисления, а не десятеричной , поэтому либо переводите в десятеричну , т.е адрес окажется 256м, либо в кодесис пишите 16#100 (в кодесис директива 16# указана согласно МЭК стандартам языка и она эквивалентна общепринятым в других стандартах 0х).
в количестве регистров укажите 8 а не 1, будете читать все 8 каналов. учтите, данных придёт в 8 раз больше и надо будет их парсить, как у Вас в коде для одного канала, также для всех( просто сдвигая индескы буфера)
Егор_Егор
27.07.2018, 14:04
да, ошибку в адресе регистра я тоже нашел. Но судя по РЭ МВ110-8АС измеренное значение 1го канала это 0х120, 0х121, 0х122, или 288, 289, 290 регистры, 2го канала это 0х123, 0х124, 0х125, или 291, 292, 293 регистры и т.д. Как понимаю мне надо считать значения с 288, 291, 294... регистров. Но как это сделать не пойму. подредактировал код, но значения, конечно, не считываются.
учтите, данных придёт в 8 раз больше и надо будет их парсить, как у Вас в коде для одного канала, также для всех( просто сдвигая индескы буфера)
как это реализовать?
VAR
i : BYTE;
pAI : POINTER TO BYTE;
AI : ARRAY[1..8] OF REAL; (* Данные с каналов модуля*)
Buffer: ARRAY[0..255] OF BYTE; (*байтовый буфер данных*)
END_VAR
и отрывок кода:
get1_modbus(
Enable:=enabl , (* разрешение работы блока *)
Mode:=MB_RTU , (*режим передачи*)
DevAddr:=32 , (*адрес*)
FirstAddr:=288 , (*номер регистра*)
Quantity:=8, (*количество регистров*)
ComHandle:=Settings.Port ,(*номер COM-порта*)
TimeOut:=TimeOut , (*Таймаут T#50ms*)
Buffer:=Buffer , (*буфер данных*)
Complete=>cmpl , (* скопировать признак завершения операции *)
Exception=>err , (* скопировать регистр ошибок *)
ByteCnt=>DataSize ); (*кол-во считанных байтов *)
(*если установлен признак завершения операции, то *)
IF cmpl THEN
master1:=1;(*переходим к выполнению следующего ФБ*)
IF err=0 THEN (*Если нет ошибок, то получаем данные из буфера типа FLOAT*)
FOR i := 1 TO 8 DO
pAI := ADR(AI);
pAI^:=Buffer[1];
pAI:=pAI+1;
pAI^:=Buffer[0];
pAI:=pAI+1;
pAI^:=Buffer[3];
pAI:=pAI+1;
pAI^:=Buffer[2];
END_FOR;
END_IF
END_IF
Трофимов Артем
27.07.2018, 15:25
с адресом регистра верно.
1 вход занимает 3 регистра (2 регистра данные + метка времени) если метка не нужна то
Quantity:=24, (*количество регистров*)
парсинг :
pAI := ADR(AI[1]);
pAI^:=Buffer[1];
pAI:=pAI+1;
pAI^:=Buffer[0];
pAI:=pAI+1;
pAI^:=Buffer[3];
pAI:=pAI+1;
pAI^:=Buffer[2];
pAI := ADR(AI[2]);
pAI^:=Buffer[7];
pAI:=pAI+1;
pAI^:=Buffer[6];
pAI:=pAI+1;
pAI^:=Buffer[9];
pAI:=pAI+1;
pAI^:=Buffer[8];
pAI := ADR(AI[2]);
pAI^:=Buffer[13];
pAI:=pAI+1;
pAI^:=Buffer[12];
pAI:=pAI+1;
pAI^:=Buffer[15];
pAI:=pAI+1;
pAI^:=Buffer[14];
и так далее
Егор_Егор
27.07.2018, 16:23
Что-то не хочет работать:(
Егор_Егор
30.07.2018, 15:06
Поделитесь, люди добрые, кодом опроса всех входов модуля МВ110-8АС. по кривому примеру с ошибками не получается никак
Мастеренко Иван
30.07.2018, 18:06
Здравствуйте.
38190
Проверьте порт, сетевые настройки и адрес модуля
Здравствуйте! Нужна помощь в организации опроса модулей ввода - вывода аналоговых сигналов с ПЛК 63. Связь с модулями настроить удалось, лампочки RS-485 мигают, но данные не считываются. Примеры с диска перепробовал. для опроса мв110-8АС использую функцию 0х03 Read Holding Registers, для МУ110-8И 0х10 Write Multiple registers.
VAR
get1_modbus: MB_RD_HOLD_REGS; (*МВ110.8АС*) (*функция 04 - чтение параметров float*)
send2_modbus: MB_WR_REGS; (*МУ110.8И*) (*функция 16 - запись параметров float*)
cmpl: BOOL;
port_opened: BYTE := 0;
Settings:COMSETTINGS; (* настройки последовательного порта *)
com_num: PORTS:=0; (*0 - RS-485, 1 - RS-232*)
enabl: BOOL; (*состояние работы блока*)
err: INT; (*номер ошибки*)
TimeOut: TIME:=T#100ms; (*таймаут*)
DataSize: WORD;
master1: BYTE:= 1;
COM_SERVICE1: COM_SERVICE;
ptr_D:POINTER TO BYTE;
(* Каналы модуля МВ110 8АС *)
pAI : POINTER TO BYTE;
Buffer: ARRAY[0..255] OF BYTE; (* байтовый буфер данных *)
(* Каналы модуля МУ110 8И *)
pAO : POINTER TO BYTE;
y: ARRAY[1..8] OF WORD;
END_VAR
VAR_INPUT
y1:WORD; (*Записываемый параметр типа WORD*)
y2:WORD; (*Записываемый параметр типа WORD*)
y3:WORD; (*Записываемый параметр типа WORD*)
y4:WORD; (*Записываемый параметр типа WORD*)
y5:WORD; (*Записываемый параметр типа WORD*)
y6:WORD; (*Записываемый параметр типа WORD*)
y7:WORD; (*Записываемый параметр типа WORD*)
y8:WORD; (*Записываемый параметр типа WORD*)
END_VAR
VAR_OUTPUT
x1:REAL; (*Принятый результат*)
x2:REAL; (*МВ110.8АС*)
x3:REAL;
x4:REAL;
x5:REAL;
x6:REAL;
x7:REAL;
x8:REAL;
END_VAR
(*Устанавливаем настройки COM-порта*)
IF port_opened=0 THEN
Settings.Port:=com_num; (*номер COM-порта*)
Settings.dwBaudRate:=115200; (*скорость*)
Settings.byParity:=0;
Settings.dwTimeout:=0;
Settings.byStopBits:=0;
Settings.dwBufferSize:=0;
Settings.dwScan:=0;
END_IF
COM_SERVICE1(Enable:=(port_opened=0) , Settings:=Settings , Task:=OPEN_TSK );
(*Если COM-порт открыт, то переходим к приему и передачи данных *)
IF COM_SERVICE1.ready THEN
port_opened:=2;
END_IF
IF port_opened=2 THEN (*Удачно проинициализировали*)
CASE master1 OF
0:
get1_modbus(
Enable:=enabl , (* разрешение работы блока *)
Mode:=MB_RTU , (*режим передачи*)
DevAddr:=32 , (*адрес*)
FirstAddr:=288 , (*номер регистра*)
Quantity:=24, (*количество регистров*)
ComHandle:=Settings.Port ,(*номер COM-порта*)
TimeOut:=TimeOut , (*Таймаут T#50ms*)
Buffer:=Buffer , (* буфер данных *)
Complete=>cmpl , (* скопировать признак завершения операции *)
Exception=>err , (* скопировать регистр ошибок *)
ByteCnt=>DataSize ); (*кол-во считанных байтов *)
(*если установлен признак завершения операции, то *)
IF cmpl THEN
master1:=1;(*переходим к выполнению следующего ФБ*)
IF err=0 THEN (*Если нет ошибок, то получаем данные из буфера типа FLOAT*)
pAI := ADR(x1);
pAI^:=Buffer[1];
pAI:=pAI+1;
pAI^:=Buffer[0];
pAI:=pAI+1;
pAI^:=Buffer[3];
pAI:=pAI+1;
pAI^:=Buffer[2];
pAI := ADR(x2);
pAI^:=Buffer[7];
pAI:=pAI+1;
pAI^:=Buffer[6];
pAI:=pAI+1;
pAI^:=Buffer[9];
pAI:=pAI+1;
pAI^:=Buffer[8];
pAI := ADR(x3);
pAI^:=Buffer[13];
pAI:=pAI+1;
pAI^:=Buffer[12];
pAI:=pAI+1;
pAI^:=Buffer[15];
pAI:=pAI+1;
pAI^:=Buffer[14];
pAI := ADR(x4);
pAI^:=Buffer[19];
pAI:=pAI+1;
pAI^:=Buffer[18];
pAI:=pAI+1;
pAI^:=Buffer[21];
pAI:=pAI+1;
pAI^:=Buffer[20];
pAI := ADR(x5);
pAI^:=Buffer[25];
pAI:=pAI+1;
pAI^:=Buffer[24];
pAI:=pAI+1;
pAI^:=Buffer[27];
pAI:=pAI+1;
pAI^:=Buffer[26];
pAI := ADR(x6);
pAI^:=Buffer[31];
pAI:=pAI+1;
pAI^:=Buffer[30];
pAI:=pAI+1;
pAI^:=Buffer[33];
pAI:=pAI+1;
pAI^:=Buffer[32];
pAI := ADR(x7);
pAI^:=Buffer[37];
pAI:=pAI+1;
pAI^:=Buffer[36];
pAI:=pAI+1;
pAI^:=Buffer[39];
pAI:=pAI+1;
pAI^:=Buffer[38];
pAI := ADR(x8);
pAI^:=Buffer[43];
pAI:=pAI+1;
pAI^:=Buffer[42];
pAI:=pAI+1;
pAI^:=Buffer[45];
pAI:=pAI+1;
pAI^:=Buffer[44];
END_IF
END_IF
1:
(*запись в буффер параметра типа Float*)
pAO:=ADR(y1);
buffer[5] := pAO^;
pAO:=pAO+1;
buffer[4] := pAO^;
pAO:=pAO+1;
buffer[7] := pAO^;
pAO:=pAO+1;
buffer[6] := pAO^;
pAO:=ADR(y2);
buffer[11] := pAO^;
pAO:=pAO+1;
buffer[10] := pAO^;
pAO:=pAO+1;
buffer[13] := pAO^;
pAO:=pAO+1;
buffer[12] := pAO^;
pAO:=ADR(y3);
buffer[17] := pAO^;
pAO:=pAO+1;
buffer[16] := pAO^;
pAO:=pAO+1;
buffer[19] := pAO^;
pAO:=pAO+1;
buffer[18] := pAO^;
pAO:=ADR(y4);
buffer[23] := pAO^;
pAO:=pAO+1;
buffer[22] := pAO^;
pAO:=pAO+1;
buffer[25] := pAO^;
pAO:=pAO+1;
buffer[24] := pAO^;
send2_modbus(
Enable:= enabl, (* разрешение работы блока *)
Mode:=MB_RTU , (*режим передачи*)
DevAddr:=48 , (*адрес*)
FirstAddr:= 0, (*номер регистра*)
Quantity:= 8, (*количество записываемых регистров*)
ComHandle:=Settings.Port ,(*номер сом-порта*)
TimeOut:=TimeOut , (*таймаут T#50ms*)
Buffer:=Buffer , (* буфер данных *)
Complete=>cmpl , (* скопировать признак завершения операции *)
Exception=>err , (* скопировать регистр ошибок *)
RegCnt=> DataSize); (*кол-во считанных байтов *)
(*если установлен признак завершения операции, то *)
IF cmpl THEN
master1:=2;(*переходим к выполнению следующего блока*)
END_IF
Попробуйте поменять местами порядок байт получаемых данных с модуля 8АС, на такой:
pAI := ADR(x1);
pAI^:=Buffer[3];
pAI:=pAI+1;
pAI^:=Buffer[2];
pAI:=pAI+1;
pAI^:=Buffer[1];
pAI:=pAI+1;
pAI^:=Buffer[0];
Егор_Егор
31.07.2018, 09:27
Спасибо, заработало)
Егор_Егор
31.07.2018, 12:02
Что-то рано я обрадовался. Происходит нечто непонятно: при загрузке в ПЛК Вашего примера все считывается, хотя ошибки прибавляются, но при копировании кода в мой проект данные прекращают считываться. В чем может быть причина?
Мастеренко Иван
01.08.2018, 09:34
приложите проект со скопированным кодом
Я пользуюсь таким алгоритмом чтения:
PROGRAM GET_MB
VAR
(*TON*)
HavePause :TON;
(*FB*)
GetModbus : MB_RD_HOLD_REGS;
ComService : COM_SERVICE;
(*BOOL*)
ES : BOOL := TRUE;
EndSendStored : BOOL;
(*BYTE*)
ComPortState : BYTE := 0;
Addr : BYTE := 2;
RegQuant : BYTE := 24;
(*INT*)
MB110_8AC_1CH_STS : INT;
MB110_8AC_2CH_STS : INT;
MB110_8AC_3CH_STS : INT;
MB110_8AC_4CH_STS : INT;
MB110_8AC_5CH_STS : INT;
MB110_8AC_6CH_STS : INT;
MB110_8AC_7CH_STS : INT;
MB110_8AC_8CH_STS : INT;
(*WORD*)
DataSize : WORD;
RegAddr : WORD := 280;
(*REAL*)
MB110_8AC_1CH_VAL : REAL;
MB110_8AC_2CH_VAL : REAL;
MB110_8AC_3CH_VAL : REAL;
MB110_8AC_4CH_VAL : REAL;
MB110_8AC_5CH_VAL : REAL;
MB110_8AC_6CH_VAL : REAL;
MB110_8AC_7CH_VAL : REAL;
MB110_8AC_8CH_VAL : REAL;
(*TIME*)
TimeOut1 : TIME := T#50ms;
TimeOut2 : TIME := T#250ms;
(*STRUCT*)
Settings : COMSETTINGS;
(*TYPES*)
ComNum : PORTS := 0;
(*ARRAY*)
Buffer : ARRAY [0..255] OF BYTE;
(*POINTER*)
Ptb : POINTER TO BYTE;
END_VAR
(*Настройки COM-порта*)
IF ComPortState=0 THEN
Settings.Port:=ComNum; (*номер COM-порта*)
Settings.dwBaudRate:=115200; (*скорость*)
Settings.byParity:=0;
Settings.dwTimeout:=0;
Settings.byStopBits:=1;
Settings.dwBufferSize:=0;
Settings.dwScan:=0;
END_IF
(*________________________________________________ _______________*)
(*Открываем COM-порт*)
ComService(ENABLE := ComPortState = 0, SETTINGS := Settings, TASK := OPEN_TSK);
(*________________________________________________ _______________*)
(*Готовность COM-порта к обмену данными*)
IF ComService.Ready THEN
ComPortState := 2;
END_IF
(*________________________________________________ _______________*)
(*Если COM-порт открыт, то запускаем обмен данными*)
IF ComPortState=2 THEN
GetModbus(
Enable := ES,
Mode := MB_RTU,
DevAddr := Addr,
FirstAddr := RegAddr,
Quantity := RegQuant,
ComHandle := Settings.Port,
TimeOut := TimeOut1,
Buffer := Buffer,
ByteCnt => DataSize);
ES := FALSE;
(*Если прием данных завершен*)
IF GetModbus.Complete THEN
(*и без ошибок,*)
IF GetModbus.Exception = 0 THEN
(*то читаем их из Buffer в соответствующие переменные*)
(*Статусы результатов измерений модулей MB110 8AC*)
(*Первый канал*)
Ptb := ADR(MB110_8AC_1CH_STS);
Ptb^ := Buffer[1];
Ptb := Ptb + 1;
Ptb^ := Buffer[0];
(*Второй канал*)
Ptb := ADR(MB110_8AC_2CH_STS);
Ptb^ := Buffer[3];
Ptb := Ptb + 1;
Ptb^ := Buffer[2];
(*Третий канал*)
Ptb := ADR(MB110_8AC_3CH_STS);
Ptb^ := Buffer[5];
Ptb := Ptb + 1;
Ptb^ := Buffer[4];
(*Четвертый канал*)
Ptb := ADR(MB110_8AC_4CH_STS);
Ptb^ := Buffer[7];
Ptb := Ptb + 1;
Ptb^ := Buffer[6];
(*Пятый канал*)
Ptb := ADR(MB110_8AC_5CH_STS);
Ptb^ := Buffer[9];
Ptb := Ptb + 1;
Ptb^ := Buffer[8];
(*Шестой канал*)
Ptb := ADR(MB110_8AC_6CH_STS);
Ptb^ := Buffer[11];
Ptb := Ptb + 1;
Ptb^ := Buffer[10];
(*Седьмой канал*)
Ptb := ADR(MB110_8AC_7CH_STS);
Ptb^ := Buffer[13];
Ptb := Ptb + 1;
Ptb^ := Buffer[12];
(*Восьмой канал*)
Ptb := ADR(MB110_8AC_8CH_STS);
Ptb^ := Buffer[15];
Ptb := Ptb + 1;
Ptb^ := Buffer[14];
(*Измеренные значения модуля MB110 8AC*)
(*Первый канал*)
Ptb := ADR(MB110_8AC_1CH_VAL);
Ptb^ := Buffer[19];
Ptb := Ptb + 1;
Ptb^ := Buffer[18];
Ptb := Ptb + 1;
Ptb^ := Buffer[17];
Ptb := Ptb + 1;
Ptb^ := Buffer[16];
(*Второй канал*)
Ptb := ADR(MB110_8AC_2CH_VAL);
Ptb^ := Buffer[25];
Ptb := Ptb + 1;
Ptb^ := Buffer[24];
Ptb := Ptb + 1;
Ptb^ := Buffer[23];
Ptb := Ptb + 1;
Ptb^ := Buffer[22];
(*Третий канал*)
Ptb := ADR(MB110_8AC_3CH_VAL);
Ptb^ := Buffer[31];
Ptb := Ptb + 1;
Ptb^ := Buffer[30];
Ptb := Ptb + 1;
Ptb^ := Buffer[29];
Ptb := Ptb + 1;
Ptb^ := Buffer[28];
(*Четвертый канал*)
Ptb := ADR(MB110_8AC_4CH_VAL);
Ptb^ := Buffer[37];
Ptb := Ptb + 1;
Ptb^ := Buffer[36];
Ptb := Ptb + 1;
Ptb^ := Buffer[35];
Ptb := Ptb + 1;
Ptb^ := Buffer[34];
(*Пятый канал*)
Ptb := ADR(MB110_8AC_5CH_VAL);
Ptb^ := Buffer[43];
Ptb := Ptb + 1;
Ptb^ := Buffer[42];
Ptb := Ptb + 1;
Ptb^ := Buffer[41];
Ptb := Ptb + 1;
Ptb^ := Buffer[40];
(*Шестой канал*)
Ptb := ADR(MB110_8AC_6CH_VAL);
Ptb^ := Buffer[49];
Ptb := Ptb + 1;
Ptb^ := Buffer[48];
Ptb := Ptb + 1;
Ptb^ := Buffer[47];
Ptb := Ptb + 1;
Ptb^ := Buffer[46];
(*Седьмой канал*)
Ptb := ADR(MB110_8AC_7CH_VAL);
Ptb^ := Buffer[55];
Ptb := Ptb + 1;
Ptb^ := Buffer[54];
Ptb := Ptb + 1;
Ptb^ := Buffer[53];
Ptb := Ptb + 1;
Ptb^ := Buffer[52];
(*Восьмой канал*)
Ptb := ADR(MB110_8AC_8CH_VAL);
Ptb^ := Buffer[61];
Ptb := Ptb + 1;
Ptb^ := Buffer[60];
Ptb := Ptb + 1;
Ptb^ := Buffer[59];
Ptb := Ptb + 1;
Ptb^ := Buffer[58];
END_IF
EndSendStored := TRUE;
END_IF
(*Временная задержка*)
HavePause(IN := EndSendStored, PT := TimeOut2);
IF HavePause.Q THEN
ES := TRUE;
EndSendStored := FALSE;
END_IF
END_IF
Можно "поиграться" с таймаутами. Никаких ошибок, при условии правильной настройки мастера и слэйва.
Я пользуюсь таким алгоритмом чтения:....
Массивы/структуры не ?
Егор_Егор
01.08.2018, 13:59
Всем спасибо, с записью проблема решилась переписыванием кода в новый пустой проект, видимо в конфигурации ПЛК что-то накрутил ненужного) Теперь пытаюсь разобраться с записью значений в МУ110-8И. Подскажите, где посмотреть порядок и номера байт для записи в модуль? или их высчитывать нужно? вот сам код опроса/записи:
FUNCTION_BLOCK mudb
VAR_INPUT
(*Çíà÷åíèÿ äëÿ çàïèñè â ÌÓ110-8È À3*)
y1:WORD; (*Çàïèñûâàåìûé ïàðàìåòð òèïà WORD*)
y2:WORD; (*Çàïèñûâàåìûé ïàðàìåòð òèïà WORD*)
y3:WORD; (*Çàïèñûâàåìûé ïàðàìåòð òèïà WORD*)
y4:WORD; (*Çàïèñûâàåìûé ïàðàìåòð òèïà WORD*)
y5:WORD; (*Çàïèñûâàåìûé ïàðàìåòð òèïà WORD*)
y6:WORD; (*Çàïèñûâàåìûé ïàðàìåòð òèïà WORD*)
(*Áèòîâàÿ ìàñêà âûõîäîâ ìîäóëÿ ÌÊ1108ÄÍ*)
mk_mask_in:WORD;
END_VAR
VAR_OUTPUT
(*ñ÷èòàííîå çíà÷åíèå ñ ÌÂ110-8ÀÑ À2*)
real1: REAL;
real2: REAL;
real3: REAL;
real4: REAL;
real5: REAL;
real6: REAL;
real7: REAL;
real8: REAL;
(*Âõîäû ìîäóëÿ ÌÊ1108ÄÍ*)
A4_in1: BOOL;
A4_in2: BOOL;
A4_in3: BOOL;
A4_in4: BOOL;
A4_in5: BOOL;
A4_in6: BOOL;
A4_in7: BOOL;
A4_in8: BOOL;
END_VAR
VAR
get3_modbus: MB_RD_HOLD_REGS; (*ôóíêöèÿ 03 - ÷òåíèå ïàðàìåòðà òèïà INT*)
send2_modbus: MB_WR_REGS; (*ÌÓ110.8È*) (*ôóíêöèÿ 16 - çàïèñü ïàðàìåòðîâ float*)
Buffer: ARRAY[0..255] OF BYTE; (* áàéòîâûé áóôåð äàííûõ *)
cmpl: BOOL; (*ïðèçíàê çàâåðøåííîñòè ðàáîòû ôóíêöèè*)
port_opened: BYTE := 0; (*ðåçóëüòàò îòêðûòèÿ ïîðòà*)
Settings:COMSETTINGS; (* íàñòðîéêè ïîñëåäîâàòåëüíîãî ïîðòà *)
com_num: PORTS:=0; (*0 - RS-485, 1 - RS-232*)
enable: BOOL; (*ñîñòîÿíèå ðàáîòû áëîêà*)
err: INT; (*íîìåð îøèáêè*)
TimeOut: TIME:=T#100ms; (*òàéìàóò*)
DataSize: WORD; (*êîë-âî ñ÷èòàííûõ áàéòîâ *)
ptr_byte:POINTER TO BYTE; (*óêàçàòåëü íà òèï byte*)
COM_SERVICE1: COM_SERVICE;
state: WORD := 0; (*ñîñòîÿíèå*)
i: WORD := 0; (*äîï. ïåðåìåííàÿ*)
t:WORD; (*÷èñëî îøèáîê*)
dwDI : WORD; (* Áèòîâàÿ ìàñêà âõîäîâ ìîäóëÿ À4*)
END_VAR
(*Óñòàíàâëèâàåì íàñòðîéêè COM-ïîðòà*)
IF port_opened=0 THEN
Settings.Port:=com_num; (*íîìåð COM-ïîðòà*)
Settings.dwBaudRate:=115200; (*ñêîðîñòü*)
Settings.byParity:=0;
Settings.dwTimeout:=0;
Settings.byStopBits:=0;
Settings.dwBufferSize:=0;
Settings.dwScan:=0;
END_IF
COM_SERVICE1(Enable:=(port_opened=0) , Settings:=Settings , Task:=OPEN_TSK );
(*Åñëè COM-ïîðò îòêðûò, òî ïåðåõîäèì ê ïðèåìó è ïåðåäà÷è äàííûõ *)
IF COM_SERVICE1.ready THEN
port_opened:=2;
END_IF
CASE state OF
0:
enable:=1;
IF port_opened=2 THEN (*Óäà÷íî ïðîèíèöèàëèçèðîâàëè*)
(* ôóíêöèÿ 03 ôëîàò - ÔÁ ñ÷èòûâàåò çíà÷åíèå ïàðàìåòðà òèïà int16 èç ïðèáîðà ñ àäðåñîì 22 c ðåãèñòðà ñ íîìàðîì 0dec ïî ïðîòîêîëó Modbus-RTU*)
get3_modbus(
Enable:=enable, (* ðàçðåøåíèå ðàáîòû áëîêà *)
Mode:=MB_RTU , (*ðåæèì ïåðåäà÷è*)
DevAddr:=32 , (*àäðåñ*)
FirstAddr:=288 , (*íîìåð ðåãèñòðà*)
Quantity:=24, (*êîëè÷åñòâî ðåãèñòðîâ*)
ComHandle:=Settings.Port ,(*íîìåð COM-ïîðòà*)
TimeOut:=TimeOut , (*Òàéìàóò T#50ms*)
Buffer:=Buffer , (* áóôåð äàííûõ *)
Complete=>cmpl , (* ñêîïèðîâàòü ïðèçíàê çàâåðøåíèÿ îïåðàöèè *)
Exception=>err , (* ñêîïèðîâàòü ðåãèñòð îøèáîê *)
ByteCnt=>DataSize ); (*êîë-âî ñ÷èòàííûõ áàéòîâ *)
(*åñëè óñòàíîâëåí ïðèçíàê çàâåðøåíèÿ îïåðàöèè, òî *)
IF cmpl THEN
IF err=0 THEN (*Åñëè íåò îøèáîê, òî ïîëó÷àåì äàííûå èç áóôåðà, ôîðìèðóåì ïåðåìåííûå*)
(*ìîäóëü ïåðåäàåò çíà÷åíèÿ ñòàðøèì ñëîâîì âïåðåä äëÿ Float32 è ñòàðøèì áàéòîì âïåðåä äëÿ Int16*)
(*ïîýòîìó ïåðåìåííûå ñîáèðàåì "ñïðàâà-íàëåâî" *)
(*âõîä1*)
ptr_byte:=ADR(real1);
ptr_byte^:=buffer[3];
ptr_byte:=ptr_byte+1;
ptr_byte^:=buffer[2];
ptr_byte:=ptr_byte+1;
ptr_byte^:=buffer[1];
ptr_byte:=ptr_byte+1;
ptr_byte^:=buffer[0];
ptr_byte:=ADR(real2);
ptr_byte^:=buffer[9];
ptr_byte:=ptr_byte+1;
ptr_byte^:=buffer[8];
ptr_byte:=ptr_byte+1;
ptr_byte^:=buffer[7];
ptr_byte:=ptr_byte+1;
ptr_byte^:=buffer[6];
ptr_byte:=ADR(real3);
ptr_byte^:=buffer[15];
ptr_byte:=ptr_byte+1;
ptr_byte^:=buffer[14];
ptr_byte:=ptr_byte+1;
ptr_byte^:=buffer[13];
ptr_byte:=ptr_byte+1;
ptr_byte^:=buffer[12];
ptr_byte:=ADR(real4);
ptr_byte^:=buffer[21];
ptr_byte:=ptr_byte+1;
ptr_byte^:=buffer[20];
ptr_byte:=ptr_byte+1;
ptr_byte^:=buffer[19];
ptr_byte:=ptr_byte+1;
ptr_byte^:=buffer[18];
ptr_byte:=ADR(real5);
ptr_byte^:=buffer[27];
ptr_byte:=ptr_byte+1;
ptr_byte^:=buffer[26];
ptr_byte:=ptr_byte+1;
ptr_byte^:=buffer[25];
ptr_byte:=ptr_byte+1;
ptr_byte^:=buffer[24];
ptr_byte:=ADR(real6);
ptr_byte^:=buffer[33];
ptr_byte:=ptr_byte+1;
ptr_byte^:=buffer[32];
ptr_byte:=ptr_byte+1;
ptr_byte^:=buffer[31];
ptr_byte:=ptr_byte+1;
ptr_byte^:=buffer[30];
ptr_byte:=ADR(real7);
ptr_byte^:=buffer[39];
ptr_byte:=ptr_byte+1;
ptr_byte^:=buffer[38];
ptr_byte:=ptr_byte+1;
ptr_byte^:=buffer[37];
ptr_byte:=ptr_byte+1;
ptr_byte^:=buffer[36];
ptr_byte:=ADR(real8);
ptr_byte^:=buffer[45];
ptr_byte:=ptr_byte+1;
ptr_byte^:=buffer[44];
ptr_byte:=ptr_byte+1;
ptr_byte^:=buffer[43];
ptr_byte:=ptr_byte+1;
ptr_byte^:=buffer[42];
state:=1;
enable:=0;
ELSE t:=t+1;
state:=1;
END_IF
END_IF
END_IF
1: (*äàëüíåéøåå çàâèñèò îò ïîëüçîâàòåëÿ*)
(*î÷èñòèì áóôåð*)
FOR i:=0 TO 255 DO
buffer[i]:=0;
END_FOR
(*âåðíåìñÿ îïÿòü â ñîñòîÿíèå 0*)
state:=2;
2:
(*çàïèñü â áóôôåð ïàðàìåòðà òèïà Float*)
enable:=1;
ptr_byte:=ADR(y1);
buffer[5] := ptr_byte^;
ptr_byte:=ptr_byte+1;
buffer[4] := ptr_byte^;
ptr_byte:=ptr_byte+1;
buffer[7] := ptr_byte^;
ptr_byte:=ptr_byte+1;
buffer[6] := ptr_byte^;
send2_modbus(
Enable:= enable, (* ðàçðåøåíèå ðàáîòû áëîêà *)
Mode:=MB_RTU , (*ðåæèì ïåðåäà÷è*)
DevAddr:=48 , (*àäðåñ*)
FirstAddr:= 0, (*íîìåð ðåãèñòðà*)
Quantity:= 8, (*êîëè÷åñòâî çàïèñûâàåìûõ ðåãèñòðîâ*)
ComHandle:=Settings.Port ,(*íîìåð ñîì-ïîðòà*)
TimeOut:=TimeOut , (*òàéìàóò T#50ms*)
Buffer:=buffer , (* áóôåð äàííûõ *)
Complete=>cmpl , (* ñêîïèðîâàòü ïðèçíàê çàâåðøåíèÿ îïåðàöèè *)
Exception=>err , (* ñêîïèðîâàòü ðåãèñòð îøèáîê *)
RegCnt=> DataSize); (*êîë-âî ñ÷èòàííûõ áàéòîâ *)
(*åñëè óñòàíîâëåí ïðèçíàê çàâåðøåíèÿ îïåðàöèè, òî *)
IF cmpl THEN
state:=3;(*ïåðåõîäèì ê âûïîëíåíèþ ñëåäóþùåãî áëîêà*)
END_IF
3:
FOR i:=0 TO 255 DO
buffer[i]:=0;
END_FOR
(*âåðíåìñÿ îïÿòü â ñîñòîÿíèå 0*)
state:=4;
enable:=0;
4:
enable:=1;
IF port_opened=2 THEN (*Óäà÷íî ïðîèíèöèàëèçèðîâàëè*)
get3_modbus(
Enable:= enable, (* ðàçðåøåíèå ðàáîòû áëîêà *)
Mode:=MB_RTU , (*ðåæèì ïåðåäà÷è*)
DevAddr:=64 , (*àäðåñ*)
FirstAddr:=51 , (*íîìåð ðåãèñòðà*)
Quantity:=1 , (*êîëè÷åñòâî ðåãèñòðîâ*)
ComHandle:= Settings.Port,(*íîìåð COM-ïîðòà*)
TimeOut:=TimeOut , (*Òàéìàóò T#50ms*)
Buffer:=buffer , (* áóôåð äàííûõ *)
Complete=>cmpl , (* ñêîïèðîâàòü ïðèçíàê çàâåðøåíèÿ îïåðàöèè *)
Exception=>err , (* ñêîïèðîâàòü ðåãèñòð îøèáîê *)
ByteCnt=> DataSize); (*êîë-âî ñ÷èòàííûõ áàéòîâ *)
(*åñëè óñòàíîâëåí ïðèçíàê çàâåðøåíèÿ îïåðàöèè, òî *)
IF cmpl THEN
IF err=0 THEN (*Åñëè íåò îøèáîê, òî ïîëó÷àåì äàííûå èç áóôåðà òèïà INT*)
dwDI:=BYTE_TO_WORD(buffer[1]) OR SHL(BYTE_TO_WORD(buffer[0]),8);
END_IF
state:=5;
END_IF
END_IF
5:
FOR i:=0 TO 255 DO
buffer[i]:=0;
END_FOR
(*âåðíåìñÿ îïÿòü â ñîñòîÿíèå 0*)
state:=6;
enable:=0;
6:
enable:=1;
(*Ïèøåì â áóôåð îòïðàâêè áèòîâóþ ìàñêó*)
ptr_byte:=ADR(mk_mask_in);
buffer[1]:=ptr_byte^;
ptr_byte:=ptr_byte+1;
buffer[0]:=ptr_byte^;
(*Âûïîëíÿåì îòïðàâêó*)
send2_modbus(
Enable:= enable, (* ðàçðåøåíèå ðàáîòû áëîêà *)
Mode:=MB_RTU , (*ðåæèì ïåðåäà÷è*)
DevAddr:=64 , (*àäðåñ*)
FirstAddr:=50 , (*íîìåð ðåãèñòðà*)
Quantity:=1 , (*êîëè÷åñòâî ðåãèñòðîâ*)
ComHandle:= Settings.Port,(*íîìåð COM-ïîðòà*)
TimeOut:=TimeOut , (*Òàéìàóò T#50ms*)
Buffer:=buffer , (* áóôåð äàííûõ *)
Complete=>cmpl , (* ñêîïèðîâàòü ïðèçíàê çàâåðøåíèÿ îïåðàöèè *)
Exception=>err , (* ñêîïèðîâàòü ðåãèñòð îøèáîê *)
RegCnt=> DataSize); (*êîë-âî ñ÷èòàííûõ áàéòîâ *)
(*åñëè óñòàíîâëåí ïðèçíàê çàâåðøåíèÿ îïåðàöèè, òî *)
IF cmpl THEN
state:=7;(*ïåðåõîäèì ê âûïîëíåíèþ ñëåäóþùåãî áëîêà*)
END_IF
IF enable = FALSE THEN
enable := TRUE;
END_IF
IF err <> 0 THEN
enable := FALSE;
END_IF
(*Ðàçáèðàåì áèòîâóþ ìàñêó âõîäîâ ÌÊ110.8ÄÍ.4Ð*)
A4_in1:=dwDI.0;
A4_in2:=dwDI.1;
A4_in3:=dwDI.2;
A4_in4:=dwDI.3;
A4_in5:=dwDI.4;
A4_in6:=dwDI.5;
A4_in7:=dwDI.6;
A4_in8:=dwDI.7;
7:
FOR i:=0 TO 255 DO
buffer[i]:=0;
END_FOR
(*âåðíåìñÿ îïÿòü â ñîñòîÿíèå 0*)
state:=0;
END_CASE
Дискретные входы/выходы и считываются и записываются нормально
Ой, пля.. Сначала немного теории:
Нюанс модбаса
В модбас сетевой порядок байт в словах (регистрах) отличается порядка байт в словах (вордах) на местном плк. На плк порядок байт 12, сетевой 21.
Важно ! Та биб-ка (модбас.либ) нифига не удосуживается приводить данные из/в сетевого порядка.
Отсюда - что при отправке, что при чтении данные нужно приводить самому.
(Местный релиз ntohw/htonw сводится к единой функции перестановки байтов попарно)
При чтении, после приведения порядка, данные повторяют таблицу регистров приведенную в РЭ для модулей.
При записи, данные повторяющие таблицу регистров нужно привести в сетевой порядок и спокойно отправлять.
Общий нюанс всех модулей Овен :
Все 32-битное на модулях (дворды, реалы) имеет другой порядок расположения слов. На плк байты 1234, там 3412
Т.е. при чтении сначала приводим из сетевого, после этого для всех 32-х битных меняем порядок слов.
При записи сначала (если есть 32-битное) приводит дабл-слова к порядку модуля, после - полученное приводим в сетевой порядок.
Теперь ньюанс конкретно 8АС/2AC
Автор таблицы регистров был пьян, поэтому реализовал таблицу кривом виде совершенно не учитывая невозможность обращения к 32-битному значению с адреса некратного 4-ем байтам. Автор не подозревает что данные можно читать все за раз.
Но это, так сказать, родовая болезнь овен-реализаторов.
fblock mu8i
var_input
out : array[1..8] of real; //например для 0..100%
end_var
var_in_out
buf : array[0..255] of byte; //отправлять на регистр 0, 8 регистров
end_var
var
p : pointer to array[1..8] of word;
---------------------------------------------
p := adr(buf);
for i := 1 to 8 do
p^[i] := real_to_word(limit(0, out[i] * 10, 1000)); // !! 0..100%
end_for
ntohw(adr(buf),sizeof(p^)); //несложная функция для самостоятельного релиза
Теперь 8ac. Читать - так все.
//не поленится описать типы, чтоб после не писать тупых коментов в коде.
enum ai_status(
status_ok := 0,
status_unready := 16#f006,
status_off := 16#f007,
status_break := 16#f00d,
...
);
struct ai_struct(
status : ai_status := status_unready,
cyclic : word;
value : real;
);
fblock mv8ac
var_in_out
buf : array[0..255] of byte; //читать с регистра 16#118, 32 регистра
end_var
var_output
ai : array[1..8] of struct_ai;
end_var
var
srd : pointer to array[1..8] of word;
read : pointer to array[1..8, 1..3] of word;
p : pointer to array[1..2] of word;
end_var
------------------------------
ntohw(adr(buf),sizeof(ai)); //все та же несложная функция для самостоятельного релиза
srd := adr(buf);
read := adr(buf) + sizeof(srd^);
for i := 1 to 8 do
p := adr(ai[i].value);
ai[i].status := srd^[i];
ai[i].cyclic := read^[i,3];
p^[1] := read^[i,2];
p^[2] := read^[i,1];
end_for
Массивы/структуры не ?
Не, мне пока и так нравится. Вполне себе рабочий алгоритм. Да он не похож на Ваш, но как по мне, он и не обязан быть похожим - сколько людей столько и мнений. Вы пользуетесь своими методами/алгоритмами, кто-то другой может пользоваться своими методами/алгоритмами.
На счет
//не поленится описать типы, чтоб после не писать тупых коментов в коде.. Комментарий - он прежде всего комментарий, а уже потом все остальное. Если Ваши исходники ни кто не читает, то это не значит, что у всех остальных будет такая же ситуация. Как говорит мой знакомый, цитирую "Инструкция должна быть написана для обезьяны. Чтобы обезьяна читала и понимала что, где и как.", поэтому дополнительный комментарий, на мой взгляд, в теле кода лишним не будет (если, конечно, это не анекдот, хотя и он может быть полезен - поспособствует кратковременному "снижению температуры мозга"), даже с учетом использования типов, структур и массивов.
Никто же не говорит что индуский код не работает. Работает. И ему да - обязательно нужны коменты )))
Я привел общее решение для приведения модбасных данных. Причем не только для Овена.
Кто как делает - мне побоку.
Жду очередной плач на форуме что никак не видно данных, например из 2A
Я привел общее решение для приведения модбасных данных. Причем не только для Овена.
За пример, от меня лично, спасибо. Реальная помощь с Вашей стороны.
Никто же не говорит что индуский код не работает. Работает. И ему да - обязательно нужны коменты )))
А вот сарказм и грубость, товарищ Валенок, здесь неуместны, и к делу никакого отношения не имеют.
Жду очередной плач на форуме что никак не видно данных, например из 2A
Так Вы возьмите и помогите нуждающимся, если есть возможность и желание, вместо того чтобы оскорблять. Начинающие (и не только) пользователи продукции ОВЕН могут не иметь глубоких познаний всех тонкостей и нюансов ее работы, поэтому каждый раз, всё снова и снова, через неопределенные (а может и нет) временные интервалы, в тех или иных ветках форума, будут появляться всё те же вопросы, нуждающиеся во всё тех же ответах.
Егор_Егор
03.08.2018, 10:03
Всем откликнувшимся большое спасибо! Все работает, пускай и на индуском коде:)
Powered by vBulletin® Version 4.2.3 Copyright © 2024 vBulletin Solutions, Inc. All rights reserved. Перевод: zCarot