Italian Calcolare CRC16 Modbus

FreeWolF

Active Member
Licensed User
Longtime User
Ciao, c'è qualcuno che sa come calcolare il valore CRC di una stringa in formato Modbus?

Per esempio, da questa stringa:


11 01 00 03 00 0C

Il CRC calcolato deve risultare

CE9F (CE High, 9F Low)

E per la stringa:
11 01 02 CD 0B

Il CRC calcolato deve essere

6D 68

Trovando una guida dice di eseguire i seguenti passaggi:

-------------------------------------------------------------------------------------------------------
Gli step necessari per il calcolo del CRC16 sono i seguenti:

Caricare un registro a 16bit con FFFh (tutti i bit a 1)
Fare l’OR esclusivo del primo carattere con il byte superiore del registro, porre il risultato nel registro.
Spostare il registro a destra di un bit.
Se il bit uscito a destra dal registro è un 1, fare l’OR esclusivo del polinomio generatore 1010000000000001 con il registro.
Ripetere per 8 volte i passi 3 e 4
Fare l’OR esclusivo del carattere successivo con il byte superiore del registro, porre il risultato nel registro.
Ripetere i passi 3 e 6 per tutti i caratteri del messaggio.
Il contenuto del registro a 16 bit è il codice di ridondanza CRC che deve essere aggiunto al messaggio.

-------------------------------------------------------------------------------------------------------

28rcchc.png


Questa è una tabella riassuntiva per i valori che si devono calcolare.

Ho provato a scrivere questo codice:

B4X:
Sub CRC(buf() As Byte, lbuf As Int) As Int
   Dim CRC1 As Int
   CRC1 = 0xffff
   For i = 0 To lbuf - 1
     CRC1 = Bit.Xor(CRC1, buf(i))
     For j = 0 To 7
       Dim k As Int = Bit.AND(crc1, 1)
       CRC1 = Bit.AND(Bit.AND(CRC1, 0xfffe) / 2, 0xf777)
       If k > 0 Then CRC1 = Bit.Xor(CRC1, 0xa001)
     Next
   Next
   Return CRC1
End Sub

a non va per niente bene, in pratica mi calcola il crc che pare a lui.....

Qualcuno saprebbe aiutarmi per favore?
 

LucaMs

Expert
Licensed User
Longtime User
Dato che sono già abbastanza rinc..., ho pensato di cercare qualcosa sul web, anziché scervellarmi.

Ho trovato questo: se è esatto, non dovrebbe essere complicato adattarlo a b4a

http://modbus.control.com/thread/1003514275

We made a function in VB for MODBUS-RTU CRC calculation...

This function in VB, recieve the modbus buffer and produce the CRC in 2 bytes. DialString is an string with the modbus buffer, the function returns an string of 2 bytes with the CRC.
'
' Calculo de CRC polinomio grado 16.
' Recibe el string a verificar
' Returna un string de dos bytes con el CRC calculado
'
Function CRC(DialString As String)
Dim G As Long, A As Long, AUX As Long
Dim ALow As Long, AHigh As Long, AL As Long, Carry As Integer
Dim i As Integer, j As Integer, cA As Long, cHex As String
'
A = 65535
G = 40961
i = 0
Do While i < Len(DialString$)
j = 0
ALow = Int(A / 256)
ALow = ALow * 256
ALow = A - ALow
AHigh = Int(A / 256) * 256
cA = Asc(Mid$(DialString, i + 1, 1))
AL = Int(cA Xor ALow)
AUX = Int(AHigh + AL)
A = AUX
Do While j < 8
j = j + 1
AUX = A
A = Int(A / 2)
Carry = AUX Mod 2
If Carry = 1 Then
A = Int(G Xor A)
End If
Loop
i = i + 1
Loop
ALow = A - Int(A / 256) * 256
AHigh = Int(A / 256)
CRC = Chr(ALow) + Chr(AHigh)
End Function


Oppure questo:
http://www.vbforums.com/showthread.php?671352-RESOLVED-CRC-16-Calculation-on-an-Array
 

LucaMs

Expert
Licensed User
Longtime User
http://www.planet-source-code.com/vb/scripts/ShowCode.asp?txtCodeId=6329&lngWId=10

