DL05 and GS4 Modbus ASCII Issue

Join Date
Sep 2008
Location
Alberta
Posts
40
I have had to write my own Modbus ASCII "driver" for an old DL05 talking to a GS4. I am using the Modbus Slave program for testing. A PID is putting out data in decimal numbers (0-9) (I know that the PLC memory is really native BCD) and I am taking that and plugging it into my to my Modbus "driver". It works.. sort of. The Modbus Slave which I assume is going to be the same as the GS4, takes my decimal values and converts them to hex when receiving and stops accepting values in certain ranges.

I am incrementing the data by 1 and transmitting to test but this is the problem I get:

Slave stops accepting over a range of 216 to 312 (and other ranges too)
Rx:001995-3A 30 31 30 36 32 30 30 31 30 30 44 37 30 31 0D 0A
Tx:001996-3A 30 31 30 36 32 30 30 31 30 30 44 37 30 31 0D 0A
Rx:001997-3A 30 31 30 36 32 30 30 31 30 30 44 38 30 30 0D 0A
Tx:001998-3A 30 31 30 36 32 30 30 31 30 30 44 38 30 30 0D 0A
Stops:
Rx:001999-3A 30 31 30 36 32 30 30 31 30 30 44 39 0F 46 0D 0A
Rx:002000-3A 30 31 30 36 32 30 30 31 30 30 44 41 0F 45 0D 0A
Rx:002001-3A 30 31 30 36 32 30 30 31 30 30 44 42 0F 44 0D 0A
etc.
Rx:002092-3A 30 31 30 36 32 30 30 31 30 31 33 36 0A 31 0D 0A
Rx:002093-3A 30 31 30 36 32 30 30 31 30 31 33 37 0A 30 0D 0A
Start again:
Rx:002094-3A 30 31 30 36 32 30 30 31 30 31 33 38 39 46 0D 0A
Tx:002095-3A 30 31 30 36 32 30 30 31 30 31 33 38 39 46 0D 0A

So I don't know how or can't find on this old DL05 with no iBoxes how to convert the decimal values to equivalent hex values before running it through the "driver".

Also, I suspect there's no way on the GS4 that it would accept decimal values and NOT turn them into hex.

Help anyone?
 
I am coming in from left field, "what's Modbus/DL05/GS4?", ASCII bit-head here, so be kind if I am only adding to the noise here, but when I see this:


3A 30 31 30 36 32 30 30 31 30 30 44 37 30 31 0D 0A
I immediately see
:0106200100D701<CR><LF>
so when I see this:
3A 30 31 30 36 32 30 30 31 30 31 33 36 0A 31 0D 0A
in the same context, I interpret it as
:010620010136<LF>1<CR><LF>
and then wonder where that linefeed (<LF>; 0A) in the middle comes from, and wonder if it messes with the line termination, especially if it is ever preceded by a carriage return (<CR>; 0D)


Is that supposed to be 41 i.e. the ASCII 'A' character, as it would be in an ASCII representation of the hexadecimal digits of the number?
 
Modbus ASCII protocol. Yes you dissected that quite nicely. The OA 31 is the LRC checksum at the end of Tx. Have you got some experience with LRC checksum calcs because that's where I think the problem is. The method I use to calc the LRC is to add up the individual bytes then XOR with FF and add 1 and ignore the MSB (if there's a carry, more than 8 bits). Then encode that to ASCII. That's supposed to be the checksum.

Page 5-15 of this manual explains the protocol structure. It's the ASCII example - the first one on the page:
https://cdn.automationdirect.com/static/manuals/gs4m/ch5.pdf
 
Last edited:
[ahh, checksum, let me check that ;)]


Again from left field, but if I were building the ASCII representation of a VALUE in a 16-bit integer, then I would do this (conceptually, ugly yes, in no particular language, where Fh and F1h are hexacimal constants meaning decimal 15 and 241, respectively):


Code:
MASK = 0h;
STRING_TO_SEND = '';

TOP:

  MULT = MASK + 1h;
  MASK = MULT * Fh;

  LOW_4_BITS := AND(VALUE, MASK) / MULT;


  ASCII_CODE = 30h+LOW_FOUR_BITS);
 
  IF (GREATER_THAN(LOW_4_BITS, 9h)) THEN
     ASCII_CODE = HEX_ASCII_CODE + 7h;
  ENDIF
 
  STRING_TO_SEND = CONCATENATE(ASCII(ASCII_CODE), STRING_TO_SEND);

  IF (LESS_THAN(MULT, 1000h)) THEN
     GOTO TOP
  ENDIF
 
