Вход

Просмотр полной версии : Целочисленные в формате u32 и u64



Dimaes
16.10.2024, 12:45
Здравствуйте!
Подключаю к ПР205 устройство по шине Modbus. Целочисленные переменные типа u16 передаются без проблем. А вот с некоторыми регистрами которые имеют формат u32 или u64 возникает проблема.
Как можно считать данные регистры и потом математически их привести к нормальной форме. Есть ли у кого нибудь мысли. Мои знания в данной области, к сожалению ограничены.

melky
16.10.2024, 12:53
к u64 никак. ПР ограничен u32. Разделить на два регистра, потом собрать.

Dimaes
16.10.2024, 12:56
Кажется я сам нашел ответ на свой вопрос. Может кому нибудь пригодится. Поправьте меня если я ошибаюсь.
при считывании числа например U64 который занимает 4 регистра нужно считать их в отдельные переменные и потом:

Чтобы получить итоговое число:
читаем регистр 0x2200
младшая часть — значение оставляем «как есть» : 0хb4dfhex = 46303dec
далее регистр 0x2201
значение умножаем на 2^16 : 0x0dffhex = 3583dec, 3583 * 65536 = 234815488
затем регистр 0x2202
значение умножаем на 2^32 : 0 * 4294967296 = 0
и в конце 0x2203
значение умножаем на 2^48 : 0 * 281474976710656 = 0

Суммируем результаты : 46303 + 234815488 + 0 + 0 = 234861791. Возможно потребуется преобразовать в число с плавающей точкой.
Может есть более изящное решение?

kondor3000
16.10.2024, 12:57
Небось опять со счётчиком, где 64 битные регистры. Это только на СПК1хх и ПЛК 2хх можно сделать
Это нормальное решение из РЭ, только это не для ПР, а для ПЛК
и 0 там только в начале, потом дикие цифры пойдут.

EFrol
16.10.2024, 13:13
Два 16-битных в одни 32-битный еще можно собрать.
А дальше?! 64-бита придется хранить в 2-х разных переменных.
Потом придется делить на 10 несколько раз, чтобы отделить по цифре и вывести.
Я делаю с помощью макроса rDIV https://owen.ru/forum/showthread.php?t=26216&p=431974&viewfull=1#post431974
Отделяю каждую цифру https://owen.ru/forum/showthread.php?t=26216&p=432009&viewfull=1#post432009

melky
16.10.2024, 13:15
float не переварит преобразование из u64, он и u32 не переварит в принципе. Там где u32 продолжит считать с 1,2 знаками после запятой, float уже загнется.
А толку от ухищрений с u64? только показать, математика будет недоступна с этим числом.

Валенок
16.10.2024, 14:29
..Подключаю к ПР205 устройство по шине Modbus. ... типа u16 передаются без проблем. А вот с некоторыми ... имеют формат u32 или u64..
.
WB-MAP какой-нить?

Dimaes
16.10.2024, 14:53
Да, Измеритель параметров электрической сети WB-MAP3E.
Но там конечно можно использовать только регистры u32. Еще есть регистры s32 (у которых есть знак). С ними как быть?

EFrol
16.10.2024, 14:56
Что Вы хотите с ними сделать?

EFrol
16.10.2024, 15:07
float не переварит преобразование из u64, он и u32 не переварит в принципе. Там где u32 продолжит считать с 1,2 знаками после запятой, float уже загнется.
А толку от ухищрений с u64? только показать, математика будет недоступна с этим числом.

Я, наверное, опять не так понял?!
Взял максимальный u32 и преобразовал его во float и обратно - вроде все биты на месте?!
79464

FPavel
16.10.2024, 15:21
Да, Измеритель параметров электрической сети WB-MAP3E.
Но там конечно можно использовать только регистры u32. Еще есть регистры s32 (у которых есть знак). С ними как быть?
Есть раздел алгоритмов - длинная арифметика. Сложение/вычитание просто поразрядно, умножение можно тоже поразрядно (как умножение на бумаге в столбик), а есть умножение Карацубы - сверхбыстрое, но при реализации потребуется рекурсия, деление - вот это совсем сложный вариант.

В данном случае арифметика будет хоть и "длинной" но весьма ограниченной 64 разрядами.

