Modbus RTU開発例

freeFree Technical Resource

This content is free to read, suitable for basic learning and search traffic.

Modbus RTU開発例

本論文ではLinux 上でlibmodbusライブラリに基づいてModbus RTUを開発し,実験を行う前にlibmodbusライブラリと仮想シリアルポートを実現するためのsocatツールをインストールする必要がある。

準備作業の準備

libmodbusのインストール

押すことができる。 libmodbusソフトウェア·ライブラリ の“インストール”セクションの手順で手動でコンパイルしてインストールします。

Socatのインストール

sudo apt install socat

Socatは強力なネットワークツールであり、この実験では2つの相互接続された仮想シリアルポートを実装するために使用されるため、実際のシリアルポートデバイスを準備する必要はありません。石鹸の詳細については、こちらをご覧ください。 socatコマンド

コードの実装

完全なコードは https://github.com/getiot/linux-c/tree/main/library/libmodbus 取得します。

Modbus RTUスレーブ

#include <stdio.h>
#ifndef _MSC_VER
#include <unistd.h>
#endif
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <stdbool.h>
#include "modbus.h" //libmodbusライブラリを参照

#define Loop             1      //サイクルの数
#define server_ID       17      //スレーブデバイスアドレス
#define ADDRESS_START    0      //テストレジスタの開始アドレス
#define ADDRESS_END     99      //テストレジスタの終了アドレス

int main int argc char *argv]
{
    mod_t *ctx = NULL;
    int nb = 0; //テストするレジスタの数
    uint8_t* tab_rq_bits;       //送受信したデータの保存(以下同じ)
    uint8_t* tab_rp_bits;
    uint16_t * tab_rq_registers;
    uint16_t * tab_rw_rq_registers;
    uint16_t *tab_rp_registers;
    CHAR * ポート;
    mod_m_t *mb_m;

    if argc == 2 {
        port = argv 1];
    (エルゼ)
        port = "COM5";
    }

    //RTU型コンテナの作成
    ctx = modbus_new_rtu(port,19200,'N',8,1);
    //スレーブアドレスを設定
    mod_set_slave ctx、Server_ID;
    //デバッグモードの設定
    mod_set_ctx true;
    // RTUモードではシリアルポートを開く
    if mod_ctx == -1
    {
        ff stderr "Connection ed %s \n" mod_strerror no;
        mod_free ctx;
        リターン-1;
    }

    //レジスタデータを格納するために4つのメモリ領域を要求し、500のレジスタアドレスを要求します。
    mb_m = mod_m_new 500 500 500 500;
    if mb_m == NULL {
        ff stderr "Error m %s\n" mod_strerror no;
        mod_free ctx;
        リターン-1;
    }

    //クエリフレームをループしてメッセージを返信
    for;;{
        uint8_t query MODBUS_TCP_MAX_ADU_LENGTH];
        rc = 0;
        rc = mod_receive ctx;//クエリメッセージを取得

        if rc = 0 {
            Rcは量子サイズです。
            mod_rectx rc mb_m; //応答メッセージの返信
        }
        else {
            //クライアントまたはエラーによる接続のクローズ
            f
        }
    }
    f

    メモリを解放する。
    mod_m_free mb_m;
    mod_clctx;
    mod_free ctx;

    リターン0;
}

Modbus RTUマスター

#include <stdio.h>
#ifndef _MSC_VER
#include <unistd.h>
#endif
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <stdbool.h>
#include "modbus.h" //libmodbusライブラリを参照

#define Loop             1        //サイクルの数
#define server_ID       17        //スレーブデバイスアドレス
#define ADDRESS_START    0        //テストレジスタの開始アドレス
#define ADDRESS_END     99        //テストレジスタの終了アドレス

