Modbus - DWORD in DEZ umwandeln klappt nicht

  • VB.NET

Es gibt 36 Antworten in diesem Thema. Der letzte Beitrag () ist von Murdersquad.

    Modbus - DWORD in DEZ umwandeln klappt nicht

    Hallo,

    ich habe momentan ein kleines Problem. Ich wollte mich mal an Modbus TCP herantasten und habe mir dafür ein Codebeispiel von Youtube geholt.

    drive.google.com/drive/folders…SiEA3H8asJJsnSlTK3OKy2vpU

    Nun folgendes Problem - über den Button btnReadHoldingRegisters werden die einzelnen Register gelesen. In den Textboxen txtReceiMsg und txtResult wird die Rückgabe des Gerätes als Byte (txtReceiMsg) und als UShort (txtResult) zurückgegeben.
    Beispiel:
    txtReceiMsg = 00 03 00 00 00 07 FF 03 04 00 7E 92 4B
    txtResult = 126/ 37451/

    Das Problem ist, dass die letzten 4 Bytes, also 00 7E 92 4B einen Messwert als DWORD enthalten. Der Messwert soll dezimal (8.294.987) ausgegeben werden.
    Wie stelle ich dies an? Ich finde keinen Weg es richtig zu konvertieren und erhalte nie das gewünschte Ergebnis...
    btw: mit welchem Datentyp wäre DWORD in VB.NET zu vergleichen? Integer?

    VB.NET-Quellcode

    1. Private Sub btnReadHoldingRegisters_Click(sender As Object, e As EventArgs) Handles btnReadHoldingRegisters.Click
    2. Try
    3. Dim slaveAddress As Byte = 255 ' The Unit Identifier
    4. Dim functionCode As Byte = 3 ' Function.
    5. Dim id As UShort = functionCode ' Transaction Identifier .
    6. Dim startAddress As UShort = 50780 ' Starting Address .
    7. Dim numberOfPoints As UShort = 2 ' Quantity of Registers . Read 2 real(float) number. Note: Unit Word(1 Word = 2byte= 16bit, 1 Real/Float = 4byte= 2 Word = 32 bits).
    8. Dim frame As Byte() = Me.ReadHoldingRegisters(id, slaveAddress, startAddress, functionCode, numberOfPoints)
    9. txtSendMsg.Text = Me.Display(frame) ' Display frame: Sends.
    10. Me.Write(frame) ' Send message(frame) to device.
    11. Thread.Sleep(100) ' Delay 100ms.
    12. ' Received data.
    13. Dim buffRecei As Byte() = Me.Read()
    14. If IsDBNull(buffRecei) Then
    15. Return
    16. End If
    17. Dim sizeBytes = buffRecei(8) ' The data byte received.
    18. If (functionCode = buffRecei(7)) Then
    19. Dim byteMsg As Byte() = New Byte(8 + sizeBytes) {}
    20. Array.Copy(buffRecei, 0, byteMsg, 0, byteMsg.Length)
    21. txtReceiMsg.Text = Me.Display(byteMsg) ' Display frame: received.
    22. Dim data As Byte() = New Byte(sizeBytes - 1) {} ' Okay: Ready!!!
    23. Array.Copy(buffRecei, 9, data, 0, data.Length)
    24. ' Process data.
    25. Dim result As UShort() = DataType.Word.ToArray(data) ' Convert byte array to ushort array.
    26. txtResult.Text = String.Empty
    27. For Each item As UShort In result
    28. txtResult.Text += String.Format("{0}/ ", item)
    29. Next
    30. 'Exception Response
    31. Else
    32. 'slave may answer with error at 8th and 9th byte
    33. '8th byte: hex 81,82,83,84,85,86,8f,90 means that response answers with error ex: if request function was 03 then error response will be 83
    34. '9th byte: the exception code
    35. Select Case buffRecei(7)
    36. Case 129, 130, 131, 132, 133, 134, 143, 144
    37. Dim byteMsg As Byte() = New Byte(8) {}
    38. Array.Copy(buffRecei, 0, byteMsg, 0, byteMsg.Length)
    39. txtReceiMsg.Text = Me.Display(byteMsg) ' Display frame: received.
    40. Select Case buffRecei(8)
    41. Case 1 : txtResult.Text = "Slave Exception: Illegal Function !!!"
    42. Case 2 : txtResult.Text = "Slave Exception: Illegal Data Address !!!"
    43. Case 3 : txtResult.Text = "Slave Exception: Illegal Data Value !!!"
    44. Case 4 : txtResult.Text = "Slave Exception: Slave Device Failure !!!"
    45. Case 5 : txtResult.Text = "Slave Exception: Acknowledge !!!"
    46. Case 6 : txtResult.Text = "Slave Exception: Slave Device Busy !!!"
    47. Case 7 : txtResult.Text = "Slave Exception: Negative Acknowledge !!!"
    48. Case 8 : txtResult.Text = "Slave Exception: Memory Parity Error !!!"
    49. Case 10 : txtResult.Text = "Slave Exception: Gateway Path Unavailable !!!"
    50. Case 11 : txtResult.Text = "Slave Exception: Gateway Target Device Failed to Respond !!!"
    51. End Select
    52. End Select
    53. End If
    54. Catch ex As Exception
    55. MessageBox.Show(Me, ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
    56. End Try
    57. End Sub
    Hey,

    hilft dir das?
    Result ist 8294987

    VB.NET-Quellcode

    1. Dim txtReceiMsg As String = "00 03 00 00 00 07 FF 03 04 00 7E 92 4B"
    2. Dim txtReceiMsgArray() As String = txtReceiMsg.Trim.Split(" "c)
    3. Dim Byte1 As String = txtReceiMsgArray(9) 'Kannst hier natürlich auch variabel die Länge abfragen, falls dein Byte-Array nicht immer gleich lang ist
    4. Dim Byte2 As String = txtReceiMsgArray(10)
    5. Dim Byte3 As String = txtReceiMsgArray(11)
    6. Dim Byte4 As String = txtReceiMsgArray(12)
    7. Dim Last4Bytes As String = Byte1 & Byte2 & Byte3 & Byte4
    8. MsgBox(Val("&H" & Last4Bytes))


    Gruß,
    xored
    @Murdersquad @xored Gugt Ihr BitConverter:

    VB.NET-Quellcode

    1. Dim bb As Byte() = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}
    2. Me.Label1.Text = BitConverter.ToString(bb)
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    xored, danke das ist genau das was ich gesucht habe.

    Einziges Problem was mir bleibt, ich wollte meinen Wert 8294987 nun wie folgt formatieren 8.294,987. Ich finde jedoch keine Formatierungsmöglichkeit hierfür. Egal wie, ich komme immer auf 8.294.987,000 Momentan hängt es bei mir überall.

    @RodFromGermany:
    Der Bitconverter wäre für mich nur hilfreich, wenn ich im hex-Bereich arbeiten möchte oder sehe ich das falsch?

    Murdersquad schrieb:

    oder sehe ich das falsch?
    Ja.

    VB.NET-Quellcode

    1. Dim bb As Byte() = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}
    2. Me.Label1.Text = BitConverter.ToInt32(bb).ToString()
    3. Me.Label2.Text = BitConverter.ToInt32(bb).ToString("X8")
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    Murdersquad schrieb:

    Egal was ich mache
    Was ganz genau machst Du denn?
    Poste mal Deinen Code.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Jetzt habe ich natürlich alle Versuche gelöscht, aber hier mal ein Beispiel mit obigen Code, wie es nicht geht:

    VB.NET-Quellcode

    1. Dim ReceiMsgArray() As String = txtReceiMsg.Text.Trim.Split(" "c)
    2. Dim Byte1 As String = ReceiMsgArray(9)
    3. Dim Byte2 As String = ReceiMsgArray(10)
    4. Dim Byte3 As String = ReceiMsgArray(11)
    5. Dim Byte4 As String = ReceiMsgArray(12)
    6. Dim Last4Bytes As String = Byte1 & Byte2 & Byte3 & Byte4
    7. Dim Merker As Decimal
    8. Merker = (Val("&H" & Last4Bytes))
    9. txtTest1.Text = Merker.ToString("#,###.000")


    Rustikale Lösung wäre es die Länge von Merker zu zählen und mit .Insert die Zeichen entsprechend einzufügen. Das finde ich jedoch nicht elegant.
    @Murdersquad So was:

    VB.NET-Quellcode

    1. Dim txtReceiMsg As String = "00 03 00 00 00 07 FF 03 04 00 7E 92 4B"
    2. Dim ReceiMsgArray() As String = txtReceiMsg.Trim.Split(" "c)
    3. Dim Byte1 As String = ReceiMsgArray(9)
    4. Dim Byte2 As String = ReceiMsgArray(10)
    5. Dim Byte3 As String = ReceiMsgArray(11)
    6. Dim Byte4 As String = ReceiMsgArray(12)
    7. Dim Last4Bytes As String = Byte1 & Byte2 & Byte3 & Byte4
    8. Dim Merker = Convert.ToInt32(Last4Bytes, 16)
    9. Label2.Text = Merker.ToString()
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Irgendwie willst du den Wert noch kleiner haben. Kann es mir nur so vorstellen.

    VB.NET-Quellcode

    1. Dim recivemsg = "00 03 00 00 00 07 FF 03 04 00 7E 92 4B"
    2. Dim splitmsg = recivemsg.Split({" "c}, StringSplitOptions.RemoveEmptyEntries).
    3. Select(Function(s) Convert.ToByte(s, 16)).ToArray
    4. Dim dwordmsg = splitmsg.Skip(splitmsg.Length - 4).ToArray
    5. 'Dim dwordmsg = New Byte(3) {}
    6. 'Array.Copy(splitmsg, splitmsg.Length - 4, dwordmsg, 0, 4)
    7. Array.Reverse(dwordmsg)
    8. Dim uints = BitConverter.ToUInt32(dwordmsg, 0)
    9. Dim result = (uints / 1000).ToString("#,###.000")


    Freundliche Grüsse

    exc-jdbi

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „exc-jdbi“ ()

    Erst so:
    Der Messwert soll dezimal (8.294.987) ausgegeben werden.

    Dann so:
    und nicht so 8.294,987.


    VB.NET-Quellcode

    1. Module Module1
    2. Sub Main()
    3. Dim t$ = " 00 03 00 00 00 07 FF 03 04 00 7E 92 4B "
    4. Dim z As Double = 0
    5. Dim E$ = ""
    6. t = t.Replace(" ", "")
    7. t = t.Substring(t.Length - 8, 8)
    8. z = ("&H" & t) / 1000
    9. E = z.ToString("#,###.000")
    10. Debug.Print(E)
    11. End Sub
    12. End Module


    Ergebnis: '8.294,987
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    So besser? ^^

    VB.NET-Quellcode

    1. Option Strict On
    2. Option Explicit On
    3. Module Module1
    4. Sub Main()
    5. '8.294.987
    6. Dim t$ = " 00 03 00 00 00 07 FF 03 04 00 7E 92 4B "
    7. Dim z As UInteger = 0 'DWord
    8. Dim E$ = ""
    9. t = t.Replace(" ", "")
    10. t = t.Substring(t.Length - 8, 8)
    11. z = Convert.ToUInt32(t, 16)
    12. E = (z / 1000).ToString("#,###.000")
    13. Debug.Print(E)
    14. End Sub
    15. End Module
    @Eierlein Etwas.
    Allerdings weiß ich noch immer nicht, was @Murdersquad eigentlich will.
    Das Problem kann doch nicht sein, wie ein numerischer Wert formatiert wird.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    Murdersquad schrieb:

    den Wert durch 1000 zu teilen
    Was hat denn das für eine numerische / physikalische Bewandtnis?
    Werden da Massen von Gramm in Kilogramm oder Längen von Meter in Kilometer umgerechnet?
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Ich muss das Thema nochmal aufgreifen.

    Ich habe nun einen Wert, den ich einfach nicht richtig umwandeln kann. Aus 436AE78E soll 234.90451 werden.
    Was mache ich aktuell falsch?
    Meine Fehlermeldung lautet: System.InvalidCastException: "Ungültige Konvertierung von der Zeichenfolge E7 in Typ Byte."
    Aber weshalb? Kann ich ein Byte nicht hexadezimal belegen?

    VB.NET-Quellcode

    1. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    2. Dim txtReceiMsg As String = "00 03 00 00 00 07 FF 03 04 43 6A E7 8E"
    3. Dim ReceiMsgArray() As String = txtReceiMsg.Trim.Split(" "c)
    4. Dim Last4Bytes As Byte() = {ReceiMsgArray(9), ReceiMsgArray(10), ReceiMsgArray(11), ReceiMsgArray(12)}
    5. Label1.Text = BitConverter.ToDouble(Last4Bytes, 0)
    6. End Sub

    @Murdersquad Hatte ich bereits in Post #13.
    Option Strict On :!:
    Visual Studio - Empfohlene Einstellungen
    Das gilt selbstverständlich auch für Dich.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!