Эта длинная тирада к тому, что если эти данные нужно просто отображать, то можно использовать самостоятельно реализованные или взятые с форума алгоритмы.
несмотря на то, что в документации по Modbus регистрам может быть указан множитель (к примеру, 1e-5) это означает всего лишь, что нужно при выводе целого числа отделить последние 5 символов (цифр) символом точка, т.е. реального деления не будет - такой формат чисел называется десятичные дроби с фиксированной точкой.
Чуть выше приведённой ранее ссылки с делением есть вывод принятого 64 разрядного числа с множителем 1e-5.
https://owen.ru/forum/showthread.php?t=26216&p=431901&viewfull=1#post431901


Собственно, скажите, что предполагает заказчик и алгоритм от этих чисел?

kondor3000
16.10.2024, 15:23
Я, наверное, опять не так понял?!
Взял максимальный u32 и преобразовал его во float и обратно - вроде все биты на месте?!
79464

float только 5-6 знаков поддерживает, остальное откидывает, при чём не только после запятой, но и перед, если знаков больше 5,
а 32 битное целочисленное считает все 10 знаков.

FPavel, вроде уже решили, что на ПР это не сделать, вы опять за своё)) Он тупо 4 регистра разом прочитать не может, не говоря про расчёты.

Валенок
16.10.2024, 15:24
Я, наверное, опять не так понял?!
Взял максимальный u32 и преобразовал его во float и обратно - вроде все биты на месте?!
79464
Случайность. На конце входного поставьте 0 заместо 5

Точнее - особенность чисто ОЛ-преобразования reaL_to_dword. Все что больше FFFF_FFFF - приводит к FFFF_FFFF

EFrol
16.10.2024, 15:44
float только 5-6 знаков поддерживает, остальное откидывает, при чём не только после запятой, но и перед, если знаков больше 5,
а 32 битное целочисленное считает все 10 знаков.

FPavel, вроде уже решили, что на ПР это не сделать, вы опять за своё)) Он тупо 4 регистра разом прочитать не может, не говоря про расчёты.

Понятно, что в мантиссу float 23 бита не впихнуть 32 бита. Однако костыли есть и для 64 бита - это 2 по 32. Работает же?!
Если очень захотеть можно приделать костыли для работы с double float.

FPavel
16.10.2024, 15:52
FPavel, вроде уже решили, что на ПР это не сделать, вы опять за своё)) Он тупо 4 регистра разом прочитать не может, не говоря про расчёты.
Изрядно забыл, чем тогда дело закончилось... А у самого не на чем проверить...
Если прибор не отдаёт 4 регистра по-отдельности, а требует чтения в один запрос, то тогда ничего не поделать.

Но если
- регистры можно прочитать,
- значение в этом 64 разрядном регистре меняется медленнее, чем несколько запросов,
- от этих данных требуется просто вывод на экран
То можно же прочитать и вывести. Для достоверности можно отбрасывать те результаты, которые отличаются более, чем на некоторое значение (возникшее при переполнении младшего регистра без своевременного прочтения старшего).

Валенок
16.10.2024, 15:55
Да, Измеритель параметров электрической сети WB-MAP3E.
Но там конечно можно использовать только регистры u32. Еще есть регистры s32 (у которых есть знак). С ними как быть?
Про 64 на ПР проще забыть. Или купить ошейник и плетку - тот же эффект, но быстрее
А со 32 signed - а ПР позволяет 2 регистра сразу прочитать? А по частям - слепить их именно как udint, посмотреть на признак знака и с учетом этого преобразовать в real. Всё просто.

Фигня может быть из-за не одномоментности считывания 2 регистров.

от этих данных требуется просто вывод на экран

тогда не страшно. А что выводить-то надо?

Или купите ПЛК. ПР - не для такого

melky
16.10.2024, 15:56
- от этих данных требуется просто вывод на экран

Вот это тут основное. И стоит ли оно затрат ПР для вывода.

Кстати на анализаторах сети часто есть double по Modbus. Учитывая, что это просто набор регистров хранения, а что туда запихнули не важно. Важно позволяет ли конечное устройство не только отображение, но еще и обработку.
А никто ведь не мешает прочитать как float два соседних регистра. У ПР то это один запрос будет. Дальше на биты и в число. Или там что-то может потеряться? как-то за ненадобностью таким не баловался.
На ПК это легко все делает, а вот на ПР?

kondor3000
16.10.2024, 16:01
Про 64 на ПР проще забыть.
Фигня может быть из-за не одномоментности считывания 2 регистров.