int main int argc char *argv]
{
    // printf "%c" 0b01000001; // A
    mod_t *ctx = NULL;

    int nb = 0; //テストするレジスタの数

    uint8_t* tab_rq_bits;       //送受信したデータの保存(以下同じ)
    uint8_t* tab_rp_bits;

    uint16_t * tab_rq_registers;
    uint16_t * tab_rw_rq_registers;
    uint16_t *tab_rp_registers;
    CHAR * ポート;

    if argc == 2 {
        port = argv 1];
    (エルゼ)
        port = "COM4";
    }

    //RTU型コンテナの作成
    ctx = modbus_new_rtu(port,19200,'N',8,1);
    //スレーブアドレスを設定
    mod_set_slave ctx、Server_ID;
    //デバッグモードの設定
    mod_set_ctx true;
    // RTUモードではシリアルポートを開く
    if modbus_connect ctx == -1 {
        ff stderr "Connection ed %s \n" mod_strerror no;
        mod_free ctx;
        リターン-1;
    }
    printf "Connection successed\n";

    /* 異なるメモリ領域の割り当てと初期化 */
    //テストが必要なレジスタの数を数える
    nb = ADDRESS_END-ADDRESS_START

    // 以下のアプリケーションメモリブロック、水着は送受信各データを保存
    tab_rq_bits = uint8_t * malnb * of uint8_t;
    memset tab_rq_bits 0 nb*sizeof uint8_t;

    tab_rp_bits = uint8_t * malnb * of uint8_t;
    memset tab_rp_bits 0 nb* of uint8_t;

    tab_rq_registers = uint16_t * malloc nb * sizeof uint16_t;
    memset tab_rq_registers 0 nb*sizeof uint16_t;

    tab_rw_rq_registers = uint16_t * malloc nb * sizeof uint16_t;
    memset tab_rw_rq_registers 0 nb* of uint16_t;

    tab_rp_registers = uint16_t * malnb * of uint16_t;
    memset tab_rp_registers 0 nb* of uint16_t;

    int nb_= 0、nb_fail = 0、= 0、rc = 0;

    while nb_loop ++ Loop {
        //開始アドレスからの順次テスト
        for = ADDRESS_START; ADDRESS_END;++{
            sleep(1);
            int i = 0;

            //テスト用の乱数の生成
            for i = 0; i nb; i++{
                tab_rq_registers i] = uint16_t 65535.0 * rand/RAND_MAX + 1.0;
                tab_rw_rq_registers i] = ~tab_rq_registers i];
                tab_rq_bits i] = tab_rq_registers i] % 2;
            }
            nb = ADDRESS_END-addr;

            //コイルレジスタの単一読み取りおよび書き込みテスト
            printf "modbus_write_bit... N 'N';
            rc = mod__bit ctx tab_rq_bits 0]; //コイルレジスタへの书き込み
            if rc != 1) {
                printf "ERROR modbus_write_bit % d\n" rc;
                printf "Address = %d value = %d \n" addr tab_rq_bits0];
                nB_fail ++;
            }
            else {
                //書き込みの後、読み取りと比較
                rc = mod_read_bits ctx 1 tab_rp_bits;
                if rc != 1つの||tab_rq_bits[ 0] != tab_rp_bits0]{
                    f
                    printf "address = %d\n" addr;
                    NB_fail ++;
                }
            }

            //テストコイルレジスタのバッチ読み取り/書き込み
            f N 'N';
            rc = mod__bits ctx nb tab_rq_bits;
            if rc != nb){
                f
                f
                nB_fail ++;
            }
            else {
                //書き込みの後、読み取りと比較
                rc = mod_read_bits ctx nb tab_rp_bits;
                if:rc != nb {{
                    printf "ERROR modbus_read_bits\n";
                    printf "address = %d nb = %d\n" addr nb;
                    NB_fail ++;
                }
                else {
                    //比較する
                    for i = 0; i nb; i++{
                        if tab_rp_bits i] != tab_rq_bits i]{
                            f
                            f %d 0x % x\n"、
                                addr, tab_rq_bits i], tab_rq_bits i],
                                tab_rp_bits i] tab_rp_bits i];
                            NB_fail ++;
                        }
                    }
                }
            }

            //テストはレジスタの単一の読み書きを保持する
            f N 'N';
            rc = mod__register ctx tab_rq_registers 0];
            if rc != 1) {
                f
                printf "Address = %d Val = %d 0x % x\n"
                    addr, tab_rq_registers 0], tab_rq_registers 0]);
                NB_fail ++;
            }
            else {
                //書き込み後の読み込み
                rc = mod_read_registers ctx 1 tab_rp_registers;
                if:rc != 1){
                    printf "ERROR modbus_read_registers % d\n" rc;
                    printf "Address = %d\n" addr;
                    NB_fail ++;
                }
                else {
                    読み取り後の比較
                    if tab_rq_registers 0] != tab_rp_registers 0]{
                        printf "ERROR modbus_read_registers % d\n" rc;
                        f %d 0x % x\n"、
                            addr, tab_rq_registers 0], tab_rq_registers 0],
                            tab_rp_registers0] tab_rp_registers0];
                        NB_fail ++;
                    }
                }
            }

            //テストコイルレジスタのバッチ読み取り/書き込み
            f N 'N';
            rc = mod__registers ctx nb tab_rq_registers;
            if rc != nb){
                f
                f
                NB_fail ++;
            }
            else {
                //Read Testの実行
                rc = mod_read_registers ctx nb tab_rp_registers;
                if:rc != nb {{
                    printf "ERROR modbus_read_registers % d\n" rc;
                    printf "Address = %d\n" addr;
                    NB_fail ++;
                }
                else {
                    for i = 0; i nb; i++{
                        読み取り後の比較
                        if tab_rq_registers i] != tab_rp_registers i]{
                            printf "ERROR modbus_read_registers % d\n" rc;
                            f %d 0x % x\n"、
                                addr, tab_rq_registers 0], tab_rq_registers 0],
                                tab_rp_registers0] tab_rp_registers0];
                            NB_fail ++;
                        }
                    }
                }
            }

            //関数コード23 (0 x 17)複数のレジスタを読み書きするテスト
            f N 'N';
            rc = mod__and_read_registers ctx
                addr nb tab_rw_rq_registers
                addr nb tab_rp_registers;

            if:rc != nb {{
                f
                f
                NB_fail ++;
            }
            else {
                //読み取りと比較
                for i = 0; i nb; i++{
                    if tab_rp_registers i] tab_rw_rq_registers i]{
                        printf "ERROR modbus_read_and_write_registers READ\n";
                        printf "Address = %d value %d 0x %X!= %d 0x %X\n "、
                            addr, tab_rp_registers i], tab_rw_rq_registers i],
                            tab_rp_registers i tab_rw_rq_registers i];
                        NB_fail ++;
                    }
                }

                rc = mod_read_registers ctx nb tab_rp_registers;
                if rc != nb){
                    printf "ERROR modbus_read_registers % d\n" rc;
                    f
                }
                else {
                    for i = 0; i nb; i++{
                        if tab_rw_rq_registers i] != tab_rp_registers i]{
                            printf "ERROR modbus_read_and_write_registers\n";
                            f= %d (0x%X)\n",
                                addr, tab_rw_rq_registers[i], tab_rw_rq_registers[i],
                                tab_rp_registers[i], tab_rp_registers[i]);
                            nb_fail++;
                        }
                    }
                }
            }
        }

        printf("Test: ");
        if (nb_fail) {
            printf("%d FAILS\n",nb_fail);
        } else {
            printf("SUCCESS\n");
        }
    }

    // FREE the memory
    free(tab_rq_bits);
    free(tab_rp_bits);
    free(tab_rq_registers);
    free(tab_rp_registers);
    free(tab_rw_rq_registers);

    // close the connection
    modbus_close(ctx);
    modbus_free(ctx);

    return 0;
}

