Email
 Microcontroller and PC projects Forum Index : Microcontroller and PC projects         Section -- Select Forum -- Off grid living and renewables   - Windmills   - Solar   - EV's Electronics and Microcontrollers   - Electronics   - Microcontroller and PC projects   - PCB Manufacturing Miscellaneous   - Other Stuff   - Site News   - Off topic archive. Classifieds   - Price Watch   - Wanted   - For Sale Guest Book   - Guest Book
 Topic: Modbus CRC.
 << Prev Page 1 2 3 of 3 Next >>
Author
 Message << Prev Topic | Next Topic >>
Turbo46
Senior Member

Joined: 24 December 2017
Location: Australia
Online Status: Offline
Posts: 200
 Posted: 10 April 2018 at 6:05pm | IP Logged Copy link to clipboard
Previously I wrote:

Quote:
 I believe that if you receive a message, then process the whole message (CRC included) with the CRC generation function, the resultant 'CRC' will be zero. That would be a simpler way of checking the validity of the message. I'm yet to try that though.

Well I have tried it with the examples in Jim's CRC calculation function and with some other real world examples and it does work eg:

test1\$ = CHR\$(01)+CHR\$(03)+CHR\$(04)+CHR\$(&H3F)+CHR\$(&H80)+CHR\$(0)+CHR\$(0)
check1\$= CHR\$(&HF7)+CHR\$(&HCF)
test1\$ = test1\$+check1\$

PRINT HEX\$(CRC(test1\$),4)

will return zero (0000)

Bill

Edited by Turbo46 on 10 April 2018 at 6:05pm

Phil23
Guru

Joined: 27 March 2016
Location: Australia
Online Status: Offline
Posts: 1536
 Posted: 15 April 2018 at 9:08am | IP Logged Copy link to clipboard
Wondering if anyone can see fault in this variation.

It returns a 2 character string that I can add to the string I'm building to sent.

Appears to test Ok, and I assume from above if I pass a response string to it, it should return "String"=Chr\$(0)+Chr\$(0).

Thanks

Phil.

PS, I am now successfully reading the first Six registers with a single request & converting them successfully.

They all reside in the address range from 30001 to 30032.

Really need a second request for the others as they are up at 30071 to 30080.
If I tried to get them all with one request the response string would be too long.

Quote:
 FUNCTION CrcStr(a\$) As String LOCAL ErrorWord% = &HFFFF, n, j, ByteVal, LSB LOCAL CrcHex As Integer FOR n = 1 TO LEN(A\$) ByteVal = ASC(MID\$(a\$, n, 1)) ErrorWord% = (ErrorWord% AND &HFFFF) XOR ASC(MID\$(a\$, n, 1)) FOR j = 1 TO 8 LSB = ErrorWord% AND &H0001 IF LSB = 1 THEN ErrorWord% = ErrorWord% - 1 ErrorWord% = ErrorWord% / 2 IF LSB = 1 THEN ErrorWord% = ErrorWord% XOR &HA001 NEXT j NEXT n CrcHex = ErrorWord% AND &HFFFF CrcStr=Chr\$(CrcHex AND &hFF)+Chr\$(CrcHex>>8)END FUNCTION

goc30
Senior Member

Joined: 12 April 2017
Location: France
Online Status: Offline
Posts: 160
 Posted: 15 April 2018 at 1:44pm | IP Logged Copy link to clipboard
Hi Phil

In the MODBUS protocol, the frames are limited to 128 bytes, including crc, which means that if a register is 4 bytes long, the slave can only send 30 registers values

Turbo46
Senior Member

Joined: 24 December 2017
Location: Australia
Online Status: Offline
Posts: 200
 Posted: 15 April 2018 at 3:05pm | IP Logged Copy link to clipboard
Hi Phil

I think it does work but you are ending up with a null string.
CHR\$(0) + CHR\$(0) = CHR\$(0) = nothing.

Bill

Edit: From what I have found the maximum Modbus frame size is 256 bytes.

Edited by Turbo46 on 15 April 2018 at 3:23pm

goc30
Senior Member

Joined: 12 April 2017
Location: France
Online Status: Offline
Posts: 160
 Posted: 16 April 2018 at 12:32am | IP Logged Copy link to clipboard
hi Turbo46

Edit: From what I have found the maximum Modbus frame size is 256 bytes.

in wikipedia for modbus they say:

