Qt下使用ModbusTcp通信协议进行PLC线圈/保持寄存器的读写(32位有符号数)

news2024/11/12 10:19:27

文章目录

  • 前言
  • 一、引入Modbus模块
  • 二、Modbus设备的连接
  • 三、各寄存器数据的读取
  • 四、各寄存器数据的写入
  • 五、示例完整代码
  • 总结


前言

本文主要讲述了使用Qt的Modbus模块来进行ModbusTcp的通信,实现对PLC的线圈寄存器和保持寄存器的读写,基于TCP/IP的Modbus协议的内容我就不做过多解释了,详见参考文章。在本文示例中采用QModbusTcpClient类作为Modbus客户端(主站),PLC作为从站,封装了一个自己的MyModbus类,希望可以帮助到大家,如有错误之处,欢迎大家批评指正。

项目效果
请添加图片描述


提示:以下是本篇文章正文内容,下面案例可供参考

一、引入Modbus模块

1.这里我实现了自己的MyModbus类的封装,使用了pri子模块的方式,也是方便日后进行此模块的复用
pri中引入Modbus模块:
MyModbus.pri

QT   += serialbus serialport

MyModbus类中添加相关头文件

#include <QModbusTcpClient>
#include <QModbusDataUnit>

二、Modbus设备的连接

1.ModbusTcp的连接只需要配置好连接参数IP+Port

//判断当前连接状态是否为断开状态
if(myClient->state() != QModbusDevice::ConnectedState)
{
    //配置ModbusTcp的连接参数IP+Port
    myClient->setConnectionParameter(QModbusDevice::NetworkAddressParameter,ip);
    myClient->setConnectionParameter(QModbusDevice::NetworkPortParameter,port);
    myClient->connectDevice();
}

三、各寄存器数据的读取

1.Modbus中有4种操作对象,这4种都能进行读取操作:线圈、离散输入、保持寄存器、输入寄存器

//读取modbus设备各寄存器数据
//typeNum:1_线圈 2_离散输入 3_保持 4_输入
bool MyModbus::readModbusData(int typeNum,int startAdd,quint16 numbers)
{
    if(myClient->state() != QModbusDevice::ConnectedState)
    {
        return false;
    }

    //确定寄存器类型
    QModbusDataUnit ReadUnit;
    if(typeNum == 1)
    {
        ReadUnit = QModbusDataUnit(QModbusDataUnit::Coils,startAdd,numbers);
    }
    else if(typeNum == 2)
    {
        ReadUnit = QModbusDataUnit(QModbusDataUnit::DiscreteInputs,startAdd,numbers);
    }
    else if(typeNum == 3)
    {
        ReadUnit = QModbusDataUnit(QModbusDataUnit::HoldingRegisters,startAdd,numbers);
    }
    else if(typeNum == 4)
    {
        ReadUnit = QModbusDataUnit(QModbusDataUnit::InputRegisters,startAdd,numbers);
    }
    else
    {
        LOGDEBUG<<"读取寄存器类型错误";
        return false;
    }
    LOGDEBUG<<"readModbusData typeNum:"<<typeNum;

    //多读
    if(auto *reply = myClient->sendReadRequest(ReadUnit,1))
    {
        if(!reply->isFinished())
        {
            if((typeNum == 1) || (typeNum == 2))
            {
                QObject::connect(reply,&QModbusReply::finished,this,&MyModbus::slot_readReadyCoils);   //读取线圈
            }
            if((typeNum == 3) || (typeNum == 4))
            {
                QObject::connect(reply,&QModbusReply::finished,this,&MyModbus::slot_readReadyRegisters);   //读取寄存器
            }
            //reply->deleteLater();
            return true;
        }
        else
        {
            reply->deleteLater();
            return false;
        }
    }
    else
    {
        LOGDEBUG<<"读取错误:" + myClient->errorString();
        return false;
    }
}

四、各寄存器数据的写入

1.Modbus中4种操作对象只有这2种能进行写入操作:线圈 、保持寄存器

