diff --git a/modbus.pro.user b/modbus.pro.user index 491e3ce..02776fd 100644 --- a/modbus.pro.user +++ b/modbus.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId diff --git a/serialcommunicator.cpp b/serialcommunicator.cpp index 8816bc0..1a70b12 100644 --- a/serialcommunicator.cpp +++ b/serialcommunicator.cpp @@ -1,5 +1,5 @@ /******************************* - * Copyright (C) 2023-, XINJE Electronic Co., Ltd. + * Copyright (C) 2025. * * File Name: serialcommunicator.cpp * Description: 串口通信管理类实现文件 @@ -238,9 +238,9 @@ void SerialCommunicator::onReadyRead() void SerialCommunicator::onRecvTimeout() { // 接收完成,发送完整数据信号,停止重发定时器 + resendTimer_->stop(); emit dataReceived(recvBuffer_); recvBuffer_.clear(); - resendTimer_->stop(); } /** diff --git a/widget.cpp b/widget.cpp index 2728b44..250dfb5 100644 --- a/widget.cpp +++ b/widget.cpp @@ -24,23 +24,30 @@ Widget::Widget(QWidget *parent) : serialComm->setResendTimeout(1000); // 重发间隔1s // 连接信号槽(串口->界面) + //当串口接收到完整数据后,SerialCommunicator会发出dataReceived信号 connect(serialComm, &SerialCommunicator::dataReceived, this, &Widget::onSerialDataReceived); + //当串口状态改变时,SerialCommunicator会发出statusChanged信号 connect(serialComm, &SerialCommunicator::statusChanged, this, &Widget::onSerialStatusChanged); + //当发送数据超过超时重发次数后仍未收到数据,SerialCommunicator会发出timeoutOccurred信号 connect(serialComm, &SerialCommunicator::timeoutOccurred, this, &Widget::onSerialTimeout); + //当串口连接出现错误时(例如串口突然断开),SerialCommunicator会发出physicalDisconnected信号 connect(serialComm, &SerialCommunicator::physicalDisconnected, this, [=](){ ui->btnConnect->setText("连接"); ui->btn_read->setEnabled(false); ui->pushWrite->setEnabled(false); - QMessageBox::warning(this, "警告", "物理连接已断开"); + QMessageBox::warning(this, "警告", "串口已断开连接"); }); + //设置默认波特率、数据位、校验位 ui->comboBox_baudRate->setCurrentIndex(3); ui->comboBox_dataBit->setCurrentIndex(3); ui->comboBox_xiaoyan->setCurrentIndex(2); + //串口未连接前锁定读取和写入按钮 ui->btn_read->setEnabled(0); ui->pushWrite->setEnabled(0); + //检查当前可用串口 QList serialList = QSerialPortInfo::availablePorts(); for(QSerialPortInfo serialInfo : serialList) { @@ -101,43 +108,53 @@ void Widget::on_btnConnect_clicked() //写线圈和写寄存器 void Widget::on_pushWrite_clicked() { - switch (ui->comboBox_gongnengma->currentIndex()) + switch (ui->comboBox_gongnengma->currentIndex()) //判断当前功能码 { case 2: //写多个线圈 { - QString sendData = ui->lineEdit->text().trimmed(); + QString sendData = ui->lineEdit->text().trimmed(); //读取输入框中的数据 + //判断输入框中是否为空 if (sendData.isEmpty()) { QMessageBox::warning(this, "提示", "请至少输入一个数据"); return; } - for (QChar ch : sendData) { - if (ch != '0' && ch != '1') { + sendData.remove(" "); //移除输入数据中的空格 + //判断输入数据是否为二进制格式 + for (QChar ch : sendData) + { + if (ch != '0' && ch != '1') + { QMessageBox::warning(this, "提示", "只允许输入 0 或 1!"); return; } } + //拆分数据 QVector coils; for (QChar ch : sendData) { coils.append(ch == '1'); } + //配置从站参数 quint16 stationAddress = ui->lineEdit_stationAddress->text().toInt(); quint16 functionCode = 0x0f; quint16 stratAddress = ui->lineEdit_stratAddress->text().toInt(); quint16 length = ui->lineEdit_length->text().toInt(); + //判断输入数据长度与设置的长度是否一致 if (coils.size() != length) { QMessageBox::warning(this, "提示", "输入数据数与设置的长度不匹配"); return; } + //将从站参数传入modbus中 modbus->Set(stationAddress,functionCode,stratAddress,length); - modbus->WriteCoil(coils); + modbus->WriteCoil(coils); //使用WriteCoil方法生成命令报文 - serialComm->sendData(modbus->SendCommand()); + serialComm->sendData(modbus->SendCommand()); //发送生成的命令报文 + //锁定按钮 ui->btn_read->setEnabled(0); ui->pushWrite->setEnabled(0); @@ -146,13 +163,15 @@ void Widget::on_pushWrite_clicked() case 3: //写多个寄存器 { - QString sendData = ui->lineEdit->text().trimmed(); + QString sendData = ui->lineEdit->text().trimmed(); //读取数据 + //判断输入框中是否为空 if (sendData.isEmpty()) { QMessageBox::warning(this, "提示", "请输入完整的寄存器数据"); return; } + //拆分输入的寄存器数据 QStringList sl = sendData.split(','); QVector values; bool ok; @@ -169,6 +188,7 @@ void Widget::on_pushWrite_clicked() } } + //若判断输入的数据不是10进制,则按16进制数据处理 for (const QString &s : sl) { quint16 v; @@ -195,20 +215,24 @@ void Widget::on_pushWrite_clicked() values.append(v); } + //配置从站参数 quint16 stationAddress = ui->lineEdit_stationAddress->text().toInt(); quint16 functionCode = 0x10; quint16 stratAddress = ui->lineEdit_stratAddress->text().toInt(); quint16 length = ui->lineEdit_length->text().toInt(); + //判断输入数据长度与设置的长度是否一致 if (values.size() != length) { QMessageBox::warning(this, "提示", "输入数据数与设置的长度不匹配"); return; } + //将从站参数传入modbus中 modbus->Set(stationAddress,functionCode,stratAddress,length); - modbus->WriteRegister(values); //要发送的报文 + modbus->WriteRegister(values); //使用WriteRegister方法生成命令报文 - serialComm->sendData(modbus->SendCommand()); + serialComm->sendData(modbus->SendCommand()); //发送生成的命令报文 + //锁定按钮 ui->btn_read->setEnabled(0); ui->pushWrite->setEnabled(0); @@ -216,6 +240,7 @@ void Widget::on_pushWrite_clicked() } default: { + //若当前操作设置错误则进行提示 QMessageBox::warning(this, "提示", "请将“操作”切换为写线圈或写寄存器"); break; } @@ -226,17 +251,18 @@ void Widget::on_pushWrite_clicked() //发送读线圈和寄存器报文 void Widget::on_btn_read_clicked() { + //若当前操作设置错误则进行提示 if (ui->comboBox_gongnengma->currentIndex() == 2 || ui->comboBox_gongnengma->currentIndex() == 3) { QMessageBox::warning(this, "提示", "请将“操作”切换为读线圈或读寄存器"); return; } + //设置从站参数 quint16 stationAddress = ui->lineEdit_stationAddress->text().toInt(); quint16 functionCode; quint16 stratAddress = ui->lineEdit_stratAddress->text().toInt(); quint16 length = ui->lineEdit_length->text().toInt(); - if (ui->comboBox_gongnengma->currentIndex() == 0) //读线圈 { functionCode = 0x01; @@ -246,46 +272,58 @@ void Widget::on_btn_read_clicked() functionCode = 0x03; } + //将从站参数传入modbus中 modbus->Set(stationAddress,functionCode,stratAddress,length); - modbus->ReadCoilAndReg(); + modbus->ReadCoilAndReg(); //使用ReadCoilAndReg方法生成命令报文 - serialComm->sendData(modbus->SendCommand()); + serialComm->sendData(modbus->SendCommand()); //发送生成的命令报文 + //锁定按钮 ui->btn_read->setEnabled(0); ui->pushWrite->setEnabled(0); } +//保存通信历史数据 void Widget::on_btn_SaveDate_clicked() { SaveDate(this,ui->textEdit_2); } +//读取通信历史数据 void Widget::on_btn_ReadDate_clicked() { ReadDate(this,ui->textEdit_2); } +//清空状态通知文本框中的信息 void Widget::on_btn_ClearDate_clicked() { ui->textEdit_2->clear(); } +//清空数据读取文本框中的信息 void Widget::on_btn_ClearRead_clicked() { ui->textEdit->clear(); } +//处理接收到的返回报文 void Widget::onSerialDataReceived(const QByteArray &data) { - QByteArray revMessage = modbus->Receive(data); // 交给Modbus解析 - if (revMessage.isEmpty()) return; - + QByteArray revMessage = modbus->Receive(data); // 接收的原始数据交给Modbus解析 // 启用操作按钮 ui->btn_read->setEnabled(true); ui->pushWrite->setEnabled(true); + if (revMessage.isEmpty()) //若modbus检测响应报文格式错误则丢弃数据,返回值为空 + { + QMessageBox::warning(this, "提示", "返回报文站地址或CRC校验错误,请重试"); + return; + } + + //显示接收到的响应报文 ui->textEdit_2->append("接收报文:" + revMessage.toHex().toUpper()); - // 检查Modbus错误码 + // 检查响应报文中是否带有错误码 int exCode = modbus->ErrorCheck(); if (exCode) { @@ -307,7 +345,7 @@ void Widget::onSerialDataReceived(const QByteArray &data) { case 0: { // 读线圈 - QVector coils = modbus->AnalReadCoil(); + QVector coils = modbus->AnalReadCoil(); //使用AnalReadCoil方法解析线圈数据 ui->textEdit->append("线圈状态:"); for (int i = 0; i < coils.size(); i++) { @@ -317,7 +355,7 @@ void Widget::onSerialDataReceived(const QByteArray &data) } case 1: { // 读寄存器 - QVector regs = modbus->AnalReadReg(); + QVector regs = modbus->AnalReadReg(); //使用AnalReadReg方法解析寄存器数据 ui->textEdit->append("寄存器值:"); for (int i = 0; i < regs.size(); i++) { @@ -328,12 +366,13 @@ void Widget::onSerialDataReceived(const QByteArray &data) } } +//显示串口状态 void Widget::onSerialStatusChanged(const QString &status) { ui->textEdit_2->append(status); // 显示状态信息(如连接成功、超时重发等) } - +//超过超时重发次数后触发 void Widget::onSerialTimeout() { QMessageBox::warning(this, "提示", "等待响应超时,请检查设备"); diff --git a/widget.ui b/widget.ui index 5fe2879..c170200 100644 --- a/widget.ui +++ b/widget.ui @@ -232,11 +232,6 @@ 8 - - - NONE - -