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