//对modbus设备各寄存器写入数据
//typeNum:1_线圈 2_保持 (这两类寄存器可读可写,其余的只读)
bool MyModbus::writeModbusData(int typeNum,int startAdd,int writeNum)
{
    if(myClient->state() != QModbusDevice::ConnectedState)
    {
        return false;
    }

    //确定寄存器类型
    QModbusDataUnit writeUnit;
    if(typeNum == 1)
    {
        writeUnit = QModbusDataUnit(QModbusDataUnit::Coils,startAdd,1);   //写入一个数据
        writeUnit.setValue(0,writeNum);

        //单写
        //bool ok;
        //quint16 hexData = writeData.toInt(&ok,16);   //转16进制
    }
    else if(typeNum == 2)
    {
        writeUnit = QModbusDataUnit(QModbusDataUnit::HoldingRegisters,startAdd,2);   //写入两个数据
        quint16 uData16[2] = {0};
        uData16[0] = writeNum & 0xffff;
        uData16[1] = (writeNum >> 16) & 0xffff;
        writeUnit.setValue(0,uData16[0]);
        writeUnit.setValue(1,uData16[1]);
        //LOGDEBUG<<"uData16[0]:"<<uData16[0]<<"   uData16[1]:"<<uData16[1]<<"   writeNum:"<<writeNum;
    }
    else
    {
        LOGDEBUG<<"写入寄存器类型错误";
        return false;
    }
    //LOGDEBUG<<"writeModbusData typeNum:"<<typeNum<<"   writeNum:"<<writeNum;
    if(auto *reply = myClient->sendWriteRequest(writeUnit,1))
    {
        if(!reply->isFinished())
        {
            connect(reply,&QModbusReply::finished,this,[reply]()
            {
                if(reply->error() == QModbusDevice::NoError)
                {
                    reply->deleteLater();
                    return true;
                }
                else
                {
                    LOGDEBUG<<"写入返回错误:"<<reply->error();
                    reply->deleteLater();
                    return false;
                }
            });
        }
        else
        {
            reply->deleteLater();
            return false;
        }
    }
    else
    {
        LOGDEBUG<<"写入错误:" + myClient->errorString();
        return false;
    }
    return true;
}

五、示例完整代码

这里是示例项目的完整代码,包含pro主程序和MyModbus.pri子文件
1.ModbusTest.pro

QT   += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++11

#定义编译选项.QT_DEPRECATED_WARNINGS表示当Qt的某些功能被标记为过时的,那么编译器会发出警告.
DEFINES += QT_DEPRECATED_WARNINGS

#设置字符(MSCV编译器下防止中文乱码)
contains( CONFIG,"msvc" ):QMAKE_CXXFLAGS += /source-charset:utf-8 /execution-charset:utf-8
contains( CONFIG,"msvc" ):QMAKE_CFLAGS +=/source-charset:utf-8 /execution-charset:utf-8

include (./MyModbus/MyModbus.pri)

SOURCES += \
    main.cpp \
    widget.cpp

HEADERS += \
    widget.h

FORMS += \
    widget.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

2.MyModbus.pri

QT       += serialbus serialport

HEADERS += \
    $$PWD/mymodbus.h

SOURCES += \
    $$PWD/mymodbus.cpp

3.mymodbus.h

#ifndef MYMODBUS_H
#define MYMODBUS_H

#include <QObject>
#include <QModbusTcpClient>
#include <QModbusDataUnit>
#include <QDebug>

#define LOGDEBUG qDebug()<<__FILE__<<__LINE__

class MyModbus : public QObject
{
    Q_OBJECT
public:
    explicit MyModbus(QObject *parent = nullptr);
    ~MyModbus();

    void initModbus();

    void connectToModbus(QString ip,int port);

    bool readModbusData(int typeNum,int startAdd,quint16 numbers);
    bool writeModbusData(int typeNum,int startAdd,int writeNum);

signals:
    void signal_stateChanged(bool flag);
    void signal_readCoils(QVector<quint16> vAllData);
    void signal_readRegisters(int resultNum);

private slots:
    void slot_stateChanged();
    void slot_readReadyCoils();
    void slot_readReadyRegisters();

private:
    QModbusTcpClient *myClient;

};
#endif // MYMODBUS_H

4.mymodbus.cpp

#include "mymodbus.h"

MyModbus::MyModbus(QObject *parent) : QObject(parent)
{
    this->initModbus();
}

MyModbus::~MyModbus()
{

}

//初始化
void MyModbus::initModbus()
{
    myClient = new QModbusTcpClient();
    //connect(myClient,SIGNAL(stateChanged()),this,SLOT(slot_stateChanged()));
    connect(myClient,&QModbusClient::stateChanged,this,&MyModbus::slot_stateChanged);
}

