PDA

Просмотр полной версии : Вопрос DWORD



a_gricaj
03.02.2017, 00:41
Здравствуйте,
Вопрос у меня простой (даже стыдно спрашивать):
1. Правильно ли для сложения 4 байтов в DWORD будет так (маска входов МВ110-32ДН):
DiDwAddr172:=SHL(Buffer[3] + DWORD#0,24)OR SHL(Buffer[2] + DWORD#0,16) OR SHL(Buffer[1] + DWORD#0,8)OR Buffer[0];
2.Как правильно разложить DWORD на 4 байта (маска выходов МВ110-32Р)?

slonegd
03.02.2017, 08:15
проще всего использовать указатель на байт.
pby: POINTER TO BYTE;
преобразование в arby: ARRAY[0..3] OF BYTE;
pby:=ADR(dw);
arby[0]:=pby^;
arby[1]:=(pby+1)^;
arby[2]:=(pby+2)^;
arby[3]:=(pby+3)^;
по второму пункту думаю сам догадаешься

a_gricaj
03.02.2017, 10:13
проще всего использовать указатель на байт.
pby: POINTER TO BYTE;
преобразование в arby: ARRAY[0..3] OF BYTE;
pby:=ADR(dw);
arby[0]:=pby^;
arby[1]:=(pby+1)^;
arby[2]:=(pby+2)^;
arby[3]:=(pby+3)^;
по второму пункту думаю сам догадаешься

а без указателей как-то можно???

slonegd
03.02.2017, 11:52
Можно, как раз с помощью логики и SHL, но мне такое читать сложнее. Даже не пытаюсь разобраться в том примере, что приведен. Вообще нет ничего проще в отладке проверить правильность написанного, и запихнуть в функцию, чтоб больше не вспоминать об этих тонкостях.

a_gricaj
03.02.2017, 12:02
Можно, как раз с помощью логики и SHL, но мне такое читать сложнее. Даже не пытаюсь разобраться в том примере, что приведен. Вообще нет ничего проще в отладке проверить правильность написанного, и запихнуть в функцию, чтоб больше не вспоминать об этих тонкостях.

Насколько я правильно понял, ваш пример разлаживает двойное слово на байты, а не на оборот( и это ответ на мой второй вопрос)??????

slonegd
03.02.2017, 12:58
Ну да, перепутал вопросы.
Наоборот так:
pby:=ADR(arby[0]); //получаем адрес первого элемента массива
pdw:=pBy; //записываем адрес в указатель на dword
dw:=pdw^; //сохраняем значение в dword

здесь pdw: POINTER TO DWORD;

a_gricaj
03.02.2017, 13:16
Ну да, перепутал вопросы.
Наоборот так:
pby:=ADR(arby[0]); //получаем адрес первого элемента массива
pdw:=pBy; //записываем адрес в указатель на dword
dw:=pdw^; //сохраняем значение в dword

здесь pdw: POINTER TO DWORD;

подскажите пожалуйста почему компилятор тут ругается
29133

вроде сделал как у вас

slonegd
03.02.2017, 15:59
видимо нельзя записывать так: (TempPtB+1)^;
(давно не писал подзабыл правила, компилятор всегда поправит)
попробуйте так:
TempPtB:=TempPtB+1;
Buffer[1]:=TempPtB^;

а вообще тут цикл напрашивается:
TempPtB:=ADR(...);
FOR i:=0 TO 3 DO
Buffer[i]:=TempPtB^;
TempPtB:=TempPtB+1;
END_FOR

PS я когда то так же организовывал связь по модбасу, использовал кейс и просто перебирал все адреса и регистры в сети. Жизнь научила, что некоторые вещи надо опрашивать быстрее (датчики положения), а некоторые реже (датчики температуры), а некоторые вообще только при изменении (в моих системах это му110-6у). А то выходило, что необходимо больше секунды жать кнопку ПУСК где-то на установке, чтоб до проги дошло, что её нажали.
PPS лучше использовать не числовые константы в кейсе (16, 17), а создать список и ссылаться на него (WriteInBuffer, ModBusFunction16). В скобках это пример, мне не известен смысл записи в 17 шаге, возможно это установка частоты привода, тогда и называть по смыслу.

a_gricaj
03.02.2017, 16:54
видимо нельзя записывать так: (TempPtB+1)^;
(давно не писал подзабыл правила, компилятор всегда поправит)
попробуйте так:
TempPtB:=TempPtB+1;
Buffer[1]:=TempPtB^;

а вообще тут цикл напрашивается:
TempPtB:=ADR(...);
FOR i:=0 TO 3 DO
Buffer[i]:=TempPtB^;
TempPtB:=TempPtB+1;
END_FOR

PS я когда то так же организовывал связь по модбасу, использовал кейс и просто перебирал все адреса и регистры в сети. Жизнь научила, что некоторые вещи надо опрашивать быстрее (датчики положения), а некоторые реже (датчики температуры), а некоторые вообще только при изменении (в моих системах это му110-6у). А то выходило, что необходимо больше секунды жать кнопку ПУСК где-то на установке, чтоб до проги дошло, что её нажали.
PPS лучше использовать не числовые константы в кейсе (16, 17), а создать список и ссылаться на него (WriteInBuffer, ModBusFunction16). В скобках это пример, мне не известен смысл записи в 17 шаге, возможно это установка частоты привода, тогда и называть по смыслу.

Спасибо так заработало:
TempPtB:=ADR(DoDwAddr236);
Buffer[3]:=TempPtB^;
TempPtB:=TempPtB+1;
Buffer[2]:=TempPtB^;
TempPtB:=TempPtB+1;
Buffer[1]:=TempPtB^;
TempPtB:=TempPtB+1;
Buffer[0]:=TempPtB^;
Так можно писать маску в МУ110-32Р
Я и в Кейсе делаю запись по изменению..., а вот "создать список и ссылаться на него" вы меня заинтересовали, если не трудно подробней пожалуйста - не понял что вы имеете ввиду...

slonegd
04.02.2017, 06:58
Хорошим тоном в программировании является не использовать каких либо чисел. Ваши числа 16, 17 по сути константы из списка. Создайте перечисление в типах данных и назовите все ваши шаги(состояния) подпрограммы. Причем числа им присваивать не обязательно компилятор сделает сам. Предположим перечисление назовем State. Объявим тип вашего Step как перечисление. (Step: State;) Теперь Step может принимать только значения из перечисления. Если назвать элементы перечислений со смыслом, то можно избавиться от комментариев типа
16: (*Запись*)
Теперь эта строка будет выглядеть
State.Write:
А переход на новый шаг оформится так:
Step:=State.MB16Func;
Write и MB16Func - это просто примеры элементов из перечисления.
Подобный подход делает код не только более понятным, но и предотвращает ошибки, когда вы случайно записываете в step какое-то не то значение или выходите за границы.

Действие в 16 степе логично не делать отдельным шагом, а впихнуть в 17:


17:
IF NOT(WriteAddr236.Enable) THEN
;(*запись в буфер*)
END_IF
(*далее действие 17 как оно у вас*)

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

a_gricaj
05.02.2017, 11:22
Хорошим тоном в программировании является не использовать каких либо чисел. Ваши числа 16, 17 по сути константы из списка. Создайте перечисление в типах данных и назовите все ваши шаги(состояния) подпрограммы. Причем числа им присваивать не обязательно компилятор сделает сам. Предположим перечисление назовем State. Объявим тип вашего Step как перечисление. (Step: State;) Теперь Step может принимать только значения из перечисления. Если назвать элементы перечислений со смыслом, то можно избавиться от комментариев типа
16: (*Запись*)
Теперь эта строка будет выглядеть
State.Write:
А переход на новый шаг оформится так:
Step:=State.MB16Func;
Write и MB16Func - это просто примеры элементов из перечисления.
Подобный подход делает код не только более понятным, но и предотвращает ошибки, когда вы случайно записываете в step какое-то не то значение или выходите за границы.

Действие в 16 степе логично не делать отдельным шагом, а впихнуть в 17:

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

СПС, за ответы