Купите ПЛК. ПР - не для такого

2 регистра читать можно и как 32 битное знаковое целочисленное пересчитать во Foat тут выложено
Функции FLOAT_TO_DINT и DINT_TO_FLOAT на ST____ https://owen.ru/forum/showthread.php?t=22915&page=311&p=429821#post429821

А вот можно ли прочитать 4 регистра, по 2 шт. за 2 раза, никто так и не написал, потому что в РЭ написано читать 4 регистра разом.

EFrol
16.10.2024, 16:02
Изрядно забыл, чем тогда дело закончилось... А у самого не на чем проверить...
Если прибор не отдаёт 4 регистра по-отдельности, а требует чтения в один запрос, то тогда ничего не поделать.

Но если
- регистры можно прочитать,
- значение в этом 64 разрядном регистре меняется медленнее, чем несколько запросов,
- от этих данных требуется просто вывод на экран
То можно же прочитать и вывести. Для достоверности можно отбрасывать те результаты, которые отличаются более, чем на некоторое значение (возникшее при переполнении младшего регистра без своевременного прочтения старшего).

Я согласен с Вами! Накопительный счетчик сохраняю в 2-х u32 и сравниваю со следующими. Если младшие u32 изменились, а старшие u32 - нет, то значению можно верить.

Валенок
16.10.2024, 16:13
2 регистра читать можно и как 32 битное знаковое целочисленное пересчитать во Foat тут выложено.
Нет никаких проблем пересчитать 2 регистра (из внешнего dint) в real. А они одновременно пришли?

kondor3000
16.10.2024, 16:19
Нет никаких проблем пересчитать 2 регистра (из внешнего dint) в real. А они одновременно пришли?

Одновременно, в ПР есть выбор читать 2 регистра, целое или Float. 4 регистра читать нельзя.

А вот можно ли прочитать 4 регистра, по 2 шт. за 2 раза, никто так и не написал, потому что в РЭ написано читать 4 регистра разом.

melky
16.10.2024, 16:24
В РЭ возможно имелось ввиду для достоверности данных, так как меняются. Если там Modbus такой, что не позволяет прочитать эти 4 регистра за два запроса, то это уже претензии к реализации Modbus конкретного прибора.

Валенок
16.10.2024, 16:39
А вот можно ли прочитать 4 регистра, по 2 шт. за 2 раза, никто так и не написал, потому что в РЭ написано читать 4 регистра разом.
Прочитать - можно. Только обрабатывать - творчески.

Dimaes
16.10.2024, 20:08
Считать со счетчика, отобразить на экране контроллера. Возможно сделать какие то расчеты, пока до конца не решил.

melky
16.10.2024, 22:45
Возможно сделать какие то расчеты вот про это лучше забудьте. Там такая каша получится, вычислять все пополам, потом творчески отображать :)

Dimaes
17.10.2024, 21:22
Друзья, из всего того, что вы тут обсуждали я понял практически ничего.
Но хотелось бы закончить вопрос практического применения полученных знаний. Касательно этого прибора я для себя понял следущюее.
1. С переменными в формате u64 я прощаюсь. Получать, выводить и анализировать данные по накопленной энергии не получится ну и ладно.

2. Большинство переменных находятся в формате u16 или u32 big endian для считывания которых в настройках контроллера Мстера установил две галки "старшим байтом вперед" (она стояла по умолчанию) "старшим регистром вперед" ее я поставил для корректного считывания big endian. Все значения читаются корректно.

Но вот с некоторыми переменными возникли сложности. в частности с теми которые в формате s32 little endian. Они, при таких настройках читаются не корректно.
Можете ли вы подсказать, как их правильно считать, преобразовать и использовать. Может макрос уже какой есть.
Заранее спасибо.

Dimaes
17.10.2024, 21:27
Небольшое уточнение. Я задал вопрос производителям счетчиков, они сначала предложили читать регистры отдельно по одному, но потом сами же предложили этого не делать, опасаясь за то, что в период считывания регистры могут поменяться и значения будут не корректные.
Потом они предложили сделать следующее:
" Я бы предложила немного иначе. Чтобы не возникало вышеописанной проблемы при считывании двух регистров разными запросами.
Я бы считала число из двух регистров, а потом математически поменяла их местами."
Но моих знаний в этой области не достаточно для совершения подобных манипуляций.

