Просмотр полной версии : Работа "POINTER TO" обрывает связь
Добрый день!
Столкнулся со следующей проблемой при разработке своего кода: попытка чтения значения переменной типа POINTER TO REAL приводит к сбросу контроллера. Проблема воспроизводится на ПЛК-100 и ПЛК-160.
В коде объявляется массив из байт, в который принимаются данные из UDP-сокета. Байты в начале массива (4 шт) представляют собой число типа Real. Объявлена переменная PtR типа POINTER TO REAL и она выставляется на начало массива:
PtR:=ADR(UDPData);
До этого места всё работает без нареканий - проект загружается, запускается, если "разворачивать" переменную PtR, то для PtR^ отображается корректное значение переменной с плавающей точкой. Но! Стоит только дописать (раскомментировать) следующую строчку (Rl : REAL):
Rl:=PtR^;
-- как при её исполнении контроллер уходит в перезагрузку. Как бороться с таким поведением?
Заранее спасибо.
Что интересно, с типами BYTE и WORD таких проблем нет - считывание проходит штатно. А вот именно при попытке считать Real по ссылке - происходит перезагрузка ПЛК с обрывом связи.
Попробуй выделить побольше памяти для переменных.
Попробуй выделить побольше памяти для переменных.
Увеличил с 16#3F8 до 16#1000 - результата нет.
Интересно, что с типами WORD и INT - работает, а вот с DWORD и DINT - зависает как и с Real.
Для строк разных размеров (1-5) всё работает, но, наверное, потому что сейчас это значение - 00000000, т.е. при преобразовании сразу получается пустая строка.
Заметил ещё одну интересную вещь: если ссылка идёт не на этот массив, а на другую четырёхбайтную структуру - преобразование работает.
Поставил костыль - считываю сначала WORD из начала массива, потом - WORD из начала массива +2 байта, считаю DWORD как W1 SHL 16 + W2, потом привожу Real к ссылке на этот DWORD. Работает. Но это же - не нормально?..
Адрес под указателем должен быть кратным размеру типа под указателям. То есть в случае с REAL указатель должен указывать на адрес, кратный 4. Иначе да, контроллер будет перезагружаться. Предполагаю, что процессор в контроллерах этого семейства один из тех, что не работают без выравнивания. Так что забудьте про указатели и используйте SysLibMem (а именно SysMemCpy).
Адрес под указателем должен быть кратным размеру типа под указателям. То есть в случае с REAL указатель должен указывать на адрес, кратный 4. Иначе да, контроллер будет перезагружаться. Предполагаю, что процессор в контроллерах этого семейства один из тех, что не работают без выравнивания. Так что забудьте про указатели и используйте SysLibMem (а именно SysMemCpy).
что за не обоснованный наезд на указатель, ТС же пишет
если "разворачивать" переменную PtR, то для PtR^ отображается корректное значение переменной с плавающей точкойздесь какая то элементарная ошибка в коде, который не предоставлен
Дмитрий Артюховский
13.07.2016, 13:11
однозначно выравнивание! UDPdata нужно объявлять как массив dword - посчитать чтобы все байты влезали, ну или REAL и наступит счастье!
однозначно выравнивание! UDPdata нужно объявлять как массив dword - посчитать чтобы все байты влезали, ну или REAL и наступит счастье!
Почему Вы все не читаете ТС, он же пишет что реал расположен в начале массива, кроме как с нулевого индекса это невозможно интерпретировать, при чем тут выравнивание. Без исходников тут всё что угодно может быть, например массив используется еще где нибудь, а присвоение переменной реал идет постоянно и поэтому где то в коде, вместо адекватного значения в вычислениях присутствует нечисло, приводяещее к зависанию
Дмитрий Артюховский
13.07.2016, 16:58
он массив читает из сокета, и наверняка объявил его байтовым, соответственно траснслятор поставил вв адресах куда пришлось
он массив читает из сокета, и наверняка объявил его байтовым, соответственно траснслятор поставил вв адресах куда пришлось
VAR
flag : BOOL;
count : INT:=0;
result : REAL;
inPtr : POINTER TO BYTE;
outPtr : POINTER TO REAL;
stuff : ARRAY[0..7] OF BYTE;
tik : TON;
END_VAR
(* @END_DECLARATION := '0' *)
IF tik.Q THEN
inPtr:=ADR(TEMPO);
stuff[count]:=inPtr^;
inPtr:=inPtr+1;
stuff[count+1]:=inPtr^;
inPtr:=inPtr+1;
stuff[count+2]:=inPtr^;
inPtr:=inPtr+1;
stuff[count+3]:=inPtr^;
outPtr:=ADR(stuff[count]);
flag:=NOT DWORD_TO_BOOL(outPtr MOD 4);
(* IF flag THEN*)
result:=outPtr^;
(* END_IF; *)
count:=(count+1) MOD 5;
END_IF;
tik(IN:=NOT tik.Q,PT:=T#2s);
END_FUNCTION_BLOCK
таким кодом у меня получилось перегрузить плк, когда указатель становится не кратным четырем, единственное чего я не добился, чтоб изначально указатель принял не кратное четырем значение, почему это вдруг транслятор, как Вы пишите, должен раздавать адреса на куда попало?
Дмитрий Артюховский
14.07.2016, 12:45
в описании переменных, перед stuff объявите байтовую переменную... у вас объявлены 4 байтные переменные, real и два указателя - транслятор произвел выравнивание, а затем под них вставил байтовый массив, который естественно получился выровненным
:) получается надо писать код неправильно чтоб обрести проблемы :)
..END_FUNCTION_BLOCK.... единственное чего я не добился, чтоб изначально указатель принял не кратное четырем значение...
Ключевое слово "END_FUNCTION_BLOCK" - т.е. структура где последовательность размещения строго по объяве, поэтому есть автовыравнивание.
В PROGRAM нет обязательного соответствия последовательности объявы и фактического размещения. Предсказать адрес байт-массива не получицца.
ну вобщем то байт перед массивом "помог" перегрузить плк, но теперь вопросов стало еще больше, я как раз рассчитывал на булеву переменную в начале объявления, которая создаст смещение на байт и не даст выполнится кратности для массива. Но оказалось, что совместно с интом она выравняла как раз кратно 4, тогда почему это не сделал добавленный байт. И еще получается что объявленные ПОУ тоже получают адреса кратные четырем, хотя и не проверил на живом плк
я как раз рассчитывал на булеву переменную в начале объявления, которая создаст смещение на байт и не даст выполнится кратности для массива. Но оказалось, что совместно с интом она выравняла как раз кратно 4, тогда почему это не сделал добавленный байтПотому что выравнивается каждая (!) переменная соответственно своему типу. Если добавленный байт смещает всё после себя, то смещается всё опять же с выравниванием. Указатели сами по себе 32-битные, и поэтому следующий за outPtr массив stuff окажется на кратном 32 битам адресе. Например, было:
DWORD - адрес 0
DWORD - адрес 4
ARRAY OF BYTE - адрес 8Поставим байт в начале:
BYTE - 0
DWORD - 4
DWORD - 8
ARRAY OF BYTE - 12Заметьте, что массив остался выровнен, а на адресах 1-3 образовалась дырка. Попробуем переставить байт к массиву:
DWORD - 0
DWORD - 4
BYTE - 8
ARRAY OF BYTE - 9Вот теперь массив на некратном четырём адресе. Но можно поменять тип массива:
DWORD - 0
DWORD - 4
BYTE - 8
ARRAY OF REAL - 12Теперь дыра на 9, 10 и 11. Такие дела.
Powered by vBulletin® Version 4.2.3 Copyright © 2026 vBulletin Solutions, Inc. All rights reserved. Перевод: zCarot