You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
326 lines
12 KiB
326 lines
12 KiB
2 years ago
|
#include "mymodbustcp.h"
|
||
|
|
||
|
MyModbusTcp::MyModbusTcp()
|
||
|
{
|
||
|
modbusDevice = new QModbusTcpClient();
|
||
|
//有错误发生时,发出提示
|
||
|
connect(modbusDevice, &QModbusClient::errorOccurred, this, &MyModbusTcp::errorOccurred_Slot);
|
||
|
//状态改变
|
||
|
if(modbusDevice == nullptr){
|
||
|
qDebug()<<"cannot create modbus client";
|
||
|
}
|
||
|
else{
|
||
|
connect(modbusDevice, &QModbusClient::stateChanged, this, &MyModbusTcp::stateChanged_SLot);
|
||
|
}
|
||
|
}
|
||
|
/**
|
||
|
* @brief MyModbusTcp::timeGoBy 等待tms
|
||
|
* @param time
|
||
|
* @param t
|
||
|
*/
|
||
|
void MyModbusTcp::timeGoBy(QTime time, int t){
|
||
|
time.start(); //设定time为当前时间
|
||
|
while(time.elapsed() < t){ //等待时间流逝500ms
|
||
|
QCoreApplication::processEvents(); //处理事件
|
||
|
}
|
||
|
}
|
||
|
//===================================数据类型转换===============================
|
||
|
/**
|
||
|
* @brief MyModbusTcp::float2Word 将浮点数f转化为2个8位数据存放在word数组中
|
||
|
* @param f 待转换的浮点数
|
||
|
* @param word 转换后的word数组
|
||
|
*/
|
||
|
void MyModbusTcp::float2Word(float f, unsigned int *word)
|
||
|
{
|
||
|
unsigned long longdata = 0;
|
||
|
longdata = *(unsigned long*)&f; //注意,会丢失精度
|
||
|
word[0] = (longdata & 0xFFFF0000) >> 16;
|
||
|
word[1] = (longdata & 0x0000FFFF);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief MyModbusTcp::word2Float 将2个word数据转化为浮点数
|
||
|
* @param p 指向word数组的指针
|
||
|
* @param dataTransformed 转化后的浮点数
|
||
|
*/
|
||
|
void MyModbusTcp:: word2Float(unsigned int *p, float dataTransformed)
|
||
|
{
|
||
|
dataTransformed=0;
|
||
|
unsigned long longdata = 0;
|
||
|
longdata = (*p<< 16) + (*(p+1) << 0);
|
||
|
dataTransformed = *(float*)&longdata;
|
||
|
}
|
||
|
|
||
|
//==========================================modbustcp====================
|
||
|
/**
|
||
|
* @brief MyModbusTcp::errorOccurred_Slot 有错误发生
|
||
|
*/
|
||
|
void MyModbusTcp::errorOccurred_Slot(){
|
||
|
qDebug()<<"new error"<<modbusDevice->errorString();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief MyModbusTcp::stateChanged_SLot 状态改变
|
||
|
*/
|
||
|
void MyModbusTcp::stateChanged_SLot(){
|
||
|
if(modbusDevice->state() == QModbusDevice::UnconnectedState){
|
||
|
qDebug()<<"Tcp Client未连接到server";
|
||
|
}
|
||
|
else if(modbusDevice->state() == QModbusDevice::ConnectingState){
|
||
|
qDebug()<<"正在连接";
|
||
|
}
|
||
|
else if(modbusDevice->state() == QModbusDevice::ConnectedState){
|
||
|
qDebug()<<"已连接";
|
||
|
}
|
||
|
else if(modbusDevice->state() == QModbusDevice::ClosingState){
|
||
|
qDebug()<<"已关闭";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief MyModbusTcp::connectModbusTcp 连接ModbusTcp
|
||
|
*/
|
||
|
void MyModbusTcp::connectModbusTcp()
|
||
|
{
|
||
|
if(!modbusDevice){
|
||
|
return;
|
||
|
}
|
||
|
if(modbusDevice->state() != QModbusDevice::ConnectedState){
|
||
|
modbusDevice->setConnectionParameter(QModbusClient::NetworkAddressParameter,"192.168.9.71");
|
||
|
modbusDevice->setConnectionParameter(QModbusClient::NetworkPortParameter,502);
|
||
|
modbusDevice->setTimeout(2000); //设置超时
|
||
|
modbusDevice->setNumberOfRetries(3); //重试
|
||
|
if(!modbusDevice->connectDevice()){
|
||
|
qDebug()<<"连接失败";
|
||
|
}
|
||
|
else {
|
||
|
qDebug()<<"连接成功";
|
||
|
}
|
||
|
}else{
|
||
|
// QMessageBox::information(this, "提示", "ModBusTcp已经连接");
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief MyModbusTcp::disconnectModbusTcp 断开连接
|
||
|
*/
|
||
|
void MyModbusTcp::disconnectModbusTcp()
|
||
|
{
|
||
|
if(modbusDevice->state() != QModbusDevice::ConnectedState){
|
||
|
// QMessageBox::critical(this, "错误", "MosBusTcp未连接");
|
||
|
return;
|
||
|
}
|
||
|
modbusDevice->disconnectDevice();
|
||
|
qDebug()<<"ModBusTCP断开连接";
|
||
|
// ui->stageShwoPlain->appendPlainText("与下位机断开连接成功!");
|
||
|
}
|
||
|
|
||
|
//===========================================数据发送、接收======================
|
||
|
/**
|
||
|
* @brief MyModbusTcp::writeSingleFloat 将单个float写入保持性寄存器
|
||
|
* @param address 写入的保持性寄存器地址
|
||
|
* @param dataSend 写入的数据
|
||
|
* @param serverID id
|
||
|
*/
|
||
|
void MyModbusTcp::writeSingleFloat(int address, float dataSend, int serverID = 1){
|
||
|
if(modbusDevice->state() != QModbusDevice::ConnectedState){
|
||
|
// QMessageBox::critical(this, "错误", "MosBusTcp未连接");
|
||
|
return;
|
||
|
}
|
||
|
QModbusDataUnit writeUnit(QModbusDataUnit::HoldingRegisters,address,2);
|
||
|
unsigned int word[2];
|
||
|
float2Word(dataSend, word);
|
||
|
writeUnit.setValue(0, word[0]);
|
||
|
writeUnit.setValue(1, word[1]);
|
||
|
if (auto *reply = modbusDevice->sendWriteRequest(writeUnit, serverID)) {// ui->spinBox_SerAddress->value()是server address sendWriteRequest是向服务器写数据
|
||
|
if (!reply->isFinished()) { //reply Returns true when the reply has finished or was aborted.
|
||
|
//接收响应信息
|
||
|
connect(reply, &QModbusReply::finished, this, [this, reply]() {
|
||
|
if (reply->error() == QModbusDevice::ProtocolError) { //接收到的响应信息是协议错误
|
||
|
qDebug() << "写入数据错误:" << reply->errorString();
|
||
|
} else if (reply->error() != QModbusDevice::NoError) { //接收到的响应消息是其它错误
|
||
|
qDebug() << "写入数据错误: " << reply->errorString();
|
||
|
}else { //接收到的消息没有错误 一般没有必要解析响应消息
|
||
|
const QModbusDataUnit data = reply->result();
|
||
|
// qDebug() << "消息数据个数:" << data.valueCount() << " :" << data.values();
|
||
|
}
|
||
|
reply->deleteLater();
|
||
|
});
|
||
|
} else { // broadcast replies return immediately
|
||
|
reply->deleteLater();
|
||
|
}
|
||
|
} else {
|
||
|
qDebug() << "sendWriteRequest Error: " << reply->errorString();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief MyModbusTcp::writeSingleWord 写入单个word(int)
|
||
|
* @param i 地址
|
||
|
* @param w 写入的数据
|
||
|
*/
|
||
|
void MyModbusTcp::writeSingleWord(int i, int w){
|
||
|
QModbusDataUnit writeUnit(QModbusDataUnit::HoldingRegisters,i,1);
|
||
|
writeUnit.setValue(0, w);
|
||
|
if (auto *reply = modbusDevice->sendWriteRequest(writeUnit, 1)) {// ui->spinBox_SerAddress->value()是server address sendWriteRequest是向服务器写数据
|
||
|
if (!reply->isFinished()) { //reply Returns true when the reply has finished or was aborted.
|
||
|
//接收响应信息
|
||
|
connect(reply, &QModbusReply::finished, this, [this, reply]() {
|
||
|
if (reply->error() == QModbusDevice::ProtocolError) { //接收到的响应信息是协议错误
|
||
|
qDebug() << "写入数据错误:" << reply->errorString();
|
||
|
} else if (reply->error() != QModbusDevice::NoError) { //接收到的响应消息是其它错误
|
||
|
qDebug() << "写入数据错误: " << reply->errorString();
|
||
|
}else { //接收到的消息没有错误 一般没有必要解析响应消息
|
||
|
const QModbusDataUnit data = reply->result();
|
||
|
// qDebug() << "消息数据个数:" << data.valueCount() << " :" << data.values();
|
||
|
}
|
||
|
reply->deleteLater();
|
||
|
});
|
||
|
} else { // broadcast replies return immediately
|
||
|
reply->deleteLater();
|
||
|
}
|
||
|
} else {
|
||
|
qDebug() << "sendWriteRequest Error: " << reply->errorString();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief MyModbusTcp::writeMultipleHR 写多个保持性寄存器HR
|
||
|
* @param address 起始地址
|
||
|
* @param num 数量
|
||
|
* @param dataSend 写入的数组
|
||
|
* @param serverID id
|
||
|
*/
|
||
|
void MyModbusTcp::writeMultipleHR(int address, int num, float *dataSend, int serverID = 1)
|
||
|
{
|
||
|
if(modbusDevice->state() != QModbusDevice::ConnectedState){
|
||
|
// QMessageBox::critical(this, "错误", "MosBusTcp未连接");
|
||
|
return;
|
||
|
}
|
||
|
//发送数据
|
||
|
qDebug() << "开始发送";
|
||
|
QModbusDataUnit writeUnit(QModbusDataUnit::HoldingRegisters, address, num);
|
||
|
unsigned int word[2]; //转换后存放的数组
|
||
|
for(int i=0;i<6;i++){
|
||
|
float2Word(dataSend[i], word);
|
||
|
qDebug() << dataSend[i];
|
||
|
// qDebug() <<*word;
|
||
|
// qDebug() <<*(word+1);
|
||
|
writeUnit.setValue(2*i,word[0]);
|
||
|
writeUnit.setValue(2*i+1,word[1]);
|
||
|
}
|
||
|
|
||
|
if (auto *reply = modbusDevice->sendWriteRequest(writeUnit, serverID)) {// ui->spinBox_SerAddress->value()是server address sendWriteRequest是向服务器写数据
|
||
|
if (!reply->isFinished()) { //reply Returns true when the reply has finished or was aborted.
|
||
|
//接收响应信息
|
||
|
connect(reply, &QModbusReply::finished, this, [this, reply]() {
|
||
|
if (reply->error() == QModbusDevice::ProtocolError) { //接收到的响应信息是协议错误
|
||
|
qDebug() << "写入数据错误:" << reply->errorString();
|
||
|
} else if (reply->error() != QModbusDevice::NoError) { //接收到的响应消息是其它错误
|
||
|
qDebug() << "写入数据错误: " << reply->errorString();
|
||
|
}else { //接收到的消息没有错误 一般没有必要解析响应消息
|
||
|
const QModbusDataUnit data = reply->result();
|
||
|
// qDebug() << "消息数据个数:" << data.valueCount() << " :" << data.values();
|
||
|
}
|
||
|
reply->deleteLater();
|
||
|
});
|
||
|
} else { // broadcast replies return immediately
|
||
|
reply->deleteLater();
|
||
|
}
|
||
|
} else {
|
||
|
qDebug() << "sendWriteRequest Error: " ;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief MyModbusTcp::readMultipleHR 读取数据并放到wordRCV数组中
|
||
|
* @param startAddress 起始地址
|
||
|
* @param num 数量
|
||
|
* @param serverID id
|
||
|
*/
|
||
|
void MyModbusTcp::readMultipleHR(int startAddress, int num, int serverID = 1){
|
||
|
if(modbusDevice->state() != QModbusDevice::ConnectedState){
|
||
|
// QMessageBox::critical(this, "错误", "MosBusTcp未连接");
|
||
|
return;
|
||
|
}
|
||
|
QModbusDataUnit data(QModbusDataUnit::HoldingRegisters, startAddress, num); //地址
|
||
|
if(auto *reply = modbusDevice->sendReadRequest(data, serverID)){ //发送请求
|
||
|
if(!reply->isFinished()){
|
||
|
connect(reply,&QModbusReply::finished, this, &MyModbusTcp::onReadReadyHR_Slot);
|
||
|
}
|
||
|
else{
|
||
|
delete reply;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief MyModbusTcp::onReadReadyHR_Slot 读取保持性寄存器数据并放到dataRCV数组中
|
||
|
*/
|
||
|
void MyModbusTcp:: onReadReadyHR_Slot(){
|
||
|
if(modbusDevice->state() != QModbusDevice::ConnectedState){
|
||
|
// QMessageBox::critical(this, "错误", "MosBusTcp未连接");
|
||
|
return;
|
||
|
}
|
||
|
QModbusReply *reply = qobject_cast<QModbusReply *>(sender());
|
||
|
if(!reply) return;
|
||
|
if(reply->error() == QModbusDevice::NoError){
|
||
|
const QModbusDataUnit responseData = reply->result(); //接收的数据
|
||
|
for(uint i = 0;i<responseData.valueCount();i++){
|
||
|
wordRCV[i]= responseData.value(i);
|
||
|
}
|
||
|
for(uint i = 0;i<responseData.valueCount();i=i+2){
|
||
|
float float_data=0;
|
||
|
unsigned long longdata = 0;
|
||
|
longdata = (wordRCV[i]<< 16) + (wordRCV[i+1] << 0);
|
||
|
float_data = *(float*)&longdata;
|
||
|
dataRCV[i/2] = float_data;
|
||
|
}
|
||
|
}
|
||
|
else if (reply->error() == QModbusDevice::ProtocolError) {
|
||
|
qDebug()<<"协议错误";
|
||
|
qDebug()<<"protocol error:"<<reply->errorString();
|
||
|
}
|
||
|
else{
|
||
|
qDebug()<<"回复错误";
|
||
|
qDebug()<<"error:"<<reply->errorString();
|
||
|
}
|
||
|
reply->deleteLater();
|
||
|
}
|
||
|
|
||
|
//=======================定时获取数据==============================
|
||
|
/**
|
||
|
* @brief MyModbusTcp::onTimeReadHR 定时读HR,并保存到dataRCV数组中
|
||
|
*/
|
||
|
//void MyModbusTcp::onTimeReadHR()
|
||
|
//{
|
||
|
// qDebug()<<"开始持续获取plc数据";
|
||
|
// timer = new QTimer(this); //启动定时器,100ms
|
||
|
// connect(timer, SIGNAL(timeout()), this, SLOT(readMultipleHR()));
|
||
|
// timer->start(1000); // 每隔1000ms
|
||
|
//}
|
||
|
|
||
|
///**
|
||
|
// * @brief MyModbusTcp::stopOnTimeReadHR 停止获取数据
|
||
|
// */
|
||
|
//void MyModbusTcp::stopOnTimeReadHR()
|
||
|
//{
|
||
|
// qDebug()<<"停止获取plc数据";
|
||
|
// timer->stop();
|
||
|
// timer->deleteLater();
|
||
|
//}
|
||
|
|
||
|
//================================等待时间=========================
|
||
|
///**
|
||
|
// * @brief MyModbusTcp::waitTime 等待tms
|
||
|
// * @param time
|
||
|
// * @param t
|
||
|
// */
|
||
|
//void MyModbusTcp::waitTime(QTime time, int t){
|
||
|
// time.start(); //设定time为当前时间
|
||
|
// while(time.elapsed() < t){ //等待时间流逝500ms
|
||
|
// QCoreApplication::processEvents(); //处理事件
|
||
|
// }
|
||
|
//}
|