//连接到modbus设备
void MyModbus::connectToModbus(QString ip,int port)
{
    if(!myClient)
    {
        return;
    }

    //判断当前连接状态是否为断开状态
    if(myClient->state() != QModbusDevice::ConnectedState)
    {
        //配置ModbusTcp的连接参数IP+Port
        myClient->setConnectionParameter(QModbusDevice::NetworkAddressParameter,ip);
        myClient->setConnectionParameter(QModbusDevice::NetworkPortParameter,port);
        myClient->connectDevice();
    }
    //else
    //{
    //    myClient->disconnectDevice();
    //}
}

//读取modbus设备各寄存器数据
//typeNum:1_线圈 2_离散输入 3_保持 4_输入
bool MyModbus::readModbusData(int typeNum,int startAdd,quint16 numbers)
{
    if(myClient->state() != QModbusDevice::ConnectedState)
    {
        return false;
    }

    //确定寄存器类型
    QModbusDataUnit ReadUnit;
    if(typeNum == 1)
    {
        ReadUnit = QModbusDataUnit(QModbusDataUnit::Coils,startAdd,numbers);
    }
    else if(typeNum == 2)
    {
        ReadUnit = QModbusDataUnit(QModbusDataUnit::DiscreteInputs,startAdd,numbers);
    }
    else if(typeNum == 3)
    {
        ReadUnit = QModbusDataUnit(QModbusDataUnit::HoldingRegisters,startAdd,numbers);
    }
    else if(typeNum == 4)
    {
        ReadUnit = QModbusDataUnit(QModbusDataUnit::InputRegisters,startAdd,numbers);
    }
    else
    {
        LOGDEBUG<<"读取寄存器类型错误";
        return false;
    }
    LOGDEBUG<<"readModbusData typeNum:"<<typeNum;

    //多读
    if(auto *reply = myClient->sendReadRequest(ReadUnit,1))
    {
        if(!reply->isFinished())
        {
            if((typeNum == 1) || (typeNum == 2))
            {
                QObject::connect(reply,&QModbusReply::finished,this,&MyModbus::slot_readReadyCoils);   //读取线圈
            }
            if((typeNum == 3) || (typeNum == 4))
            {
                QObject::connect(reply,&QModbusReply::finished,this,&MyModbus::slot_readReadyRegisters);   //读取寄存器
            }
            //reply->deleteLater();
            return true;
        }
        else
        {
            reply->deleteLater();
            return false;
        }
    }
    else
    {
        LOGDEBUG<<"读取错误:" + myClient->errorString();
        return false;
    }
}

//对modbus设备各寄存器写入数据
//typeNum:1_线圈 2_保持 (这两类寄存器可读可写,其余的只读)
bool MyModbus::writeModbusData(int typeNum,int startAdd,int writeNum)
{
    if(myClient->state() != QModbusDevice::ConnectedState)
    {
        return false;
    }

    //确定寄存器类型
    QModbusDataUnit writeUnit;
    if(typeNum == 1)
    {
        writeUnit = QModbusDataUnit(QModbusDataUnit::Coils,startAdd,1);   //写入一个数据
        writeUnit.setValue(0,writeNum);

        //单写
        //bool ok;
        //quint16 hexData = writeData.toInt(&ok,16);   //转16进制
    }
    else if(typeNum == 2)
    {
        writeUnit = QModbusDataUnit(QModbusDataUnit::HoldingRegisters,startAdd,2);   //写入两个数据
        quint16 uData16[2] = {0};
        uData16[0] = writeNum & 0xffff;
        uData16[1] = (writeNum >> 16) & 0xffff;
        writeUnit.setValue(0,uData16[0]);
        writeUnit.setValue(1,uData16[1]);
        //LOGDEBUG<<"uData16[0]:"<<uData16[0]<<"   uData16[1]:"<<uData16[1]<<"   writeNum:"<<writeNum;
    }
    else
    {
        LOGDEBUG<<"写入寄存器类型错误";
        return false;
    }
    //LOGDEBUG<<"writeModbusData typeNum:"<<typeNum<<"   writeNum:"<<writeNum;
    if(auto *reply = myClient->sendWriteRequest(writeUnit,1))
    {
        if(!reply->isFinished())
        {
            connect(reply,&QModbusReply::finished,this,[reply]()
            {
                if(reply->error() == QModbusDevice::NoError)
                {
                    reply->deleteLater();
                    return true;
                }
                else
                {
                    LOGDEBUG<<"写入返回错误:"<<reply->error();
                    reply->deleteLater();
                    return false;
                }
            });
        }
        else
        {
            reply->deleteLater();
            return false;
        }
    }
    else
    {
        LOGDEBUG<<"写入错误:" + myClient->errorString();
        return false;
    }
    return true;
}

