Vai al contenuto
PLC Forum


Calcolo Crc


christian ceruti

Messaggi consigliati

christian ceruti

buonasera a tutti

stò implementando un'applicazione in vb che comunica tramite modbus (ascii) con una apparecchiatura ed ho problemi con il calcolo del crc

il pacchetto spedito dall'apparecchiatura è :

:DE100000000A141E6100000000000000000000000000000000000075

in cui "75" dovrebbe essere il crc di

DE100000000A141E61000000000000000000000000000000000000

forse sbaglio il calcolo, ma a me 75 non viene con nessun tipo di crc... (crc16 crc32 ecc...)

secondo voi che calcolo viene utilizzato???

Link al commento
Condividi su altri siti


Ciao,

Il CRC per il modbus ascii non e' lo stesso della versione "binario" (RTU) che e' basato su un polinomio di confronto.

Qualche anno fa la rivista Fare Elettronica dedico' una serie di articoli all' argomento "modbus ascii".

Se non ricordo male dovrebbe essere piu' o meno cosi':

Fai la somma di tutti i byte, usando come lunghezza sempre 1 byte (no riporto) :

DE +
10 +
00 +
00 +
00 + 
0A +
14 =

10C -> usare solo 0C 

continuando...

0C +

1E + 
61 +
00 +
00 +
00 +
00 +
00 +
00 +
00 +
00 +
00 +
00 +
00 +
00 +
00 +
00 +
00 +
00 +
00 +
00 =

8B => 139 decimale => 10001011 binario

Puoi farlo a mano con la calcolatrice di windows in modalita' scentifica
Nelle impostazoni Hex imposta la lunghezza in Byte, defalut mi pare sia al massimo (Qword), ma alla fine non cambia niente.


Sul risultato fai il complemento a 2 (http://it.wikipedia.org/wiki/Complemento_a_due)


In pratica neghi il risultato (inverti 0 con 1 e 1 con 0) e ci aggiungi 1 :

risultato

1 0 0 0 1 0 1 1 

inversione dei bit

0 1 1 1 0 1 0 0 

somma con 1 
0 1 1 1 0 1 0 0 +
0 0 0 0 0 0 0 1=

0 1 1 1 0 1 0 1 => 117 dec => 75 hex.

Forse la spaziatura non da l' idea dell' incolonnamento, ma se lo fai su carta viene meglio.

Nota: In questo caso l' operazione e' semplice perche' il bit meno significativo dell' "invertito" e' 0, pero' ricorda che 1+1 = 0 con riporto di 1.

I riporti vanno considerati nella somma, come si fa in decimale con le unita', decine, ecc.

Se attendi qualcuno di piu' esperto magari te lo spiega meglio e piu' tecnicamente. :)

Modificato: da Gabriele Riva
Aggiunto tag "Code"
Link al commento
Condividi su altri siti

christian ceruti

sembra funzionare... grazie! :thumb_yello:

Public Function crc_modbus(ByVal s As String) As byte

somma = 0

lenght = Len(s) / 2

For i = 1 To lenght

hex_byte = CLng("&H" & Mid(s, i * 2 - 1, 2))

somma = somma + hex_byte

If somma > 255 Then somma = somma - 256

Next

somma = 256 - somma

crc_modbus = somma

End Function

Link al commento
Condividi su altri siti

christian ceruti

funziona perfettamente grazie!

Public Function crc_modbus(ByVal s As String) As Byte

somma = 0

lenght = Len(s) / 2

For i = 1 To lenght

hex_byte = CLng("&H" & Mid(s, i * 2 - 1, 2))

somma = somma + hex_byte

If somma > 255 Then somma = somma - 256

Next

somma = somma Xor &HFF

somma = somma + 1

crc_modbus = somma

End Function

Link al commento
Condividi su altri siti

  • 1 year later...

Salve, ho un problema analogo a questo già risolto, scrivo qui per non aprire un'altra discussione. Premetto che non molta eperienza con le reti MODBUS.

Devo pilotare un passo passo con un PLC inviando comandi in modbus.

Il passo passo ha già l'azionamento predisposto con collegamento RS485 e utilizzando il software a corredo, tramite PC, non c'è nessun problema, collego la mia USB ad un convertitore USB - RS232 poi ad un convertitore RS232-RS 485 e poi all' azionamento poi da PC posso comandarlo con l'interfaccia già fatta ad hoc.

Usando il PLC , finchè invio comandi "fissi" tipo Servo-On Servo-Off oppure Azzeramento o Richiesta posizione tutto a posto,

il "pacchetto" comprende anche un software di traduzione che mi indica la stringa da spedire all'azionamento per il relativo comando che mi serve.

Es:

Header (sempre lo stesso)-Slave-Comando(42=ServoEnable)-Dato(1 o 0)-CRC(Nota dolente)-Coda(sempre la stessa)

AACC 00 2A 01 AF60 AAEE

Io non faccio altro che scrivere su dei data memory i valori che mi restituisce il software ( AACC002A01AF60AAEE )

