Windows側、libmodbus + Qt PCテスト

Windows側、libmodbus + Qt PCテスト

この記事はVSでのmodbus通信の実現に基づいており、Qtでmodbus通信を実現するためにQtにいくつかの簡単な変更が加えられています。(国を救うための曲線とみなすことができます)

明晰な思考力

長い間、Modbus-Master(マスター側)とModbus-Slave(スレーブ側)の間の通信で、どちらの端がレジスタに割り当てられているかについて少し悩んでいます。
主な理由:

  • 1.通信の概念が明確でないためです。ホスト側とスレーブ側の両方がデータを送信でき、どちらもレジスタに値を割り当てることができます。
  • 2.インターネット上の情報を参照すると、マスターとスレーブ間のほとんどの接続はQt側​​で確立されており、割り当てはツールModbus Slaveで行われるため、誤解が生じます。

Embedded STM32 study notes(8)-libmodbus + Qt host computer test
本文に示されている機能は、Modbus Slaveツールでレジスターに値を割り当てることです。接続が成功すると、コマンドウィンドウに値の転送が表示されます。
しかし、私の実際の状況では、ホストコンピューターとしてのQtは、命令を送信する効果を得るために値をスレーブエンドに渡す必要があります。そのため、機能するようにコードを変更する必要があります。

検証アイデア

コードを記述する前に、アイデアが妥当かどうかを確認する必要があります。まず、Modbus補助ツールを使用します。

Modbus補助ツールテスト

Modbus PollおよびModbus Slave接続を確立するための補助ツールを借用し、Modbus Pollを使用してModbus Slaveにデータを送信し、次にModbus Slaveを使用してModbus Pollにデータを送信します。
1.下の図1に示すように、Modbus Pollから0〜9の値をModbusスレーブに渡します。
図1

Txは送信、Rxは受信を意味します。
Modbusポーリングが最初に送信03 00 00 00 0A C5 CD
Modbusスレーブがこのコード文字列を受信し、
Modbusスレーブが
03 14 00 00 00 01 00 02 00 03 00 04 00 05 00 06 00 07 00 08 00 09 CD 51
Modbusを送信世論調査で受け取った

このプロセスについて少し混乱していますが、なぜですか?
この補助ソフトウェアにはバグがあり、Modbus Poll割り当てプロセス中にModbusスレーブに値を直接送信しますが、このテストでは問題は説明されませんでした。
2.下の図2に示すように、Modbusスレーブ側からModbusポーリング側に10-1の値を渡します。
図2

同様に、Txは送信を意味し、Rxは受信を意味します。
Modbusポーリングが最初に送信03 00 00 00 0A C5 CD
Modbusスレーブが受信03 00 00 00 0A C5 CD
Modbusスレーブが送信
03 14 00 0A 00 09 00 08 00 07 00 06 00 05 00 04 00 03 00 02 00 01 AD B5
Modbusポーリング終了を受信しました

Modbus-MasterとしてのQtホストコンピューター

上位コンピュータQtはModbus-Master(ホスト側)として使用され、ホスト側ではランダムサンプリング割り当て方式を使用してレジスタが割り当てられます。
最初にコードを貼り付けます:
1.mywidget.h

#ifndef MYWIDGET_H
#define MYWIDGET_H

#include <QWidget>
#include <libmodbus/modbus.h>

#define ADDRESS_START 0
#define ADDRESS_END 9
#define LOOP  1

QT_BEGIN_NAMESPACE
namespace Ui {
    
     class myWidget; }
QT_END_NAMESPACE

class myWidget : public QWidget
{
    
    
    Q_OBJECT

public:
    myWidget(QWidget *parent = nullptr);
    ~myWidget();

private slots:
    void on_pushButton_clicked();

private:
    Ui::myWidget *ui;
    modbus_t *ctx;
    uint16_t *tab_reg;
    uint16_t *send_tab_reg;
    int nb;
    int addr;
    modbus_mapping_t *mb_mapping;
    int nb_fail;
    int nb_loop;
};
#endif // MYWIDGET_H