//监听TCP连接的状态,若状态发生改变,发出对应的信号
void MyModbus::slot_stateChanged()
{
    LOGDEBUG<<myClient->state();
    if(myClient->state() == QModbusDevice::ConnectedState)
    {
        emit signal_stateChanged(true);
    }
    else if(myClient->state() == QModbusDevice::UnconnectedState)
    {
        emit signal_stateChanged(false);
    }
}

//接收到读取线圈/离散输入寄存器请求后执行的槽函数
void MyModbus::slot_readReadyCoils()
{
    QVector<quint16> vAllData;
    QModbusReply *reply = qobject_cast<QModbusReply *>(sender());
    if(!reply)
    {
        LOGDEBUG<<"读取线圈/离散输入寄存器错误";
        return;
    }
    if(reply->error() == QModbusDevice::NoError)
    {
        const QModbusDataUnit unit = reply->result();
        vAllData = unit.values();
        emit signal_readCoils(vAllData);
    }
    else
    {
        LOGDEBUG<<"线圈/离散输入寄存器回复错误:"<<reply->error();
    }
    reply->deleteLater();
}

//接收到读取保持/输入寄存器请求后执行的槽函数
void MyModbus::slot_readReadyRegisters()
{
    QModbusReply *reply = qobject_cast<QModbusReply *>(sender());
    if(!reply)
    {
        LOGDEBUG<<"读取保持/输入寄存器错误";
        return;
    }
    if(reply->error() == QModbusDevice::NoError)
    {
        const QModbusDataUnit unit = reply->result();
        auto valueList = unit.values();
        int nSize = valueList.size();
        if(nSize == 2)
        {
            quint16 uData16[2] = {0};
            uData16[0] = valueList[0];
            uData16[1] = valueList[1];
            int resultNum = uData16[0] | (uData16[1] << 16);
            //LOGDEBUG<<"uData16[0]:"<<uData16[0]<<"   uData16[1]:"<<uData16[1]<<"   resultNum:"<<resultNum;
            emit signal_readRegisters(resultNum);
        }
        else
        {
            LOGDEBUG<<"保持寄存器返回数据错误,个数:"<<nSize;
        }
    }
    else
    {
        LOGDEBUG<<"保持/输入寄存器回复错误:"<<reply->error();
    }
    reply->deleteLater();
}

/*
//读取保持/输入寄存器数据的另一种方式,已废弃
//当前数据格式为大端模式,高位存低地址
//判断正负数,以高8位的16进制是否为f判断
int resultNum = 0;
if(QString::number(valueList[1],16).left(1) == "f")   //负数
{
    //判断是否小于-65535,高16位的10进制为65535
    if(valueList[1] == 65535)
    {
        resultNum = valueList[0] - 65536;
    }
    else
    {
        resultNum = (valueList[1] - 65535) * 65536 + (valueList[0] - 65536);
    }
}
else
{
    //判断是否大于65535,高16位的10进制大于0
    if(valueList[1] > 0)
    {
        resultNum = valueList[1] * 65536 + valueList[0];
    }
    else
    {
        resultNum = valueList[0];
    }
}
*/

5.widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QFileDialog>
#include <QDateTime>
#include <QMessageBox>
#include "MyModbus/mymodbus.h"

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

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

    void initWidget();

private slots:
    void slot_stateChanged(bool flag);
    void slot_readCoils(QVector<quint16> vAllData);
    void slot_readRegisters(int resultNum);

private slots:
    void on_pb_connect_clicked();
    void on_pb_readM_clicked();
    void on_pb_writeM_clicked();
    void on_pb_readD_clicked();
    void on_pb_writeD_clicked();

private:
    Ui::Widget *ui;

    MyModbus *m_myModsbus;   //MyModbus对象

};
#endif // WIDGET_H

6.widget.cpp

#include "widget.h"
#include "ui_widget.h"

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

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

