PDA

Просмотр полной версии : Чтение с помощью библиотеки UNM



baritone
18.12.2014, 15:08
Возможно, глупый вопрос: как читать данные из последовательного порта с помощью библоитеки UNM?
Гляжу пример - там читают по одному байту за цикл программы, и сразу же анализируют:

(*Ïðèåì îòâåòà*)
t1;
otvet_RB:=GetByte(DeviceNumber);
(*Åñëè ïîëó÷èëè íîâûé áàéò, òî ñîáèðàåì åãî â ðåçóëüòàò*)
(*è âåäåì ïîäñ÷åò ïðèíÿòûõ áàéò*)
IF otvet_RB>0 THEN
p:=ADR(otvet)+count;
p^:=otvet_RB^.data;
count:=count+1;
END_IF

(*Åñëè ïîëó÷èëè ïåðâûé áàéò, ïðîâåðÿåì àäðåñ óñòðîéñòâà*)
IF count=1 AND otvet[0]<>DeviceAdr AND t1.Q=FALSE THEN
error:=1;
t1(IN:=FALSE);
t1;
stat:=6;
ready:=TRUE;
END_IF

(*&#197;&#241;&#235;&#232; &#239;&#238;&#235;&#243;&#247;&#232;&#235;&#232; &#226;&#242;&#238;&#240;&#238;&#233; &#225;&#224;&#233;&#242;, &#242;&#238; &#239;&#240;&#238;&#226;&#229;&#240;&#255;&#229;&#236; &#240;&#224;&#231;&#236;&#229;&#240; &#239;&#238;&#241;&#251;&#235;&#234;&#232;*)
(*&#200;&#235;&#232; &#239;&#240;&#238;&#226;&#229;&#240;&#255;&#229;&#236; &#234;&#238;&#228; &#238;&#248;&#232;&#225;&#234;&#232;*)
IF count=2 AND t1.Q=FALSE THEN
IF otvet[1]<>16#03 AND otvet[1]<>16#83 THEN
error:=2;
t1(IN:=FALSE);
t1;
stat:=6;
ready:=TRUE;
ELSIF otvet[1]=16#83 THEN
modbus_error:=TRUE;
END_IF
END_IF

(*&#197;&#241;&#235;&#232; &#239;&#238;&#235;&#243;&#247;&#232;&#235;&#232; &#242;&#240;&#229;&#242;&#232;&#233; &#225;&#224;&#233;&#242;, &#242;&#238; &#239;&#240;&#238;&#226;&#229;&#240;&#255;&#229;&#236; &#240;&#224;&#231;&#236;&#229;&#240; &#239;&#238;&#241;&#251;&#235;&#234;&#232;*)
IF count=3 AND modbus_error=FALSE AND otvet[2]<>Quantity*2 AND t1.Q=FALSE THEN
error:=3;
t1(IN:=FALSE);
t1;
stat:=6;
ready:=TRUE;
END_IF

(*&#197;&#241;&#235;&#232; &#226; &#238;&#242;&#226;&#229;&#242;&#229; &#225;&#251;&#235; &#234;&#238;&#228; &#238;&#248;&#232;&#225;&#234;&#232;, &#242;&#238; &#226; &#242;&#240;&#229;&#242;&#252;&#229;&#236; &#225;&#224;&#233;&#242;&#229; &#247;&#232;&#242;&#224;&#229;&#236; &#232;&#241;&#234;&#235;&#254;&#247;&#229;&#237;&#232;&#229;*)
IF count=3 AND modbus_error=TRUE AND t1.Q=FALSE THEN
IF otvet[2]=1 THEN
error:=4;
ELSIF otvet[2]=2 THEN
error:=5;
ELSIF otvet[2]=3 THEN
error:=6;
ELSIF otvet[2]=4 THEN
error:=7;
ELSE
error:=8;
END_IF
END_IF

(*&#197;&#241;&#235;&#232; &#239;&#238;&#235;&#237;&#238;&#241;&#242;&#252;&#254; &#239;&#240;&#232;&#248;&#229;&#235; &#238;&#248;&#232;&#225;&#238;&#247;&#237;&#251;&#233; &#238;&#242;&#226;&#229;&#242; &#231;&#224; &#228;&#238;&#239;&#243;&#241;&#242;&#232;&#236;&#238;&#229; &#226;&#240;&#229;&#236;&#255;, &#239;&#240;&#238;&#226;&#229;&#240;&#255;&#229;&#236; CRC*)
IF count=otvet_len_error AND modbus_error=TRUE AND t1.Q=FALSE THEN
(*&#208;&#224;&#241;&#247;&#229;&#242; CRC*)
p:=ADR(otvet);
CRC:=MB_CRC(p, otvet_len_error-2);
p:=ADR(CRC);
crc1:=p^;
p:=ADR(CRC)+1;
crc2:=p^;
(*&#209;&#226;&#229;&#240;&#255;&#229;&#236; CRC*)
IF crc1=otvet[otvet_len_error-2] AND crc2=otvet[otvet_len_error-1] THEN
error:=error;
ELSE
error:=9;
END_IF
t1(IN:=FALSE);
t1;
stat:=6;
ready:=TRUE;
modbus_error:=FALSE;
END_IF

(*&#197;&#241;&#235;&#232; &#239;&#238;&#235;&#243;&#247;&#229;&#237; &#238;&#242;&#226;&#229;&#242; &#231;&#224; &#228;&#238;&#239;&#243;&#241;&#242;&#232;&#236;&#238;&#229; &#226;&#240;&#229;&#236;&#255; &#238;&#230;&#232;&#228;&#224;&#237;&#232;&#255;, &#242;&#238; &#239;&#240;&#238;&#226;&#229;&#240;&#255;&#229;&#236; CRC *)
(*&#200; &#244;&#238;&#240;&#236;&#232;&#240;&#243;&#229;&#236; &#240;&#229;&#231;&#243;&#235;&#252;&#242;&#224;&#242;*)
IF count=otvet_len AND t1.Q=FALSE THEN
(*&#208;&#224;&#241;&#247;&#229;&#242; CRC*)
p:=ADR(otvet);
CRC:=MB_CRC(p, otvet_len-2);
p:=ADR(CRC);
crc1:=p^;
p:=ADR(CRC)+1;
crc2:=p^;
(*&#209;&#226;&#229;&#240;&#255;&#229;&#236; CRC*)
IF crc1=otvet[otvet_len-2] AND crc2=otvet[otvet_len-1] THEN
error:=0;
(*&#194;&#251;&#228;&#224;&#229;&#236; &#240;&#229;&#231;&#243;&#235;&#252;&#242;&#224;&#242;*)
FOR i:=0 TO Quantity*2-1 DO
out[i]:=otvet[3+i];
END_FOR

FOR i:=Quantity*2 TO 127 DO
out[i]:=0;
END_FOR
(*&#194;&#251;&#228;&#224;&#229;&#236; &#247;&#232;&#241;&#235;&#238; &#225;&#224;&#233;&#242; &#226; &#238;&#242;&#226;&#229;&#242;&#229;*)
ByteCount:=Quantity*2;
ELSE
error:=10;
END_IF
t1(IN:=FALSE);
t1;
stat:=6;
ready:=TRUE;
END_IF

IF t1.IN AND t1.Q THEN
error:=11;
t1(IN:=FALSE);
t1;
stat:=6;
ready:=TRUE;
END_IF


Для сравнения, с помощью библиотеки SysLibCom читают буфер в цикле целиком, не дожидаясь следующего вызова программы:


(*&#215;&#242;&#229;&#237;&#232;&#229; &#225;&#243;&#244;&#229;&#240;&#224; &#239;&#240;&#232;&#229;&#236;&#224;*)
0:
(*&#194;&#251;&#231;&#251;&#226;&#224;&#229;&#236; &#242;&#224;&#233;&#236;&#229;&#240; &#238;&#230;&#232;&#228;&#224;&#237;&#232;&#255; &#238;&#242;&#226;&#229;&#242;&#224;*)
T1();
(*&#194; &#239;&#229;&#240;&#229;&#236;&#229;&#237;&#237;&#243;&#254; byte_read &#236;&#251; &#239;&#238;&#235;&#243;&#247;&#224;&#229;&#236; &#247;&#232;&#241;&#235;&#238; &#239;&#240;&#232;&#237;&#255;&#242;&#251;&#245; &#225;&#224;&#233;&#242; &#239;&#240;&#232; &#247;&#242;&#229;&#237;&#232;&#232; &#239;&#238;&#240;&#242;&#224;*)
byte_read:=SysComRead(port_number, ADR(buf_otvet), 8, 0);
(*&#197;&#241;&#235;&#232; &#236;&#251; &#239;&#238;&#235;&#243;&#247;&#232;&#235;&#232; &#238;&#242;&#226;&#229;&#242; &#238;&#242; &#243;&#241;&#242;&#240;&#238;&#233;&#241;&#242;&#226;&#224;, &#242;&#238; &#239;&#240;&#232;&#237;&#255;&#242;&#243;&#254; &#232;&#237;&#244;&#238;&#240;&#236;&#224;&#246;&#232;&#254; &#241;&#238;&#225;&#232;&#240;&#224;&#229;&#236; &#226; &#225;&#238;&#235;&#229;&#229; &#225;&#238;&#235;&#252;&#248;&#238;&#233; &#225;&#243;&#244;&#229;&#240; &#238;&#242;&#226;&#229;&#242;&#224;
&#242;&#238; &#229;&#241;&#242;&#252; &#241;&#238;&#225;&#232;&#240;&#224;&#229;&#236; &#238;&#242;&#226;&#229;&#242; &#226; &#243;&#228;&#238;&#225;&#237;&#251;&#233; &#228;&#235;&#255; &#238;&#225;&#240;&#224;&#225;&#238;&#242;&#234;&#232; &#244;&#238;&#240;&#236;&#224;&#242;*)
IF byte_read>0 THEN
FOR i:=0 TO byte_read-1 DO
otvet[l+i]:=buf_otvet[i];
END_FOR
l:=l+byte_read;

(*&#194; &#228;&#224;&#237;&#237;&#238;&#236; &#236;&#229;&#241;&#242;&#229; &#239;&#240;&#238;&#227;&#240;&#224;&#236;&#236;&#251; &#237;&#229;&#238;&#225;&#245;&#238;&#228;&#232;&#236;&#238; &#240;&#229;&#224;&#235;&#232;&#231;&#238;&#226;&#224;&#242;&#252; &#238;&#225;&#240;&#224;&#225;&#238;&#242;&#234;&#243; &#239;&#240;&#232;&#237;&#255;&#242;&#238;&#233; &#232;&#231; &#239;&#238;&#240;&#242;&#224; &#232;&#237;&#244;&#238;&#240;&#236;&#224;&#246;&#232;&#232;*)
(*&#196;&#224;&#225;&#251; &#241;&#232;&#235;&#252;&#237;&#238; &#237;&#229; &#239;&#229;&#240;&#229;&#227;&#240;&#243;&#230;&#224;&#242;&#252; &#239;&#240;&#232;&#236;&#229;&#240; &#232;&#237;&#244;&#238;&#240;&#236;&#224;&#246;&#232;&#232; &#237;&#232;&#230;&#229; &#232;&#241;&#239;&#238;&#235;&#252;&#231;&#243;&#229;&#242;&#241;&#255; &#239;&#238;&#228;&#238;&#225;&#232;&#229; &#231;&#224;&#227;&#235;&#243;&#248;&#234;&#232;*)
(*&#200;&#231;&#226;&#229;&#241;&#242;&#237;&#238; &#247;&#242;&#238; &#228;&#235;&#232;&#237;&#224; &#238;&#242;&#226;&#229;&#242;&#224; &#237;&#224; &#232;&#241;&#239;&#238;&#235;&#252;&#231;&#243;&#229;&#236;&#251;&#229; &#226; &#239;&#240;&#238;&#227;&#240;&#224;&#236;&#236;&#229; &#231;&#224;&#239;&#240;&#238;&#241;&#251; &#241;&#242;&#238;&#240;&#238;&#227;&#238; 8 &#225;&#224;&#233;&#242;*)
(*&#207;&#238;&#253;&#242;&#238;&#236;&#243; &#237;&#232;&#230;&#229; &#239;&#240;&#238;&#232;&#231;&#226;&#238;&#228;&#232;&#242;&#241;&#255; &#224;&#237;&#224;&#235;&#232;&#231; &#240;&#224;&#231;&#236;&#229;&#240;&#224; &#239;&#240;&#232;&#237;&#255;&#242;&#238;&#227;&#238; &#238;&#242;&#226;&#229;&#242;&#224;*)
(*&#202;&#224;&#234; &#242;&#238;&#235;&#252;&#234;&#238; &#239;&#240;&#232;&#245;&#238;&#228;&#232;&#242; &#231;&#224; &#238;&#242;&#226;&#229;&#228;&#229;&#237;&#237;&#251;&#233; &#232;&#237;&#242;&#229;&#240;&#226;&#224;&#235; &#226;&#240;&#229;&#236;&#229;&#237;&#232; &#237;&#243;&#230;&#237;&#238;&#229; &#234;&#238;&#235;&#232;&#247;&#229;&#241;&#242;&#226;&#238; &#225;&#224;&#233;&#242;, &#237;&#224;&#247;&#232;&#237;&#224;&#229;&#236; &#238;&#225;&#240;&#224;&#225;&#238;&#242;&#234;&#243; &#239;&#240;&#232;&#237;&#255;&#242;&#238;&#233; &#234;&#238;&#236;&#224;&#237;&#228;&#251;*)
IF ( l=7) THEN
(*&#207;&#238;&#235;&#243;&#247;&#232;&#235;&#232; &#237;&#243;&#230;&#237;&#238;&#229; &#234;&#238;&#235;&#232;&#247;&#229;&#241;&#242;&#226;&#238; &#225;&#224;&#233;&#242;*)
(*&#207;&#240;&#238;&#232;&#231;&#226;&#238;&#228;&#232;&#236; &#240;&#224;&#241;&#239;&#224;&#234;&#238;&#226;&#234;&#243; &#238;&#242;&#226;&#229;&#242;&#224; &#232; &#231;&#224;&#239;&#232;&#241;&#251;&#226;&#224;&#229;&#236; &#229;&#227;&#238; &#237;&#224; &#226;&#251;&#245;&#238;&#228; &#225;&#235;&#238;&#234;&#224;*)
p1:=ADR(otvet[4]);
p:=ADR(rez);
p^:=p1^;
p1:=ADR(otvet[3]);
p:=p+1;
p^:=p1^;
(*&#206;&#241;&#242;&#224;&#237;&#224;&#226;&#235;&#232;&#226;&#224;&#229;&#236; &#242;&#224;&#233;&#236;&#229;&#240; &#238;&#230;&#232;&#228;&#224;&#237;&#232;&#255; &#238;&#242;&#226;&#229;&#242;&#224;*)
T1(IN:=FALSE, PT:=T#0s );
(*&#206;&#248;&#232;&#225;&#238;&#234; &#237;&#229;&#242;*)
errors:=0;
(*&#199;&#237;&#224;&#247;&#232;&#237;&#232;&#255; &#237;&#224; &#226;&#251;&#245;&#238;&#228;&#229; &#225;&#235;&#238;&#234;&#224; &#241;&#244;&#238;&#240;&#236;&#232;&#240;&#238;&#226;&#224;&#237;&#251;, &#232;&#245; &#236;&#238;&#230;&#237;&#238; &#232;&#241;&#239;&#238;&#235;&#252;&#231;&#238;&#226;&#224;&#242;&#252; &#226; &#239;&#240;&#238;&#227;&#240;&#224;&#236;&#236;&#229;*)
ready:=TRUE;
(*&#207;&#229;&#240;&#229;&#226;&#238;&#228;&#232;&#236; &#225;&#235;&#238;&#234; &#226; &#240;&#229;&#230;&#232;&#236; &#238;&#242;&#239;&#240;&#224;&#226;&#234;&#232; &#231;&#224;&#239;&#240;&#238;&#241;&#224;*)
status:=1;
END_IF
END_IF


Нельзя ли и с помощью функции из библиотеки UNM так же по байту читать буфер в цикле целиком? И, кстати, какова длина входного буфера у ПЛК110?

capzap
18.12.2014, 15:50
а Вы для разнообразия засеките время от момента начала слушанья порта до приема нужных данных через SysLibCom, возможно усредненно так же выйдет байт в цикл, все зависит конечно от времени устанавливаемого мин.цикла

baritone
19.12.2014, 13:15
У меня нет пока железа, так что померить не могу.
Мне нужно читать положение по энкодеру, подключенному к RS485, расчетно весь цикл его опроса должен занимать около 3 мс, а в ответе может быть до 7 байт, так что читать ответ побайтно при каждом вызове программы, мягко говоря, нерационально.

capzap
19.12.2014, 13:26
контроллеры любого бренда для работы с энкодерами используют аппаратные "быстрые" входа, ни кто по последовательному порту не ловит сигналы энкодера, если это отдельный модуль, то в любом случае Вы будете считывать уже результируещее значение

lara197a
19.12.2014, 13:30
там похоже речь про энкодер с интерфейсом.
модель напишите и что с ним хотите делать.

baritone
22.12.2014, 11:40
Прошу прощения, не заметил ответа.
Мне надо считывать положение по относительному энкодеру с TTL-выходом для позиционирования поршней и заливных трубок машины по разливке продукта. Варианта рассматриваются два:
- использовать встроенные энкодеры ПЛК110 (новый) с модулем согласования уровня сигнала (например, ЛИР-901);
- использовать модули СКБ ИС ЛИР-915 (http://skbis.ru/index.php?p=3&c=8&d=55), передающий данные по RS485. Последний вариант приходится рассматривать, потому что нет гарантии, что частота сигнала от энкодера не будет превышать 100 кГц.

Если использовать модуль ЛИР-915, то я могу гонять трубки и поршня на высокой скорости, а перед остановкой снижать скорость в разы, чтобы получить требуемую точность, несмотря на задержку с ответом. Я собираюсь организовать запрос данных с модуля ЛИР-915, ожидание, получение ответа, да еще и задание скорости с помощью отдельной короткой программы, вызываемой с периодом в 1 мс. Если я смогу считывать ответ с модуля сопряжения с энкодером в течение одного цикла работы программы, то полный цикл управления позиционированием (опрос-считывание энкодера-задание скорости) не превысит 8-10 вызовов для 2-х осей, что, с учетом замедления, вполне приемлемо. Если не смогу, а придется читать по одному байту ответа за каждый вызов - это удлинит цикл управления позиционированием в три раза, и система уже не будет поспевать. Сначала я стал писать программу с использованием библиотеки UNM, а когда стал смотреть, как организовано считывание данных из порта, немного испугался.

Yegor
13.01.2016, 07:58
Столкнулся с ЛИР-915. Вот код чтения относительной координаты:
VAR step, _step, count: DINT;
timeout: TON := (PT := T#300ms);
request: ARRAY [0..1] OF BYTE := 51, 1;
rsp: ARRAY [0..5] OF BYTE;
pos: DINT;
rpt: BOOL;
END_VAR
VAR CONSTANT
port: COMSETTINGS := (Port := COM1, dwBaudRate := 115200, dwBufferSize := 1);
END_VAR

REPEAT
rpt := FALSE;


CASE step OF


0:
IF SysComOpen(port.Port) = 0 = SysComSetSettings(port.Port, ADR(port)) THEN
step := step + 1;
END_IF
1:
step := step + 1;


2:
count := count + SysComWrite(port.Port, ADR(request) + count, SIZEOF(request) - count, 0);
IF count >= 2 THEN
step := step + 1;
rpt := TRUE;
END_IF


3:
count := count + SysComRead(port.Port, ADR(rsp) + count, SIZEOF(rsp) - count, 0);
IF count >= 6 THEN
IF rsp[0] = 10 AND rsp[5] = 11 THEN


pos :=
SHR(rsp[4], 4) * 10000000 + (rsp[4] AND 15) * 1000000 +
SHR(rsp[3], 4) * 100000 + (rsp[3] AND 15) * 10000 +
SHR(rsp[2], 4) * 1000 + (rsp[2] AND 15) * 100 +
SHR(rsp[1], 4) * 10 + (rsp[1] AND 15);




IF SHR(rsp[4], 4) = 9 THEN
pos := pos - 100000000;


END_IF


step := 2;
rpt := TRUE;
END_IF
END_IF


END_CASE


timeout(IN := step = _step);
IF timeout.Q THEN
(* Discard input to resync *)
SysComRead(port.Port, ADR(rsp), SIZEOF(rsp), 0);
step := 1;
END_IF


IF step <> _step THEN
count := 0;
_step := step;
END_IF


UNTIL NOT rpt END_REPEATИ вот картина по времени (ПЛК160, RS232, 115200, ЛИР в «двоично-десятичном» режиме); D0 — запросы:

21722

Любопытно, что ЛИР отвечает гораздо быстрее, если датчик стоит примерно на нуле:

21723