Reading ASCII and RTU Modbus Devices via RS232, RS422, RS485 or TCP/IP

How to read data from Modbus devices over serial (RS232, RS422, RS485) and network (TCP/IP) lines, using the Windmill COMIML software as an example.

In Modbus systems, a master or client initiates queries to a slave or server (the measurement device). The slave/server responds either by supplying data or taking an action. Slaves only respond to queries from the master.

Windmill supports any mix of digital and analogue inputs and outputs. These can be distributed across any set of Modbus slave devices. You can configure the slave device address and the parameter number (register number) for each channel individually.

The Modbus protocol defines two modes of transmission: ASCII and RTU (Remote Terminal Unit). Windmill supports both modes.

In ASCII mode each 8-bit byte in a message is sent as two ASCII characters. It allows intervals of up to 1 second between characters, without causing an error. Messages start with a colon and end with a Carriage Return followed by a Linefeed. The advantages of ASCII mode is that it allows intervals of up to a second to occur between characters without causing an error. ASCII mode is only used over serial (RS232, RS422 and RS485) lines.

The RTU mode uses binary coding. Each 8-bit byte in a message contains two 4-bit hexadecimal characters. Greater character density allows better data throughput than ASCII for the same baud rate. Each message is transmitted in a continuous stream. The final part of a serial RTU message is a cyclic redundancy check, CRC. This calculates its value based on all earlier bytes in the message, it then adds its 2 bytes into the message. The computer therefore knows when it has received a corrupted message and can ask the instrument to resend its data. RTU mode is used over serial and network (TCP/IP) lines

Modbus and RS232, RS422 and RS485 | Modbus and TCP/IP: Ethernet/Internet | Transferring 4-Byte Values: 32-bit Integers and Floating Points | Convert Decimal to Hexadecimal | Parsing Messages



Modbus messages sent over Serial Lines: RS232, RS422 and RS485

Each message comprises four parts: device address, function code, data, error check.

The Device or Slave Address identifies your instrument. It contains one byte of information. In ASCII it is coded with two hexadecimal characters, in RTU with one byte. Valid addresses are between 0 and 247.

The Function Code specifies the type of message. It contains one byte of information. In ASCII it is coded with two hexadecimal characters, in RTU with one byte.


Modbus Com Port Settings

ASCII
Start Bit = 1
Data Bits=7
If Parity is even or off then Stop Bits = 1
If Parity is none then Stop Bits = 2

RTU
Start Bit = 1
Data Bits=8
If Parity is even or off then Stop Bits = 1
If Parity is none then Stop Bits = 2


Modbus Serial Message Settings when using ComDebug

You can use the Windmill ComDebug software to enter Modbus settings and send test messages.

In ComDebug's Message or Terminal screen use the Prompt Grid to send commands and data to your Modbus device. If you are sending binary rather than ASCII messages, either type directly into the Hex column or use the NumLock key on the keyboard to enter decimal addresses, codes, etc. Address 1, for example, would be shown as Char 001 and Hex 01.

Modbus input registers commonly start counting at 40001; these can only be read. They are addressed with addresses starting at 0. You may need to subtract 40001 from the register number to find the starting address. (If your input register number has less than 5 digits, just subtract 1. For example, Register 1 is Address 0.) Use code 04 to read an input register.

Similarly holding register numbers start at 30001. This is really register 0001 (address 0) and is read using Modbus function code 03.

The holding register comprises two bytes and may be used to return measured values such as temperature. A holding register can be read or written to. To write a value to an analogue output holding register, use the Modbus function code 06.

If your input or holding register address starts with a 6, for example 62592, convert this number to hex. You can use the converter at the bottom of this page. 62592, for example, converts to F480 and so you would enter F4 into the Hex column of Byte 3 and 80 into the Hex column of Byte 4.

To Read a Single Modbus Register

Byte 1 = (slave) device address
Byte 2 = Modbus function code, eg:
03 (read holding register) or
04 (read input registers)
Byte 3 = msb of register: starting address
Byte 4 = lsb of register: starting address
Byte 5 = msb of number of bytes to read: normally 0
Byte 6 = lsb of number of bytes to read: for example 2
Byte 7 = CRC: use the CRC menu

Modbus Settings: Reading Registers from Slave Device
Entering Modbus serial settings into ComDebug:
Reading Registers from Device 1

The Serial Reply Comprises

Byte 1 = device address
Byte 2 = function code
Byte 3 = number of bytes read
Byte 4 = 1st word, msb
Byte 5 = 1st word, lsb
Byte 6 = 2nd word, msb
Byte 7 = 2nd word, lsb
   :
   :
Byte n = CRC

To Write to a Register over Serial Communications

Byte 1 = device address
Byte 2 = Modbus function code 06
Byte 3 = address of register, msb
Byte 4 = address of register, lsb
Byte 5 = value of word to write, msb
Byte 6 = value of word, lsb
Byte 7 = CRC

The Serial Reply Comprises

Byte 1 = device address
Byte 2 = Modbus function code 06
Byte 3 = address of register, msb
Byte 4 = address of register, lsb
Byte 5 = value of word written, msb
Byte 6 = value of word written, lsb
Byte 7 = CRC

(In ComDebug you use the Outputs menu to choose the correct format in which to send data values. For floating point and 32-bit values see Transferring 4-Byte Values below.)



Modbus messages sent over TCP/IP: Ethernet/Internet

