Browse Source

增加了从站掉线检测功能

master
鹏鹏 李 5 days ago
parent
commit
05c0894947
6 changed files with 122 additions and 10 deletions
  1. +1
    -1
      modbus.pro.user
  2. +46
    -4
      serialcommunicator.cpp
  3. +10
    -0
      serialcommunicator.h
  4. +30
    -0
      widget.cpp
  5. +4
    -0
      widget.h
  6. +31
    -5
      widget.ui

+ 1
- 1
modbus.pro.user View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 4.0.3, 2025-08-01T15:38:03. -->
<!-- Written by QtCreator 4.0.3, 2025-08-04T09:20:47. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>


+ 46
- 4
serialcommunicator.cpp View File

@@ -25,19 +25,25 @@ SerialCommunicator::SerialCommunicator(QObject *parent) : QObject(parent)
, serialPort_(new QSerialPort(this))
, recvTimer_(new QTimer(this))
, resendTimer_(new QTimer(this))
, stationCheck_(new QTimer(this))
, checkTimeOut_(new QTimer(this))
, comCount_(0)
, maxRetry_(3)
, recvTimeout_(50)
, resendTimeout_(1000)
, test_(QByteArray::fromHex("010100010001AC0A"))
{
// 配置定时器(单次触发)
recvTimer_->setSingleShot(true);
resendTimer_->setSingleShot(true);
stationCheck_->setSingleShot(true);

// 连接信号槽
connect(serialPort_, &QSerialPort::readyRead, this, &SerialCommunicator::onReadyRead);
connect(recvTimer_, &QTimer::timeout, this, &SerialCommunicator::onRecvTimeout);
connect(resendTimer_, &QTimer::timeout, this, &SerialCommunicator::onResendTimeout);
connect(stationCheck_, QTimer::timeout, this, SerialCommunicator::stationCheck);
connect(checkTimeOut_, QTimer::timeout, this, SerialCommunicator::checkTimeOut);
connect(serialPort_, SIGNAL(error(QSerialPort::SerialPortError)),
this, SLOT(handleSerialError(QSerialPort::SerialPortError)));
}
@@ -119,6 +125,7 @@ bool SerialCommunicator::open()
if (serialPort_->open(QIODevice::ReadWrite))
{
emit statusChanged("串口连接成功");
stationCheck_->start(1000);
return true;
}
else
@@ -145,8 +152,11 @@ void SerialCommunicator::close()
//关闭所有定时器
recvTimer_->stop();
resendTimer_->stop();
stationCheck_->stop();
checkTimeOut_->stop();

// 清除可能存在的待处理数据
emit stationConnect(false);
serialPort_->clear();

// 关闭串口
@@ -175,6 +185,8 @@ void SerialCommunicator::sendData(const QByteArray &data)
emit statusChanged("串口未打开,无法发送数据");
return;
}
stationCheck_->stop();
checkTimeOut_->stop();
// 保存待重发数据,初始化计数器,启动重发定时器
currentData_ = data;
comCount_ = 0;
@@ -233,6 +245,11 @@ bool SerialCommunicator::isOpen() const
return serialPort_->isOpen();
}

void SerialCommunicator::setCheckMsg(QByteArray msg)
{
this->test_ = msg;
}

// ====================== 私有槽函数 ====================== //

/**
@@ -245,10 +262,20 @@ bool SerialCommunicator::isOpen() const
*/
void SerialCommunicator::onReadyRead()
{
// 读取数据到缓冲区
recvBuffer_.append(serialPort_->readAll());
//重置接收超时定时器
recvTimer_->start(recvTimeout_);
if(checkTimeOut_->isActive() || stationCheck_->isActive())
{
checkTimeOut_->stop();
serialPort_->clear();
emit stationConnect(true);
stationCheck_->start(1000);
}
else
{
// 读取数据到缓冲区
recvBuffer_.append(serialPort_->readAll());
//重置接收超时定时器
recvTimer_->start(recvTimeout_);
}
}

/**
@@ -262,6 +289,7 @@ void SerialCommunicator::onReadyRead()
void SerialCommunicator::onRecvTimeout()
{
// 接收完成,发送完整数据信号,停止重发定时器
stationCheck_->start(1000);
resendTimer_->stop();
emit dataReceived(recvBuffer_);
recvBuffer_.clear();
@@ -289,6 +317,7 @@ void SerialCommunicator::onResendTimeout()
{
// 达到最大重发次数,触发超时信号
resendTimer_->stop();
stationCheck_->start(1000);
emit timeoutOccurred();
}
}
@@ -382,3 +411,16 @@ void SerialCommunicator::handleSerialError(QSerialPort::SerialPortError error)
}

}

void SerialCommunicator::stationCheck()
{
serialPort_->write(test_);
checkTimeOut_->setSingleShot(true);
checkTimeOut_->start(200);
}

void SerialCommunicator::checkTimeOut()
{
emit stationConnect(false);
stationCheck_->start(1000);
}

+ 10
- 0
serialcommunicator.h View File

@@ -117,6 +117,8 @@ public:
*/
bool isOpen() const;

