From 86611b2a140c6a485f97acb3de80bdc57f11ec9c Mon Sep 17 00:00:00 2001 From: lipengpeng Date: Mon, 28 Jul 2025 19:28:15 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B0=81=E8=A3=85=E4=BA=86=E4=B8=B2=E5=8F=A3?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E7=9B=B8=E5=85=B3=E7=9A=84=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- modbus.pro | 6 +- modbus.pro.user | 2 +- mymodbus.h | 17 +-- serialcommunicator.cpp | 268 +++++++++++++++++++++++++++++++++++++++++ serialcommunicator.h | 178 +++++++++++++++++++++++++++ widget.cpp | 243 +++++++++++++++---------------------- widget.h | 18 +-- 7 files changed, 569 insertions(+), 163 deletions(-) create mode 100644 serialcommunicator.cpp create mode 100644 serialcommunicator.h diff --git a/modbus.pro b/modbus.pro index 2dae3d8..37f9f24 100644 --- a/modbus.pro +++ b/modbus.pro @@ -16,10 +16,12 @@ TEMPLATE = app SOURCES += main.cpp\ widget.cpp \ mymodbus.cpp \ - communicationhistory.cpp + communicationhistory.cpp \ + serialcommunicator.cpp HEADERS += widget.h \ mymodbus.h \ - communicationhistory.h + communicationhistory.h \ + serialcommunicator.h FORMS += widget.ui diff --git a/modbus.pro.user b/modbus.pro.user index 1101bb9..5ffbe48 100644 --- a/modbus.pro.user +++ b/modbus.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId diff --git a/mymodbus.h b/mymodbus.h index 5e38467..7a995e2 100644 --- a/mymodbus.h +++ b/mymodbus.h @@ -1,11 +1,3 @@ -#ifndef MYMODBUS_H -#define MYMODBUS_H - -#include -#include -#include -#include - /****************************************************************************** * Copyright (C) 2025-. * @@ -18,6 +10,15 @@ * ******************************************************************************/ +#ifndef MYMODBUS_H +#define MYMODBUS_H + +#include +#include +#include +#include + + /** * @class MyModbus * @brief Modbus RTU协议封装类 diff --git a/serialcommunicator.cpp b/serialcommunicator.cpp new file mode 100644 index 0000000..4e7b691 --- /dev/null +++ b/serialcommunicator.cpp @@ -0,0 +1,268 @@ +/******************************* + * Copyright (C) 2023-, XINJE Electronic Co., Ltd. + * + * File Name: serialcommunicator.cpp + * Description: 串口通信管理类实现文件 + * Others: + * Version: 1.0 + * Author: lipengpeng + * Date: 2025-7-23 + *******************************/ + +#include "serialcommunicator.h" + +/** + * @brief 构造函数 + * @param parent 父对象指针 + * + * @details 初始化串口通信组件,包括: + * 1. 创建串口对象 + * 2. 创建接收和重发定时器 + * 3. 设置默认超时参数 + * 4. 连接信号槽 + */ +SerialCommunicator::SerialCommunicator(QObject *parent) : QObject(parent) + , serialPort(new QSerialPort(this)) + , recvTimer(new QTimer(this)) + , resendTimer(new QTimer(this)) + , comCount(0) + , maxRetry(3) + , recvTimeout(50) + , resendTimeout(1000) +{ + // 配置定时器(单次触发) + recvTimer->setSingleShot(true); + resendTimer->setSingleShot(true); + + // 连接信号槽 + connect(serialPort, &QSerialPort::readyRead, this, &SerialCommunicator::onReadyRead); + connect(recvTimer, &QTimer::timeout, this, &SerialCommunicator::onRecvTimeout); + connect(resendTimer, &QTimer::timeout, this, &SerialCommunicator::onResendTimeout); +} + +/** + * @brief 析构函数 + * @note 确保串口关闭并释放资源 + */ +SerialCommunicator::~SerialCommunicator() +{ + close(); +} + +/** + * @brief 设置串口参数 + * @param portName 串口号(如"COM1") + * @param baudRate 波特率(如9600) + * @param dataBits 数据位 + * @param parity 校验位 + * @param stopBits 停止位 + * + * @note 此方法应在打开串口前调用,设置值将在下次open()时生效 + */ +void SerialCommunicator::setPortParams(const QString &portName, qint32 baudRate, + QSerialPort::DataBits dataBits, + QSerialPort::Parity parity, + QSerialPort::StopBits stopBits) +{ + this->portName = portName; + this->baudRate = baudRate; + this->dataBits = dataBits; + this->parity = parity; + this->stopBits = stopBits; +} + +/** + * @brief 打开串口 + * @return true-打开成功, false-打开失败 + * + * @details 执行流程: + * 1. 关闭已打开的串口(如果存在) + * 2. 配置串口参数(波特率、数据位等) + * 3. 尝试打开串口 + * 4. 发送状态变化信号 + */ +bool SerialCommunicator::open() +{ + // 关闭已打开的串口(如果存在) + if (serialPort->isOpen()) + { + serialPort->close(); + } + + // 配置串口参数 + serialPort->setPortName(portName); + if (!serialPort->setBaudRate(baudRate)) + { + emit statusChanged("波特率设置失败"); + return false; + } + if (!serialPort->setDataBits(dataBits)) + { + emit statusChanged("数据位设置失败"); + return false; + } + if (!serialPort->setParity(parity)) + { + emit statusChanged("校验位设置失败"); + return false; + } + if (!serialPort->setStopBits(stopBits)) + { + emit statusChanged("停止位设置失败"); + return false; + } + serialPort->setFlowControl(QSerialPort::NoFlowControl); // 无流控制 + + // 打开串口 + if (serialPort->open(QIODevice::ReadWrite)) + { + emit statusChanged("串口连接成功"); + return true; + } + else + { + emit statusChanged("串口连接失败,请检查参数"); + return false; + } +} + +/** + * @brief 关闭串口 + * + * @details 执行流程: + * 1. 检查串口是否打开 + * 2. 关闭串口 + * 3. 发送状态变化信号 + */ +void SerialCommunicator::close() +{ + if (serialPort->isOpen()) + { + serialPort->close(); + emit statusChanged("串口断开"); + } +} + +/** + * @brief 发送数据并启动超时重发机制 + * @param data 待发送的数据 + * + * @details 执行流程: + * 1. 检查串口是否打开 + * 2. 保存待发送数据(用于重发) + * 3. 重置重发计数器 + * 4. 发送数据 + * 5. 启动重发超时定时器 + */ +void SerialCommunicator::sendData(const QByteArray &data) +{ + if (!serialPort->isOpen()) + { + emit statusChanged("串口未打开,无法发送数据"); + return; + } + // 保存待重发数据,初始化计数器,启动重发定时器 + currentData = data; + comCount = 0; + serialPort->write(data); // 发送数据 + emit statusChanged("发送报文:" + data.toHex().toUpper()); + resendTimer->start(resendTimeout); // 启动超时计时 +} + +/** + * @brief 设置最大重发次数 + * @param count 最大重发次数 + */ +void SerialCommunicator::setMaxRetry(int count) +{ + maxRetry = count; +} + +/** + * @brief 设置接收完成超时时间 + * @param ms 超时时间(毫秒) + * + * @note 当串口持续ms毫秒无新数据时,认为接收完成 + */ +void SerialCommunicator::setRecvTimeout(int ms) +{ + recvTimeout = ms; +} + +/** + * @brief 设置重发间隔时间 + * @param ms 重发间隔(毫秒) + */ +void SerialCommunicator::setResendTimeout(int ms) +{ + resendTimeout = ms; +} + +/** + * @brief 检查串口是否打开 + * @return true-已打开, false-已关闭 + */ +bool SerialCommunicator::isOpen() const +{ + return serialPort->isOpen(); +} + +// ====================== 私有槽函数 ====================== // + +/** + * @brief 串口数据到达处理 + * + * @details 执行流程: + * 1. 读取所有可用数据到接收缓冲区 + * 2. 重启接收超时定时器 + * 3. 定时器超时后将触发onRecvTimeout + */ +void SerialCommunicator::onReadyRead() +{ + // 读取数据到缓冲区 + recvBuffer.append(serialPort->readAll()); + //重置接收超时定时器 + recvTimer->start(recvTimeout); +} + +/** + * @brief 接收完成超时处理 + * + * @details 执行流程: + * 1. 发送dataReceived信号包含完整数据 + * 2. 清空接收缓冲区 + * 3. 停止重发定时器(表示已收到响应) + */ +void SerialCommunicator::onRecvTimeout() +{ + // 接收完成,发送完整数据信号,停止重发定时器 + emit dataReceived(recvBuffer); + recvBuffer.clear(); + resendTimer->stop(); +} + +/** + * @brief 重发超时处理 + * + * @details 执行流程: + * 1. 检查是否达到最大重发次数 + * 2. 未达到则重发数据并更新计数器 + * 3. 达到最大次数则触发超时信号 + */ +void SerialCommunicator::onResendTimeout() +{ + if (comCount < maxRetry) + { + // 重发数据,更新计数器 + serialPort->write(currentData); + comCount++; + emit statusChanged(QString("通信超时,重新发送中(%1/%2)").arg(comCount).arg(maxRetry)); + resendTimer->start(resendTimeout); // 继续计时 + } + else + { + // 达到最大重发次数,触发超时信号 + resendTimer->stop(); + emit timeoutOccurred(); + } +} diff --git a/serialcommunicator.h b/serialcommunicator.h new file mode 100644 index 0000000..72307f6 --- /dev/null +++ b/serialcommunicator.h @@ -0,0 +1,178 @@ +/******************************* + * Copyright (C) 2025-. + * + * File Name: serialcommunicator.h + * Description: 串口通信管理类,封装串口操作、数据收发和超时处理 + * Others: + * Version: 1.0 + * Author: lipengpeng + * Date: 2025-7-23 + *******************************/ +#ifndef SERIALCOMMUNICATOR_H +#define SERIALCOMMUNICATOR_H + +#include +#include +#include +#include + +/** + * @brief 串口通信管理类 + * @class SerialCommunicator + * + * @details 此类封装了串口通信的核心功能,包括: + * 1. 串口参数配置与开关控制 + * 2. 数据发送与自动重发机制 + * 3. 数据接收与完整性判断 + * 4. 超时处理与状态通知 + * + * @note 使用流程: + * 1. 设置串口参数(setPortParams) + * 2. 打开串口(open) + * 3. 发送数据(sendData) + * 4. 接收数据(通过dataReceived信号) + * 5. 关闭串口(close) + */ +class SerialCommunicator : public QObject +{ + Q_OBJECT +public: + /** + * @brief 构造函数 + * @param parent 父对象指针 + */ + explicit SerialCommunicator(QObject *parent = nullptr); + + /** + * @brief 析构函数 + * @note 自动关闭串口并释放资源 + */ + ~SerialCommunicator(); + + // ====================== 串口配置 ====================== // + + /** + * @brief 设置串口参数 + * @param portName 串口号(如"COM1"或"/dev/ttyS0") + * @param baudRate 波特率(如9600, 115200) + * @param dataBits 数据位(通常为QSerialPort::Data8) + * @param parity 校验位(无校验/奇校验/偶校验) + * @param stopBits 停止位(通常为QSerialPort::OneStop) + * @note 此方法应在打开串口前调用 + */ + void setPortParams(const QString &portName, qint32 baudRate, + QSerialPort::DataBits dataBits, + QSerialPort::Parity parity, + QSerialPort::StopBits stopBits); + + /** + * @brief 打开串口 + * @return true-打开成功, false-打开失败 + * @note 成功打开后会发出statusChanged信号 + */ + bool open(); + + /** + * @brief 关闭串口 + * @note 关闭后会发出statusChanged信号 + */ + void close(); + + // ====================== 数据操作 ====================== // + + /** + * @brief 发送数据并启动超时重发机制 + * @param data 待发送的数据 + * @note 数据发送后启动重发定时器,如达到最大重发次数仍未收到响应, + * 将发出timeoutOccurred信号 + */ + void sendData(const QByteArray &data); + + // ====================== 超时配置 ====================== // + + /** + * @brief 设置最大重发次数 + * @param count 重发次数(默认3次) + */ + void setMaxRetry(int count); + + /** + * @brief 设置接收完成超时时间 + * @param ms 超时时间(毫秒,默认50ms) + * @note 当串口持续ms毫秒无新数据时,认为接收完成 + */ + void setRecvTimeout(int ms); + + /** + * @brief 设置重发间隔时间 + * @param ms 重发间隔(毫秒,默认1000ms) + */ + void setResendTimeout(int ms); + + // ====================== 状态查询 ====================== // + + /** + * @brief 检查串口是否打开 + * @return true-已打开, false-已关闭 + */ + bool isOpen() const; + +signals: + /** + * @brief 接收到完整数据信号 + * @param data 接收到的完整数据包 + */ + void dataReceived(const QByteArray &data); + + /** + * @brief 状态变化信号 + * @param status 状态描述文本 + * @note 可能的状态: "已连接", "已断开", "接收超时"等 + */ + void statusChanged(const QString &status); + + /** + * @brief 通信超时信号 + * @note 当达到最大重发次数仍未收到响应时触发 + */ + void timeoutOccurred(); + +private slots: + /** + * @brief 串口数据到达处理 + * @note 当串口有数据可读时触发,数据存入缓冲区并启动接收超时定时器 + */ + void onReadyRead(); + + /** + * @brief 接收完成超时处理 + * @note 当recvTimer超时,认为数据接收完成,发出dataReceived信号 + */ + void onRecvTimeout(); + + /** + * @brief 重发超时处理 + * @note 当resendTimer超时,检查重发次数并决定是否重发数据 + */ + void onResendTimeout(); + +private: + QSerialPort *serialPort; // 串口对象 + QTimer *recvTimer; // 接收完成判断定时器 + QTimer *resendTimer; // 超时重发定时器 + QByteArray recvBuffer; // 接收缓冲区 + QByteArray currentData; // 当前待重发数据 + int comCount; // 重发计数器 + int maxRetry; // 最大重发次数 + int recvTimeout; // 接收超时时间(ms) + int resendTimeout; // 重发间隔(ms) + + // 串口参数 + QString portName; + qint32 baudRate; + QSerialPort::DataBits dataBits; + QSerialPort::Parity parity; + QSerialPort::StopBits stopBits; +}; + +#endif // SERIALCOMMUNICATOR_H diff --git a/widget.cpp b/widget.cpp index d7c24bc..fe99b7c 100644 --- a/widget.cpp +++ b/widget.cpp @@ -8,36 +8,24 @@ #include #include #include -#include "mymodbus.h" -#include "communicationhistory.h" Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { - ui->setupUi(this); - serialPort = new QSerialPort(this); modbus = new MyModbus(); - recvTimer = new QTimer(this); + ui->setupUi(this); + serialComm = new SerialCommunicator(this); // 初始化串口通信类 - connect(serialPort, &QSerialPort::readyRead, this, &Widget::onReadyRead); - connect(recvTimer, &QTimer::timeout, this, &Widget::on_SerialData_ReadyToRead); - QObject::connect(&timer, &QTimer::timeout, [this]{ - if (comCount < 3) - { - ui->textEdit_2->append("通信超时,重新发送中"); + // 配置串口参数 + serialComm->setMaxRetry(3); // 最大重发3次 + serialComm->setRecvTimeout(50); // 接收超时50ms + serialComm->setResendTimeout(1000); // 重发间隔1s - serialPort->write(modbus->SendCommand()); - comCount ++; - } - else - { - QMessageBox::warning(this, "提示", "等待响应超时,请检查设备状态。"); - ui->btn_read->setEnabled(1); - ui->pushWrite->setEnabled(1); - timer.stop(); - } - }); + // 连接信号槽(串口->界面) + connect(serialComm, &SerialCommunicator::dataReceived, this, &Widget::onSerialDataReceived); + connect(serialComm, &SerialCommunicator::statusChanged, this, &Widget::onSerialStatusChanged); + connect(serialComm, &SerialCommunicator::timeoutOccurred, this, &Widget::onSerialTimeout); ui->comboBox_baudRate->setCurrentIndex(3); ui->comboBox_dataBit->setCurrentIndex(3); @@ -56,6 +44,7 @@ Widget::Widget(QWidget *parent) : Widget::~Widget() { delete modbus; + delete serialComm; delete ui; } @@ -64,47 +53,40 @@ void Widget::on_btnConnect_clicked() { if (ui->btnConnect->text() == "连接") { - //配置串口号 - serialPort->setPortName(ui->comboBox_serialNum->currentText()); - //配置波特率 - serialPort->setBaudRate(ui->comboBox_baudRate->currentText().toInt()); - //配置数据位 - serialPort->setDataBits(QSerialPort::DataBits(ui->comboBox_dataBit->currentText().toInt())); - //配置校验位 + // 获取界面配置的串口参数 + QString portName = ui->comboBox_serialNum->currentText(); + qint32 baudRate = ui->comboBox_baudRate->currentText().toInt(); + QSerialPort::DataBits dataBits = QSerialPort::DataBits(ui->comboBox_dataBit->currentText().toInt()); + QSerialPort::Parity parity; switch (ui->comboBox_xiaoyan->currentIndex()) { - case 0: - serialPort->setParity(QSerialPort::NoParity); - break; - case 1: - serialPort->setParity(QSerialPort::OddParity); - break; - case 2: - serialPort->setParity(QSerialPort::EvenParity); + case 0: parity = QSerialPort::NoParity; break; + case 1: parity = QSerialPort::OddParity; break; + case 2: parity = QSerialPort::EvenParity; break; + default: parity = QSerialPort::NoParity; } - //配置停止位 - serialPort->setStopBits(QSerialPort::StopBits(ui->comboBox_stopBit->currentText().toInt())); - //打开串口 - if (serialPort->open(QIODevice::ReadWrite)) + QSerialPort::StopBits stopBits = QSerialPort::StopBits(ui->comboBox_stopBit->currentText().toInt()); + + // 配置并打开串口 + serialComm->setPortParams(portName, baudRate, dataBits, parity, stopBits); + if (serialComm->open()) { - ui->textEdit_2->append("串口连接成功"); ui->btnConnect->setText("断开"); - ui->btn_read->setEnabled(1); - ui->pushWrite->setEnabled(1); + ui->btn_read->setEnabled(true); + ui->pushWrite->setEnabled(true); } else { - QMessageBox::warning(this, "提示", "串口连接失败,请检查串口参数配置"); + QMessageBox::warning(this, "提示", "串口连接失败"); } } else { - serialPort->close(); - ui->btn_read->setEnabled(0); - ui->pushWrite->setEnabled(0); - qDebug() << "Serial close"; + // 断开串口 + serialComm->close(); ui->btnConnect->setText("连接"); - ui->textEdit_2->append("串口断开"); + ui->btn_read->setEnabled(false); + ui->pushWrite->setEnabled(false); } } @@ -149,14 +131,10 @@ void Widget::on_pushWrite_clicked() modbus->Set(stationAddress,functionCode,stratAddress,length); modbus->WriteCoil(coils); - ui->textEdit_2->append("发送报文"+modbus->SendCommand().toHex().toUpper()); - serialPort->write(modbus->SendCommand()); + serialComm->sendData(modbus->SendCommand()); ui->btn_read->setEnabled(0); ui->pushWrite->setEnabled(0); - comCount = 0; - timer.start(1000); // 1 s 后触发超时 - break; } @@ -196,14 +174,10 @@ void Widget::on_pushWrite_clicked() modbus->Set(stationAddress,functionCode,stratAddress,length); modbus->WriteRegister(values); //要发送的报文 - ui->textEdit_2->append("发送报文"+modbus->SendCommand().toHex().toUpper()); - serialPort->write(modbus->SendCommand()); + serialComm->sendData(modbus->SendCommand()); ui->btn_read->setEnabled(0); ui->pushWrite->setEnabled(0); - comCount = 0; - timer.start(1000); // 1 s 后触发超时 - break; } default: @@ -215,80 +189,6 @@ void Widget::on_pushWrite_clicked() } } -//处理回复报文 -void Widget::on_SerialData_ReadyToRead() -{ - QByteArray revMessage = recvBuffer; - recvBuffer.clear(); - revMessage = modbus->Receive(revMessage); - if (!revMessage.isEmpty()) - { - ui->btn_read->setEnabled(1); - ui->pushWrite->setEnabled(1); - timer.stop(); - } - else - { - return; - } - QString hexData = revMessage.toHex().toUpper(); - ui->textEdit_2->append("接收报文"+hexData); - - int exCode = modbus->ErrorCheck(); - if (exCode) - { - QString errorMsg; - switch (exCode) - { - case 0x01: errorMsg = "非法功能码"; break; - case 0x02: errorMsg = "非法数据地址"; break; - case 0x03: errorMsg = "非法数据值"; break; - case 0x04: errorMsg = "从站设备故障"; break; - default: errorMsg = "未知异常"; break; - } - - QMessageBox::warning(this, "异常响应", - QString("异常\n错误码: 0x%1 (%2)") - .arg(QString::number(exCode, 16).toUpper().rightJustified(2, '0')) - .arg(errorMsg)); - - return; - } - - switch (ui->comboBox_gongnengma->currentIndex()) - { - //解析读线圈的返回报文 - case 0: - { - QVector coil = modbus->AnalReadCoil(); - - ui->textEdit->append("线圈状态:"); - for (int i = 0; i < coil.size(); i++) - { - bool state = coil.at(i); - ui->textEdit->append("线圈"+QString::number(i+1)+":"+QString::number(state)); - } - - break; - } - //解析读寄存器的返回报文 - case 1: - { - QVector registers = modbus->AnalReadReg(); - - ui->textEdit->append("寄存器的值:"); - for (int i = 0; i < registers.size(); i++) - { - ui->textEdit->append("寄存器"+QString::number(i+1)+":"+QString::number(registers.at(i))); - } - - break; - - } - - } -} - //发送读线圈和寄存器报文 void Widget::on_btn_read_clicked() { @@ -315,13 +215,10 @@ void Widget::on_btn_read_clicked() modbus->Set(stationAddress,functionCode,stratAddress,length); modbus->ReadCoilAndReg(); - serialPort->write(modbus->SendCommand()); //发送报文 - ui->textEdit_2->append("发送报文"+modbus->SendCommand().toHex().toUpper()); + serialComm->sendData(modbus->SendCommand()); ui->btn_read->setEnabled(0); ui->pushWrite->setEnabled(0); - comCount = 0; - timer.start(1000); // 1 s 后触发超时 } void Widget::on_btn_SaveDate_clicked() @@ -339,13 +236,73 @@ void Widget::on_btn_ClearDate_clicked() ui->textEdit_2->clear(); } -void Widget::onReadyRead() +void Widget::on_btn_ClearRead_clicked() { - recvBuffer.append(serialPort->readAll()); - recvTimer->start(50); // 50ms 内无新数据即认为接收完成 + ui->textEdit->clear(); } -void Widget::on_btn_ClearRead_clicked() +void Widget::onSerialDataReceived(const QByteArray &data) { - ui->textEdit->clear(); + QByteArray revMessage = modbus->Receive(data); // 交给Modbus解析 + if (revMessage.isEmpty()) return; + + // 启用操作按钮 + ui->btn_read->setEnabled(true); + ui->pushWrite->setEnabled(true); + ui->textEdit_2->append("接收报文:" + revMessage.toHex().toUpper()); + + // 检查Modbus错误码 + int exCode = modbus->ErrorCheck(); + if (exCode) + { + QString errorMsg; + switch (exCode) { + case 0x01: errorMsg = "非法功能码"; break; + case 0x02: errorMsg = "非法数据地址"; break; + case 0x03: errorMsg = "非法数据值"; break; + case 0x04: errorMsg = "从站设备故障"; break; + default: errorMsg = "未知异常"; break; + } + QMessageBox::warning(this, "异常响应", + QString("错误码: 0x%1(%2)").arg(QString::number(exCode, 16).toUpper(), errorMsg)); + return; + } + + // 解析并显示数据(根据功能码) + switch (ui->comboBox_gongnengma->currentIndex()) + { + case 0: + { // 读线圈 + QVector coils = modbus->AnalReadCoil(); + ui->textEdit->append("线圈状态:"); + for (int i = 0; i < coils.size(); i++) + { + ui->textEdit->append(QString("线圈%1: %2").arg(i+1).arg(coils[i] ? "1" : "0")); + } + break; + } + case 1: + { // 读寄存器 + QVector regs = modbus->AnalReadReg(); + ui->textEdit->append("寄存器值:"); + for (int i = 0; i < regs.size(); i++) + { + ui->textEdit->append(QString("寄存器%1: %2").arg(i+1).arg(regs[i])); + } + break; + } + } +} + +void Widget::onSerialStatusChanged(const QString &status) +{ + ui->textEdit_2->append(status); // 显示状态信息(如连接成功、超时重发等) +} + + +void Widget::onSerialTimeout() +{ + QMessageBox::warning(this, "提示", "等待响应超时,请检查设备"); + ui->btn_read->setEnabled(true); + ui->pushWrite->setEnabled(true); } diff --git a/widget.h b/widget.h index a4781ae..6e40a4b 100644 --- a/widget.h +++ b/widget.h @@ -5,6 +5,8 @@ #include #include #include "mymodbus.h" +#include "communicationhistory.h" +#include "serialcommunicator.h" namespace Ui { class Widget; @@ -23,8 +25,6 @@ private slots: void on_pushWrite_clicked(); - void on_SerialData_ReadyToRead(); - void on_btn_read_clicked(); void on_btn_SaveDate_clicked(); @@ -33,18 +33,18 @@ private slots: void on_btn_ClearDate_clicked(); - void onReadyRead(); - void on_btn_ClearRead_clicked(); + void onSerialDataReceived(const QByteArray &data); + + void onSerialStatusChanged(const QString &status); + + void onSerialTimeout(); + private: Ui::Widget *ui; - QSerialPort *serialPort; + SerialCommunicator *serialComm; MyModbus *modbus; - QTimer timer; - int comCount; - QByteArray recvBuffer; - QTimer *recvTimer; }; #endif // WIDGET_H