Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Modbus Communication Protocol Implementation Guide

Tech 1

Modbus is a serial communication protocol developed by Modicon (now Schneider Electric) in 1979 for programmable logic controllers (PLCs). Due to its simplicity and reliability, it has become a de facto standard in industrial automation.

Protocol Overview

Modbus operates on a master-slave architecture where one master device communicates with multiple slave devices. The protocol supports three main variants:

  • Modbus RTU: Binary transmission mode, typically used with RS-485
  • Modbus ASCII: ASCII character-based mode, commonly used with RS-232
  • Modbus TCP/IP: TCP/IP-based mode for Ethernet communication

Data Storage Model

Modbus defines four distinct data types:

Data Type Access Size Typical Use
Coils Read/Write 1 bit Binary control signals
Discrete Inputs Read-only 1 bit Sensor status
Holding Registers Read/Write 16 bits Configuration parameters
Input Registers Read-only 16 bits Measurement values

Common Function Codes

Function Code Name Description
0x01 Read Coils Read binary output status
0x02 Read Discrete Inputs Read binary input status
0x03 Read Holding Registers Read 16-bit configuration data
0x04 Read Input Registers Read 16-bit sensor data
0x05 Write Single Coil Write single binary output
0x06 Write Single Register Write single 16-bit value
0x0F Write Multiple Coils Write multiple binary outputs
0x10 Write Multiple Registers Write multiple 16-bit values

RS-485 Wiring Configuration

RS485 uses differential signaling for robust communication in noisy industrial environments. Proper wiring is critical:

Master Device     Slave Device 1   Slave Device 2
    A --------------- A --------------- A
    B --------------- B --------------- B
   GND ------------- GND ------------- GND
    |                                 |
   120Ω                              120Ω

Key requirements:

  • Use shielded twisted pair cable (24 AWG recommended)
  • Install 120Ω termination resistors at both ends of the bus
  • All devices must share a common ground reference
  • Maximum cable length: 1200 meters (depending on baud rate)
  • Use bus topology, avoid star topology

STM32 Implementation Example

UART Configuration for Modbus RTU

For STM32F103C8T6, the serial peripheral can be configured as follows:

typedef struct {
    USART_TypeDef *instance;
    uint32_t baud_rate;
    uint8_t data_bits;
    uint8_t stop_bits;
    uint8_t parity;
} modbus_uart_config_t;

void uart_init(modbus_uart_config_t *config) {
    USART_InitTypeDef usart_init;
    usart_init.USART_BaudRate = config->baud_rate;
    usart_init.USART_WordLength = config->data_bits == 8 ? 
        USART_WordLength_8b : USART_WordLength_9b;
    usart_init.USART_StopBits = config->stop_bits == 1 ? 
        USART_StopBits_1 : USART_StopBits_2;
    usart_init.USART_Parity = config->parity == 0 ? 
        USART_Parity_None : USART_Parity_Even;
    usart_init.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    usart_init.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    
    USART_Init(USART2, &usart_init);
    USART_Cmd(USART2, ENABLE);
}

Serial Port Layer Implementation

typedef enum {
    MB_PORT_OK = 0,
    MB_PORT_ERROR
} mb_status_t;

mb_status_t serial_send_byte(uint8_t data) {
    while (USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET);
    USART_SendData(USART2, data);
    return MB_PORT_OK;
}

mb_status_t serial_receive_byte(uint8_t *data) {
    if (USART_GetFlagStatus(USART2, USART_FLAG_RXNE) != RESET) {
        *data = USART_ReceiveData(USART2);
        return MB_PORT_OK;
    }
    return MB_PORT_ERROR;
}

CRC16 Calculation

Modbus RTU uses CRC-16 for error detection:

uint16_t calculate_crc16(const uint8_t *buffer, uint16_t length) {
    uint16_t crc = 0xFFFF;
    
    for (uint16_t i = 0; i < length; i++) {
        crc ^= buffer[i];
        for (uint8_t j = 0; j < 8; j++) {
            if (crc & 0x0001) {
                crc = (crc >> 1) ^ 0xA001;
            } else {
                crc = crc >> 1;
            }
        }
    }
    return crc;
}

Modbus TCP Implementation

For Ethernet-based communication, an external PHY module (such as W5500) is required since STM32F103C8T6 lacks an integrated Ethernet controller:

typedef struct {
    uint8_t transaction_id[2];
    uint8_t protocol_id[2];
    uint8_t length[2];
    uint8_t unit_id;
    uint8_t function_code;
} modbus_tcp_header_t;

int modbus_tcp_process_request(uint8_t *request, uint16_t req_len,
                                uint8_t *response, uint16_t *resp_len) {
    modbus_tcp_header_t *header = (modbus_tcp_header_t *)request;
    uint8_t function_code = header->function_code;
    
    switch (function_code) {
        case 0x03:  // Read holding registers
            return handle_read_holding_registers(request, req_len,
                                                  response, resp_len);
        case 0x06:  // Write single register
            return handle_write_register(request, req_len,
                                          response, resp_len);
        default:
            return -1;
    }
}

Frame Format

RTU Frame Structure

[Address] [Function Code] [Data] [CRC Low] [CRC High]
 1 byte      1 byte        N bytes   1 byte     1 byte

Frame timing requirement: Minimum 3.5 character idle time between frames.

TCP Frame Structure

[Transaction ID] [Protocol ID] [Length] [Unit ID] [Function Code] [Data]
    2 bytes        2 bytes     2 bytes   1 byte      1 byte       N bytes

Testing Tools

  • Modbus Poll: Master device simulator for testing slave devices
  • Modbus Slave: Simulates slave device responses
  • QModMaster: Open-source Modbus testing utility
  • Virtual Serial Port Driver: Creates paired COM ports for testing

For Linux, virtual COM port pairs can be created using socat:

sudo socat -d -d pty,raw,echo=0 pty,raw,echo=0

Development Considerations

  1. Baud Rate Selection: Higher baud rates (up to 115200) work well for short distances; lower rates (9600-19200) provide better reliability for longer cables.
  2. Timeout Handling: Implement proper timeout mechanisms for Modbus RTU frame detection.
  3. Error Handling: Monitor CRC errors and implement retry logic for reliable communication.
  4. Address Assignment: Each slave device must have a unique address (1-247) on the bus.

Conclusion

Modbus remains a widely adopted protocol in industrial automation due to its simplicity, robustness, and vendor neutrality. Understanding the protocol fundamentals and proper implemantation techniques enables reliable communication between PLCs, sensors, and control devices in industrial environments.

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.