//**************************************
// Name: Modbus CRC calc
// Description:This routine will calculate a 16 bit or two byte, Modbus CRC value.
// By: Matthew Lewis
//
// Inputs:Just enter the byte array and number of bytes to use from this array and the return value will be the crc calculated.
//
// Returns:The return value will be the crc calculated.
// If you pass only the modbus message bytes to the function it will return the crc value.
// If you pass the modbus message bytes including the crc bytes to the function it will return zero if the modbus message is correct. ( This can be
// used to check incoming messages from the network)
//**************************************

Function CRC16(ByVal MB_aray() As Byte, ByVal mNum As Integer) As Long
Dim i As Long = 0
Dim Temp As UInteger = 0
Dim CRC As UInteger = 65535
Dim j As Integer = 0
For i = 0 To mNum - 1
Temp = (CRC)
CRC = Temp Xor (MB_aray(i))
For j = 0 To 7
If (CRC And 1) Then
CRC = ((CRC >> 1) Xor 40961) '&H1021&)
Else
CRC = (CRC >> 1) 'And 65535
End If
Next j
Next i
CRC16 = CRC And 65535
End Function
 

FreeWolF

Active Member
Licensed User
Longtime User
Grazie mille! Ora provo a convertire il tutto per B4A (sempre se ci salto fuori). In tutti i casi riuscirci sarebbe interessante, visto che ho letto di altre persone che cercano qualcosa del genere :)

Grazie ancora, davvero!!!!
 

FreeWolF

Active Member
Licensed User
Longtime User
Ho visto che mi hai risposto dall' altra parte, grazie ancora :)

Ho provato ad implementare il tuo codice, ma il programma esce dicendomi "Unfortunatley B4A Example has stopped". Se vado a leggere il log di debug, mi dà un errore alla riga 77 ossia:

LogCat connected to: emulator-5554
--------- beginning of /dev/log/main


--------- beginning of /dev/log/system
java.lang.RuntimeException: java.io.EOFException


at anywheresoftware.b4a.shell.Shell.virtualAssets(Shell.java:159)
at anywheresoftware.b4a.shell.Shell.start(Shell.java:91)
at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:76)
at b4a.example.main.afterFirstLayout(main.java:90)
at b4a.example.main.access$100(main.java:16)
at b4a.example.main$WaitForLayout.run(main.java:76)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5017)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.io.EOFException
at libcore.io.Streams.readFully(Streams.java:83)
at java.io.DataInputStream.readInt(DataInputStream.java:103)
at anywheresoftware.b4a.shell.Shell.virtualAssets(Shell.java:131)
... 14 more
Copying updated assets files (1)


** Activity (main) Create, isFirst = true **


Error occurred on line: 77 (main)
java.lang.NumberFormatException: Invalid double: "x"


at java.lang.StringToReal.invalidReal(StringToReal.java:63)
at java.lang.StringToReal.parseDouble(StringToReal.java:269)
at java.lang.Double.parseDouble(Double.java:295)
at b4a.example.main._crc(main.java:386)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at anywheresoftware.b4a.shell.Shell.runMethod(Shell.java:636)
at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:305)
at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:238)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:121)
at b4a.example.main.afterFirstLayout(main.java:98)
at b4a.example.main.access$100(main.java:16)
at b4a.example.main$WaitForLayout.run(main.java:76)
at android.os.Handler.handleCallback(Handler.java:733)


at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5017)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
at dalvik.system.NativeStart.main(Native Method)
** Activity (main) Resume **


Il codice che ho scritto io è il seguente:

B4X:
#Region  Project Attributes
   #ApplicationLabel: B4A Example
   #VersionCode: 1
   #VersionName:
   'SupportedOrientations possible values: unspecified, landscape or portrait.
   #SupportedOrientations: unspecified
   #CanInstallToExternalStorage: False
#End Region

#Region  Activity Attributes
   #FullScreen: False
   #IncludeTitle: True
#End Region

Sub Process_Globals
   'These global variables will be declared once when the application starts.
   'These variables can be accessed from all modules.
     

End Sub

Sub Globals
   'These global variables will be redeclared each time the activity is created.
   'These variables can only be accessed from this module.

   Private Button1 As Button
   Private EditText1 As EditText
   Private EditText2 As EditText
   
   