void Widget::initWidget()
{
    //初始化MyModbus对象
    m_myModsbus = new MyModbus();
    connect(m_myModsbus,SIGNAL(signal_stateChanged(bool)),this,SLOT(slot_stateChanged(bool)));
    connect(m_myModsbus,SIGNAL(signal_readCoils(QVector<quint16>)),this,SLOT(slot_readCoils(QVector<quint16>)));
    connect(m_myModsbus,SIGNAL(signal_readRegisters(int)),this,SLOT(slot_readRegisters(int)));

}

void Widget::slot_stateChanged(bool flag)
{
    if(flag)
    {
        ui->lb_state->setText("连接成功");
        ui->te_show->appendPlainText(QTime::currentTime().toString("hh:mm:ss: ") + "连接成功");
        QMessageBox::warning(this,"警告","连接成功!");
    }
    else
    {
        ui->lb_state->setText("连接断开");
        ui->te_show->appendPlainText(QTime::currentTime().toString("hh:mm:ss: ") + "连接断开");
        QMessageBox::warning(this,"警告","连接断开!");
    }
}

void Widget::slot_readCoils(QVector<quint16> vAllData)
{
    LOGDEBUG<<"readCoils size:"<<vAllData.size();
    for(int i=0;i<vAllData.size();i++)
    {
        LOGDEBUG<<"i:"<<vAllData[i];

        ui->te_show->appendPlainText(QTime::currentTime().toString("hh:mm:ss: ") + "读取M区返回数据:" + QString::number(vAllData[i]));
        ui->le_dataM->setText(QString::number(vAllData[0]));
    }
}

void Widget::slot_readRegisters(int resultNum)
{
    LOGDEBUG<<"resultNum:"<<resultNum;

    ui->te_show->appendPlainText(QTime::currentTime().toString("hh:mm:ss: ") + "读取D区返回数据:" + QString::number(resultNum));
    ui->le_dataD->setText(QString::number(resultNum));
}

void Widget::on_pb_connect_clicked()
{
    QString ip = ui->le_ip->text();
    int port = ui->le_port->text().toInt();
    LOGDEBUG<<"ip:"<<ip<<"   port:"<<port;
    ui->te_show->appendPlainText(QTime::currentTime().toString("hh:mm:ss: ") + "ip:" + ip + " port:" + QString::number(port));

    //连接到modbus设备
    m_myModsbus->connectToModbus(ip,port);
}

void Widget::on_pb_readM_clicked()
{
    int startAdd = ui->le_addressM->text().toInt();
    LOGDEBUG<<"startAdd:"<<startAdd;

    if(!m_myModsbus->readModbusData(1,startAdd,1))
    {
        QMessageBox::warning(this,"警告","M区数据读取失败!");
    }
}

void Widget::on_pb_writeM_clicked()
{
    int startAdd = ui->le_addressM->text().toInt();
    int writeNum = ui->le_dataM->text().toInt();
    LOGDEBUG<<"startAdd:"<<startAdd<<"   writeNum:"<<writeNum;

    //单写
    if(!m_myModsbus->writeModbusData(1,startAdd,writeNum))
    {
        QMessageBox::warning(this,"警告","M区数据写入失败!");
    }
}

void Widget::on_pb_readD_clicked()
{
    int startAdd = ui->le_addressD->text().toInt();
    LOGDEBUG<<"startAdd:"<<startAdd;

    if(!m_myModsbus->readModbusData(3,startAdd,2))
    {
        QMessageBox::warning(this,"警告","D区数据读取失败!");
    }
}

void Widget::on_pb_writeD_clicked()
{
    int startAdd = ui->le_addressD->text().toInt();
    int writeNum = ui->le_dataD->text().toInt();;
    LOGDEBUG<<"startAdd:"<<startAdd<<"   writeNum:"<<writeNum;

    //进行写入寄存器数据的处理
    if(!m_myModsbus->writeModbusData(2,startAdd,writeNum))
    {
        QMessageBox::warning(this,"警告","D区数据写入失败!");
    }
}

7.main.cpp

#include "widget.h"
#include <QApplication>
#include <QMutex>

