Мои исследования, если кому интересно будет:
— структура из разнородных массивов, т.е. структура в которую входит массив из 10 word-ов, за ним еще массив из 10 word-ов, за ним еще массив уже из 10 DWord-oв функция MB_SERVER не смогла переварить (хотя компилирование и загрузка успешны), по-крайней мере со стороны клиента выдается сообщение, что не может открыть сессию. Может это и у нас такой modbus TCP клиент.
— serialize/deserialize: функции хорошие. Но ситуация следующая, чтобы сделать то что я хочу, а это из массива на 1024 слова выдернуть нужные слова (учитывая, что 2 слова — это одно real значение) и переконвертировать в real-значения. Сделал функцию в которой берется массив из 12 слов (6 real значений), пропускается через функцию serialize, получается фарш из 24 байт, потом пропускаю эти 24 байта через функцию deserialize и записываю в массив из 6 real (можно в массив из 6 dword, если кому надо, а потом пропускать через CONV). Какие недостатки такой реализации в моем случае, поскольку real значения в буфере хранятся, неправильным для меня образом, два последовательных слова надо менять местами, чтобы получилось правильное real значение, приходится делать предварительную обработку. Кроме этого надо из основного буфера на 1024 слова выдергивать необходимые слова в промежуточный буфер, который подается на serialize. В общем, по итогу, сделать можно, но муторно.
— написал небольшой скрипт на SCL
#temp_dword := #input_1;
#temp_dword := SHL(IN := #temp_dword, N := 16);
#temp_dword := #temp_dword OR #input_2;
#output := DWORD_TO_REAL(#temp_dword);
Т.е. беру два слова, первое слово сдвигаю на 16 бит, делаю логическое или между двумя словами, соответственно получается на выходе DWORD в котором упакованы два слова, затем преобразовываем двойное слово в real значение.
Все это поскольку, скада самописная.
P.S. если честно, извиняюсь и понимаю что на форуме это не принято, но «заипа..и эти самописные скады», потом занимаешься каким-то…
Этот функциональный блок позволяет преобразовать две переменные WORD в переменной DWORD. Операнд MSW передается старшим битам 16, операнд LSW передается в младшие биты 16 Out.
Функциональная блокировка
CODESYS: Не доступно
LogicLab: eLLabUtyLib
MSW (WORD) MSW выходного значения.
LSW (WORD) LSW выходного значения.
Out (DWORD) Исходящее значение.
примеров
Как пользоваться примерами.
В примере две переменные WORD со значением 16 # 1234 и 16 # 5678 переносятся в переменную DWORD результат будет 16 # 12345678. В примере на языке ST подчеркнуто, что та же самая операция намного проще, написав ее непосредственно с операндами языка.
LogicLab (Ptp114)
PROGRAM ST_WordToDouble VAR High : WORD := 16#1234; (* MSW word *) Low : WORD := 16#5678; (* LSW word *) Result : ARRAY[ 0..1 ] OF DWORD; (* Compress result *) WCom : WordToDouble; (* Word compress *) END_VAR // ***************************************************************************** // PROGRAM "ST_WordToDouble" // ***************************************************************************** // This program shows the use of WordToDouble function block. // ----------------------------------------------------------------------------- // ------------------------------------------------------------------------- // COMPRESS WORD // ------------------------------------------------------------------------- // Compress byte using the FB. WCom(MSW:=High, LSW:=Low); Result[0]:=WCom.Out; //Compress result // ------------------------------------------------------------------------- // COMPRESS WORD // ------------------------------------------------------------------------- // The same operation as above executed directly using ST statements. Result[1]:=(High*16#10000)+Low; //Compress result // [End of file]
Была ли эта статья полезна?
MrPLC.com sells used surplus products. MrPLC.com is not an authorized distributor, affiliate, or representative for the brands we carry. Products sold by MrPLC.com come with MrPLC.com’s 1-year, 2-year, or 3-year warranty and do not come with the original manufacturer’s warranty. Designated trademarks, brand names and brands appearing herein are the property of their respective owners. This website is not sanctioned or approved by any manufacturer or tradename listed.
Rockwell Disclaimer: The product is used surplus. MrPLC.com is not an authorized surplus dealer or affiliate for the Manufacturer of this product. The product may have older date codes or be an older series than that available direct from the factory or authorized dealers. Because MrPLC.com is not an authorized distributor of this product, the Original Manufacturer’s warranty does not apply. While many Allen-Bradley PLC products will have firmware already installed, MrPLC.com makes no representation as to whether a PLC product will or will not have firmware and, if it does have firmware, whether the firmware is the revision level that you need for your application. MrPLC.com also makes no representations as to your ability or right to download or otherwise obtain firmware for the product from Rockwell, its distributors, or any other source. MrPLC.com also makes no representations as to your right to install any such firmware on the product. MrPLC.com will not obtain or supply firmware on your behalf. It is your obligation to comply with the terms of any End-User License Agreement or similar document related to obtaining or installing firmware.
short val1 = short.MaxValue;
short val2 = short.MaxValue;
int result = val1;
result |= val2 << 16;
Console.WriteLine( "Result =t" + result ); //2147450879
Console.WriteLine( "Expected =t" + int.MaxValue ); //2147483647
asked Dec 17, 2009 at 15:56
2
short
is signed, so the maximum value is 0x7FFF
. Concatenated this results in 0x7fff7fff
instead of 0x7fffffff
which is 2147450879. So what you’re seeing is actually correct.
answered Dec 17, 2009 at 16:00
JoeyJoey
341k85 gold badges687 silver badges681 bronze badges
1
That looks like C#. Short is signed. A signed negative value extended to int will fill all the leftmost 16 bits. Thus, the proposed code will fail whenever «val1» is negative.
This code works (note that WORD and DWORD are unsigned quantities):
public static uint MakeDWord(ushort a, ushort b) {
return ((uint)a << 16) | b;
}
answered Dec 17, 2009 at 16:09
Jon WatteJon Watte
6,3374 gold badges49 silver badges61 bronze badges
1
This is what you need
ushort val1 = ushort.MaxValue;
ushort val2 = ushort.MaxValue;
int result = val1;
result |= val2 << 15;
answered Dec 17, 2009 at 16:04
FredouFredou
19.7k10 gold badges58 silver badges113 bronze badges
2
try this, similar to MAKEWORD in < windef.h >:
#define MAKEDWORD(_a, _b) ((DWORD)(((WORD)(((DWORD_PTR)(_a)) & 0xffff)) | ((DWORD)((WORD)(((DWORD_PTR)(_b)) & 0xffff))) << 16))
answered Nov 22, 2011 at 6:29
jichijichi
6,1151 gold badge31 silver badges25 bronze badges
-
Алексей29
- Сообщения: 113
- Зарегистрирован: 17 дек 2020, 12:28
- Откуда: Воронеж
word -> dword
Листая прикладные инструкции не нашел конвертацию word в dword, может лыжи не едут… но все-таки.
Имеется ввиду в целое, а не с плавающей запятой
-
Yozik
- Сообщения: 103
- Зарегистрирован: 19 ноя 2015, 17:33
Re: word -> dword
Сообщение
Yozik » 07 апр 2021, 17:15
Алексей29 писал(а): ↑
07 апр 2021, 16:34
Имеется ввиду в целое, а не с плавающей запятой
Если быть точным знаковое целое
MMOV instruction sends the data in 16-bit device S to 32-bit device D. Sign bit (MSB) of
source device will be copied to every bit in the high byte of D.
-
and909
- Сообщения: 808
- Зарегистрирован: 28 май 2013, 13:20
Re: word -> dword
Сообщение
and909 » 13 апр 2021, 06:06
bayk писал(а): ↑
12 апр 2021, 22:48
Интересно, а результат работы mul — это dword?
Да, чтобы получить word нужно использовать mul16 (как и div)
-
tvent
- Сообщения: 971
- Зарегистрирован: 11 янв 2011, 17:02
Re: word -> dword
Сообщение
tvent » 13 апр 2021, 07:01
and909 писал(а): ↑
13 апр 2021, 06:06
bayk писал(а): ↑
12 апр 2021, 22:48
Интересно, а результат работы mul — это dword?Да, чтобы получить word нужно использовать mul16 (как и div)
В AS-серии нет MUL/DIV для результата DWold. Нужно явно указывать MUL16 для Word или MUL32 для DWord.
-
Сергей Валерьевич
- Сообщения: 68
- Зарегистрирован: 26 окт 2016, 10:23
Re: word -> dword
Сообщение
Сергей Валерьевич » 16 мар 2022, 10:42
Продолжу тут … Серия AS300
CFC , работа с блоками.
возник вопрос, как обрабатывать * и / для DWORD
результатом получаю 4 WORD, то есть 64 разряд.
Пока приходится эти операции вытягивать с блока в программу, там производить операции, сохранять в регистрах, а потом часть этих регистров, а именно D0, D0+1 опять запускать в блоки.. Знаю заранее, что значения не выйдут за 2 WORD
Может есть какое то более изящное решение в самом блоке?
.
Команды передачи данных
MOV | Присваивание |
CMOVxx | Условное присваивание |
XCHG | Обмен значений |
BSWAP | Перестановка байтов |
XADD | Обмен и сложение |
CMPXCHG | Сравнение и обмен |
CMPXCHG8B | Сравнение и обмен 8 байтов |
PUSH | Поместить значение в стек |
POP | Взять значение из стека |
PUSHA/PUSHAD | Поместить значения регистров общего назначения в стек |
POPA/POPAD | Взять значения регистров общего назначения из стека |
IN | Прочитать значение из порта ввода/вывода |
OUT | Записать значение в порт ввода/вывода |
CWD | Преобразовать Word в DWord |
CDQ | Преобразовать DWord в QWord |
CBW | Преобразовать Byte в Word |
CWDE | Преобразовать Word в DWord в регистре eax |
MOVSX | Присвоить и расширить с учетом знака |
MOVZX | Присвоить и расширить нулевым значением |
Двоичные арифметические команды
ADD | Сложение |
ADC | Сложение с переносом |
SUB | Вычитание |
SBB | Вычитание с заемом |
IMUL | Знаковое умножение |
MUL | Беззнаковое умножение |
IDIV | Знаковое деление |
DIV | Беззнаковое деление |
INC | Инкремент |
DEC | Декремент |
NEG | Смена знака |
CMP | Сравнение |
Двоично-десятичные (BCD) арифметические команды
DAA | Десятичная коррекция после сложения |
DAC | Десятичная коррекция после вычитания |
AAA | ASCII коррекция после сложения |
AAS | ASCII коррекция после вычитания |
AAM | ASCII коррекция после умножения |
AAD | ASCII коррекция перед делением |
Логические команды
AND | Побитовое логическое И |
OR | Побитовое логическое ИЛИ |
XOR | Побитовое логическое Исключающее ИЛИ |
NOT | Побитовое логическое НЕ |
Команды побитового сдвига и вращения
SAR | Арифметический сдвиг вправо |
SHR | Логический сдвиг вправо |
SAL/SHL | Арифметический/логический сдвиг влево |
SHRD | Двойной сдвиг вправо |
SHLD | Двойной сдвиг влево |
ROR | Вращение вправо |
ROL | Вращение влево |
RCR | Вращение вправо через флаг переноса |
RCL | Вращение влево через флаг переноса |
Команды работы с битами и байтами
BT | Проверка бита |
BTS | Проверка и установка бита |
BTR | Проверка и сброс бита |
BTC | Проверка и инверсия бита |
BSF | Проверка бита в прямом направлении |
BSR | Проверка бита в обратном направлении |
SETxx | Установить значение байта в зависимости от флага |
TEST | Логическое сравнение |
Команды передачи управления
JMP | Безусловный переход |
Jxx | Условный переход |
JCXZ/JECXZ | Переход, если cx/ecx равен 0 |
LOOP | Цикл со счетчиком в ecx |
LOOPZ/LOOPE | Цикл со счетчиком в ecx и выходом при нуле / равенстве |
LOOPNZ/LOOPNE | Цикл со счетчиком в ecx и выходом при не нуле / неравенстве |
CALL | Вызов подпрограммы |
RET | Возврат из подпрограммы |
IRET | Возврат из прерывания |
INT | Вызов программного прерывания |
INTO | Вызов прерывания по переполнению |
BOUND | Переход при выходе значения за заданные рамки |
ENTER | Высокоуровневый вход в процедуру |
LEAVE | Высокоуровневый выход из процедуры |
Команды работы со строками (последовательностями)
MOVS | Перемещение строки |
MOVSB | Перемещение строки байтов |
MOVSW | Перемещение строки слов |
MOVSD | Перемещение строки двойных слов |
CMPS | Сравнение строки |
CMPSB | Сравнение строки байтов |
CMPSW | Сравнение строки слов |
CMPSD | Сравнение строки двойных слов |
SCAS | Проверка строки |
SCASB | Проверка строки байтов |
SCASW | Проверка строки слов |
SCASD | Проверка строки двойных слов |
LODS | Чтение строки |
LODSB | Чтение строки байтов |
LODSW | Чтение строки слов |
LODSD | Чтение строки двойных слов |
STOS | Запись строки |
STOSB | Запись строки байтов |
STOSW | Запись строки слов |
STOSD | Запись строки двойных слов |
REP | Префикс повторения: пока ecx не равен 0 |
REPE/REPZ | Префикс повторения: пока равно / ноль |
REPNE/REPNZ | Префикс повторения: пока не равно / не ноль |
INS | Чтение из порта строки |
INSB | Чтение из порта строки байтов |
INSW | Чтение из порта строки слов |
INSD | Чтение из порта строки двойных слов |
OUT | Запись в порт строки |
OUTB | Запись в порт строки байтов |
OUTW | Запись в порт строки слов |
OUTD | Запись в порт строки двойных слов |
Команды управления флагами
STC | Установить флаг переноса |
CLC | Очистить флаг переноса |
CMC | Инвертировать флаг переноса |
CLD | Очистить флаг направления |
STD | Установить флаг направления |
LAHF | Загрузить флаги в ah |
SAHF | Записать ah в флаги |
PUSHF/PUSHFD | Поместить EFLAGS в стек |
POPF/POPFD | Взять EFLAGS из стека |
STI | Установить флаг прерывания |
CLI | Очистить флаг прерывания |
Тема: Как «располовинить» DWORD? (Прочитано 3676 раз)
Добрый день!
Из контроллера приходят данные: два слова, упакованные в одну переменную типа DWORD. Как можно извлечь эти две переменные?
« Изменён: 18 Ноября 2016, 11:27:06 от Simple-Scada »
Здравствуйте.
Это можно сделать следующим скриптом:
var
aHiWord, aLowWord: Word;
begin
aHiWord := Word(varDWord.AsInt shr 16);
aLowWord := Word(varDWord.AsInt);
end.
, где varDWord — переменная с контроллера, типа DWord, которую нужно разложить на слова. aHiWord — старшее слово. aLowWord — младшее слово. При этом не забывайте, что для корректной работы у DWord переменной должна быть выбрана шкала в Simple-Scada с диапазоном 0..4294967295. Типу данных DWord в Simple-Scada 2 соответствует тип LongWord.
« Изменён: 14 Ноября 2016, 16:16:47 от Simple-Scada »
А возможно ли обратное преобразование: две переменные типа Word в одну типа LongWord?
Конечно, обратным способом:
var
aHiWord, aLowWord: Word;
begin
aHiWord := 1883; // для примера
aLowWord := 52501; // для примера
varDWord.Value := LongWord(aHiWord shl 16) or aLowWord;
end.
Насколько я понимаю переменные aHiWord и aLowWord являются локальными для процедуры. А возможно ли «разобрать» переменную, которую мы берем из OPC и «половинки» присвоить внутренним переменным? И по какому событию это можно сделать?
Переменные с OPC-сервера мало чем отличаются от локальных переменных, поэтому здесь принцип такой же.
Из переменной OPC-сервера varDWord (тип LongWord) в две внутренние переменные varHiWord и varLowWord (типа Word):
begin
varHiWord.Value := Word(varDWord.AsInt shr 16);
varLowWord.Value := Word(varDWord.AsInt);
end.
И по какому событию это можно сделать?
Лучше всего по изменению переменной varDWord, т.е. по событию OnDataChange. Сейчас для этого придется создать объект (например Поле), связать его с переменной varDWord, перейти к OnDataChange-скрипту этого объекта и вставить в него код, которые представлен выше. В будущем можно будет создавать OnDataChange скрипты без создания объекта.
Конечно, обратным способом:
var
aHiWord, aLowWord: Word;
begin
aHiWord := 1883; // для примера
aLowWord := 52501; // для примера
varDWord.Value := LongWord(aHiWord shl 16) or aLowWord;
end.
У меня сегодня подобная конструкция не срабтала ввиду провтыка LongWord()… пришлось срагулить:
var
aHiWord, aLowWord: Word;
begin
aHiWord := 1883; // для примера
aLowWord := 52501; // для примера
varDWord.Value := aHiWord*65536 + aLowWord;
end.