2.mywidget.cpp

#include "mywidget.h"
#include "ui_mywidget.h"

#include "libmodbus/modbus.h"
#include "QThread"
#include <QtDebug>
#include <errno.h>
#include <stdlib.h>
#include <malloc.h>


myWidget::myWidget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::myWidget)
{
    
    
    ui->setupUi(this);
}

myWidget::~myWidget()
{
    
    
    delete ui;
}


void myWidget::on_pushButton_clicked()
{
    
    
    int rc;
    int i;

    ctx = modbus_new_rtu("COM3", 115200, 'N', 8, 1);
    modbus_set_slave(ctx,1);

    modbus_set_debug(ctx,TRUE);

    if (modbus_connect(ctx)==-1)
        {
    
    
            fprintf(stderr, "Connection failed: %s\n",modbus_strerror(errno));
            modbus_free(ctx);
        }


        /*
        uint32_t old_response_to_sec;//秒
        uint32_t old_response_to_usec;//微秒,1秒=1,000,000微秒

        modbus_get_response_timeout(ctx, &old_response_to_sec, &old_response_to_usec);//获取当前设置的超时

        modbus_set_response_timeout(ctx,0,50000);//设定超时,默认50ms(50,000us)
        qDebug()<<"get timeout sec:"<<old_response_to_sec;
        qDebug()<<"get timeout usec:"<<old_response_to_usec;



        printf("\n----------------\n");*/
        nb=ADDRESS_END-ADDRESS_START;

        tab_reg=(uint16_t *)malloc(nb * sizeof(uint16_t));
        memset(tab_reg,0,nb * sizeof(uint16_t));

        /*写入保持寄存器数值*/
        nb_loop=nb_fail=0;
        while(nb_loop++<LOOP)
        {
    
    
            for(addr=ADDRESS_START;addr<ADDRESS_END;addr++)
            {
    
    
                int i;
                for(i=0;i<nb;i++)
                {
    
    
                    tab_reg[i]=(uint16_t)(65535*rand()/(RAND_MAX+1.0));
                }
                nb=ADDRESS_END-addr;

                rc=modbus_write_register(ctx,addr,tab_reg[0]);
                if(rc !=1)
                {
    
    
                    printf("ERROR modbus_write_register(%d)\n",rc);
                    nb_fail++;
                }
                else
                {
    
    
                    rc = modbus_read_registers(ctx,addr,1, tab_reg); //03#读取保持寄存器的值,(对象,起始地址,读取数量,存储读取到的值)
                    if (rc != 1)
                    {
    
    
                        fprintf(stderr,"%s\n", modbus_strerror(errno));
                        qDebug()<<"rc错误"<<modbus_strerror(errno);
                        nb_fail++;
                    }
                    else
                    {
    
    
                        qDebug()<<"链接成功";
                        for (i=0; i<10; i++)
                        {
    
    
                            printf("reg[%d] = %d(0x%x)\n", i, tab_reg[i], tab_reg[i]);
                            qDebug()<<"rc收到:"<<tab_reg[i];
                        }
                     }

                 }

               }
        }
        modbus_close(ctx);  //关闭modbus连接
        modbus_free(ctx);   //释放modbus资源,使用完libmodbus需要释放掉
}




実行後の効果は下図に示すとおり
画像3
です。レジスタに割り当てられた値がModbusスレーブに転送され、Modbusマスター側でこのコードが有効であることを示しています。
さらに、このテストを行うときは、libmodbusライブラリの編集やmodbus通信シミュレーションなど、最後の2つの記事の参照を使用したいと思っています。
リファレンス1:WindowsのQt 5でlibmodbusを使用する際の注意事項
リファレンス2:Visual Studioのlibmodbusライブラリに基づくmodbus RTUモードでの通信シミュレーション
リファレンス3:組み込みSTM32学習ノート(8)-libmodbus + Qt PCテスト

おすすめ

転載: blog.csdn.net/qq_43552324/article/details/108714390