//程序输出日志
void outputMessage(QtMsgType type,const QMessageLogContext &context,const QString &msg)
{
    static QMutex mutex;
    mutex.lock();

    //初始化log文件夹
    QString logFilePath = QCoreApplication::applicationDirPath() + "/LogFile/";
    QDir dstDir(logFilePath);
    if(!dstDir.exists())
    {
        if(!dstDir.mkpath(logFilePath))
        {
            LOGDEBUG<<"程序输出日志创建失败!";
        }
        else
        {
            LOGDEBUG<<"程序输出日志创建成功!";
        }
    }

    //获取输出内容
    QString debugMsg;
    if(type == QtDebugMsg)
    {
        QString debugDateTime = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
        debugMsg = QString("%1\n%2%3").arg(debugDateTime).arg(msg).arg(context.function);
    }

    //保存文件
    QString curDate = QDate::currentDate().toString("yyyyMMdd");
    QString logFile = logFilePath + "log_" + curDate + ".txt";
    QFile file(logFile);
    file.open(QIODevice::WriteOnly | QIODevice::Append);
    QTextStream textStream(&file);
    textStream << debugMsg << "\n\n";
    file.flush();
    file.close();

    mutex.unlock();
}

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    qInstallMessageHandler(outputMessage);
    Widget w;
    w.show();
    return a.exec();
}

8.widget.ui
请添加图片描述


总结

基于Qt使用这个ModbusTcp协议进行通信,还是比较简单的,首先就是确定下寄存器的类型,直接使用相关的函数进行读写。需要注意的一点是在进行保持寄存器读写的时候,我们PLC某个地址上的数是个16位的数,所以在进行32位有符号数读写的时候,要考虑两个相邻地址的组合,文中就对此进行了处理,这种情况下PLC那边也别忘记进行相应的设置哈。


hello:
共同学习,共同进步,如果还有相关问题,可在评论区留言进行讨论。

参考博客:
QT下的Modbus TCP 通讯
C++与PLC通过Modbus TCP协议进行PLC内部寄存器的值的读取/写入总结

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/908295.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JavaSE【 String 类】

一、String 类 1、字符串构造 常用三种 String的构造方法&#xff1a;有带参数的&#xff0c;和不带参数的 public class Test {public static void main(String[] args) {//字符串直接赋值String str "hello";//string是一个引用类型&#xff0c;str这个变量存的…

【Redis】Redis 的学习教程(一)入门基础

1. 简介 Redis 全称&#xff1a;Remote Dictionary Server&#xff08;远程字典服务器&#xff09;&#xff0c;是一款开源的&#xff0c;遵守 BSD 协议&#xff0c;使用 C 语言开发的 key-value 存储系统。简单的说&#xff0c;它是一款跨平台的非关系型数据库&#xff0c;支…

第 111 场LeetCode 双周赛题解

A 统计和小于目标的下标对数目 数据量小&#xff0c;直接枚举数对 class Solution { public:int countPairs(vector<int> &nums, int target) {int n nums.size();int res 0;for (int i 0; i < n; i)for (int j 0; j < i; j)if (nums[i] nums[j] < tar…

day23 遍历 所有文件夹 子文件夹 文件

