Администрация форума не несёт ответственности за достоверность информации и оставляет за собой право редактировать или в особых случаях даже удалять посты без предупреждения. Спасибо за понимание.

Программирование ATMEL в BASCOM.

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.



Modbus rtu

Сообщений 1 страница 8 из 8

1

Здравствуйте, вопрос может быть конечно не совсем по теме форума, за это прошу прощение, но тут очень много умных людей, поэтому решил написать сюда, написал приложение на visual basic 6 обмен данными по modbus rtu с контроллером Atmega, используя библиотеку MBAXP Modbus RTU/ASCII ActiveX Control, на нашем форуме я встречал упоминание о ней, переменные типа int 16 читаются и пишутся отлично, а вот с float 32 засада. С контроллера передаю двумя регистрами, подскажите пожалуйста как в VB6 объединить две переменные integer16 и конвертировать их в Float. Заранее благодарен.

0

2

Не знаю, как на VB пишу на Delphi, но может пригодится.
Из моего устройства на ПК передавалось n - байт информации в котором были и целые и вещественные числа.
Всё принималось в буфер с именем BUF (неожиданно да?  :crazyfun: ).
Известно, что число типа 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)

0

3

Большое спасибо за ответ, алгоритм примерно понял, буду разбираться. Как получится отпишусь на форуме.

0

4

catalex написал(а):

С контроллера передаю двумя регистрами, подскажите пожалуйста как в VB6 объединить две переменные integer16 и конвертировать их в Float.

1. Я бы вообще принимал в стринг, а потом бы разбирал.
2. Но если у вас либа отдаёт "integer", то надо понять что вообще там приходит. Почему два "integer"? Т.е. приходит старшый/младший разряд или там какие-то отрицательные числа бывают? И зачем на выходе "Float" (тобишь Single)?

0

5

RDW написал(а):

1. Я бы вообще принимал в стринг, а потом бы разбирал.

В принципе совершенно пофиг как принимать. В любом случае будет буфер, а это массив и в нём есть какие то значения.
Что это будет коды символов или просто значения чисел совершенно безразлично. Однозначно нужно всё это как то переконвертировать в нужное нам значение.
Если подразумевается, что из контроллера заведомо приходят числа, то принимать их строкой как то не по фэншую. Хотя я и сам использую такой подход, но это при работе с IoT.
Там смесь строк и чисел, поэтому безразлично. Каждый сам себе строит горы и затем их преодолевает.
Мой сложившийся подход состоит в том, что я практически всегда передаю и принимаю HEX. Это тоже строка, но мне так проще разобраться. Привык уже.
Да и зная состав кадра проще разобрать где текст, а где числа.

0

6

Подходов много, да проще принимать байт в массив, но если протокол с разной длинной, то проще в строку, ибо всё быстрее описывать.
Случаи бывают разные, надо изначально знать вводные данные (вход/выход).

0

7

У меня прием не 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)

0

8

Ну, простым копированием не получится, надо преобразовывать.
Если на входе байт, то 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)

0