The Modbus Savior for Embedded Developers: Full-Function Industrial Communication in 2000 Lines of Code

Follow+Star Public Account Number, don’t miss out on exciting content

Source | Uncle Wheat

Modbus is considered a classic communication protocol in the embedded field; however, efficiently implementing the Modbus protocol in resource-constrained embedded systems is often a significant challenge.

This article introduces a lightweight C language library designed specifically for embedded systems—nanoModbus—to help developers quickly build stable and efficient Modbus communication functionality.The Modbus Savior for Embedded Developers: Full-Function Industrial Communication in 2000 Lines of Code

Project Homepage

Project Address: https://github.com/debevv/nanoMODBUS

1. Why Do We Need nanoModbus?

Traditional Modbus libraries are often large and consume considerable memory and computational resources, making them difficult to run in environments with limited hardware resources, such as microcontrollers. nanoModbus was born out of this need, with its core design philosophy being streamlined efficiency:

  • Minimal Code Size: Only about 2000 lines of code, with no redundancy in core functionality.
  • No Dynamic Memory Allocation: Avoids memory leak risks, suitable for real-time systems.
  • Modular Design: Client/server code can be disabled, allowing for feature trimming as needed.
  • Cross-Platform Support: Only relies on the C99 standard library, making it easy to port to various hardware.

2. Overview of Core Features

1. Comprehensive Protocol Support

  • Transmission Modes: Dual support for RTU (serial) and TCP (network).
  • Role Support: Client (master) and server (slave) can be independently enabled.
  • Function Code Coverage: Includes common functions such as reading coils (01), reading registers (03/04), writing single registers (06), and bulk writing (15/16), as well as advanced operations like file record read/write (20/21) and device identification (43/14).

2. Performance Optimization Design

  • User-Defined CRC Calculation: Allows replacement with efficient hardware-accelerated implementations.
  • Flexible Timeout Mechanism: Supports byte-level timeout settings to adapt to different network environments.
  • Broadcast Communication Support: Meets the needs of group control device scenarios.

3. Quick Start Example

The following TCP client example demonstrates how to use nanoModbus to implement register read/write:

#include "nanomodbus.h"

// Custom platform read/write functions (to be implemented by the developer)
int32_t my_transport_read(uint8_t* buf, uint16_t count, int32_t timeout_ms, void* conn) {
    return tcp_read((SocketHandle)conn, buf, count, timeout_ms);
}

int32_t my_transport_write(const uint8_t* buf, uint16_t count, int32_t timeout_ms, void* conn) {
    return tcp_write((SocketHandle)conn, buf, count, timeout_ms);
}

int main() {
    // 1. Initialize platform configuration
    nmbs_platform_conf platform_conf;
    nmbs_platform_conf_create(&platform_conf);
    platform_conf.transport = NMBS_TRANSPORT_TCP;
    platform_conf.read = my_transport_read;
    platform_conf.write = my_transport_write;
    platform_conf.arg = tcp_connect("192.168.1.100", 502); // Connect to Modbus server

    // 2. Create client instance
    nmbs_t nmbs;
    nmbs_client_create(&nmbs, &platform_conf);

    // 3. Write 2 registers (address 26)
    uint16_t write_data[2] = {123, 124};
    nmbs_write_multiple_registers(&nmbs, 26, 2, write_data);

    // 4. Read for verification
    uint16_t read_data[2];
    nmbs_read_holding_registers(&nmbs, 26, 2, read_data);

    tcp_close(platform_conf.arg);
    return 0;
}

Communication can be completed in four simple steps, with concise and maintainable code.

4. Integration and Installation

nanoModbus provides two integration methods:

1. Manual Integration

Directly add <span>nanomodbus.c</span> and <span>nanomodbus.h</span> to the project, suitable for small projects.

2. CMake Integration (Recommended)

Automatically pull the repository and link library files via CMake:

include(FetchContent)
FetchContent_Declare(
    nanomodbus
    GIT_REPOSITORY https://github.com/debevv/nanoMODBUS
    GIT_TAG master
)
FetchContent_MakeAvailable(nanomodbus)
target_link_libraries(your_project nanomodbus)

5. Platform Adaptation Guide

nanoModbus achieves cross-platform compatibility through platform function abstraction, requiring developers to implement two key functions:

// Read data from serial/TCP
int32_t your_read_func(uint8_t* buf, uint16_t count, int32_t timeout_ms, void* arg);

// Write data to serial/TCP
int32_t your_write_func(const uint8_t* buf, uint16_t count, int32_t timeout_ms, void* arg);
  • Timeout Handling: Functions must strictly adhere to the timeout parameter (in milliseconds), where <span>timeout_ms < 0</span> indicates infinite wait, and <span>=0</span> indicates non-blocking.
  • Error Handling: Return the actual number of bytes read/written, with negative values indicating errors.

6. Advanced Optimization Techniques

  1. Code Trimming: Disable unnecessary features through macro definitions, such as <span>NMBS_CLIENT_DISABLED</span> to remove client code, further reducing size.

  2. Debug Support: Define the <span>NMBS_DEBUG</span> macro to print communication messages, facilitating problem diagnosis.

  3. Timeout Settings: Use <span>nmbs_set_read_timeout()</span> to adjust timeout thresholds for different network environments, enhancing communication stability.

7. Conclusion

Through this introduction, we hope you can quickly grasp the core capabilities of nanoModbus, adding efficient communication support to your embedded projects.

———— END ————

The Modbus Savior for Embedded Developers: Full-Function Industrial Communication in 2000 Lines of Code

Key Points in Designing Battery-Powered MCU Products

The Modbus Savior for Embedded Developers: Full-Function Industrial Communication in 2000 Lines of Code

Characteristics of Several Common RTOS in Embedded Systems

The Modbus Savior for Embedded Developers: Full-Function Industrial Communication in 2000 Lines of Code

A Method for Absolute Memory Address Location in MCUs

Leave a Comment