QT+ModbusTCP 全网唯一好用,基于QTcpSocket纯手搓modbustcp协议

这篇具有很好参考价值的文章主要介绍了QT+ModbusTCP 全网唯一好用,基于QTcpSocket纯手搓modbustcp协议。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、编写缘由

1.发现问题

最近项目上要把之前的modbus RTU改为TCP形式,因此之前的modbus通讯线程得重构,一开始当然是使用Qt自带的QModbusTcpClient类,很快就重构好线程,读取数据没有问题,但是只要一发送写数据请求,整个tcp连接就会断开,做了很多尝试,排除了从站的问题,即使直接连modbusslave也是出现这种问题。

2.查找问题

于是自己写了一个tcp server,抓取QModbusTcpClient写数据的报文,和modbuspoll上的对比,果然对不上,qt中的报文比modbuspoll上的多出来一截,想必是协议错误了。

3.解决策略

QModbusTcpClient不就是在tcp通讯上添加了modbus协议嘛,既然它的协议都错了,那就没有使用的必要了,我们直接用QTcpSocket手搓一个ModbusTcp类就好了。

二、代码编写

1.协议解析

通过modbuspoll上的通信日志和网络上的modbustcp协议分析文章对比,研究出协议的标准格式。ModbusTCP协议报文分析

2.封装函数
void writeCoil(quint16 address,bool value);
void writeCoils(quint16 address,QVector<bool> values);
void writeRegist(quint16 address,quint16 value);
void writeRegists(quint16 address,QVector<quint16> values);

我共封装了以上4个函数,分别是写单个线圈、写多个线圈、写单个保持寄存器、写多个保持寄存器。
具体实现如下:

void ModbusTcp::writeRegist(quint16 address,quint16 value)
{
    QByteArray request;
    request.resize(12);
    request[0]=0x0;
    request[1]=0x0;
    request[2]=0x0;
    request[3]=0x0;
    request[4]=0x0;
    request[5]=0x06;
    request[6]=0x01;
    request[7]=0x06;
    uchar addh = address/256;
    request[8]=addh;//起始地址h
    uchar addl = address%256;
    request[9]=addl;//起始地址l
    uchar valueh = value/256;
    uchar valuel = value%256;
    request[10]=valueh;//值1h
    request[11]=valuel;//值1l
    client->write(request);
}

void ModbusTcp::writeRegists(quint16 address, QVector<quint16> values)
{
    QByteArray request;
    request.resize(13+values.count()*2);
    request[0]=0x0;
    request[1]=0x0;
    request[2]=0x0;
    request[3]=0x0;
    uchar lenh = (7+values.count()*2)/256;
    uchar lenl = (7+values.count()*2)%256;
    request[4]=lenh;//往后包长度h
    request[5]=lenl;//往后包长度l
    request[6]=0x01;
    request[7]=0x10;
    uchar addh = address/256;
    request[8]=addh;//起始地址h
    uchar addl = address%256;
    request[9]=addl;//起始地址l
    uchar numh = values.count()/256;
    uchar numl = values.count()%256;
    request[10]=numh;//数量h
    request[11]=numl;//数量l
    request[12]=values.count()*2;//字节数
    for(int i=0;i<values.count();i++){
        uchar valueh = values.at(i)/256;
        uchar valuel = values.at(i)%256;
        request[13+i*2]=valueh;
        request[14+i*2]=valuel;
    }
    client->write(request);
}

void ModbusTcp::writeCoil(quint16 address, bool value)
{
    QByteArray request;
    request.resize(12);
    request[0]=0x0;
    request[1]=0x0;
    request[2]=0x0;
    request[3]=0x0;
    request[4]=0x0;
    request[5]=0x06;
    request[6]=0x01;
    request[7]=0x05;
    uchar addh = address/256;
    uchar addl = address%256;
    request[8]=addh;//起始地址h
    request[9]=addl;//起始地址l
    if(value)
    	request[10]=0xFF;
    else
    	request[10]=0x0;
    request[11]=0x0;
    client->write(request);
}

void ModbusTcp::writeCoils(quint16 address, QVector<bool> values)
{
    QByteArray request;
    request.resize(13+ceil(values.count()/8));
    request[0]=0x0;
    request[1]=0x0;
    request[2]=0x0;
    request[3]=0x0;
    uchar lenh = (7+ceil(values.count()/8))/256;
    uchar lenl = int(7+ceil(values.count()/8))%256;
    request[4]=lenh;//往后包长度h
    request[5]=lenl;//往后包长度l
    request[6]=0x01;
    request[7]=0xF;
    uchar addh = address/256;
    request[8]=addh;//起始地址h
    uchar addl = address%256;
    request[9]=addl;//起始地址l
    uchar numh = values.count()/256;
    uchar numl = values.count()%256;
    request[10]=numh;//数量h
    request[11]=numl;//数量l
    request[12]=ceil(values.count()/8);//字节数
    QVector<uchar> bs;
    uchar a=0;
    uchar dy=values.count()%8;
    for(uchar i=0;i<dy;i++){
        if(values.at(values.count()-1-i))
            a+=pow(2,i);
    }
    bs.append(a);
    for(uchar i=0;i<values.count()/8;i++){
        a = 0;
        for(uchar j=dy+i*8;j<dy+i*8+8;j++){
            if(values.at(values.count()-1-j))
                a+=pow(2,(j-dy)%8);
        }
        bs.append(a);
    }
    for(uchar k=0;k<bs.count();k++){
        request[13+k]=bs.at(bs.count()-1-k);
    }
    client->write(request);
}

