Sign in to follow this  
OkiePC

5 Digit Versus 6 Digit Modbus Addresses 400001, 40001 Or Just 1?

Recommended Posts

I am trying to communicate via Modbus TCP with a device (Automation Direct P2000 PLC) which uses 6 digit Modbus addresses.  The PLC is tag based and quite flexible in the fact that I can assign Modbus address numbers to the tags.  But when I choose a data type as 32 bit floating point, for example, their software prefixes the address with 4, and there is nothing I can do to prevent it.

 

For example I have a tank level that I have set up in the PLC software as Modbus address 15, which ends up being   400015 rather than 40015 which I think would make DAQFactory "happy" with it.  So, I get CRC errors in the comms watch window.

 

I am pretty sure that the problem is a result of the number of digits used by one device versus what DAQfactory uses.

 

I tried putting 400015 in the Channel number instead of just 15 and I then get an error "Invalid Address" in the alert window.  I also tried using 40015 as the address, and I get the CRC error.  It seems that every combination of the choices that list (4) in the dropdown for Modbus I/O type and 15 versus 40015 result in a CRC error or a timeout error.

 

I think there are quite a few devices out there that use the 6 digit addressing form so this may have been asked already.  I did search the forum briefly and did not find anything on the subject, but I would be grateful if someone can point me in the right direction to solve it. If necessary I can connect that PC to the internet and get some screen shots or some captures of the watch windows to help.

 

Thanks,

Paul

Share this post


Link to post
Share on other sites

We love Modbus, but its one major hickup is the way it does addressing.  Internally, in the actually bytes that get sent to the device, the addressing is dead simple.  Each of the four types, coil, input status, input register and holding register all have 65535 different 16 bit tag locations available.  But for some reason, when they created Modbus they decided they should create a separate addressing scheme on top of this.  This addressing is solely a documentation thing and has nothing to do with what is sent to the device.  They decided that really, no device is ever really going to need more than 9999 addresses within each type, so lets put a number in front so its obvious which type it is.  So, they put a 4 in front for holding registers, 3 for input registers, 1 for input status and left coils alone.  Why they picked 4 and 3 I don't know since the function for holding register is actually 3, and for input register is 4, which is opposite.  Now if that wasn't enough, for some reason they thought that electricians, who when Modbus was invented back in the 70's were the ones doing all the installs, couldn't count from 0 like programmers.  Why I don't know.  All the electricians I've ever met were very smart people and probably could do math in base 6 if they had to.  Anyhow, since they thought they couldn't count from 0, the offset all the addresses by 1.

 

As I said, this is solely a documentation thing.  This means that if the documentation says holding register 40,001, what is actually sent to the device is 0.  You strip off the 4, which tells you what type, and subtract 1 because of the silly offset.  40,284 becomes 283, and 30,084 becomes 83.

 

But of course, things get more complicated.  Some manufacturers use this format.  Some manufacturers specify registers in the actual number sent to the device, so instead of 40,001, they'll just specify 0.   Some manufacturers will use the 0 offset notation but actually go up into the 30,000 and 40,000 range.  In my personal opinion, unless you actually have 30,000 registers, you should never do this as it makes it confusing as to which format you are using.  Some manufacturers get it even more wrong.  I've seen several that will specify 40,001 in their documentation and what actually needs to go out to the device is 40,000.  So in this case, they forgot to strip the 4.

 

Then there are the "extended" modbus registers, which is what you are seeing.  In this case, the manufacturer wants access to more than 9999 registers, but still, for some reason, doesn't want to use the 0 index notation in their docs, possibly for consistency with other devices in their line.  In this case, they put the 4 in the 100,000's place instead of the 10,000's place.  The concept is the same though, you just strip the open 4.  400,001 just gets translated to 0, and 300,843 becomes 842.

 

Personally, after 15 years supporting DAQFactory and the huge variety of devices our customers connect to it, I think all manufacturers should just use 0 notation for all registers.  Then it is simple. 0 is 0, 5 is 5, and 2084 is 2084.  If they really want to differentiate holding registers from input registers in the register itself, add an alpha character, like H or I, or IS, or C to it, but really I think this is unnecessary as it is no longer really possible to fully specify a Modbus tag by a number anyway due to the variety of different data types, which brings up another complication when using Modbus: data type.

 

The Modbus spec defines a register as a 16 bit signed integer.  That's the only type it officially supports.  However, most manufacturers want to pass bigger values, or values with a decimal point, or even strings so they will do some tricks to make it work.  For unsigned 16 bit registers, they'll simply document it as a such and you have to tell your software to interpret the value as an unsigned 16 bit value.  But that still only gives a range of 0-65535 for the register, so sometimes, a manufacturer will combine two consecutive registers to form a single 32 bit register.  Sometimes, they'll take those same two consecutive registers and format the data as a floating point value.  And sometimes, they'll even combine 4 consecutive registers to form 64 bit values, such as double floating point.  Finally, sometimes they will use consecutive registers to form character strings, either one character per register, or more usually packed, two characters per register.  

 

So, unless the device only supports one data type, you can't document your tags with just a number.  You have to provide the data type of each register.  So, if you are going to do that, why not just specify the Modbus type, Holding register vs input register as well.

 