Modbus TCP/IP Port Settings

This sections tells you how to communicate with a Modbus device over TCP/IP using the free ComDebug program. However, the settings apply to other software as well.

In ComDebug, edit an existing instrument file (or create a new one) and choose TCPIP Communications.

The master and slave must use the same port, usually port 502.

TCP/IP
Configuring the free Windmill ComDebug software to log from a TCP/IP device
For full details on what to enter here see the Understanding TCP/IP page.


Modbus TCP/IP settings
Entering Modbus TCP/IP settings

Using ComDebug to send a message via TCP/IP

Use the prompt grid in ComDebug's Terminal screen to send commands and data to your Modbus device. Either type directly into the Hex column or use the NumLock key on the keyboard to enter decimal addresses, codes, etc. Address 1, for example, would be shown as Char 001 and Hex 01.

Each message comprises three parts: modbus application header, function code and data. When more than one byte specifies an item, the most significant byte is sent first.

The Modbus Application Header (MBAP) is a 7-byte header at the start of the message.
The Function Code specifies the type of message. It contains one byte of information (Byte 8).

Bytes 1 & 2 are a transaction identifier, usually 0 0, but may be different depending on how the system has been set up.
Bytes 3 & 4 are a protocol identifier, always 0 0.
Bytes 5 & 6 identify the number of bytes to follow. Byte 5 is always 0 as messages are shorter than 256 bytes
Byte 7 identifies a unit. It is used when the Modbus device is actually several devices behind a gateway or bridge, and specifies the Slave address of one of those devices.
Byte 8 is the Modbus function code, eg:
03 (read holding register)
04 (read input registers)
06 (write holding register)
Byte 9 is the msb of register: starting address
Byte 10 is the lsb of register: starting address
Byte 11 is the msb of number of bytes to read or write: normally 0
Byte 12 is the lsb of number of bytes to read or write: for example 2

As with serial Modbus communication, the function code 03 reads the holding register. This comprises two bytes. You can read or write to a holding register. The function code 04 reads an input register; this can only be read. It may be used to return measured analogue input values such as temperature. The function code 06 writes an output value to a holding register.

(In ComDebug you use the Outputs menu to choose the correct format in which to write data values to the holding register with Modbus command 06. For floating point and 32-bit values see Transferring 4-Byte Values below.)

Modbus input registers commonly start counting at 40001. They are addressed with addresses starting at 0. You need to subtract 40001 from the register number to find the starting address. If your register address starts with a 6, for example 62592, convert this number to hex. You can use the converter at the bottom of this page. 62592, for example, converts to F480 and so you would enter F4 into the Hex column of Byte 3 and 80 into the Hex column of Byte 4. Similarly holding register numbers start at 30001. This is really register 0001 (address 0) and is accessed using Modbus function code 03.

The Reply to a Read Input Register Request (TCP/IP) Comprises

Byte 1 = function code (04)
Byte 2 = number of bytes read 
Byte 3 = 1st word, msb
Byte 4 = 1st word, lsb
Byte 5 = 2nd word, msb
Byte 6 = 2nd word, lsb
etc


Transferring 4-Byte Values: 32-bit Integers and Floating Point Numbers

The above discussions comply to the Modbus standard which uses 2-byte register values, with the most significant byte preceding the least significant byte. There is no guidance in the standard for 4-byte values - signed and unsigned 32-bit values and floating point numbers. Manufacturers of Modbus devices can therefore choose for themselves in which order the bytes need transmitting.

If we think of a 4-byte number as comprising bytes A, B, C and D with A as the most significant byte and D as the least significant, there are four ways a manufacturer could order the byte transfer.

Standard Sequence: ABCD
Byte Swap Sequence: BADC
Word Swap Sequence: CDAB
Byte and Word Swap Sequence:DCBA

In ComDebug use the Outputs menu to choose in which format to send data values.



Convert Decimal to Hexadecimal

Insert decimal number (must be an integer):

Hexadecimal result:



Parsing Messages

There are two steps to parsing the data:

  1. Locate the data in which you are interested
  2. Extract the data

Locating the Data

You can locate the data by:

  1. Searching for specific characters in the message string. The next action occurs after all the specified characters
  2. Ignoring characters until one of the ones in which you are interested appears. The next action occurs on any one of the specified characters
  3. Ignoring a number of characters in the message string.

At first glance methods 1 and 2 seem to do the same job. However, when you search for characters the next action occurs AFTER the searched for characters. When you ignore characters the next action occurs ON the specified character. So if you searched for a + sign you would not be able to extract it, but if you ignored all characters until the + sign you would. Also, a search will look for the entire string specified (eg "abc"), whilst ignoring characters will stop at any of the characters specified (eg "a" or "b" or "c"). Use the NonPrint menu to enter characters like carriage returns.

Be aware that with instruments that constantly send data Windmill will not know where the beginning of the message is. So it's no use starting by ignoring a number of characters in these cases..

Extracting the Data

Once you've located the data you need to extract it. There are several ways to do this, the two most commonly used are:

  1. Extract until a specified character occurs. The next action occurs on this character.
  2. Extract the next so many characters.

Extract until means COMIML or ComDebug will extract values until it finds any one of the characters specified. The next command then acts ON this character: it will not be extracted.

For full details of all the extract options, see the ComDebug Help menu.

For more details see Parsing Messages.



Related Topics

Need more help? See Getting Started with ComDebug and COMIML.