Because register values are 2-bytes wide and only 127 bytes worth of values can be sent, only 63 holding registers can be preset/written at once

Wikipedia

Edited by goc30 on 16 April 2018 at 12:34am

Turbo46
Senior Member

Joined: 24 December 2017
Location: Australia
Online Status: Offline
Posts: 200
 Posted: 16 April 2018 at 8:23am | IP Logged Copy link to clipboard
Hi goc30

You may well be right! I have only had experience with small RTUs. My reference though is the 'Modicon Modbus Protocol Reference Guide' Here. Check out page 58 where it states:

'The quantity of registers to be read, combined with all other fields in the expected response, must not exceed the allowable length of Modbus messages: 256 bytes.'

Cheers
Bill

goc30
Senior Member

Joined: 12 April 2017
Location: France
Online Status: Offline
Posts: 160
 Posted: 16 April 2018 at 4:22pm | IP Logged Copy link to clipboard
Hi Turbo46

The MODBUS protocol is open, you can create your own function codes (I created some for clients). The 128-byte limit must have a historical reason (maybe for slow speed reasons)

Modicon use a partial modbus protocol (not 100% compatible, and many functions no-standards) but it is not important. They use also an ascii communication, for this they need more bytes maybe

Turbo46
Senior Member

Joined: 24 December 2017
Location: Australia
Online Status: Offline
Posts: 200
 Posted: 27 September 2018 at 6:50pm | IP Logged Copy link to clipboard
Those of you who have researched the Modbus CRC may be aware of the lookup table method of CRC calculation. It is supposed to be much faster than the above presented method. I have found some examples in Basic and converted the program to MMBasic. The program below generates the CRC lookup table rather than having to enter it manually.

 ' Modbus CRC Generation using lookup table' Test programOPTION EXPLICITDIM INTEGER crc_table(255)DIM INTEGER crc_const = &HA001DIM INTEGER i, j, kDIM STRING test1\$, test2\$, test3\$' Make the CRC table firstCRCTable' Test messagestest1\$ =  CHR\$(01)+CHR\$(03)+CHR\$(04)+CHR\$(&H3F)+CHR\$(&H80)+CHR\$(0)+CHR\$(0)'  check1\$= CHR\$(&HF7)+CHR\$(&HCF)test2\$ = CHR\$(01)+CHR\$(&H10)+CHR\$(0)+CHR\$(02)+CHR\$(0)+CHR\$(02)+CHR\$(04)+CHR\$(&H42)+CHR\$(&H70)+CHR\$(0)+CHR\$(0)'  check2\$= CHR\$(&H67)+CHR\$(&HD5)test3\$ =  CHR\$(01)+CHR\$(03)+CHR\$(00)+CHR\$(00)+CHR\$(00)+CHR\$(02)'  check3\$= CHR\$(&HC4)+CHR\$(&H0B)PRINT HEX\$(CRC16(test1\$),4)PRINT HEX\$(CRC16(test2\$),4)PRINT HEX\$(CRC16(test3\$),4)END' Generates the lookup tableSUB CRCTableFOR i = 0 TO 255  k = i'  print k  FOR j = 1 TO 8    IF k AND 1 THEN      k = k >> 1      k = k XOR crc_const    ELSE      k = k >> 1    END IF  NEXT j crc_table(i)=kNEXT iEND SUB' Calculates the Modbus CRCFUNCTION CRC16(a\$)LOCAL CRC = &HFFFF, n  FOR n = 1 TO LEN(a\$)  CRC = (crc >> 8) XOR crc_table(crc XOR ASC(MID\$(a\$, n, 1)) AND &HFF)NEXT nCRC16 = (CRC MOD 256)*256 + INT(CRC/256) MOD 256END FUNCTION

The test program above uses the same example messages as TassyJim's program above and the times to calculate the CRC with the Maximite are shown below - the first set of times are for the program above and are about 10 times faster than the second set which is from the TassyJim program.

RUN
4 msec
F7CF
6 msec
67D5
3 msec
C40B
>
> RUN
37 msec
F7CF
61 msec
67D5
32 msec
C40B
>

This should reduce the possibility of communications timeouts.

Bill

Turbo46
Senior Member

Joined: 24 December 2017
Location: Australia
Online Status: Offline
Posts: 200
 Posted: 28 November 2018 at 5:05pm | IP Logged Copy link to clipboard