kondor3000
17.10.2024, 21:45
Небольшое уточнение. Я задал вопрос производителям счетчиков, они сначала предложили читать регистры отдельно по одному, но потом сами же предложили этого не делать, опасаясь за то, что в период считывания регистры могут поменяться и значения будут не корректные.
Потом они предложили сделать следующее:
" Я бы предложила немного иначе. Чтобы не возникало вышеописанной проблемы при считывании двух регистров разными запросами.
Я бы считала число из двух регистров, а потом математически поменяла их местами."
Но моих знаний в этой области не достаточно для совершения подобных манипуляций.

32 битное целочисленное занимает 2 регистра, ПР позволяет их читать вместе за один раз.
Если я правильно перевёл, u32 big endian - обратный порядок байт
s32 little endian - прямой порядок байт, для этого как раз и нужны галки старшим байтом и старшим регистром вперёд, перестановка регистров и байт.
Так же регистры и байты можно переставить в программе. Но для начала надо проверить правильность предположений.
Если имеются ввиду 32 битные знаковые целочисленные, то ответ тут
Функции FLOAT_TO_DINT и DINT_TO_FLOAT на ST____ https://owen.ru/forum/showthread.php?t=22915&page=311&p=429821#post429821
Пробуйте читать так и так и смотрите результат. Скрины выложите тут.

melky
18.10.2024, 09:18
ПР не понимает напрямую отрицательные числа s32. Если оно будет приходить с минусом, то вы по умолчанию будете получать непонятное значение.
Вроде были макросы, которые позволяли работать со знаковыми числами, но при переводе через float возможно будут возникать ошибки.

EFrol
18.10.2024, 10:25
Я возможно делаю, что-то неправильно:


Sign := s32.31; // Sign = false - число положительное, Sign = true - число отрицательное
if Sign then
u32 := 0 - s32; // Модуль числа s32, т.е. без знака
else
u32 := s32;
end_if


Можно ли считать, что если ValH(старшие 32 бита) и ValL(младшие 32 бита) считанные 2 раза подряд и давшие один и тот же результат,
дали результат верный shl(ValH, 32) + ValL?

melky
18.10.2024, 10:32
EFrol дальше в математику ПР это все пихните. когда отрицательное число будет -2 100 999 например
Речь же не всегда об отображении.

EFrol
18.10.2024, 10:46
Понятно, что будут сложности, но они ведь решаемы!!


Прочитать - можно. Только обрабатывать - творчески.

Давайте добавим макросы для работы c s32, u64, s64 и даже с double float.
Можем же ведь?!

melky
18.10.2024, 11:09
EFrol дело не в "можем ведь" а в том, что это начнет отжирать ресурсы ПР и увеличивать время цикла. Зачем насильничать над ПР? :)

EFrol
18.10.2024, 13:03
EFrol дело не в "можем ведь" а в том, что это начнет отжирать ресурсы ПР и увеличивать время цикла. Зачем насильничать над ПР? :)

Ну это пусть каждый решает сам для себя.
Я, например, перехожу на Arduino. Мне как-то всё равно.

kondor3000
18.10.2024, 13:37
Понятно, что будут сложности, но они ведь решаемы!!
Давайте добавим макросы для работы c s32, u64, s64 и даже с double float.
Можем же ведь?!

Для S32 уже всё обсудили и выложили, только в этой теме уже 2 раза ссылку давал.
Про 64 бита сделали только сложение, до умножения так и не дошло. Ссылку давал FPavel в начале.

EFrol
18.10.2024, 16:00
Опять я, наверно, не те макросы использую?!


function_block u64_MUL

var_input
x1H, x1L : udint;
x2H, x2L : udint;
end_var

var_output
qH, qL : udint;
end_var

var
cnt : udint;
end_var

qH := 0; qL := 0;

for cnt := 0 to 63 do
if x2L.0 then
qL := qL + x1L;
qH := qH + x1H;
if (qL < x1L) then qH := qH + 1; end_if
end_if
x2L := shr(x2L, 1); x2L.31 := x2H.0; x2H := shr(x2H, 1);
x1H := shl(x1H, 1); x1H.0 := x1L.31; x1L := shl(x1L, 1);
end_for

end_function_block




function_block u64_DIV

var_input
x1h, x1l : udint; // Делимое
x2h, x2l : udint; // Делитель
end_var

