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

Hello everyone, I am Mai Ge.

In industrial automation and IoT device development, the Modbus protocol has become a commonly used standard for device communication due to its simplicity and reliability.

However, efficiently implementing the Modbus protocol in resource-constrained embedded systems is often a significant challenge.

This article will introduce 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 URL: 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 beingstreamlined efficiency:

  • Minimal code size: Approximately 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 multiple registers (address 26)
    uint16_t write_data[2] = {123, 124};
    nmbs_write_multiple_registers(&nmbs, 26, 2, write_data);

    // 4. Read and verify
    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 code that is concise and easy to maintain.

4. Integration and Installation

nanoModbus offers two integration methods:

1. Manual Integration

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

2. CMake Integration (Recommended)

Automatically pull the repository and link the library files using 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 throughplatform 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),<span>timeout_ms < 0</span> indicates infinite wait,<span>=0</span> indicates non-blocking.
  • Error handling: Return the actual number of bytes read/written, negative values indicate 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, I hope you can quickly grasp the core capabilities of nanoModbus and add efficient communication support to your embedded projects.

Recently, I have encountered the following issue when logging into GitHub:

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

Unknown Error

Therefore, the author has downloaded the source code. If anyone needs it, you can reply with 【nanoModbus】 in the backend of the “Xiao Mai Da Shu” public account to obtain the source code.

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

END

Source: Xiao Mai Da Shu

Copyright belongs to the original author. If there is any infringement, please contact for removal..Recommended ReadingSharing several BootLoaders suitable for MCUWhy some domestic chips do not disclose data sheets?Incredible! These 17 C pointer tricks have made countless programmers collect them overnight.→ Follow for more updates ←

Leave a Comment