Makefile

CC=gcc
CFLAGS=-I/usr/local/include/modbus/ -lmodbus -g

MASTER=modbus-rtu-master
SLAVE=modbus-rtu-slave

all:
        (CC) -o(MASTER) (MASTER).c(CFLAGS)
        (CC) -o(SLAVE) (SLAVE).c(CFLAGS)

clean:
        rm -rf (MASTER)(SLAVE)

テストテスト

仮想シリアルポートの起動

$ socat  -d  -d  PTY  PTY
2021/07/16 14:36:43 socat[23932] N PTY is /dev/pts/7
2021/07/16 14:36:43 socat[23932] N PTY is /dev/pts/8
2021/07/16 14:36:43 socat[23932] N starting data transfer loop with FDs [5,5] and [7,7]

スレーブ装置を起動し、マスターのCommandを待つ

./modbus-rtu-slave /dev/pts/7

マスターステーションを起動し、スレーブステーションにCommandを出す

./modbus-rtu-master /dev/pts/8

これで、ターミナルからModbus RTUマスターとスレーブ間のデータCommunicationプロセスを見ることができます。

Related Tags
Put this resource to use in a real project?

Go to the Tool Center for message parsing, CRC verification and device debugging, or submit your requirements for selection and integration advice.

Engineer Membership

Turn this article into actionable debugging resources

After activation, you can use advanced message parsing, resource pack downloads, code examples, engineering cases and priority technical support, suitable for real project delivery.

Unlimited Advanced Tools
Resource & Code Packs
Complete Engineering Case Library
Priority Technical Support

Leave a Reply

Your email address will not be published. Required fields are marked *.