Recommended Posts

I started a new project, completely blank, using a new Modbus capture device.  My channel's I/O Type is Read Holding Float R Words.  If I select the channel to be 1, I don't get accurate data in the "Watch" window.  If I have my channel set to 0, I get what I would expect.  If I now change my channel to 40001, the data streams as what I would expect and if I change my channel back to 1, it remains accurate.  Is this by design?

Share this post

Link to post
Share on other sites

Yes, this is expected.  It has to do with how Modbus addressing works and is a side effect of a poor choice they made when they first created Modbus.  At that time they for some reason thought that electricians, who were the primary people installing PLCs at the time (like 40+ years ago), could not count from 0 like programmers do.  Silly really as all the electricians I know are quite smart.  So, even though Modbus internally numbers everything from 0, they started addresses at 1.  On top of that, they put a digit in the 10,000's place to indicate the type of register.  So 40,001 is the first Holding register, and 30,001 is the first Input Register.  10,000 is input status and 0 is coils.  I don't know why they skipped the 20,000 range.

Anyhow, when you ask for 40,001, what actually is put in the Modbus query is 0.  And when you ask for 40,184, what actually gets asked for is 183.  This was all fine for a while, but then PLC's got fancy enough that they needed more than the 9,999 register limit of this notation.  Modbus itself allows for 65336 registers in the protocol, but the notation was limiting it to 9999.  So, manufacturers started simply documenting registers the way it is in the Modbus packet instead of this arbitrary notation.  So, 0 is 0, 1 is 1, and 65535 is 65535.
Nowadays the problem is that some device manufactures document their hardware using the 40,001 notation, and others use the 0 indexed notation.  And yet others just do it completely wrong, using 40,001 notation but actually keeping 40,001 in the packet, or using 0 indexed, but subtracting 1.  Those are rarer fortunately.
DAQFactory tries to figure this out for you, but doesn't always do the best job.  Basically, until you read a register in the 30,000-50,000 range, it will assume that the channel # you ask is exactly how it should go out to the device.  So, 1 is 1, 5, is 5, 0 is 0.  Once you read something in the 30,000-50,000 range, it assumes you are going to stick with that notation, so 40,001 becomes 0; 40,002 becomes 1, etc.  It just strips the 10,000's place and subtracts 1.  The type of register is determined by the I/O type.  Now the problem is if you go back and ask for Channel #1, it is still doing this, so 1 becomes 0 now instead of 1.  
This is why it didn't work until you read 40,001, and then did work after that.  The register is actually at 0, but you tried to read 1, which is invalid for a float that requires 2 registers and starts at 0.  Once you read 40,001, DAQFactory requested register 0, the correct register, even when you subsequently requested 1.
The bottom line is that you have to choose which notation you want to use.  It is totally a documentation thing and has nothing to do with the actual protocol and communications or the device, as that is always using 0 indexed register numbers.  I personally do everything in 0 indexed notation and just translate in my head.  So when I see 40,001 I just tell DAQFactory to read register 0.  And when I see 43,483 I put in 3482.  I don't really ever put use the 40,001 notation, even when the device's docs are provided using those numbers.

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