e poi li invio all'azionamento tramite RS485 e fin qui tutto OK.

Il mio problema è che se ho necessita di muovere il motore di una distanza variabile devo scrivere il CRC corretto in base ai valori inseriti nella stringa e non avendo capito il modo corretto per calcolarlo non sono nemmeno in grado di scrivermi un prg ladder per poterlo calcolare.

Girando in rete ci sono molti esempi ho addirittura trovato questo sito:

http://www.lammertbies.nl/comm/info/crc-calculation.html

se metto la parte centrale della stringa Slave - Comando - Dato (002A01) mi restituisce il CRC corretto, anche se invertito (60AF), ho provato con altri comandi e i CRC tornano tutti (confrontati con il software di "traduzione")

Il manuale del azionamento mi riporta questo

2) ‘X16+X15+X2+1’of CRC-16-IBM

unsigned short CalcCRCbyAlgorithm(unsigned char* pDataBuffer, unsigned long usDataLen)

{

// Use the Modbus algorithm as detailed in the Watlow comms guide

const unsigned short POLYNOMIAL = 0xA001;

unsigned short wCrc;

int iByte, iBit;

/* Initialize CRC */

wCrc = 0xffff;

for (iByte = 0; iByte < usDataLen; iByte++)

{

/* Exclusive-OR the byte with the CRC */

wCrc ^= *(pDataBuffer + iByte);

- 9 -

/* Loop through all 8 data bits */

for (iBit = 0; iBit <= 7; iBit++)

{

/* If the LSB is 1, shift the CRC and XOR the polynomial mask with the CRC */

// Note - the bit test is performed before the rotation, so can't move the << here

if (wCrc & 0x0001)

{

wCrc >>= 1;

wCrc ^= POLYNOMIAL;

}

else

{

// Just rotate it

wCrc >>= 1;

}

}

}

return wCrc;

}

purtroppo non riesco a capirlo e comunque dovrei tradurlo in ladder per il PLC.

Magari è più complesso di quello che credo ma se qualcuno potesse darmi qualche dritta ne sarei molto grato.

Saluti e Buon anno a tutti

Yuri

Link al commento
Condividi su altri siti

Mi sto troppo arenando.

Qualcuno può visulaizzarmi i passaggi per calcolare il CRC di 002A01 so già che deve tornare 60AF ma non riesco a capire come arrivarci

Link al commento
Condividi su altri siti

In che linguaggio lo vuoi? C?

Questo è in visual basic

'-------------------------------------------------

Public Function CRC(buf() As Byte, lbuf As Integer) As Integer

'-------------------------------------------------

' ritorna il CRC MODBUS dei primi lbuf byte di un buffer "buf" (buf è la stringa di byte completa)

Dim CRC1 As Integer

CRC1 = &HFFFF

For i = 0 To lbuf - 1 Step 1 '

CRC1 = CRC1 Xor buf(i)

For j = 0 To 7 Step 1

k = CRC1 And 1

CRC1 = ((CRC1 And &HFFFE) / 2) And H7FFF

If k > 0 Then CRC1 = CRC1 Xor &HA001

Next j

Next i

CRC = CRC1

End Function

Modificato: da NoNickName
Link al commento
Condividi su altri siti

Scusa, intendevo a livello di bit tipo

002A01= 0000 0000 0010 1010 0000 0001

e il polinomio CRC è X16+X15+X2+1 che se non sbaglio è 1010 0000 0000 0001

vorrei "vedere" il passaggio per arrivare a 60AF = 110000010101111 se ho ben capito si deve uno XOR ma non ho capito quanti zeri aggiungere e come shiftarli.

Link al commento
Condividi su altri siti

Ma in che linguaggio lo devi scrivere, me lo dici o te lo tieni per te? E' la terza volta che te lo chiedo.

Nessun numero, neanche binario, inizia con zero. Al più un byte può avere il primo nibble uguale a zero.

E comunque il tuo documento è corrotto.

Modificato: da NoNickName
Link al commento
Condividi su altri siti

E comunque il tuo documento è corrotto.

NNN è un file PDF e si apre regolarmente.

Nel documento il numero da "dividere" inizia per 1 il mio inizia con 0 e non ho ben capito, nel mio caso, cosa devo fare

Guarda che anche gli esempio del documento iniziano con "0". :)

