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

文章目录

  • 前言
  • 一、引入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+PortmyClient->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 guigreaterThan(QT_MAJOR_VERSION, 4): QT += widgetsCONFIG += 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-8include (./MyModbus/MyModbus.pri)SOURCES += \main.cpp \widget.cppHEADERS += \widget.hFORMS += \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 serialportHEADERS += \$$PWD/mymodbus.hSOURCES += \$$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+PortmyClient->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进制为65535if(valueList[1] == 65535){resultNum = valueList[0] - 65536;}else{resultNum = (valueList[1] - 65535) * 65536 + (valueList[0] - 65536);}
}
else
{//判断是否大于65535,高16位的10进制大于0if(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_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic: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.rhkb.cn/news/104605.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

设计模式大白话——命令模式

命令模式 一、概述二、经典举例三、代码示例&#xff08;Go&#xff09;四、总结 一、概述 ​ 顾名思义&#xff0c;命令模式其实和现实生活中直接下命令的动作类似&#xff0c;怎么理解这个命令是理解命令模式的关键&#xff01;&#xff01;&#xff01;直接说结论是很不负责…

MindManager

MindManager 简介下载安装crack 简介 MindManager是一款由Mindjet公司开发的思维导图软件。思维导图是一种图形化的方法&#xff0c;用于在一个中心主题周围组织和呈现各种相关思想、想法和信息。MindManager允许用户创建、编辑和共享思维导图&#xff0c;以帮助他们更好地组织…

【Unity3D赛车游戏】【四】在Unity中添加阿克曼转向,下压力,质心会让汽车更稳定

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;Uni…

SMC状态机 讲解2 从模型到SMC

SMC状态机 讲解2 从模型到SMC 1、实例化有限状态机&#xff08;FSM)2、简单转换 Simple Transition3、外部环回转换 External Loopback Transition4、内部环回转换 Internal Loopback Transition5、转换动作6、转换Guard7、转换参数8、Entry 和 Exit动作9、Push 转换10、Pop转换…

鼠标拖拽盒子移动

目录 需求思路代码页面展示【补充】纯js实现 需求 浮动的盒子添加鼠标拖拽功能 思路 给需要拖动的盒子添加鼠标按下事件鼠标按下后获取鼠标点击位置与盒子边缘的距离给 document 添加鼠标移动事件鼠标移动过程中&#xff0c;将盒子的位置进行重新定位侦听 document 鼠标弹起&a…

【1-3章】Spark编程基础(Python版)

课程资源&#xff1a;&#xff08;林子雨&#xff09;Spark编程基础(Python版)_哔哩哔哩_bilibili 第1章 大数据技术概述&#xff08;8节&#xff09; 第三次信息化浪潮&#xff1a;以物联网、云计算、大数据为标志 &#xff08;一&#xff09;大数据 大数据时代到来的原因…

Docker环境安装elasticsearch和kibana

一、安装elasticsearch 创建es-network&#xff0c;让es、kibana在同一个网段&#xff1a; docker network create --driverbridge --subnet192.168.1.10/24 es-network运行elasticsearch docker run -d \ --name elasticsearch \ # 容器名 --hostname elasticsearch # 主机…

【开发笔记】ubuntu部署指定版本的前后端运行环境(npm nodejs mysql)

目录 1 背景2 环境要求3 部署流程3.1 npm的安装3.2 nodejs的安装3.3 MySQL的安装 4 可能的问题 1 背景 在远程服务器上的Ubuntu系统中&#xff0c;部署指定版本的前后端项目的运行环境 2 环境要求 npm 9.5.1Nodejs v18.16.1MySQL 8.0.33 3 部署流程 3.1 npm的安装 通过安…

Vue3新特性

认识vue3 1. Vue2 选项式 API vs Vue3 组合式API <script> export default {data(){return {count:0}},methods:{addCount(){this.count}} } </script><script setup> import { ref } from vue const count ref(0) const addCount ()> count.value &l…

安装docker服务及docker基本操作

一、docker安装&#xff08;yum安装&#xff09; 基于centos7 1.添加docker-ce 源信息 安装依赖包&#xff08;yum-utils 提供了 yum-config-manager &#xff0c;并且 device mapper 存储驱动程序需要device-mapper-persistent-data 和 lvm2&#xff09; yum install yum-…

​山东省图书馆典藏《乡村振兴战略下传统村落文化旅游设计》鲁图中大许少辉博士八一新书

​山东省图书馆《乡村振兴战略下传统村落文化旅游设计》鲁图中大许少辉博士八一新书

SpringCloud全家通新人入门手册

一、架构图 二、springCloud全家桶组件库 三、Spring Cloud 实战项目全景规划 四、技术选型 第一阶段&#xff1a;搭建基础的微服务功能&#xff0c;实现微服务之间的通信&#xff1b; 1、服务治理&#xff1a;服务治理的重点是搭建基础的跨服务调用功能。我会把用户服务、优…

LeetCode108. 将有序数组转换为二叉搜索树

108. 将有序数组转换为二叉搜索树 一、题目 给你一个整数数组 nums &#xff0c;其中元素已经按 升序 排列&#xff0c;请你将其转换为一棵 高度平衡 二叉搜索树。 高度平衡 二叉树是一棵满足「每个节点的左右两个子树的高度差的绝对值不超过 1 」的二叉树。 示例 1&#x…

PDF怎么批量加密?掌握这招事半功倍

PDF文件是一种广泛使用的文档格式&#xff0c;而加密可以有效地保护PDF文件的安全性。当需要批量加密PDF文件时&#xff0c;以下是一些方法及注意事项。 PDF批量加密的方法 相信很多小伙伴平时都是直接在PDF阅读器中对文档进行加密&#xff0c;但是这样只能每次对当前打开的文…

Android JNI系列详解之CMake编译工具的使用

一、CMake工具的介绍 如图所示&#xff0c;CMake工具的主要作用是&#xff0c;将C/C编写的native源文件编译打包生成库文件&#xff08;包含动态库或者静态库文件&#xff09;&#xff0c;集成到Android中使用。 二、CMake编译工具的使用 使用主要是配置两个文件&#xff1a;CM…

0103水平分片-jdbc-shardingsphere-中间件

文章目录 1 准备服务器1.1 创建server-order0容器1.2 创建server-order1容器 2、基本水平分片2.1、基本配置2.2、数据源配置2.3、标椎分片表配置2.4、行表达式2.5、分片算法配置2.6、分布式序列算法 3、多表关联3.1、创建关联表3.2、创建实体类3.3、创建Mapper3.4、配置关联表3…

Python土力学与基础工程计算.PDF-压水试验

Python 求解代码如下&#xff1a; 1. import math 2. 3. # 输入参数 4. L 2.0 # 试验段长度&#xff0c;m 5. Q 120.0 # 第三阶段计算流量&#xff0c;L/min 6. p 1.5 # 第三阶段试验段压力&#xff0c;MPa 7. r0 0.05 # 钻孔半径&#xff0c;m 8. 9. # 计算透…

kafka--技术文档--spring-boot集成基础简单使用

阿丹&#xff1a; 查阅了很多资料了解到&#xff0c;使用了spring-boot中整合的kafka的使用是被封装好的。也就是说这些使用其实和在linux中的使用kafka代码的使用其实没有太大关系。但是逻辑是一样的。这点要注意&#xff01; 使用spring-boot整合kafka 1、导入依赖 核心配…

如何安装指定版本node.js,安装旧版本node

1、查看当前是否安装node&#xff0c;如果安装了需要先卸载当前版本node 搜索控制面板 -> 找到程序/卸载程序 -> 在里面找到node -> 然后右击卸载 2、卸载完成后就要安装其他版本得node.js 找到想要安装的对应版本&#xff0c;安装.msi格式的安装包 注&#xff…

权重初始化

常用的权重初始化方法&#xff1a; 随机初始化&#xff08;Random Initialization&#xff09; Xavier 初始化&#xff08;Glorot Initialization&#xff09; He 初始化&#xff08;He Initialization&#xff09;Kaiming 零初始化&#xff08;Zero Initialization&#x…