Modbus RTU開発例

無料無料技术资料

这篇内容可直接阅读,适合用于基础学习和検索引流。

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;
}@@MB_TAG_202@@>Makefile@@MB_TAG_203@@>@@MB_TAG_204@@>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)@@MB_TAG_205@@>テストテスト@@MB_TAG_206@@>仮想シリアルポートの起動@@MB_TAG_207@@>@@MB_TAG_208@@>$ 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]@@MB_TAG_209@@>スレーブ装置を起動し、マスターの命令を待つ@@MB_TAG_210@@>@@MB_TAG_211@@>./modbus-rtu-slave /dev/pts/7@@MB_TAG_212@@>マスターステーションを起動し、スレーブステーションに命令を出す@@MB_TAG_213@@>@@MB_TAG_214@@>./modbus-rtu-master /dev/pts/8@@MB_TAG_215@@>これで、ターミナルからModbus RTUマスターとスレーブ間のデータ通信プロセスを見ることができます。@@MB_TAG_216@@>@@MB_TAG_217@@>@@MB_TAG_218@@>@@MB_TAG_219@@>@@MB_TAG_220@@>@@MB_TAG_221@@>@@MB_TAG_222@@>
			@@MB_TAG_223@@>@@MB_TAG_224@@>@@MB_TAG_225@@>@@MB_TAG_226@@>@@MB_TAG_227@@>@@MB_TAG_228@@>打赏@@MB_TAG_229@@>@@MB_TAG_230@@>@@MB_TAG_231@@>@@MB_TAG_232@@>赞@@MB_TAG_233@@>@@MB_TAG_234@@>@@MB_TAG_235@@>@@MB_TAG_236@@>微海报@@MB_TAG_237@@>@@MB_TAG_238@@>@@MB_TAG_239@@>@@MB_TAG_240@@>分享@@MB_TAG_241@@>
@@MB_TAG_242@@>@@MB_TAG_243@@>@@MB_TAG_244@@>@@MB_TAG_245@@>@@MB_TAG_246@@>AI 推荐阅读@@MB_TAG_247@@>@@MB_TAG_248@@>@@MB_TAG_249@@>匹配 65%PHPとGo言語のModbusライブラリの使用ガイド:phpmodbusとgo-modbus@@MB_TAG_250@@>@@MB_TAG_251@@>匹配 63%libmodbus -Linux、Mac OS、FreeBSD、Windows用のModbusライブラリ@@MB_TAG_252@@>@@MB_TAG_253@@>匹配 62%SimpleModbus Arduinoライブラリの使い方:ArduinoをModbus RTUで通信させる@@MB_TAG_254@@>@@MB_TAG_255@@>匹配 59%EasyModbusTCP. NETサンプル·コード{{EasyModbusTCP. NETさんぷるこーど}}マッチング 58%. NETを使用したMODBUS TCP通信例
関連タグ
この資料を実際のプロジェクトに活用しませんか?

ツールセンターで電文解析、CRCチェック、デバイスデバッグを行うか、要件を送信して選定と接続のアドバイスを受けましょう。

エンジニア会員

この記事を実行可能なデバッグ資料に

登録すると、高度な電文解析、資料パックのダウンロード、コード例、エンジニアリングケース、優先技術サポートが利用可能に。実際のプロジェクト納品に最適です。

高度なツール無制限
資料パックとコードパック
完全なエンジニアリングケースライブラリ
優先技術サポート窓口

发表回复

あなたのメールアドレスアドレス不会被公开。 必須項目已用 * 标注