var_output
QH, QL : udint; // Частное
MH, ML : udint; // Остаток
end_var

var
cnt : udint;
end_var

if x2h = 0 and x2l = 0 then return; end_if

cnt := 1; QH := 0; QL := 0;

while x2h < 2147483648 do
x2h := shl(x2h, 1);
if x2l > 2147483647 then x2h := x2h + 1; end_if
x2l := shl(x2l, 1); cnt := cnt + 1;
end_while

while cnt > 0 do
QH := shl(QH, 1);
if QL > 2147483647 then QH := QH + 1; end_if
QL := shl(QL, 1);

if x1h > x2h then
x1h := x1h - x2h; QL := QL + 1;
if x1l >= x2L then
x1l := x1l - x2l;
else
x1l := x2l - x1l; x1l := 0 - x1l;
x1h := x1h - 1;
end_if
elsif x1h = x2h then
if x1l >= x2l then
x1h := 0; x1l := x1l - x2l; QL := QL + 1;
end_if
end_if

x2l := shr(x2l, 1);
if x2h > shl(shr(x2h, 1), 1) then x2l := x2l + 2147483648; end_if
x2h := shr(x2h, 1);

cnt := cnt - 1;
end_while
MH := x1h; ML := x1l;

end_function_block

kondor3000
18.10.2024, 18:47
Это всё конечно хорошо, но почему никто не смотрит, какие числа надо перемножать и складывать ?
число 2 в 32 и в 48 спепени перемножить с числом в 3 и 4 регистре, а потом всё сложить.
То есть умножить надо 2 раза 16 битное на 64 битное, а потом всё сложить. Сложение нужно 1 число 32 битное + 2 числа 64 битных.
2 регистр можно посчитать просто умножением в Лоджике 65535*65536=4294901760 .

Еще раз, что надо посчитать, вот скрин 74299

1 регистр 0x2200
младшая часть — значение оставляем «как есть» (может быть до 65535)
2 регистр 0x2201
значение умножаем на 2^16 (может быть до 4294901760)
3 регистр 0x2202
значение умножаем на 2^32 (сейчас 0, а будет число до 5 знаков, например 65535 * 4294967296=281470681743360 )
4 регистр 0x2203
значение умножаем на 2^48 (сейчас 0, а будет число до 5 знаков, например 65535 * 281474976710656=18446462598732840960 )

65535+4294901760+281470681743360+18446462598732840 960=18446744073709551615 - максимально возможное 20-значное число
умноженное на 0.00001=184467440737095.51615
Деление делать не надо, просто откинуть 5 последних знаков.

FPavel
18.10.2024, 21:21
kondor3000, Вы несколько запутались в формате принимаемого числа.

В том РЭ приведён пример, как из 4-х принятых регистров составить 64-разрядное число.
На самом деле при приёме ничего умножать не нужно - для подобного, обычно, пользуются или сдвигами или приведением типа результата к массиву слов (или рассыпухе из 4 слов).
Если бы дело происходило в CODESYS 3.5, можно было бы поступить следующими способами (забыл только обозначение там 64-разрядного типа, пусть будет u64)

type TConvert:
union
My64: u64;
x0, x1, x2, x3: uint;
a: array [0..3] of uint;
end_union
end_type

v: TConvert; // промежуточная переменная
r0, r1, r2, r3: uint; //регистры из Modbus
v64: u64; // это и есть итоговая переменная

// заполним её регистрами при помощи вспомогательной переменной
v.x0 := r0; v.x1 := r1; v.x2 := r2; v.x3 := r3;
v64 := v.My64;

// можно аналогично через массив
x.a[0] := r0; // ....... и так далее
v64 := v.My64;

// можно через сдвиги
v64 := r0 + shl(r1, 16) + shl(r2, 32) + shl(r3, 48);

// можно через умножение
v64 := r0 + r1 * 65536 + r2 * ........ // не помню дальше константы, но смысл понятен

А EFrol приводит макросы арифметических операций над уже полученными 64-разрядными числами, он "уже их принял" и ведёт дальнейшую обработку - считает деньги по тарифу ;)

FPavel
18.10.2024, 21:49
Да, открывал, видел, но при наборе примера не стал забивать голову константами - именно эти константы вместе с умножением - исключительно бумажный пример без практического применения, т.к. сдвиг всегда быстрее умножения, а прямое размещение данных сразу в нужном месте (привет, union!) - ещё быстрее.