void setCheckMsg(QByteArray msg);

signals:
/**
* @brief 接收到完整数据信号
@@ -143,6 +145,8 @@ signals:
*/
void physicalDisconnected();

void stationConnect(bool online);

private slots:
/**
* @brief 串口数据到达处理
@@ -168,16 +172,22 @@ private slots:
*/
void handleSerialError(QSerialPort::SerialPortError error);

void stationCheck();
void checkTimeOut();

private:
QSerialPort *serialPort_; // 串口对象
QTimer *recvTimer_; // 接收完成判断定时器
QTimer *resendTimer_; // 超时重发定时器
QTimer *stationCheck_; // 检测是否连接到从站
QTimer *checkTimeOut_;
QByteArray recvBuffer_; // 接收缓冲区
QByteArray currentData_; // 当前待重发数据
int comCount_; // 重发计数器
int maxRetry_; // 最大重发次数
int recvTimeout_; // 接收超时时间(ms)
int resendTimeout_; // 重发间隔(ms)
QByteArray test_;

// 串口参数
QString portName_;


+ 30
- 0
widget.cpp View File

@@ -56,6 +56,8 @@ Widget::Widget(QWidget *parent) :
this, &Widget::onBtnBatchInputClicked);
connect(ui_->line_input, &QLineEdit::textChanged,
this, &Widget::onTextChanged);
connect(ui_->btn_checkmsg, &QPushButton::clicked,
this, &Widget::onBtnCheckmsgClicked);
//当串口接收到完整数据后,serialComm_会发出dataReceived信号
connect(serialComm_, &SerialCommunicator::dataReceived,
this, &Widget::onSerialDataReceived);
@@ -68,6 +70,8 @@ Widget::Widget(QWidget *parent) :
//当串口连接出现错误时(例如串口突然断开),serialComm_会发出physicalDisconnected信号
connect(serialComm_, &SerialCommunicator::physicalDisconnected,
this, &Widget::sicalDisconnected);
connect(serialComm_, &SerialCommunicator::stationConnect,
this, &Widget::staionConneting);

//设置默认波特率、数据位、校验位
ui_->combo_baud_rate->setCurrentIndex(3);
@@ -492,6 +496,18 @@ void Widget::onTextChanged()
ui_->line_number->setText(QString::number(data.size()));
}

void Widget::staionConneting(bool online)
{
if(online)
{
ui_->label_staion->setText("成功连接到从站");
}
else
{
ui_->label_staion->setText("未连接到从站");
}
}

/**
* @brief 串口通信超时处理
*
@@ -535,3 +551,17 @@ void Widget::onBtnBatchInputClicked()
ui_->line_input->insert(inputData);
}
}

void Widget::onBtnCheckmsgClicked()
{
bool ok;
quint16 stationAddress = ui_->line_station_address->text().toUShort(&ok);
if (!ok || 0 == stationAddress)
{
QMessageBox::warning(this, "输入错误", "从站地址应为大于0的整数");
return;
}
modbus_->setStation(stationAddress,0x01,0x01,0x01);
modbus_->readCoilAndReg();
serialComm_->setCheckMsg(modbus_->sendCommand());
}

+ 4
- 0
widget.h View File

@@ -84,6 +84,8 @@ private slots:

void onTextChanged();

void staionConneting(bool online);

// 串口通信超时处理槽函数
void onSerialTimeout();

@@ -91,6 +93,8 @@ private slots:

void onBtnBatchInputClicked();

void onBtnCheckmsgClicked();

private:
Ui::Widget *ui_; // 指向用户界面的指针
SerialCommunicator *serialComm_; // 串口通信处理对象


+ 31
- 5
widget.ui View File

@@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>700</width>
<height>500</height>
<height>503</height>
</rect>
</property>
<property name="windowTitle">
@@ -309,9 +309,9 @@
<property name="geometry">
<rect>
<x>240</x>
<y>20</y>
<y>30</y>
<width>211</width>
<height>271</height>
<height>261</height>
</rect>
</property>
<property name="title">
@@ -335,9 +335,9 @@
<property name="geometry">
<rect>
<x>470</x>
<y>20</y>
<y>30</y>
<width>221</width>
<height>271</height>
<height>261</height>
</rect>
</property>
<property name="title">
@@ -508,6 +508,32 @@
<bool>true</bool>
</property>
</widget>
<widget class="QWidget" name="">
<property name="geometry">
<rect>
<x>251</x>
<y>1</y>
<width>241</width>
<height>30</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_staion">
<property name="text">
<string>未连接到从站</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btn_checkmsg">
<property name="text">
<string>重新生成检测报文</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>


Loading…
Cancel
Save