四个函数中除了写多个线圈还有问题外,其他都已验证,可以正确写入。
最后,我的tcp是作为一个子线程的,线程初始化函数如下:

void ModbusTcp::initModbus()
{
    client = new QTcpSocket(this);
    connect(client,&QTcpSocket::readyRead,this,&ModbusTcp::parseData);
    client->connectToHost("192.168.1.100",502);
    if(client->waitForConnected(3000)){
        qDebug()<<"trans connect success";
        timer = new QTimer(this);
        connect(timer,&QTimer::timeout,this,&ModbusTcp::startThread);
        timer->setSingleShot(false);
        timer->setInterval(1000);
        timer->start();
    }
    else{
        qDebug()<<"trans connect faild";
    }
}

三、源码下载

模块下载文章来源地址https://www.toymoban.com/news/detail-770074.html

四、最后的最后再吐槽一下QModbusTcpClient是真的垃圾,完全不能用。另外,大家在网上找到的QtModbusTCP资源,无一例外都是不能用的!!!处非和我一样纯手搓。

到了这里,关于QT+ModbusTCP 全网唯一好用,基于QTcpSocket纯手搓modbustcp协议的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • QT-使用QTcpSocket建立TCP客户端连接

    使用QT的QTcpSocket建立TCP客户端方式,十分的简单,上手也快,代码量不多,并且还自动支持重连接机制,也就是说如果你的服务端突然死机了,然后服务端又重启,那么我们的客户端这个时候是会自动去再连接的,不需要你的程序再做重连接的机制,所以我们应用起来是十分

    2024年02月14日
    浏览(31)
  • Qt 套接字类(QTcpSocket和QUdpSocket)解密:迈向 Qt 网络编程之巅

    套接字类在网络编程中起着至关重要的作用。套接字(Socket)为基于网络的通信提供了一种机制,使得不同设备、不同操作系统上的应用程序可以互相传输数据。套接字类负责建立连接、发送和接收数据、处理错误等任务,以简化网络通信的实现。通过使用套接字类,开发人

    2023年04月19日
    浏览(24)
  • uniapp接入友盟(全网唯一 很全!!!)

    (1)、在小程序文件夹下输入下面代码 npm install umtrack-wx --save (2)、在小程序components文件夹下新建umeng.js (3)、在umeng.js中写入下面代码 (4)、并且需要在友盟管理后台 = 设备管理 = 应用信息 输入AppID和AppSecret 不然的话,无法授权友盟自动获取Openid (5)、接着在微信公

    2024年02月10日
    浏览(33)
  • ZCU106的FMC接口AD/DA(全网唯一、全网最详)

    马上就要毕业啦,好久没写文章了,今天给大家带来硕士期间的最后一次AD/DA实验的实验记录,废话少说,先看连接与视频。 连接 视频 我做的实验是AN108+FL9613的DA与AD回环测试,可能和本节教程有点出入,不过没关系,能成功就行。 实验视频 一、实验任务 采用xilinx的dds波形

    2024年02月02日
    浏览(36)
  • 使用QTcpServer和QTcpSocket在QT中实现TCP通信的方法

    学习如何在QT中使用QTcpServer和QTcpSocket类实现TCP通信,建立服务器端和客户端,实现可靠的数据传输。

    2023年04月27日
    浏览(28)
  • 全网唯一!Matlab世界顶尖艺术品配色包Rmetbrewer

    想要绘制一幅颜色搭配合理、好看又不花哨的论文插图,该如何操作呢? 正所谓 求其上者得其中,求其中者得其下 。 那么, 向高手借鉴思路 ,无疑是一种不落下乘的好策略。 而在色彩搭配领域, 像莫奈、梵高这些世界顶级大师,其对色彩的理解和运用,又可谓是上中上

    2023年04月23日
    浏览(35)
  • 全网唯一最全彻底删除VS及VS注册表!

    当我们不再需要vs或者vs ide出现问题,并且你的专业课老师不教的情况下,怎么样独自且快速的情况下卸载干净。需要重装时,发现总是卸载不干净,卸载重装后该存在的问题还是存在,没有因重装而解决。那么如何彻底的卸载vs不留残留? 设备:HPZHAN66ProA14G3基于x64的电脑

    2024年02月03日
    浏览(27)
  • FPGA----VCU128的DDR4无法使用问题(全网唯一)

    1、在Vivado 2019.1版本中使用DDR4的IP核会遇到如下图所示的错误, 即便过了implementation生成了bit,DDR4也无法正常启动。 2、解决办法,上xilinx社区搜一下就知道了 AMD Customer Community https://support.xilinx.com/s/article/69035?language=en_US 这是关于DDR4的所已知问题的解决方案  AMD Customer Comm

    2024年02月07日
    浏览(34)
  • Qt 服务器 获取发送客户端的QTcpSocket对象 和 该socket的ip和端口号

    遇到问题:         众多客户端发送过来请求数据,如何找到该客户端的 QTcpsocket对象给该对象回复消息? 解决办法:         QTcpSocket *ptr =   dynamic_castQTcpSocket *(sender());         解释:通过 dynamic_cast强行转换。QTcpSocket *类型的对象、谁发送了信号就会触发      

    2024年02月12日
    浏览(28)
  • 【MATLAB】全网唯一的7种信号分解+ARIMA联合的时序预测算法全家桶

    有意向获取代码,请转文末观看代码获取方式~ 大家吃一顿火锅的价格便可以拥有7种信号分解+ARIMA组合的时序预测算法,绝对不亏,知识付费是现今时代的趋势,而且都是我精心制作的教程,有问题可随时反馈~也可单独获取某一算法的代码(见每一算法介绍后文)~ 接下来详

    2024年02月06日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包