Well, the examples in that chapter 5 make no sense, so I am still trying to decode what a Modbus ASCII LRC actually is, but in any case I am sure that you should not be sending 0Dh as a hex character representing a nibble of the LRC, but ASCII character 'D' i.e. ASCII code 44h.


Because what if the LRC comes out to DAh? then you would be sending codes 0Dh 0Ah i.e. the message termination i.e. <CR><LF>,
 
Last edited:
Skip all the XOR stuff, just subtract each code cumulatively from 0 and the low byte gives the same result:


Code:
### Python test script:




% cat lrc_check.py 
 
def iso1155(lrcsum): return (((lrcsum & 0xff) ^ 0xff) + 1) & 0xff
def iso1155_alternate(lrcsum): return (-lrcsum) & 0xff

def iso1155_compare(lrcsum):
  i1155,i1155_alt = iso1155(lrcsum),iso1155_alternate(lrcsum)
  if i1155 == i1155_alt: return None
  return dict(lrcsum=lrcsum,i1155=i1155,i1155_alt=i1155_alt)

list_compare  = [rtn for rtn in map(iso1155_compare,range(0x10000)) if not (None is rtn)]

print(dict(list_compare=list_compare))
assert not list_compare
 print('The result is as expected:  (((lrcsum & 0xff) ^ 0xff) + 1) & 0xff) is equivalent to ((-lrcsum) & 0xff)')




### Execute the Python code:


 % python lrc_check.py 


{'list_compare': []}
 The result is as expected:  (((lrcsum & 0xff) ^ 0xff) + 1) & 0xff) is equivalent to ((-lrcsum) & 0xff)
 
Can you not just use modbus rtu? The dl05 should support being modbus rtu master on port2. The gs4 should support being modbus rtu slave.
 
STEM's code is basically there: it calculates the LRC value correctly; the only thing failing is the conversion of high nibbles greater than 9 to their ASCII code; i.e. if it calculates an LRC of A0h, it becomes ASCII codes 0Ah and 30h in the message LRC, instead of 41h and 30h. The code already converts low nibbles greater than 9, so I suspect it is a simple oversight and easily fixed.

I used Python to code the algorithm to calculate the LRC. The python script is in the attached .ZIP; the results are below. The last line, in blue bold italics, is a sample ASCII message from the Modbus Wiki here.





% python lrc_check.py



{'list_compare': []}
The result is as expected: (((lrcsum & 0xff) ^ 0xff) + 1) & 0xff) is equivalent to ((-lrcsum) & 0xff)


{'URL': 'https://en.wikipedia.org/wiki/Modbus#Modbus_ASCII_frame_format_(primarily_used_on_7-_or_8-bit_asynchronous_serial_lines)', 'raw': ':F7031389000A60\r\n', 'doc_ascii': '\nTX:-3A 46 37 30 33 31 33 38 39 30 30 30 41 36 30 0D 0A'}


