Просмотр полной версии : Вопрос 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Р)?
проще всего использовать указатель на байт.
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)^;
по второму пункту думаю сам догадаешься
а без указателей как-то можно???
Можно, как раз с помощью логики и SHL, но мне такое читать сложнее. Даже не пытаюсь разобраться в том примере, что приведен. Вообще нет ничего проще в отладке проверить правильность написанного, и запихнуть в функцию, чтоб больше не вспоминать об этих тонкостях.
a_gricaj
03.02.2017, 12:02
Можно, как раз с помощью логики и SHL, но мне такое читать сложнее. Даже не пытаюсь разобраться в том примере, что приведен. Вообще нет ничего проще в отладке проверить правильность написанного, и запихнуть в функцию, чтоб больше не вспоминать об этих тонкостях.
Насколько я правильно понял, ваш пример разлаживает двойное слово на байты, а не на оборот( и это ответ на мой второй вопрос)??????
Ну да, перепутал вопросы.
Наоборот так:
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
вроде сделал как у вас
видимо нельзя записывать так: (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Р
Я и в Кейсе делаю запись по изменению..., а вот "создать список и ссылаться на него" вы меня заинтересовали, если не трудно подробней пожалуйста - не понял что вы имеете ввиду...
Хорошим тоном в программировании является не использовать каких либо чисел. Ваши числа 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 язык, который эту концепцию в графическом виде показывает. Сам не пробовал, но надо бы уже.
СПС, за ответы
Powered by vBulletin® Version 4.2.3 Copyright © 2025 vBulletin Solutions, Inc. All rights reserved. Перевод: zCarot