ModBUS RTU su VB.net

di il
4 risposte

ModBUS RTU su VB.net

Buongiorno a tutti,
sto cercando di realizzare un software ModBUS master con Visual Basic 2017 (VB code) per leggere i dati di alcuni sensori slave.

Qualcuno ha già un codice di un software fatto e finito in modo che mi metta a studiarlo?

Al momento sono riuscito a collegarmi al sensore utilizzando la porta seriale "COM4", ad inviare e ricevere il messaggio in un array di byte ma purtroppo il dato restituito non è quello aspettato.

Credo che sia necessario convertire il dato restituito nei diversi formati (float, piuttosto che UInt 32)

Sul web on ci sono molte guide che spieghino come realizzare da zero questo tipo di progetto.

Grazie a chi mi saprà aiutare.

4 Risposte

  • Re: ModBUS RTU su VB.net

    Anni (decenni ) fa mi interfacciai con una periferica utilizzando il protocollo Modbus, tutto in linguaggio C, ma francamente non ricordo molto e quindi non credo di poter esserti molto utile.
    Ciononostante devo segnalarti che se cerchi con google "Modbus vbnet" trovi una marea di informazioni; ad esempio questo https://www.codeproject.com/Questions/811594/VB-code-for-MODBUS-RTU in cui trovi una serie di link utilissimi.
    Naturalmente in questo caso non puoi pretendere di trovare del codice di esempio che utilizza i tuoi sensori (eventualmente del codice di esempio così specifico te lo potrebbe fornire il produttore dei dispositivi); devi fare un mix fra gli esempi che trovi, la documentazione del protocollo e le informazioni specifiche che hai dal produttore dei sensori.
  • Re: ModBUS RTU su VB.net

    Ciao Candaluar,
    grazie per la risposta... sto cercando di "capire" bene la logica dell'invio del messaggio, la risposta del dispositivo slave e del calcolo CRC.

    Al momento ho compilato il mio programma test che potete vedere di seguito, solo che non funziona.

    Non ho ben capito come devo gestire il risultato restituito dal dispositivo che vado ad interrogare; nel manuale del dispositivo molti valori sono in "Float" e altri in "Uint32" o "Uint16"... immagino che debba convertire il risultato a seconda del formato specificato, ma non so come.
    Per di più ho visto che bisogna considerare anche l'ordine dei byte! Il mio dispositivo utilizza l'ordine "ABCD" (poi ne ho un altro che utilizza il CDAB)... cosa devo impostare per dialogare in questi due diversi modi?

    Imports System.IO.Ports
    Imports System.Threading
    
    Public Class ReadHoldingRegistersForm
    
    'dichiarazione della porta seriale
    Dim serialPort as SerialPort = Nothing
    
    'Al caricamento della Form, definisco le impostazioni della porta
     Private Sub ReadHoldingRegistersForm_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Try
                serialPort = New SerialPort("COM4", 19200, Parity.Even, 8, StopBits.One)
                serialPort.Open() 'Open COM4
            Catch ex As Exception
                MessageBox.Show(Me, ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
            End Try
        End Sub
    
    
    '--> ECCO LA SUB che secondo me mi da l'errore!
    'Alla pressione di un pulsante definisco l'indirizzo dello slave, il codice funzione 03 (relativo alla lettura), l'indirizzo modbus da puntare e il numero di punti da leggere (perché 16*2???)
    
     Private Sub btnReadHoldingRegisters_Click(sender As Object, e As EventArgs) Handles btnReadHoldingRegisters.Click
            Try
                Dim slaveAddress As Byte = 1
                Dim functionCode As Byte = 3
                Dim startAddress As UShort = 41269
                Dim numberOfPoints = 16 * 2 ' Read 4 Float.
    
                Dim frame As Byte() = Me.ReadHoldingRegisters(slaveAddress, functionCode, startAddress, numberOfPoints)
    
                txtSendMsg.Text = Me.DisplayValue(frame) ' Diplays frame: send.
    
                serialPort.Write(frame, 0, frame.Length) ' Send frame to modbus slave.
    
                Thread.Sleep(100) ' Delay 100ms.
    
                If serialPort.BytesToRead >= 5 Then  '			--> perché >=5???
                    Dim buffRecei As Byte() = New Byte(serialPort.BytesToRead) {}
                    serialPort.Read(buffRecei, 0, buffRecei.Length) ' Read data from modbus slave.
                    txtReceiMsg.Text = Me.DisplayValue(buffRecei) ' Display frame: received.  ']--> il messaggio che ricevo è sempre uguale, non cambia se utilizzo un altro registro modbus! perché?
    
                    Dim data As Byte() = New Byte(buffRecei.Length - 5) {}
                    Array.Copy(buffRecei, 3, data, 0, data.Length)
    
                    'Convert byte array to word array
                    Dim result As  '......  ????? in che formato devo gestirlo il risultato???
    
                    'Display Result
    
    
                   txtResult.Text = String.Empty
                    For Each item As Single In result
                        txtResult.Text += String.Format("{0}/ ", item)
                    Next
                End If
    
            Catch ex As Exception
            MessageBox.Show(Me, ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
            End Try
        End Sub
    
    
    'Definisco una funzione per creare il messaggio in un array di byte
    Private Function ReadHoldingRegisters(slaveAddress As Byte, functionCode As Byte, startAddress As UShort, numberOfPoints As UShort) As Byte()
            Dim frame As Byte() = New Byte(7) {} ' Total 8 Bytes       '--> perchè un array da 8 Bytes??
            frame(0) = slaveAddress ' Slave Address
            frame(1) = functionCode 'Function
            frame(2) = CByte(startAddress / 256) 'Starting Address Hi.      '--> perché diviso 256?
            frame(3) = CByte(startAddress Mod 256) 'Starting Address Lo.                         '--> perché ho bisogno di restituire il resto?
            frame(4) = CByte(numberOfPoints / 256) ' Quantity of Registers Hi.
            frame(5) = CByte(numberOfPoints Mod 256) ' Quantity of Registers Lo.
            Dim crc As Byte() = Me.CRC(frame) ' Call CRC Calculate.
            frame(6) = crc(0) ' Error Check Lo
            frame(7) = crc(1) ' Error Check Hi
            Return frame '
    End Function
    
    ' Modbus CRC calculation in VB 
    '--> Questo codice l'ho trovato su internet e l'ho copiato senza modificare nulla; non so se è giusto e se vale per ogni dispositivo ModBUS in RS485... secondo voi?
    
        Private Function CRC(data As Byte()) As Byte()
            Dim CRCFull As UShort = &HFFFF
            Dim CRCHigh As Byte = &HF, CRCLow As Byte = &HFF
            Dim CRCLSB As Char
            Dim result As Byte() = New Byte(1) {}
            For i As Integer = 0 To (data.Length) - 3
                CRCFull = CUShort(CRCFull Xor data(i))
    
                For j As Integer = 0 To 7
                    CRCLSB = ChrW(CRCFull And &H1)
                    CRCFull = CUShort((CRCFull >> 1) And &H7FFF)
    
                    If Convert.ToInt32(CRCLSB) = 1 Then
                        CRCFull = CUShort(CRCFull Xor &HA001)
                    End If
                Next
            Next
            CRCHigh = CByte((CRCFull >> 8) And &HFF)
            CRCLow = CByte(CRCFull And &HFF)
            Return New Byte(1) {CRCLow, CRCHigh}
        End Function
    
    'Display frame
    '--> Converto l'array di byte in stringa
    
        Private Function DisplayValue(values As Byte()) As String
            Dim result As String = String.Empty
            For Each item As Byte In values
                result += String.Format("{0:X2} ", item)
            Next
            Return result
        End Function
    
    End Class

    Allegati:
    23713_0e8d05b6626063d4778136e1fdb06421.png
    23713_0e8d05b6626063d4778136e1fdb06421.png

    23713_fb6a261cb45914fdd617f97e22ebb935.png
    23713_fb6a261cb45914fdd617f97e22ebb935.png
  • Re: ModBUS RTU su VB.net

    Ciao
    io uso con parecchia soddisfazione questa dll : EasyModbusLibrary for .NET (DLL)
    Semplice e intuitiva

    ciao
  • Re: ModBUS RTU su VB.net

    Ciao Dafora,
    grazie mille per il consiglio, la proverò quabto prima
Devi accedere o registrarti per scrivere nel forum
4 risposte