MODBUS Function Library: A Practical PLC Library

To communicate with other devices in a PLC, the MODBUS function library is definitely the most commonly used. Let me share my experiences and some tips from my work~

As the “universal solution” in the field of industrial automation, the MODBUS library allows our PLC to communicate with other devices that support the MODBUS protocol. It supports both RTU and TCP modes, making it particularly versatile. However, in actual projects, I have encountered many interesting issues that I want to document and discuss with everyone.

Consider this scenario: a customer has several frequency converters on their production line, all needing to communicate with the PLC via MODBUS. If we follow the old method of reading and writing one by one, not only will the program be lengthy, but it is also prone to errors. I thought I needed to come up with a better solution.

There are a few common issues regarding communication that we need to address one by one:

Issue 1: Data Anomalies After Communication FailureThis issue can be quite troublesome! Sometimes when communication breaks, the data in the PLC can become chaotic. If we directly use this data, the device could unexpectedly start a “concert”. I once encountered this in an injection molding machine project where the temperature control data got scrambled, nearly causing the barrel temperature to soar to 300 degrees.

The solution is straightforward: just add a communication status check. After every read/write operation, check the communication status before processing the data:

 1// Communication status check code
 2VAR
 3    mbRead: MB_MASTER_RTU;    // MODBUS read instance
 4    xComOK: BOOL;             // Communication status flag
 5    wReadData: ARRAY[0..9] OF WORD;  // Read data array
 6END_VAR
 7
 8mbRead(
 9    UNIT := 1,               // Slave address
10    FUNCTION := 3,           // Function code: read holding registers
11    ADDR := 0,              // Starting address
12    QTY := 10,              // Number of reads
13    DATABUFFER := wReadData // Data buffer
14);
15
16xComOK := mbRead.DONE ANDNOT mbRead.ERROR;
17
18// Data processing only occurs when communication is normal
19IF xComOK THEN
20    // Your data processing code
21END_IF

Issue 2: Slow Read/Write SpeedThis is also a headache. In a medical device project, there was a requirement to complete the read/write of 20 data points within 50ms, which could not be achieved using the normal method. I discovered a few small techniques to speed things up: batch reading/writing, adjusting the communication cycle, and differentiating data priorities.

Batch reading/writing means reading/writing data from continuous addresses at once, which can significantly reduce communication times. Adjusting the communication cycle means not all data needs to be updated in real-time; slow-changing variables like temperature can have a relaxed collection cycle. Data priority is even more interesting, where important data (like emergency stop signals) is given high priority, while less critical data (like accumulated running time) has its update frequency lowered.

Implementing the code is not difficult:

 1// Optimized code
 2VAR
 3    mbMultiRead: MB_MASTER_RTU;
 4    tCycle: TON;             // Cycle timer
 5    xTrigger: BOOL;          // Trigger flag
 6END_VAR
 7
 8// Execute communication every 200ms
 9tCycle(IN := NOT tCycle.Q, PT := T#200MS);
10xTrigger := tCycle.Q;
11
12IF xTrigger THEN
13    mbMultiRead(
14        UNIT := 1,
15        FUNCTION := 3,
16        ADDR := 0,
17        QTY := 20,          // Multi-read data points at once
18        DATABUFFER := wReadData
19    );
20END_IF

Issue 3: Trouble with Data Type ConversionMODBUS only recognizes WORD type data, but in practical applications, we often need to handle complex data types like floating-point numbers and long integers. I wrote a universal conversion function that can convert two WORDs into a REAL type:

 1// Data type conversion function
 2FUNCTION WORD_TO_REAL : REAL
 3VAR_INPUT
 4    wLow: WORD;   // Low 16 bits
 5    wHigh: WORD;  // High 16 bits
 6END_VAR
 7VAR
 8    dwTemp: DWORD;
 9END_VAR
10
11dwTemp := WORD_TO_DWORD(wHigh);
12dwTemp := SHL(dwTemp, 16);
13dwTemp := dwTemp OR WORD_TO_DWORD(wLow);
14WORD_TO_REAL := DWORD_TO_REAL(dwTemp);

Here’s a small tip: when doing data conversions, remember to consider byte order issues. Different devices may use different byte orders, and I have seen cases where neglecting this led to floating-point numbers displaying astronomical values.

Speaking of debugging, I recommend using the MODBUS Poll tool; it’s particularly useful. When encountering communication issues, use it to capture packets and analyze them; it can quickly reveal where the problem lies. I remember troubleshooting a communication failure once, unable to find the cause, and upon using this tool, I discovered that the customer’s slave address was set incorrectly, and correcting it resolved the issue.

If anyone encounters any problems, feel free to ask me below; let’s exchange knowledge and learn from each other to improve together!

Leave a Comment