Projects » MyIO » Documentation » 2.0 Interface » 2.2 modbus Protocol » 2.2a My Modbus

2.2a My Modbus-a-like interface

This is not the protocol I'm using...

After a bit of flip-flopping about using a full modbus implementation, I decided not to write my own protocol, but to use an implimentation of the modbus protocol.

This is retained as a reference to see what my thoughts were along the way.

Overview of protocol:

Frame format:

|Address | Function | Payload | chksum |
| 1 Byte | 1 Byte | X Bytes | 1 Byte |

Response from slave is in the same format, details in the notes for each function linked below.

Device Addresses The device addresses can be in the range 1 to 199, device 0 is not valid, and 200-255 are reserved for special 'broadcast' functions.

Address   Function
------- --------
0 Invalid
1-199 Device addresses
200 Broadcast
222 Address Config Broadcast


All numerical data is sent as 'Big-Endian' 16 bit words. ie: most significant Byte first.

Single Byte data is sent in the second data Byte of the data word, and the first Byte is ignored.

Bitwise data is sent as all ones or all zeros in the high order byte, the low order byte is ignored. ie 0xff?? or 0xff??. This might seem odd, but it's as per the modbus standard.


Register Addresses

Registers 0-127 are device specific. Registers 128 through 255 are reserved for special purposes.

Register  Function
-------- --------
128 16bit - Input frame count - Serial frames recieved for this device (inc. broadcast)
129 16bit - Output frame count - Serial frames sent from this device
130 16bit - Frame error count - Number of partial or failed checksum frames
131 16bit - command error count - Invalid register or command fields

An example register map for an 8 bit digital I/O board might be:

Register  Function
-------- --------
0 Input Port 0 read-only 8-bit register
1 Output Port 0, read/write 8 bit register
0x10 Output Port 0, bit 0 timer read/write register
0x17 Output Port 0, bit 7 timer read/write register

Function Code

The function code is a single byte between 1 and 255.

1-127 = master to slave instructions

128-255 = slave to master responses.

Function code summary:

code   Function
---- --------
0 Invalid
1 Read register
2 Write register
3 Read single input (bit wise read)
4 Write single output (bit wise write)
8 Write String (For ASCII output devices)

64 Respond with ID - Used as broadcast, devices delay before responding
delay based on ID. ie: ID 1 has short delay, ID 200 has a long one.
65 Retrieve ID string - Returns ASCII string to master with device Description.
66 Reset Counters

128 Failed command - Used in return from slaves to master.

The success of a command is implicit in the reply packet to the master. If it succeeds the function code is repeated in the reply packet. If it fails the function code is '128' and the error is in the frame payload.

The size of the data payload in a given frame is determined by the function code. See detail of each function below.

Function 1 - Read register

The payload for command 1 is a single byte containing the register address, and the return is the register number and the 16 bit number from the register contents, . Byte and bit-wise registers are converted as per the data rules above.

e.g.: The master reads address 0x02 on device 0x12 and gets 0x3d4e back...

            |addr| Fn |reg |  CRC    |
Master out: |0x12|0x01|0x02|0x??,0x??|

|addr| Fn | data | CRC |
Slave reply: |0x12|0x01|0x3d|0x4e|0x??,0x??|

Function 2 - Write register

The payload for Write register is 3 bytes. The address of the register, and the 16 bit value to write. Byte and Bit-wise registers are expanded as per the data comment above.

The response from the device is to essentially return the frame un-modified if there was no error.

e.g.: The master writes 0xef into byte-sized register 0x02 of device 0x06

            |addr| Fn |reg |  data   |  CRC    |
Master out: |0x06|0x02|0x02|0x00,0xef|0x??,0x??|

|addr| Fn |reg | data | CRC |
Slave reply:|0x06|0x02|0x02|0x00,0xef|0x??,0x??|

Function 3 - Read single input

The payload for Read single input 2 bytes. The address of the register, and the bit position you wish to read.

The response from the device is to return the bit packed into a 16bit word as per the data comment above.

e.g.: The master reads the 6th bit of register 0x05 of device 0x06 which is true/on.

            |addr| Fn |reg |bit |  CRC    |
Master out: |0x06|0x03|0x02|0x06|0x??,0x??|

|addr| Fn | data | CRC |
Slave reply:|0x06|0x03|0xff,0x00|0x??,0x??|

Function 4 - Write single output

The payload for Write single output is 4 bytes. The address of the register, the bit position, and the bit data to be written packed into a 16 bit value as per the data comment above.

The response from the device is to essentially return the frame un-modified if there was no error.

e.g.: The master writes a 0/false value into bit 9 of register 0x02 of device 0x06

            |addr| Fn |reg |bit |  data   |  CRC    |
Master out: |0x06|0x04|0x02|0x09|0x00,0x00|0x??,0x??|

|addr| Fn |reg |bit | data | CRC |
Slave reply:|0x06|0x04|0x02|0x09|0x00,0x00|0x??,0x??|

Function 8 - Write String

The write-string command is for devices such as LCD screens that require ASCII data to be passed from the bus to them un-modified.

The string is null-terminated, so the maximum string length per frame is 26 characters, given the overall maximum of 28 bytes per frame, and the first byte of the data is the 'register' to which the data is to be sent, allowing for multiple character outputs per slave device.

The response from the slave is the frame less the data payload.

e.g.: The master sends "Hello" to register 5 on device 8

            |addr| Fn |reg |       Data             |  CRC    |
Master out: |0x08|0x08|0x05|'H','e','l','l','o',0x00|0x??,0x??|

|addr| Fn | CRC |
Slave reply: |0x12|0x08|0x??,0x??|

Function 64 - Respond with ID

Respond with ID has no data payload, and is sent to the broadcast address of 200.

The device responds with it's ID.

e.g.: The master sends out a Respond with ID request and slave 0x34 responds

            |addr| Fn |  CRC    |
Master out: |0xc8|0x40|0x??,0x??|

|addr| Fn | CRC |
Slave reply: |0x34|0x40|0x??,0x??|

This function is to allow the Master to map out the devices connected to it. Every connected device responds to this after a delay based on it's ID on the bus.

The delay is 10 character times on the bus multiplied by the ID of the device. In the case of the one above at 9600baud that would be 10.4ms

Function 65 - Retrieve ID String

Function 65 allows the master to find out what sort of device something is. Typically after function 64 has been used to identify what ID's are in use on the bus.

There is no data payload in the request for this function.

The device responds with a null terminated string describing what it is.

e.g.: Master queries the ID string of device 0x23

            |addr| Fn |  CRC    |
Master out: |0x23|0x65|0x??,0x??|

|addr| Fn | data | CRC |
Slave reply: |0x23|0x65|"8bit Digital I/O",0x00|0x??,0x??|

Function 66 - Reset Counters

The reset counters function resets the frame and error counters in the slave device specified.

The is no payload data for function 66, and the device just responds with the same packet back as confirmation.

e.g.: the master resets the counters in device 0x23

            |addr| Fn |  CRC    |
Master out: |0x23|0x66|0x??,0x??|

|addr| Fn | CRC |
Slave reply:|0x23|0x66|0x??,0x??|
Powered by Etomite CMS.