{'LRC': '01', 'LRCASCII': '30 31', 'lcrsum': 255, 'rawline': 'Rx:001995-3A 30 31 30 36 32 30 30 31 30 30 44 37 30 31 0D 0A'}
{'LRC': '01', 'LRCASCII': '30 31', 'lcrsum': 255, 'rawline': 'Tx:001996-3A 30 31 30 36 32 30 30 31 30 30 44 37 30 31 0D 0A'}
{'LRC': '00', 'LRCASCII': '30 30', 'lcrsum': 256, 'rawline': 'Rx:001997-3A 30 31 30 36 32 30 30 31 30 30 44 38 30 30 0D 0A'}
{'LRC': '00', 'LRCASCII': '30 30', 'lcrsum': 256, 'rawline': 'Tx:001998-3A 30 31 30 36 32 30 30 31 30 30 44 38 30 30 0D 0A'}
{'LRC': 'FF', 'LRCASCII': '46 46', 'lcrsum': 257, 'rawline': 'Rx:001999-3A 30 31 30 36 32 30 30 31 30 30 44 39 0F 46 0D 0A'}
{'LRC': 'FE', 'LRCASCII': '46 45', 'lcrsum': 258, 'rawline': 'Rx:002000-3A 30 31 30 36 32 30 30 31 30 30 44 41 0F 45 0D 0A'}
{'LRC': 'FD', 'LRCASCII': '46 44', 'lcrsum': 259, 'rawline': 'Rx:002001-3A 30 31 30 36 32 30 30 31 30 30 44 42 0F 44 0D 0A'}
{'LRC': 'A1', 'LRCASCII': '41 31', 'lcrsum': 95, 'rawline': 'Rx:002092-3A 30 31 30 36 32 30 30 31 30 31 33 36 0A 31 0D 0A'}
{'LRC': 'A0', 'LRCASCII': '41 30', 'lcrsum': 96, 'rawline': 'Rx:002093-3A 30 31 30 36 32 30 30 31 30 31 33 37 0A 30 0D 0A'}
{'LRC': '9F', 'LRCASCII': '39 46', 'lcrsum': 97, 'rawline': 'Rx:002094-3A 30 31 30 36 32 30 30 31 30 31 33 38 39 46 0D 0A'}
{'LRC': '9F', 'LRCASCII': '39 46', 'lcrsum': 97, 'rawline': 'Tx:002095-3A 30 31 30 36 32 30 30 31 30 31 33 38 39 46 0D 0A'}
{'LRC': '60', 'LRCASCII': '36 30', 'lcrsum': 416, 'rawline': 'TX:-3A 46 37 30 33 31 33 38 39 30 30 30 41 36 30 0D 0A'}
 
You guys are great!

Can't use Modbus RTU. This is a conversion from an old Hitachi SJ700 that used it's own proprietary command codes on ASCII 7N2. So I have to keep talking the same 19200 7N2 thing for the new VFD because of the other Hitachis. On top of it this old DL05 doesn't support the MWX command anyway. Wish it were so simple. Would have been done over a week ago.

As for the A0 nibble at the front, that's a colon and in Modbus that's the STX. The OD and OA at the end are CR and LF to finish the message. That's according to the spec and observed and tested with Modbus poll that it is correct.|

What is in between is the issue. 00 01 (30 31) is the unit address, 00 06 (30 36) is the command (write single register - 16 bits), 02 00 00 01 (32 30 30 31) is the address in the unit to write to (hex) and the next 4 are the data (hex) representing the decimal frequency (5.1 hz = 510) followed by the two nibble checksum.

I'm headed in to put what I have in. Modbus Slave shows the data but it "skips". I'm wondering if their implementation of the LRC in the VFD will do the same thing.

Thank you gents.
 
I have a ladder logic implementation of Modbus ASCII that I did for a project several years ago using a GE PLC. I'll see if I can convert it to Direct Logic and get the same result.
My rung comments from the checksum calculation are:

The checksum calculation is:
1. Add up the values represented by each pair of ASCII characters
2. Negate the sum
3. The eight least significant bits of the result are the checksum.

The reference to each pair of ASCII characters is because each 16-bit address in the PLC contains two ASCII characters.
 
As for the A0 nibble at the front, that's a colon and in Modbus that's the STX. The OD and OA at the end are CR and LF to finish the message. That's according to the spec and observed and tested with Modbus poll that it is correct.|




