Sfoglia il codice sorgente

异常处理

master
鹏鹏 李 2 settimane fa
parent
commit
7e12821346
4 ha cambiato i file con 117 aggiunte e 32 eliminazioni
  1. +1
    -1
      modbus.pro.user
  2. +91
    -18
      widget.cpp
  3. +2
    -0
      widget.h
  4. +23
    -13
      widget.ui

+ 1
- 1
modbus.pro.user Vedi File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 4.0.3, 2025-07-24T14:53:28. -->
<!-- Written by QtCreator 4.0.3, 2025-07-25T10:54:01. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>


+ 91
- 18
widget.cpp Vedi File

@@ -17,11 +17,18 @@ Widget::Widget(QWidget *parent) :
serialPort = new QSerialPort(this);

connect(serialPort,&QSerialPort::readyRead,this,&Widget::on_SerialData_ReadyToRead);
QObject::connect(&timer, &QTimer::timeout, [&]{
QMessageBox::warning(this, "提示", "等待响应超时,请检查设备状态。");
timer.stop();
});

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<QSerialPortInfo> serialList = QSerialPortInfo::availablePorts();
for(QSerialPortInfo serialInfo : serialList)
{
@@ -34,6 +41,7 @@ Widget::~Widget()
delete ui;
}

//串口连接
void Widget::on_btnConnect_clicked()
{
if (ui->btnConnect->text() == "连接")
@@ -63,6 +71,8 @@ void Widget::on_btnConnect_clicked()
{
qDebug() << "Serial open success";
ui->btnConnect->setText("断开");
ui->btn_read->setEnabled(1);
ui->pushWrite->setEnabled(1);
}
else
{
@@ -72,21 +82,27 @@ void Widget::on_btnConnect_clicked()
else
{
serialPort->close();
ui->btn_read->setEnabled(0);
ui->pushWrite->setEnabled(0);
qDebug() << "Serial close";
ui->btnConnect->setText("连接");
}

}

//写线圈和写寄存器
void Widget::on_pushWrite_clicked()
{
switch (ui->comboBox_gongnengma->currentIndex())
{
case (2): //写多个线圈
case 2: //写多个线圈
{
QString sendData = ui->lineEdit->text().trimmed();
if (sendData.isEmpty()) return;

if (sendData.isEmpty())
{
QMessageBox::warning(this, "提示", "请至少输入一个数据,缺少的数据默认为0");
return;
}
for (QChar ch : sendData) {
if (ch != '0' && ch != '1') {
QMessageBox::warning(this, "提示", "只允许输入 0 或 1!");
@@ -131,13 +147,24 @@ void Widget::on_pushWrite_clicked()
SendCommand.append(temp%256); //加入计算的crc值
SendCommand.append(temp/256);

ui->textEdit_2->append("发送报文"+SendCommand.toHex().toUpper());
serialPort->write(SendCommand);

timer.isActive();
timer.start(2000); // 2 s 后触发超时

qDebug() << "SenOk" <<sendData;
break;
}

case 3:
{
QString sendData = ui->lineEdit->text().trimmed();
if (sendData.isEmpty()) return;
if (sendData.isEmpty())
{
QMessageBox::warning(this, "提示", "请输入完整的寄存器数据");
return;
}

QStringList sl = sendData.split(',');
QVector<quint16> values;
@@ -147,7 +174,7 @@ void Widget::on_pushWrite_clicked()
quint16 v = s.toUShort(&ok, 16);
if (!ok)
{
QMessageBox::warning(this, "提示", "请输入正确的十六进制值!");
QMessageBox::warning(this, "提示", "请输入正确的十六进制值,或检查逗号是否是英文格式!");
return;
}
values.append(v);
@@ -172,20 +199,40 @@ void Widget::on_pushWrite_clicked()
SendCommand.append(temp%256); //加入计算的crc值
SendCommand.append(temp/256);

ui->textEdit_2->append("发送报文"+SendCommand.toHex().toUpper());
serialPort->write(SendCommand);

timer.isActive();
timer.start(2000); // 2 s 后触发超时

qDebug() << "SenOk" <<sendData;
break;
}
default:
{
QMessageBox::warning(this, "提示", "请将“操作”切换为写线圈或写寄存器");
break;
}

}
}


//处理回复报文
void Widget::on_SerialData_ReadyToRead()
{
timer.stop();

QByteArray revMessage = serialPort->readAll();
QString hexData = revMessage.toHex().toUpper();
qDebug() << hexData;
ui->textEdit->append(hexData);
ui->textEdit_2->append("接收报文"+hexData);

//首先对接收报文的长度进行检验
if (revMessage.size() < 3) {
QMessageBox::warning(this, "警告", "无效的响应格式");
qDebug() << "响应报文过短,长度 =" << revMessage.size();
return;
}

//对接收的报文进行CRC校验
QByteArray payload = revMessage.left(revMessage.length() - 2);
@@ -203,6 +250,33 @@ void Widget::on_SerialData_ReadyToRead()
if(calcCrcLow == receivedCrcLow && calcCrcHigh == receivedCrcHigh)
{
qDebug() << "接收成功";
if ((revMessage.at(1) & 0x80) == 0x80) {
// MODBUS异常响应结构:地址 | 功能码+0x80 | 异常码 | CRC
quint8 originalFunctionCode = revMessage.at(1) & 0x7F; // 去掉最高位
quint8 exCode = revMessage.at(2);

QString errorMsg;
switch (exCode) {
case 0x01: errorMsg = "非法功能码"; break;
case 0x02: errorMsg = "非法数据地址"; break;
case 0x03: errorMsg = "非法数据值"; break;
case 0x04: errorMsg = "从站设备故障"; break;
case 0x05: errorMsg = "确认"; break;
case 0x06: errorMsg = "从站设备忙"; break;
case 0x07: errorMsg = "负确认"; break;
case 0x08: errorMsg = "存储奇偶错误"; break;
default: errorMsg = "未知异常"; break;
}

QMessageBox::warning(this, "异常响应",
QString("功能码 0x%1 异常\n错误码: 0x%2 (%3)")
.arg(QString::number(originalFunctionCode, 16).toUpper())
.arg(QString::number(exCode, 16).toUpper().rightJustified(2, '0'))
.arg(errorMsg));

return;
}

switch (ui->comboBox_gongnengma->currentIndex())
{
//解析读线圈的返回报文
@@ -251,17 +325,6 @@ void Widget::on_SerialData_ReadyToRead()
}
break;
}
case 2:
{

if (revMessage.at(1) == '\x8f')
{
quint8 exCode = revMessage.at(2);
qDebug() << "异常响应,异常码 =" << exCode;
return;
}
}


}
}
@@ -274,6 +337,12 @@ void Widget::on_SerialData_ReadyToRead()
//发送读线圈和寄存器报文
void Widget::on_btn_read_clicked()
{
if (ui->comboBox_gongnengma->currentIndex() == 2 ||
ui->comboBox_gongnengma->currentIndex() == 3)
{
QMessageBox::warning(this, "提示", "请将“操作”切换为读线圈或读寄存器");
return;
}
QByteArray SendCommand; //要发送的报文
SendCommand.append(ui->comboBox_stationAddress->currentText().toInt()%256); //加入站地址
if (ui->comboBox_gongnengma->currentIndex() == 0) //读线圈
@@ -295,5 +364,9 @@ void Widget::on_btn_read_clicked()
SendCommand.append(temp/256);

qDebug() << SendCommand.toHex();
ui->textEdit_2->append("发送报文"+SendCommand.toHex().toUpper());
serialPort->write(SendCommand); //发送报文

timer.isActive();
timer.start(2000); // 2 s 后触发超时
}

+ 2
- 0
widget.h Vedi File

@@ -3,6 +3,7 @@

#include <QSerialPort>
#include <QWidget>
#include <QTimer>

namespace Ui {
class Widget;
@@ -28,6 +29,7 @@ private slots:
private:
Ui::Widget *ui;
QSerialPort *serialPort;
QTimer timer;
};

#endif // WIDGET_H

+ 23
- 13
widget.ui Vedi File

@@ -224,8 +224,8 @@
<widget class="QLineEdit" name="lineEdit">
<property name="geometry">
<rect>
<x>340</x>
<y>250</y>
<x>330</x>
<y>410</y>
<width>301</width>
<height>31</height>
</rect>
@@ -234,8 +234,8 @@
<widget class="QPushButton" name="pushWrite">
<property name="geometry">
<rect>
<x>340</x>
<y>290</y>
<x>330</x>
<y>460</y>
<width>93</width>
<height>28</height>
</rect>
@@ -248,9 +248,9 @@
<property name="geometry">
<rect>
<x>40</x>
<y>170</y>
<y>230</y>
<width>251</width>
<height>271</height>
<height>211</height>
</rect>
</property>
</widget>
@@ -336,7 +336,7 @@
<item>
<widget class="QLabel" name="label_10">
<property name="text">
<string>对象</string>
<string>操作</string>
</property>
</widget>
</item>
@@ -397,17 +397,27 @@
<widget class="QLabel" name="label_13">
<property name="geometry">
<rect>
<x>340</x>
<y>160</y>
<x>330</x>
<y>300</y>
<width>311</width>
<height>91</height>
<height>101</height>
</rect>
</property>
<property name="text">
<string>写线圈时,使用1、0代表线圈的开关,
<string>写线圈时,使用1、0代表线圈的开关状态
从左到右依次输入每个线圈的开关;
写寄存器时,每个寄存器的值用16进制表示,
相邻寄存器的值之间用&quot;,&quot;分离。</string>
写寄存器时要写入所有寄存器的16进制数值,
相邻寄存器的值之间用英文&quot;,&quot;分离。</string>
</property>
</widget>
<widget class="QTextEdit" name="textEdit_2">
<property name="geometry">
<rect>
<x>40</x>
<y>150</y>
<width>671</width>
<height>61</height>
</rect>
</property>
</widget>
</widget>


Caricamento…
Annulla
Salva