I have updated my Modbus CRC program to make it more user friendly. It now returns a string value (as Phil's version of Jim's code above does) and is formatted ready to append to a message string.

 OPTION EXPLICITDIM INTEGER crc_table(255) ' lookup table for CRC generationgenCRCtable ' generate the lookup table'------------------------------------------------------------'generates a lookup table for fast crc calculationSUB genCRCtableLOCAL i%, j%, k%, crc_const% = &HA001FOR i% = 0 TO 255  k% = i%  FOR j% = 1 TO 8    IF k% AND 1 THEN      k% = k% >> 1      k% = k% XOR crc_const%    ELSE      k% = k% >> 1    END IF  NEXT j% crc_table(i%)=k%NEXT i%END SUB'' returns the CRC as a stringFUNCTION CRC16\$(a\$)  LOCAL CRC% = &HFFFF, n%  FOR n% = 1 TO LEN(a\$)    CRC% = (CRC% >> 8) XOR crc_table(CRC% XOR ASC(MID\$(a\$, n%, 1)) AND &HFF)  NEXT n%  CRC16\$ = CHR\$(CRC% AND &HFF) + CHR\$((CRC%>>8) AND &HFF)END FUNCTION'-------------------------------------------------------------

To use it: include the Subroutine and Function in your program (of course) and dimension the lookup table -

 DIM INTEGER crc_table(255) ' lookup table for CRC generation

Run the table generation subroutine early in the program, at least before using the CRC16\$() Function.

 genCRCtable ' generate the lookup table

To use the CRC\$16() function, first assemble a transmit message as a string (say TxMsg\$). Then append the CRC to the end of the message by:

 TxMsg\$ = TxMsg\$ + CRC16\$(TxMsg\$)

and transmit it.

To check that a received message (say RxMsg\$) has the correct CRC and is otherwise not corrupted, test if by:

 IF CRC16\$(RxMsg\$) = CHR\$(0) + CHR\$(0) THEN ' CRC is OK

Be aware that this routine requires a table of 256 bytes of 64 bit integers, if space is a problem and speed is not then use Phil's routine above. It is used in exactly the same way - except there is no table to initialise (and take up memory). Just use:

 TxMsg\$ = TxMsg\$ + CrcStr(TxMsg\$)

and

 IF CrcStr(RxMsg\$) = CHR\$(0) + CHR\$(0) THEN ' CRC is OK

If you want to see what is in the message as a debugging exercise you could use the subroutine below:

 SUB PrintStr(b\$)LOCAL i%  FOR i% = 1 TO LEN(b\$)    PRINT HEX\$(ASC(MID\$(b\$,i%,1)),2); ", ";  NEXT i%END SUB

For example:

 PrintStr CRC16\$(TxMsg\$)

Please consider the use of a CRC for any communication programs. I hope the above explanation will encourage some of you to do so.

Bill

PS If someone could tell me how to get colour in the code I would be grateful. I printed to RTF in MMEdit but the colour did not come across when I copied and pasted.

disco4now
Guru

Joined: 18 December 2014
Location: Australia
Online Status: Offline
Posts: 343
 Posted: 28 November 2018 at 9:09pm | IP Logged Copy link to clipboard
File/Format for TBS Forum gets it into the clipboard.
Then paste into the forum.

Phil23
Guru

Joined: 27 March 2016
Location: Australia
Online Status: Offline
Posts: 1536
 Posted: 29 November 2018 at 5:53am | IP Logged Copy link to clipboard
Missed this continuation.

No issues at present, but more efficient is better on all scores.
Can't see any reason not to use the better code.

Incidentally, the 3 meters I'm reading have performed faultlessly for the past 8 of 9 months, 6378kWh used from the grid, 2715kWh of Solar production.

Haven't got back to the updated interface of SD logging yet.
It's that WIP that gets pushed to the bottom of the list.

Cheers.

Edited by Phil23 on 29 November 2018 at 5:54am

Turbo46
Senior Member

Joined: 24 December 2017
Location: Australia
Online Status: Offline
Posts: 200
 Posted: 01 December 2018 at 2:44pm | IP Logged Copy link to clipboard
@ disco4now, thanks for that, it didn't work for me but I now realise that you have to use QUOTE instead of CODE.

@ Phil23, I did spot the deliberate mistake in your (and Jim's original) CrcStr(a\$) function. ByteVal is assigned a value in line 5 but not used, the byte value itself is calculated again and used in line 6 where ByteVal was probably meant to be used. ByteVal is redundant.

Bill