The 'A0' is not at the front (that's a 3A code = colon character i.e. the Modbus ASCII STX, as you note); the 'A0' I am talking about is the hexadecimal representation of the LRC you are calculating i.e. the LRC you calculate 160 decimal = A0h for this line:

  • Rx:002093-3A 30 31 30 36 32 30 30 31 30 31 33 37 0A 30 0D 0A
The ASCII codes, in hexadecimal, for that LRC (160d=A0h) are in red and blue above. They should be ASCII codes 41 and 30, which will send ASCII characters 'A' and '0' in the actual message.




  • Message ASCII frame ASCII codes:
    • 30h 31h 30h 36h 32h 30h 30h 31h 30h 31h 33h 37h
  • => ASCII message: 010620010137
  • => Integers in message: 01h 06h 20h 01h 01h 37h
  • => negative of sum is -60h = -96 decimal
  • => -96 decimal = FFA0h (two's complement)
  • => FFA0h AND FFh => A0h
  • => also 100h - 60h => A0h
  • => also 256 - 96 = 160 decimal
 
My rung comments from the checksum calculation are:

The checksum calculation is:
1. Add up the values represented by each pair of ASCII characters
2. Negate the sum
3. The eight least significant bits of the result are the checksum.




That is correct; I verified in Python that that gives the same result as e.g. here:


  • sum all hex digit pairs between : [STX] and LRC
    • e.g. so for :123456788ABC<LRC><CRLF>
      • => 12h + 34h + 56h + 78h + 9Ah + BCh
      • => 26Ah
  • Add 1
  • AND with 0FFh.
 
Now that I'm on site, I ran my code in my dev PLC plugged into the VFD and as per the very first message, it did not accept that range of numbers.

Using Modbus Poll, it accepted data in that range. Brian has got this down pat. 18 years on this program.

So I trapped the strings that worked on Modbus poll in the range that my code won't gen a proper LRC. Plus a few strings on the front and the back that do work coming into the range. As you were kind enough to gen a bit of code to check the check sum, can you tell me if your code gens up the same LRC?

By the way, this is being done in Ladder Logic on a DL05 using DirectSoft6.
My method has been to use the sum of the first 4 bytes (28h) and add it to the next two bytes of data being sent. Then I XOR the sum and add 1. I'm starting to think that I should process each byte separately every pass but not sure how to process every byte separately. What boolean logic function would gen up what I need for every byte separately and to be added together at the end?

Tx:000200-3A 30 31 30 36 32 30 30 31 30 30 44 43 46 43 0D 0A
Rx:000201-3A 30 31 30 36 32 30 30 31 30 30 44 43 46 43 0D 0A
Tx:000202-3A 30 31 30 36 32 30 30 31 30 30 45 36 46 32 0D 0A
Rx:000203-3A 30 31 30 36 32 30 30 31 30 30 45 36 46 32 0D 0A
Tx:000204-3A 30 31 30 36 32 30 30 31 30 30 46 30 45 38 0D 0A
Rx:000205-3A 30 31 30 36 32 30 30 31 30 30 46 30 45 38 0D 0A
Tx:000206-3A 30 31 30 36 32 30 30 31 30 30 46 41 44 45 0D 0A
Rx:000207-3A 30 31 30 36 32 30 30 31 30 30 46 41 44 45 0D 0A
Tx:000208-3A 30 31 30 36 32 30 30 31 30 31 30 34 44 33 0D 0A
Rx:000209-3A 30 31 30 36 32 30 30 31 30 31 30 34 44 33 0D 0A
Tx:000210-3A 30 31 30 36 32 30 30 31 30 31 30 45 43 39 0D 0A
Rx:000211-3A 30 31 30 36 32 30 30 31 30 31 30 45 43 39 0D 0A
Tx:000212-3A 30 31 30 36 32 30 30 31 30 31 31 38 42 46 0D 0A
Rx:000213-3A 30 31 30 36 32 30 30 31 30 31 31 38 42 46 0D 0A
Tx:000214-3A 30 31 30 36 32 30 30 31 30 31 32 32 42 35 0D 0A
Rx:000215-3A 30 31 30 36 32 30 30 31 30 31 32 32 42 35 0D 0A
Tx:000216-3A 30 31 30 36 32 30 30 31 30 31 32 43 41 42 0D 0A
Rx:000217-3A 30 31 30 36 32 30 30 31 30 31 32 43 41 42 0D 0A
Tx:000218-3A 30 31 30 36 32 30 30 31 30 31 33 36 41 31 0D 0A
Rx:000219-3A 30 31 30 36 32 30 30 31 30 31 33 36 41 31 0D 0A
Tx:000220-3A 30 31 30 36 32 30 30 31 30 31 34 30 39 37 0D 0A
Rx:000221-3A 30 31 30 36 32 30 30 31 30 31 34 30 39 37 0D 0A
Tx:000222-3A 30 31 30 36 32 30 30 31 30 31 34 41 38 44 0D 0A
Rx:000223-3A 30 31 30 36 32 30 30 31 30 31 34 41 38 44 0D 0A
Tx:000224-3A 30 31 30 36 32 30 30 31 30 31 43 32 31 35 0D 0A
Rx:000225-3A 30 31 30 36 32 30 30 31 30 31 43 32 31 35 0D 0A
Tx:000226-3A 30 31 30 36 32 30 30 31 30 31 43 43 30 42 0D 0A
Rx:000227-3A 30 31 30 36 32 30 30 31 30 31 43 43 30 42 0D 0A
Tx:000228-3A 30 31 30 36 32 30 30 31 30 31 44 36 30 31 0D 0A
Rx:000229-3A 30 31 30 36 32 30 30 31 30 31 44 36 30 31 0D 0A
Tx:000230-3A 30 31 30 36 32 30 30 31 30 31 45 30 46 37 0D 0A
Rx:000231-3A 30 31 30 36 32 30 30 31 30 31 45 30 46 37 0D 0A
Tx:000232-3A 30 31 30 36 32 30 30 31 30 31 45 41 45 44 0D 0A
Rx:000233-3A 30 31 30 36 32 30 30 31 30 31 45 41 45 44 0D 0A
Tx:000234-3A 30 31 30 36 32 30 30 31 30 31 46 34 45 33 0D 0A
Rx:000235-3A 30 31 30 36 32 30 30 31 30 31 46 34 45 33 0D 0A
Tx:000236-3A 30 31 30 36 32 30 30 31 30 31 46 45 44 39 0D 0A
Rx:000237-3A 30 31 30 36 32 30 30 31 30 31 46 45 44 39 0D 0A
Tx:000238-3A 30 31 30 36 32 30 30 31 30 32 30 38 43 45 0D 0A
Rx:000239-3A 30 31 30 36 32 30 30 31 30 32 30 38 43 45 0D 0A
Tx:000240-3A 30 31 30 36 32 30 30 31 30 32 31 32 43 34 0D 0A
Rx:000241-3A 30 31 30 36 32 30 30 31 30 32 31 32 43 34 0D 0A
Tx:000242-3A 30 31 30 36 32 30 30 31 30 32 31 43 42 41 0D 0A
Rx:000243-3A 30 31 30 36 32 30 30 31 30 32 31 43 42 41 0D 0A
Tx:000244-3A 30 31 30 36 32 30 30 31 30 32 32 36 42 30 0D 0A
Rx:000245-3A 30 31 30 36 32 30 30 31 30 32 32 36 42 30 0D 0A
Tx:000246-3A 30 31 30 36 32 30 30 31 30 32 33 30 41 36 0D 0A
Rx:000247-3A 30 31 30 36 32 30 30 31 30 32 33 30 41 36 0D 0A
Tx:000248-3A 30 31 30 36 32 30 30 31 30 32 33 41 39 43 0D 0A
Rx:000249-3A 30 31 30 36 32 30 30 31 30 32 33 41 39 43 0D 0A
Tx:000250-3A 30 31 30 36 32 30 30 31 30 32 34 34 39 32 0D 0A
Rx:000251-3A 30 31 30 36 32 30 30 31 30 32 34 34 39 32 0D 0A
Tx:000252-3A 30 31 30 36 32 30 30 31 30 32 34 45 38 38 0D 0A
Rx:000253-3A 30 31 30 36 32 30 30 31 30 32 34 45 38 38 0D 0A
 
Last edited:
You say this one works:

Tx:001998-3A 30 31 30 36 32 30 30 31 30 30 44 38 30 30 0D 0A

and this one doesn't work:

Rx:001999-3A 30 31 30 36 32 30 30 31 30 30 44 39 0F 46 0D 0A

Checksum for the one that works
01 + 06 + 32 + 01 + 00 + 216 = 256
Negate it to get -256 hex FF00
Take only lower byte = 00
That's 30 30 as you've shown

Checksum for the one that doesn't work
01 + 06 + 32 + 01 + 00 + 217 = 257
Negate it to get -257 hex FEFF
Take only lower byte = FF
That's 46 46, not 0F 46
 

Similar Topics

need to find C bits in the logic. They are hidden someplace! Thank you! Bob
Replies
5
Views
159
I have a c-more micro with a three digit input box on one of the screens. This is being written to a memory location in a DL05. I don't have the...
Replies
3
Views
83
Does anyone have example code of how to read/write a discrete push button from a C-More Micro to a DL05. I just bought these two items and I am...
Replies
2
Views
969
Is it correct to say that the dl05 program when uploaded does not store the current value in a v memory location? I have a customer that has one...
Replies
8
Views
3,069
Hi, I am trying to learn how to use my encoder with my PLC. I recently got a high-speed counter module (H0-CTRIO2) for my DirectLogic05 PLC. I...
Replies
5
Views
2,184
Back
Top Bottom