Il documento è chiarissimo, forse il problema è tuo. Come ti ha già ripetutamente chiesto NNN, se non comunichi il linguaggio che vuoi usare non ti si può aiutare. :(

Link al commento
Condividi su altri siti

NNN è un file PDF e si apre regolarmente.

Adesso si apre. Boh.

Guarda che anche gli esempio del documento iniziano con "0".

Giusto per chiarire: 00000001 = 1. I cosidetti "leading zeroes" vengono messi solo per giustificare le colonne e per esemplificare il funzionamento delle tabelle di verità, o anche per chiarire la lunghezza della parola di bit che si va a confrontare.

Link al commento
Condividi su altri siti

Scusate , il problema è effettivamente mio , vediamo se innanzitutto mi capisco io.

purtroppo non riesco a capirlo e comunque dovrei tradurlo in ladder per il PLC.

Devo scriverlo in ladder o meglio devo far fare il calcolo ad un PLC Omron Cj2 senza scheda SCU, adesso sto inviando delle stringhe finite già comprese di CRC invece dovrei fare in modo di carlcolarlo in base a dei valori che non sono fissi ma variabili, di conseguenza mi variano il CRC

Il documento è chiaro, ma c'è un passaggio nel mio calcolo che non mi torna vediamo se riesco a spiegrmi

0000 0000 0010 1010 0000 0001 Questo è 002A01 in binario , 1010 0000 0000 0001 = A001 è il polinomio per il calcolo

perciò

0000 0000 0010 1010 0000 0001 devo aggiungere 15 zeri

diventa

000000000010101000000001000000000000000 se faccio lo xor

1010000000000001 devo togliere i primi 8 zeri percè il dividendo comici per 1 perciò

10101000000001000000000000000 ecco adesso il dubbio, dovrei "far scendere" 8 zeri oppure comicio il calcolo da qui???? cioè con

1010000000000001----------------------2 0 presi da quelli aggiunti?

Purtroppo non sono praticissimo di MODBUS e i calcoli in binario a mano non li faccio più da molto

però se veglio scrivere il calcolo in ladder devo prima capire bene i passaggi da effettuare altrimenti non ci riesco di sicuro

Scusate ancora , stasera potrò dedicare più tempo a questa cosa e magari spiegarmi ancora meglio o meglio ancora risolvere il problema

Link al commento
Condividi su altri siti

Ora sono io a non capire.

Quali sono i numeri con cui devi fare lo XOR? Non conosco il tuo PLC, ma presumo che le costanti le puoi scrivere anche in esadecimale e non solo in binario.

Certo che farsi il calcolo del CRC, anche con il semplice XOR, non è semplice in ladder. Quando lo feci per lo S7-226 usai AWL, poi usai la traduzione automatica in ladder per mettere il file di esempio. :)

Link al commento
Condividi su altri siti

1010 0000 0000 0001 = A001 è il polinomio per il calcolo

Non è un polinomio, è un numero.... Ma da dove salta fuori questo numero?

0000 0000 0010 1010 0000 0001 devo aggiungere 15 zeri

Partiamo da qua. Spiegami questo passaggio...

Link al commento
Condividi su altri siti

Prima di tutto ringrazio comuque per la pazienza.

Non è un polinomio, è un numero.... Ma da dove salta fuori questo numero?

vero non è un polinomio ma da manuale, come ripotavo nel mio primo post del 2/01/2012 il polinimio è:

2) ‘X16+X15+X2+1’of CRC-16-IBM

unsigned short CalcCRCbyAlgorithm(unsigned char* pDataBuffer, unsigned long usDataLen)

{

// Use the Modbus algorithm as detailed in the Watlow comms guide

const unsigned short POLYNOMIAL = 0xA001;

unsigned short wCrc;

Partiamo da qua. Spiegami questo passaggio...

Questo passaggio l'ho letto nel documento che ho allegato ed in altri che ho trovato,

Riporto dal testo del documento:

Il polinomio generatore (0x1a) è

lungo 5 bit, quindi il resto e' di quattro bit. Aggiungo quindi quattro bit a 0:

1010 0011 1010 1100 0000

il "mio polinomio" generatore è 16 bit perciò aggiuno 15 zeri.

Link al commento
Condividi su altri siti

Per Livio, ho trovato chi ha già fatto il grosso del lavoro dai "colleghi" di MrPLC

http://forums.mrplc.com/index.php?showtopic=6919

però per modificarlo come seve a me devo capire come funziona il sistema.

Ora ho metà di oggi e (bambina permettendo) metà di domani per rileggermi tutto e capire cosa non capisco.

Modificato: da Yurigas
Link al commento
Condividi su altri siti

il "mio polinomio" generatore è 16 bit perciò aggiuno 15 zeri.

:senzasperanza:

0x1A = 11010 che sono 5 bit.

e adesso aggiungendo 4 bit come dice lì, come si arriva ad una parola di 16 bit?

Link al commento
Condividi su altri siti

Scusami,

ti riporto ancora una volta ciò che ho scritto nel manuale del azionamento che devo controllare

2) ‘X16+X15+X2+1’of CRC-16-IBM

unsigned short CalcCRCbyAlgorithm(unsigned char* pDataBuffer, unsigned long usDataLen)

{

// Use the Modbus algorithm as detailed in the Watlow comms guide

const unsigned short POLYNOMIAL = 0xA001;

unsigned short wCrc;

0xA001 = ?

Link al commento
Condividi su altri siti

Crea un account o accedi per commentare

Devi essere un utente per poter lasciare un commento

Crea un account

Registrati per un nuovo account nella nostra comunità. è facile!

Registra un nuovo account

Accedi

Hai già un account? Accedi qui.

Accedi ora
×
×
  • Crea nuovo/a...