统计目录大小 public static long getAllFilesLength(File file) {long length 0l;if (file null) {System.out.println("文件为空");}long fileLengths[] new long[0];File files[] file.listFiles();for (int i 0; i < files.length; i) {if (files[i].isD…

用例图的基本概念及其使用方式(包含案例)

一、引言 用例(Use Case)&#xff0c;是软件工程或系统工程中对系统如何反应外界请求的描述&#xff0c;是一种通过用户的使用场景来获取需求的技术。此概念“用例”的提出者为Ivar Jacobson。每个用例提供了一个或多个场景&#xff0c;该场景说明了系统是如何和最终用户或其它…

C++(8.21)c++初步

1.斐波那契&#xff1a; #include <iostream> #include<iomanip>using namespace std;int main() {cout << "Hello World!" << endl;int a[10];for(int i0;i<10;i){if(0i||1i){a[i]1;}elsea[i]a[i-1]a[i-2];cout <<setw(4) <&l…

微信扫码报修系统哪家好?的修报修管理系统有什么优势?

“的修app”是一款基于互联网和云计算技术的在线报修系统&#xff0c;主要服务于物业管理公司、企业、机关单位、学校、医院等机构和组织。它提供了一系列报修管理服务&#xff0c;包括故障报修、设备管理、巡检管理、耗材管理等功能。用户只需用手机扫一下二维码&#xff0c;即…

Linux 多线程中执行fork的情况

一、普通多线程中执行fork的情况 1.多线程中没有执行fork的情况 代码如下&#xff1a; #include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<pthread.h> #include<string.h> #include<semaphore.h>void*fun(void* arg) …

PSP - 基于开源框架 OpenFold Multimer 蛋白质复合物的结构预测与BugFix

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/132410296 AlphaFold2-Multimer 是一个基于 AlphaFold2 的神经网络模型&#xff0c;可以预测多链蛋白复合物的结构。该模型在训练和推理时都可以处…

Lnton羚通算法算力云平台如何在OpenCV-Python中使用cvui库创建复选框

CVUI 之 复选框 Python import numpy as np import cv2 import cvuidef checkbox_test():WINDOW_NAME Checkbox-Testchecked [False]# 创建画布frame np.zeros((300, 400, 3), np.uint8)# 初始化窗口cvui.init(WINDOW_NAME)while True:# 画布填色frame[:] (100, 200, 100…

WEB APIs day5

一、window对象 BOM属于window对象 1.BOM&#xff08;浏览器对象模型&#xff09; bom里面包含着dom,只不过bom我们平时用得比较少&#xff0c;我们经常使用的是dom操作&#xff0c;因为我们页面中的这些标签都是在dom中取的&#xff0c;所以我们操作dom多一点。 window对象…

大数据、人工智能、机器学习、深度学习关系联系前言

1.大数据和人工智能关系 2.机器学习、深度学习、人工智能关系 3.监督学习、无监督学习、半监督学习、强化学习、迁移学习关系 4.机器学习具体内容 一、大数据和人工智能之间存在相促进并相互支持&#xff0c;推动了科技发展 1.数据驱动的人工智能&#xff1a;人工智能系统需要…

【是C++,不是C艹】 手把手带你实现Date类(附源码)

&#x1f49e;&#x1f49e;欢迎来到 Claffic 的博客&#x1f49e;&#x1f49e; &#x1f449; 专栏&#xff1a;《是C&#xff0c;不是C艹》&#x1f448; 前言&#xff1a; 恍惚间&#xff0c;已经两个月没更新了 &#xff08;&#xff1b;д&#xff40;&#xff09;ゞ 我忏…

K8s+Docker+KubeSphere+DevOps笔记

K8sDockerKubeSphereDevOps 前言一、阿里云服务器开通二、docker基本概念1.一次构建、到处运行2、docker基础命令操作3、docker进阶操作1.部署redis中间件2.打包docker镜像 三、kubernetes 大规模容器编排系统1、基础概念&#xff1a;1、服务发现和负载均衡2、存储编排3、自动部…

基于springboot+vue的流动人口登记系统(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目介绍…

因果推断(五)基于谷歌框架Causal Impact的因果推断

因果推断&#xff08;五&#xff09;基于谷歌框架Causal Impact的因果推断 除了传统的因果推断外&#xff0c;还有一些机器学习框架可以使用&#xff0c;本文介绍来自谷歌框架的Causal Impact。该方法基于合成控制法的原理&#xff0c;利用多个对照组数据来构建贝叶斯结构时间…

javaScript:常用的js字符串方法

目录 一.前言 二.字符串方法 1.charAt(num) 获取字符串指定位置上的字符 解释 示例 注意 2.length属性 获取字符串长度 解释 示例讲解 3.substring()字符串的截取 解释 特点 示例 4.slice()字符串截取 解释 特点 示例 应用 单行文本加省略号 字符串劫…

Dockerfile制作镜像与搭建LAMP环境

1、编写Dockerfile制作Web应用系统nginx镜像&#xff0c;生成镜像nginx:v1.1&#xff0c;并推送其到私有仓库。 具体要求如下&#xff1a; &#xff08;1&#xff09;基于centos基础镜像&#xff1b; &#xff08;2&#xff09;指定作者信息&#xff1b; &#xff08;3&#x…

卷积神经网络——中篇【深度学习】【PyTorch】

文章目录 5、卷积神经网络5.5、经典卷积神经网络&#xff08;LeNet&#xff09;5.5.1、理论部分5.5.2、代码实现 5.6、深度卷积神经网络&#xff08;AlexNet&#xff09;5.6.1、理论部分5.6.2、代码实现 5.7、使用块的网络&#xff08;VGG&#xff09;5.7.1、理论部分5.7.2、代…

从浅到深研究矩阵的特征值、特征向量

本篇特征值、特征向量笔记来源于MIT线性代数课程。 矩阵特征值与特征向量 ✨引言✨什么是特征向量呢&#xff1f;✨表示✨从特例看特征值与特征向量✨如何求解方程▶️ 思路&#xff1a;✨对称矩阵例子&#xff1a;✨对比观察两个矩阵及它们的特征值及特征向量&#xff1a;✨旋…