I'll cut my lecture short here and get to how this applies to DAQFactory: DAQFactory tries to figure out which notation format you are using.  If you have tags in the 30,001-49999 range then it will assume that all your tags use the +1 notation and will strip the 10,000's place and subtract 1 before sending that value to the device.  If there are no tags in that range, it will assume your tags are indexed from 0 and will pass the values as is directly to the device.  For manufacturers that index from 0 but actually use tags in the 30,000-49,999 range, you can do a single read of an arbitrary tag address in the 50,000+ range to force DAQFactory into 0 indexed format.  You only have to read this register once, and it doesn't matter if the device doesn't respond or generates an error because the tag doesn't exist.

 

In 15 years of DAQFactory we've only had two inquiries that I can remember about 400,001+ registers, and as it happens, both were in the last week!  Because of this, DAQFactory doesn't do any translation on values this big, and since 400,001 doesn't fit in the 65535 limit of the Modbus frame you get an error.  The solution for you is simple, do the translation manually yourself.  So, instead of putting 400,015 in the Channel table, put 14.  Do this for all addresses, even the ones in the 40,000 range.

Share this post


Link to post
Share on other sites

post-11067-0-59909300-1450393416_thumb.p

 

Well, I tried your suggestion of 14 and had no luck.  Here is a copy of the Comm Monitor I am seeing:

 

Tx: \000\004\000\014\000\002\017\217
Rx: \000\004\000\014\000\003\017\217\001
Tx: \000\004\000\014\000\002\017\217
Rx: \000\004\000\014\000\003\017\217\001
Tx: \000\004\000\014\000\002\017\217
Rx: \000\004\000\014\000\003\017\217\001
Tx: \000\004\000\014\000\002\017\217
Rx: \000\004\000\014\000\003\017\217\001
 
I am getting CRC errors no matter which version of the read float instruction i use.I tried changing the PLC project settings back and forth between word swap or not.  Maybe the screen shot and trace pasted above will help.
 
 
 

Share this post


Link to post
Share on other sites

Any chance you can send the docs over.  The response from the device is not proper Modbus as it flat out lacks a CRC, and echos back the transmit CRC with an extra value.  Do any of the standard register values work or are they all in the 400,000 range?

 

Also, a 400,000 range value should be a holding register, not an input register, so you'll need to change the I/O type to match.  The transmit should have \003 as the second item, not \004.

 

Finally, the ID of your device technically should be non-zero.  Zero is a reserved broadcast address.  The ID is determined by the D# or device number of the channel.  Most devices default to 1.  Its the first byte in the Modbus transmission.

Share this post


Link to post
Share on other sites

I had tried device number 1.  I started out with a float, thinking that I could get comms established and byte swap issues handled right off the bat.  I am going to start over with a boolean and a float and a new ctl file, and a new P2000 file and I will stay with device number 1 this time.

 

In the P2000 software (Productivity Suite) all floats get the 6 digit Modbus address prefixed with a "4".  It might be possible to add an analog input card and get a "3", but I am not sure that matters.  I had tried all of your options with a (3) or a (4) and did see some differences among some of them in the comms trace.  My screenshot was just the last one I ended up with.  After I run a trial from scratch, starting iwth a bit address, I will post back with more info.  Hopefully this thread will help future users once we get this nailed down.  I appreciate your assistance and expertise on this.  

Share this post


Link to post
Share on other sites

I'm sorry, I completely missed this: you said in your original post that you are trying to connect over Modbus TCP, but the comm log that you posted is ModbusRTU!  Are you sure you have the right protocol selected in DAQFactory?

Share this post


Link to post
Share on other sites

I started with a fresh (file New) ctl file and a boolean and a float.  Right off the bat the CRC errors stopped, but I was not getting good values back for the float, only zero until I added the bit reference.  I was able to use the Boolean tag to prove that, yes, I do need to account for the "off by 1" Modbus thing which I have had to do before.  I made my bit Modbus address 1, and had to use 0 in DAQ to get the right number.  While I was doing that, I had switched my float tag to a "test" device so I could look at only the comm trace for the bit.  So I switched my float tag back to my device "P2000" and theI/O type to "Read Holding Register" and voila, it is working now.  I have 32 bit word swap turned off in the Productivity Suite Project Properties.

 

So now I opened up my other test file and it works too.  Even though I have restarted DAQFacotry multiple times, and restarted the PC twice during my previous test, whatever I have done since then with your help has made things right with the world of Modbus TCP.  I may have at one point had the device type as Modbus RTU, but it is not now.  I am pretty sure I did not alter the device type after I copied that trace.

 

I would go ahead and call it success, and provide screenshots of how to make DAQFactory talk to P2000, but I want to go further first and make sure I can write back successfully to those channels and test all the different types I will need for this project.  I will add some conclusions later on with some details and examples when I am more confident in what I just saw a few minutes ago.

 

One thing still bugs me.  Even with my new file, I am seeing stuff in the Watch window that is old from the first original project.  How to I clear the watch list or delete variables from it?

Share this post


Link to post
Share on other sites

I still say that the post of the comm trace was ModbusRTU not ModbusTCP.  ModbusTCP pretty much always starts with \000\000\000\000\000\006 in DAQFactory.  ModbusTCP also has no CRC so you wouldn't see CRC errors ever if you were actually using TCP.

 

Just go through and delete the expressions out of the watch window.

Share this post


Link to post
Share on other sites

Okay.  I figured out I can double click the expressions and delete them one by one from the watch list.

 

You may be right about the RTU driver.  I have had so many things going on the past few days... But when I opened up that other file it worked before I changed anything.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this