End Sub

Sub Activity_Create(FirstTime As Boolean)
   'Do not forget to load the layout file created with the visual designer. For example:
   'Activity.LoadLayout("Layout1")
   Activity.LoadLayout("Main")
   
   EditText1.Text = "0x19 0x03 0x00 0x44 0x 00 0x03"
   
   CRC(EditText1.Text)
   
   
End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub


Sub Button1_Click
   
End Sub

Sub CRC(DialString As String) As String
  Dim Res As String

  Dim G As Long, A As Long, AUX As Long
  Dim ALow As Long, AHigh As Long, AL As Long
  Dim Carry As Int
  Dim i, J As Int
  Dim cA As Long

  A = 65535
  G = 40961
  i = 0
  Do While i < DialString.Length
  J = 0
  ALow = A / 256
  ALow = ALow * 256
  ALow = A - ALow
  AHigh = (A / 256) * 256
  'cA =  Asc(Mid$(DialString, i + 1, 1))
  cA = DialString.SubString2(i, i + 1)
  AL = Bit.Xor(cA, ALow)
  AUX = AHigh + AL
  A = AUX
  Do While J < 8
  J = J + 1
  AUX = A
  A = A / 2
  Carry = AUX Mod 2
  If Carry = 1 Then
  A = Bit.Xor(G, A)
  End If
  Loop
  i = i + 1
  Loop
  ALow = A - (A / 256) * 256
  AHigh = A / 256
  Res = Chr(ALow) & Chr(AHigh)
   
 ' Return Res
   
   EditText2.Text = Res
   
End Sub
 

FreeWolF

Active Member
Licensed User
Longtime User
Si, avevo già provato anche così ma nulla...

Niente da fare, non ci riesco in nessun modo.....ti ringrazio ancora una volta per l'aiuto che mi hai dato e ti auguro un bellissimo weekend!!
 

magoandroid

Member
Licensed User
Longtime User
@FreeWolF forse questo può esserti di aiuto.

B4X:
#Region  Project Attributes
  #ApplicationLabel: B4A Example
  #VersionCode: 1
  #VersionName:
  'SupportedOrientations possible values: unspecified, landscape or portrait.
  #SupportedOrientations: unspecified
  #CanInstallToExternalStorage: False
#End Region

#Region  Activity Attributes
  #FullScreen: False
  #IncludeTitle: True
#End Region

Sub Process_Globals
  'These global variables will be declared once when the application starts.
  'These variables can be accessed from all modules.
 
End Sub

Sub Globals
  'These global variables will be redeclared each time the activity is created.
  'These variables can only be accessed from this module.

  Private Button1 As Button
  Private EditText1 As EditText
  Private EditText2 As EditText
 
 
End Sub

Sub Activity_Create(FirstTime As Boolean)
  'Do not forget to load the layout file created with the visual designer. For example:
  'Activity.LoadLayout("Layout1")
  Activity.LoadLayout("Main")
 
  'EditText1.Text = "0x19 0x03 0x00 0x44 0x 00 0x03"
 
  EditText1.Text = "11010003000C"
 
End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub


Sub Button1_Click
  EditText2.Text = Modbus_CRC(EditText1.Text)
End Sub

Sub Modbus_CRC(strInput As String) As String
    Dim RetCRC As String
    Dim RetStr As String
   
    Dim CRCREG As Int
    Dim MVAL As Int
   
    Dim R As Short
    Dim I As Short
    Dim A As Int
    Dim B As Int
   
    CRCREG = 0xFFFF

    For R = 0 To strInput.Length - 1 Step 2
        RetStr = strInput.SubString2(R, R + 2)
        MVAL = Bit.ParseInt(RetStr, 16)
       
        CRCREG = Bit.Xor(CRCREG, MVAL)
        CRCREG = Bit.AND(CRCREG, 0xFFFF)

        For I = 1 To 8 Step 1
            If Bit.AND(CRCREG, 0x01) = 1 Then
                CRCREG = Bit.Xor(Bit.UnsignedShiftRight(CRCREG, 1), 0xA001)
                CRCREG = Bit.AND(CRCREG, 0xFFFF)
            Else
                CRCREG = Bit.UnsignedShiftRight(CRCREG, 1)
                CRCREG = Bit.AND(CRCREG, 0xFFFF)
            End If
        Next
    Next

    A = Bit.AND(CRCREG, 0xFF)
    B = Bit.AND(CRCREG, 0xFF00)
    A = A * 256
    B = B / 256

    If (A + B) < 16 Then
        RetCRC = "000" & (A + B)
    Else If (A + B) < 256 Then
        RetCRC = "00" & Bit.ToHexString(A + B)
    Else If (A + B) < 4096 Then
        RetCRC = "0" & Bit.ToHexString(A + B)
    Else
        RetCRC = Bit.ToHexString(A + B)
    End If
   
    Return RetCRC.ToUpperCase
