Understanding MODBUS-RTU Protocol: Mastering Industrial Communication with Four Core Function Codes (01/03/05/06)

In the field of industrial control, MODBUS-RTU is one of the most universal and time-tested communication protocols. It acts like the “Mandarin” among devices, allowing instruments, PLCs, and controllers from different manufacturers to communicate smoothly.

Today, I will set aside complex theories and directly guide you through the four most commonly used function codes:01, 03, 05, 06, combined with practical code examples on the PIC microcontroller, to help you thoroughly grasp the essence of MODBUS-RTU.

1. Simple Introduction to MODBUS-RTU Protocol

You can think of MODBUS communication as an ordered question-and-answer:

Master (Master) asks: “Slave 1, what is the status of your coil?”

Slave (Slave) replies: “Slave 1 replies, my coil status is XXXX.”

Protocol Frame Format (Key Point): Both questions and answers follow the structure below, which is fundamental for analyzing and debugging all issues.

Slave Address

Function Code

Data

CRC Checksum

1 Byte

1 Byte

N Bytes

2 Bytes

Slave Address: 0 is the broadcast address, 1-255 are device addresses.

Function Code: Indicates what action the slave should perform.

Data: The specific content of the request or reply.

CRC Checksum: Ensures that data is not corrupted during transmission (low 8 bits first, high 8 bits last).

2. Detailed Explanation of the Four Core Function Codes

1. Function Code 01 (Read Coils) – Read Coil Status

Function: Reads the status of a group of digital outputs (DO), such as the activation or deactivation of a relay.

Master Request Frame (e.g., read from Slave 1, starting at coil address 0x0000 for 4 coil statuses)

Address

Function Code

Start Address High8 Bits

Start Address Low8 Bits

Quantity High8 Bits

Quantity Low8 Bits

CRC16

0x01

0x01

0x00

0x00

0x00

0x04

0x31CA

Slave Normal Reply (assuming the statuses of 4 coils are: ON, OFF, ON, OFF)

Address

Function Code

Byte Count

Data (Coil Status)

CRC16

0x01

0x01

0x01

0x05 (Binary 0000 0101)

0xE1C8

Note: The binary of data 0x05 is 0000 0101, which corresponds to coils 1ON, 2OFF, 3ON, 4OFF. If the number of returned coils is not a multiple of 8, the remaining bits in the last data byte are filled with zeros, and the byte count indicates the total number of data bytes.

2. Function Code 05 (Write Single Coil) – Force Single Coil

Function: Forcefully changes the state of a single digital output, commonly used to activate or deactivate a relay.

Master Request Frame (forcefully setting Slave 1’s coil at address 0x0002 to ON)

Address

Function Code

Output Address High8 Bits

Output Address Low8 Bits

Output Value High8 Bits

Output Value Low8 Bits

CRC16

0x01

0x05

0x00

0x02

0xFF

0x00

0x8C3A

Note: Forcefully ON is fixed at 0xFF00, and forcefully OFF is fixed at 0x0000.

Slave Normal Reply: Replies with the same data sent by the master, indicating successful execution.

Address

Function Code

Output Address High8 Bits

Output Address Low8 Bits

Output Value High8 Bits

Output Value Low8 Bits

CRC16

0x01

0x05

0x00

0x02

0xFF

0x00

0x8C3A

3. Function Code 03 (Read Holding Registers) – Read Holding Registers

Function: Reads device parameters, collected data, etc., and is one of the most frequently used function codes. For example, reading temperature, pressure, flow, etc.

Master Request Frame (reading from Slave 1, starting at address 0x0000 for 2 registers)

Address

Function Code

Start Address High8 Bits

Start Address Low8 Bits

Quantity High8 Bits

Quantity Low8 Bits

CRC16

0x01

0x03

0x00

0x00

0x00

0x02

0xC40B

Slave Normal Reply (assuming the values of the two registers are 0x1234, 0x5678)

Address

Function Code

Byte Count

Data1 High8 Bits

Data1 Low8 Bits

Data2 High8 Bits

Data2 Low8 Bits

CRC16

0x01

0x03

0x04

0x12

0x34

0x56

0x78

0x1FE1

4. Function Code 06 (Write Single Register) – Preset Single Register

Function: Modifies a parameter of the device, such as setting target temperature, pressure limits, etc.

Master Request Frame (changing the value of the register at address 0x0001 of Slave 1 to 0x55AA)

Address

Function Code

Register Address High8 Bits

Register Address Low8 Bits

Data High8 Bits

Data Low8 Bits

CRC16

0x01

0x06

0x00

0x01

0x55

0xAA

0x12E4

Slave Normal Reply: Similarly, replies with the same command from the master, indicating successful modification.

3. PIC Microcontroller MODBUS-RTU Code

Below is part of the main program:

#include<pic16f1947.h> // Taking PIC16F1947 as an example

unsigned char address_485=1;// Default slave address is 1

unsigned char recive[100]; // Slave receive data buffer of 100 bytes

unsigned int crc_hl; //16 bit two-byte checksum

void calccrc(uchar crcbuf) // Checksum algorithm subroutine

{

uchar i;

crc_hl=crc_hl^crcbuf;

for(i=0;i<8;i++)

{

uchar TT;

TT=crc_hl&1;

crc_hl=crc_hl>>1;

crc_hl=crc_hl&0x7fff;

if(TT==1)

crc_hl=crc_hl^0xa001;

crc_hl=crc_hl&0xffff;

}

}

void main()

{

unsigned char i,j;

// Initialization

while(1)

{

if(x) // x is the condition to determine successful communication reception of a data packet

{

crc_hl=0xffff;

for(i=0; i<6; i++)

{

calccrc(recive[i]);

}

if((recive[0]== address_485)&&(recive[1]==0x03)&&(recive[6]==(crc_hl&0xff))&&(recive[7]==(crc_hl>>8))) // Check address, function code, and checksum

{

//1 Determine register address and fill in the data to reply

//2 Checksum calculation

//3 Send the data to reply and checksum to the master

// For function codes 05, 06, directly send the data to the master without needing 2 these two steps

}

}

}

MODBUS-RTU physical layer typically uses RS-485. A stable and reliable RS-485 circuit is essential for communication.

The following is the RS485 interface circuit diagram I have been using:

For detailed introduction, please refer to my other article: In-Depth Analysis of RS-232, RS-485, RS422 Bus and Practical Protection Circuit

By mastering the four core function codes: 01, 03, 05, 06, you can solve over 80% of MODBUS-RTU application scenarios. The protocol itself is not difficult; the key lies in rigorous implementation and protection against field interference.

If you are interested in this article or have any questions, feel free to leave a comment.

More valuable content is coming, let’s progress together in the world of microcontrollers.

Leave a Comment