Здравствуйте, вопрос может быть конечно не совсем по теме форума, за это прошу прощение, но тут очень много умных людей, поэтому решил написать сюда, написал приложение на visual basic 6 обмен данными по modbus rtu с контроллером Atmega, используя библиотеку MBAXP Modbus RTU/ASCII ActiveX Control, на нашем форуме я встречал упоминание о ней, переменные типа int 16 читаются и пишутся отлично, а вот с float 32 засада. С контроллера передаю двумя регистрами, подскажите пожалуйста как в VB6 объединить две переменные integer16 и конвертировать их в Float. Заранее благодарен.
Modbus rtu
Сообщений 1 страница 8 из 8
Поделиться22019-01-10 10:46:13
Не знаю, как на VB пишу на Delphi, но может пригодится.
Из моего устройства на ПК передавалось n - байт информации в котором были и целые и вещественные числа.
Всё принималось в буфер с именем BUF (неожиданно да?
).
Известно, что число типа FLOAT32 имеет длину 4 байта. Пусть например в нашем буфере оно начиналось с позиции 5.
Тогда буфер выглядел так: BUF[5]:=08 BUF[6]:=AF BUF[7]:=AA BUF[8]:=12 т.е. Число типа FLOAT имеет вид 08 AF AA 12.
Идём дальше:
Для работы определим переменные.
Var
C: Integer; //Число куда будем собирать данные из буфера
P: ^Single; //Указатель на область памяти типа FLOAT
X: Single; //Само число
Теперь получаем то, что хотели.
C:=MakeLW(5); //Соберём всё из буфера
P:=@C; //Установим указатель на число, которое собрали
X:=P^; //Восстановим это число, как Single
В переменной X есть искомое число типа FLOAT.
Теперь осталось написать П/П MakeLW
Это просто.
//---------- Объединяем два WORD в LONGWORD)-----------------
function MakeLW(N: Byte):LongWord;
Var
N1,N2: Word;
LW: LongWord;
begin
N1:=(256*Buf[N])+Buf[N+1]; // Сначала из двух байт соберём WORD получим N1 = 08 AF
N2:=(256*Buf[N+2])+Buf[N+3]; // Получим второй WORD N2 = AA 12
LW:=(65536*N1)+N2; // И наконец LONGWORD LW = 08 AF AA 12
MakeLW:=LW; // Оно и присваивается переменной C
end;
Думаю, что в этом куске всё понятно. N - это номер позиции в буфере откуда начинается наше число.
Отредактировано sva-don (2019-01-10 10:59:50)
Поделиться32019-01-10 12:07:40
Большое спасибо за ответ, алгоритм примерно понял, буду разбираться. Как получится отпишусь на форуме.
Поделиться42019-01-10 12:47:41
С контроллера передаю двумя регистрами, подскажите пожалуйста как в VB6 объединить две переменные integer16 и конвертировать их в Float.
1. Я бы вообще принимал в стринг, а потом бы разбирал.
2. Но если у вас либа отдаёт "integer", то надо понять что вообще там приходит. Почему два "integer"? Т.е. приходит старшый/младший разряд или там какие-то отрицательные числа бывают? И зачем на выходе "Float" (тобишь Single)?
Поделиться52019-01-10 13:22:19
1. Я бы вообще принимал в стринг, а потом бы разбирал.
В принципе совершенно пофиг как принимать. В любом случае будет буфер, а это массив и в нём есть какие то значения.
Что это будет коды символов или просто значения чисел совершенно безразлично. Однозначно нужно всё это как то переконвертировать в нужное нам значение.
Если подразумевается, что из контроллера заведомо приходят числа, то принимать их строкой как то не по фэншую. Хотя я и сам использую такой подход, но это при работе с IoT.
Там смесь строк и чисел, поэтому безразлично. Каждый сам себе строит горы и затем их преодолевает.
Мой сложившийся подход состоит в том, что я практически всегда передаю и принимаю HEX. Это тоже строка, но мне так проще разобраться. Привык уже.
Да и зная состав кадра проще разобрать где текст, а где числа.
Поделиться62019-01-10 14:09:53
Подходов много, да проще принимать байт в массив, но если протокол с разной длинной, то проще в строку, ибо всё быстрее описывать.
Случаи бывают разные, надо изначально знать вводные данные (вход/выход).
Поделиться72019-01-11 13:25:42
У меня прием не integer16 а байтами. Делаю через CopyMemory
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" ( _
ByRef Destination As Any, _
ByRef Source As Any, _
ByVal Length As Long)
Dim temp_single As Single
'Копирование в Single
Call CopyMemory(temp_single, temp_buf(1), 4)
'Копирование в Long
Call CopyMemory(temp_long, temp_buf(1), 4)
Отредактировано lan_tosno (2019-01-11 13:25:58)
Поделиться82019-01-11 14:39:32
Ну, простым копированием не получится, надо преобразовывать.
Если на входе байт, то sva-don вам принцип описал, могу как упрощенный вариант описать, по старинке:
Dim Bh As Byte
Dim Bl As Byte
Dim A As Integer
Dim S As Single
A = 12345
' разбираем на байты
Bh = Int(A / 256) ' #30
Bl = A - Bh * 256 ' #39
' собираем обратно
S = Bh * 256 + BlЭто если без знака.
Если надо с знаком и "Integer" в "Single", то вообще проще некуда:
S = CSng(A)