End Sub


Un cordiale saluto a tutti.
MAgo
 

Attachments

  • ModbusCRC.png
    ModbusCRC.png
    288.7 KB · Views: 558

magoandroid

Member
Licensed User
Longtime User
Se funziona, sei ufficialmente... Mago ;)

Grazie Luca,
per l'INVESTITURA (fortunatamente non Stradale) :D
Vedo che abbiamo orari di Veglia comuni.

Ho trovato questo calcolatore di CRC (crc.xls) che mi ha ispirato, ma visto l'orario, la probabilità che ci sia qualche cosa da rivedere nel codice è alta. :p

Una buona giornata a tutti.
Maurizio Agosti
 

FreeWolF

Active Member
Licensed User
Longtime User
MagoAndroid: ma io ti faccio un monumento, anzi, dimmi di dove sei che se non abitiamo troppo lontano ti offro 36 birre!!!! Il programma funziona PERFETTAMENTE ed era proprio quello che cercavo. Grazie, grazie e ancora grazie!!!!!!!
E Grazie anche a te LucaMs !!!!
 

magoandroid

Member
Licensed User
Longtime User
MagoAndroid: ma io ti faccio un monumento, anzi, dimmi di dove sei che se non abitiamo troppo lontano ti offro 36 birre!!!! Il programma funziona PERFETTAMENTE ed era proprio quello che cercavo. Grazie, grazie e ancora grazie!!!!!!!
E Grazie anche a te LucaMs !!!!

Ciao @FreeWolF,
mi fa molto piacere che funzioni e che era quello che cercavi, così posso accettare l'investitura di @LucaMs ;)

Ho visto che in questo post Erel (il Grande) ti propone un codice con il passaggio di un Array e l'utilizzo dei valori tabellati per ottenere il CRC (provato funziona).
Buona Domenica.
MAgo (PR)
 

FreeWolF

Active Member
Licensed User
Longtime User
Ho visto anche il codice di Erel, ma però non sono ben riuscito a capire come funziona, cioè come si fa a mettere i dati e a visualizzare quelli restituiti.....però si, dei due metodi possibili (cioè quello basato su tabella che ha scritto Erel e quello basato su algoritmo, che hai scritto tu), direi che su due piedi preferisco il tuo :)

Buona domenica anche a te e grazie ancora!!
 

LucaMs

Expert
Licensed User
Longtime User
MagoAndroid: ma io ti faccio un monumento, anzi, dimmi di dove sei che se non abitiamo troppo lontano ti offro 36 birre!!!! Il programma funziona PERFETTAMENTE ed era proprio quello che cercavo. Grazie, grazie e ancora grazie!!!!!!!
E Grazie anche a te LucaMs !!!!


Ecco, così dopo le 36 birre, l'investitura sarà molto probabile... che un Mago investa un Wolf :D
 

LucaMs

Expert
Licensed User
Longtime User
Era un po' sarcastica ;)


A me fa piacere se Erel viene a trovarci anche nel forum italiano.
I'm glad if Erel comes to visit us also in the Italian forum.
أنا سعيد إذا إيريل يأتي لزيارتنا أيضا في المنتدى الإيطالية
:D
 

FreeWolF

Active Member
Licensed User
Longtime User
Me too I'm glad if Erel come here to visit us :)
Excuse me for my bad english :)

Pensavo che si fosse "arrabbiato" perchè avevo preferito un'altro codice al suo oppure perchè non lo avevo ringraziato subito :)
 
Top