Procházet zdrojové kódy

新建串口连接,实现串口通信

main
email před 15 hodinami
rodič
revize
0df52275bf
7 změnil soubory, kde provedl 385 přidání a 31 odebrání
  1. +50
    -28
      untitled/mainwindow.cpp
  2. +4
    -0
      untitled/mainwindow.h
  3. +0
    -0
      untitled/modbusmanager.cpp
  4. +4
    -0
      untitled/modbusmanager.h
  5. +263
    -0
      untitled/serialportmanager.cpp
  6. +57
    -0
      untitled/serialportmanager.h
  7. +7
    -3
      untitled/untitled.pro

+ 50
- 28
untitled/mainwindow.cpp Zobrazit soubor

@@ -24,34 +24,27 @@ MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
setWindowTitle("综合平台编程器");
setGeometry(500, 200, 1000, 700);

// 1. 先创建中央区域
QWidget* centralContainer = new QWidget;
QHBoxLayout* centralLayout = new QHBoxLayout(centralContainer);
centralLayout->setContentsMargins(0, 0, 0, 0);

// 2. 左侧工具栏区
createToolbars(); // 创建工具栏对象
centralLayout->addWidget(m_leftToolBar);

// 3. 中央文档区
m_tabWidget = new QTabWidget;
m_tabWidget->setTabsClosable(true);
centralLayout->addWidget(m_tabWidget, 1); // 占据剩余空间

// 4. 设置中央部件
setCentralWidget(centralContainer);

// 5. 创建日志面板
createLogPanel();

// 连接信号
connect(m_tabWidget, &QTabWidget::currentChanged, this, &MainWindow::onTabChanged);
connect(m_tabWidget, &QTabWidget::tabCloseRequested, this, &MainWindow::onCloseTab);

// 创建菜单
createMenus();
setGeometry(500, 200, 1000, 700);
// 1. 先创建中央区域
QWidget* centralContainer = new QWidget;
QHBoxLayout* centralLayout = new QHBoxLayout(centralContainer);
centralLayout->setContentsMargins(0, 0, 0, 0);
// 2. 左侧工具栏区
createToolbars(); // 创建工具栏对象
centralLayout->addWidget(m_leftToolBar);
// 3. 中央文档区
m_tabWidget = new QTabWidget;
m_tabWidget->setTabsClosable(true);
centralLayout->addWidget(m_tabWidget, 1); // 占据剩余空间
// 4. 设置中央部件
setCentralWidget(centralContainer);
// 5. 创建日志面板
createLogPanel();
// 连接信号
connect(m_tabWidget, &QTabWidget::currentChanged, this, &MainWindow::onTabChanged);
connect(m_tabWidget, &QTabWidget::tabCloseRequested, this, &MainWindow::onCloseTab);
// 创建菜单
createMenus();
}

MainWindow::~MainWindow()
@@ -206,8 +199,37 @@ void MainWindow::createMenus()
editMenu->addAction(copyAction);
editMenu->addAction(pasteAction);
editMenu->addAction(deleteAction);

// 添加仿真菜单项
QMenu *simulationMenu = menuBar()->addMenu("仿真");
simulationMenu->setFont(itemFont);

// 连接动作
QAction *connectAction = new QAction("连接设置", this);
connectAction->setFont(itemFont);
connect(connectAction, &QAction::triggered, this, &MainWindow::onConnectClicked);
simulationMenu->addAction(connectAction);

// 运行动作 (暂时留空)
QAction *runAction = new QAction("运行", this);
runAction->setFont(itemFont);
runAction->setEnabled(false);
simulationMenu->addAction(runAction);

}
void MainWindow::onConnectClicked()
{
if (!m_serialDialog) {
m_serialDialog = new SerialPortManager(this);
connect(m_serialDialog, &SerialPortManager::logMessage,this, &MainWindow::handleSerialLog);
}

m_serialDialog->exec();
}
void MainWindow::handleSerialLog(const QString &message)
{
m_logEdit->append(message);
}
// 创建左侧工具栏
void MainWindow::createToolbars()
{


+ 4
- 0
untitled/mainwindow.h Zobrazit soubor

@@ -7,6 +7,7 @@
#include <QAction>
#include<QTextEdit>
#include "basedocument.h"
#include "serialportmanager.h"
#include<QPushButton>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
@@ -33,7 +34,10 @@ private slots:
void onCloseTab(int index); // 关闭标签页
void onClearLogButtonClicked();
void showLogContextMenu(const QPoint &pos);
void onConnectClicked(); // 连接菜单项槽函数
void handleSerialLog(const QString &message);
private:
SerialPortManager *m_serialDialog=nullptr; // 串口对话框
void createMenus(); // 创建菜单栏
QWidget* m_logPanelContainer;
QDockWidget* m_logDock;


+ 0
- 0
untitled/modbusmanager.cpp Zobrazit soubor


+ 4
- 0
untitled/modbusmanager.h Zobrazit soubor

@@ -0,0 +1,4 @@
#ifndef MODBUSMANAGER_H
#define MODBUSMANAGER_H

#endif // MODBUSMANAGER_H

+ 263
- 0
untitled/serialportmanager.cpp Zobrazit soubor

@@ -0,0 +1,263 @@
#include "serialportmanager.h"
#include <QSerialPortInfo>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QGroupBox>
#include <QMessageBox>
#include <QDebug>

SerialPortManager::SerialPortManager(QWidget *parent)
: QDialog(parent), m_serial(new QSerialPort(this))
{
setWindowTitle("串口连接设置");
setFixedSize(450,200);

// 连接串口信号
connect(m_serial, &QSerialPort::readyRead, this, &SerialPortManager::handleReadyRead);
connect(m_serial, &QSerialPort::errorOccurred, this, &SerialPortManager::handleError);

// 主布局
QVBoxLayout *mainLayout = new QVBoxLayout(this);

// 创建单个GroupBox - 串口参数设置
QGroupBox *settingsGroup = new QGroupBox("串口参数设置", this);
QFormLayout *formLayout = new QFormLayout(settingsGroup);

// 串口选择行
m_portComboBox = new QComboBox(this);
QPushButton *refreshButton = new QPushButton("刷新", this);
QHBoxLayout *portComboLayout = new QHBoxLayout;
portComboLayout->addWidget(m_portComboBox, 5);
portComboLayout->addWidget(refreshButton, 1);
formLayout->addRow("串口:", portComboLayout);

// 波特率选择行
m_baudComboBox = new QComboBox(this);
populateBaudRates();
formLayout->addRow("波特率:", m_baudComboBox);

// 奇偶校验选择行
m_parityComboBox = new QComboBox(this);
populateParities();
formLayout->addRow("奇偶校验:", m_parityComboBox);

// 从站地址行
m_stationSpinBox = new QSpinBox(this);
m_stationSpinBox->setRange(1, 247);
m_stationSpinBox->setValue(1);
formLayout->addRow("从站地址:", m_stationSpinBox);

// 添加到主布局
mainLayout->addWidget(settingsGroup);

// 按钮区域
QHBoxLayout *buttonLayout = new QHBoxLayout;
m_connectBtn = new QPushButton("连接", this);
QPushButton *cancelButton = new QPushButton("取消", this);

// 状态标签
m_statusLabel = new QLabel("状态: 未连接", this);
m_statusLabel->setStyleSheet("QLabel { color: red; }");

buttonLayout->addWidget(m_statusLabel);
buttonLayout->addStretch();
buttonLayout->addWidget(m_connectBtn);
buttonLayout->addWidget(cancelButton);

// 添加到主布局
mainLayout->addLayout(buttonLayout);

// 连接信号
connect(refreshButton, &QPushButton::clicked, this, &SerialPortManager::refreshPorts);
connect(m_connectBtn, &QPushButton::clicked, this, &SerialPortManager::onConnectClicked);
connect(cancelButton, &QPushButton::clicked, this, &QDialog::reject);

// 初始刷新端口
refreshPorts();
}

SerialPortManager::~SerialPortManager()
{
if (m_serial->isOpen()) {
m_serial->close();
}
}

// 串口操作接口实现
bool SerialPortManager::isOpen() const
{
return m_serial->isOpen();
}

void SerialPortManager::openSerialPort()
{
if (!m_serial->isOpen()) {
onConnectClicked();
}
}

void SerialPortManager::closeSerialPort()
{
if (m_serial->isOpen()) {
m_serial->close();
updateConnectionState(false);
}
}

QByteArray SerialPortManager::readAll()
{
return m_serial->readAll();
}

void SerialPortManager::write(const QByteArray &data)
{
if (m_serial->isOpen()) {
m_serial->write(data);
}
}

// 连接按钮槽函数
void SerialPortManager::onConnectClicked()
{
if (m_serial->isOpen()) {
// 如果已连接,则断开
m_serial->close();
updateConnectionState(false);
return;
}

// 获取配置
QString portName = m_portComboBox->currentData().toString();
int baudRate = m_baudComboBox->currentData().toInt();
QSerialPort::Parity parity = static_cast<QSerialPort::Parity>(m_parityComboBox->currentData().toInt());

if (portName.isEmpty()) {
QMessageBox::warning(this, "错误", "请选择有效的串口");
return;
}

// 配置串口
m_serial->setPortName(portName);
m_serial->setBaudRate(baudRate);
m_serial->setDataBits(QSerialPort::Data8);
m_serial->setParity(parity);
m_serial->setStopBits(QSerialPort::OneStop);

if (m_serial->open(QIODevice::ReadWrite))
{
updateConnectionState(true);
QString logMsg = QString("串口连接成功: %1, %2 bps, 从站地址: %3")
.arg(portName)
.arg(baudRate)
.arg(m_stationSpinBox->value());
emit logMessage(logMsg); // 发送统一日志
}
else
{
QString errorMsg = QString("串口连接失败: %1").arg(m_serial->errorString());
emit logMessage(errorMsg); // 发送统一日志
}

}

// 更新连接状态
void SerialPortManager::updateConnectionState(bool connected)
{
if (connected) {
m_connectBtn->setText("断开");
m_statusLabel->setText("状态: 已连接");
m_statusLabel->setStyleSheet("QLabel { color: green; }");
} else {
m_connectBtn->setText("连接");
m_statusLabel->setText("状态: 未连接");
m_statusLabel->setStyleSheet("QLabel { color: red; }");
}
}

// 数据接收处理
void SerialPortManager::handleReadyRead()
{
QByteArray data = m_serial->readAll();
if (!data.isEmpty()) {
QString hexString = data.toHex().toUpper(); // 转换为大写的十六进制
emit logMessage("接收: " + hexString); // 发送统一日志
}

}

// 错误处理
void SerialPortManager::handleError(QSerialPort::SerialPortError error)
{
if (error != QSerialPort::NoError)
{
QString errorMsg = QString("串口错误: %1").arg(m_serial->errorString());
emit logMessage(errorMsg); // 发送统一日志
}
}

void SerialPortManager::populateBaudRates()
{
m_baudComboBox->clear();
m_baudComboBox->addItem("4800", QSerialPort::Baud4800);
m_baudComboBox->addItem("9600", QSerialPort::Baud9600);
m_baudComboBox->addItem("19200", QSerialPort::Baud19200);
m_baudComboBox->addItem("38400", QSerialPort::Baud38400);
m_baudComboBox->addItem("57600", QSerialPort::Baud57600);
m_baudComboBox->addItem("115200", QSerialPort::Baud115200);
m_baudComboBox->setCurrentIndex(1); // 默认9600
}

void SerialPortManager::populateParities()
{
m_parityComboBox->clear();
m_parityComboBox->addItem("无校验", QSerialPort::NoParity);
m_parityComboBox->addItem("奇校验", QSerialPort::OddParity);
m_parityComboBox->addItem("偶校验", QSerialPort::EvenParity);
m_parityComboBox->setCurrentIndex(0); // 默认无校验
}

void SerialPortManager::refreshPorts()
{
m_portComboBox->clear();
const auto ports = QSerialPortInfo::availablePorts();

for (const QSerialPortInfo &port : ports) {
QString description = port.description();
if (description.isEmpty()) description = "未知设备";

QString itemText = QString("%1 (%2)")
.arg(port.portName())
.arg(description);

m_portComboBox->addItem(itemText, port.portName());
}
if (ports.isEmpty())
{
m_portComboBox->addItem("无可用端口", "");
}
}

QString SerialPortManager::portName() const
{
return m_portComboBox->currentData().toString();
}

int SerialPortManager::baudRate() const
{
return m_baudComboBox->currentData().toInt();
}

QSerialPort::Parity SerialPortManager::parity() const
{
return static_cast<QSerialPort::Parity>(m_parityComboBox->currentData().toInt());
}

QSerialPort::StopBits SerialPortManager::stopBits() const
{
return QSerialPort::OneStop;
}

int SerialPortManager::stationAddress() const
{
return m_stationSpinBox->value();
}

+ 57
- 0
untitled/serialportmanager.h Zobrazit soubor

@@ -0,0 +1,57 @@
#ifndef SERIALPORTMANAGER_H
#define SERIALPORTMANAGER_H

#include <QDialog>
#include <QSerialPort>
#include <QComboBox>
#include <QPushButton>
#include <QFormLayout>
#include <QSpinBox>
#include <QLabel>

class SerialPortManager : public QDialog
{
Q_OBJECT
public:
explicit SerialPortManager(QWidget *parent = nullptr);
~SerialPortManager();

// 获取串口配置
QString portName() const;
int baudRate() const;
QSerialPort::Parity parity() const;
QSerialPort::StopBits stopBits() const;
int stationAddress() const;

// 新增串口操作接口
bool isOpen() const;
void openSerialPort();
void closeSerialPort();
QByteArray readAll();
void write(const QByteArray &data);

signals:
void errorOccurred(const QString &error);
void logMessage(const QString &message);

private slots:
void refreshPorts();
void onConnectClicked();
void handleReadyRead();
void handleError(QSerialPort::SerialPortError error);

private:
void populateBaudRates();
void populateParities();
void updateConnectionState(bool connected);

QSerialPort *m_serial; // 串口对象
QComboBox *m_portComboBox;
QComboBox *m_baudComboBox;
QComboBox *m_parityComboBox;
QSpinBox *m_stationSpinBox;
QPushButton *m_connectBtn; // 连接/断开按钮
QLabel *m_statusLabel; // 状态标签
};

#endif // SERIALPORTMANAGER_H

+ 7
- 3
untitled/untitled.pro Zobrazit soubor

@@ -1,5 +1,5 @@
QT += core gui
QT += core gui widgets serialport
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++11
@@ -21,16 +21,20 @@ SOURCES += \
hmidocument.cpp \
main.cpp \
mainwindow.cpp \
modbusmanager.cpp \
plcdocument.cpp \
plcitems.cpp
plcitems.cpp \
serialportmanager.cpp

HEADERS += \
basedocument.h \
graphicsitems.h \
hmidocument.h \
mainwindow.h \
modbusmanager.h \
plcdocument.h \
plcitems.h
plcitems.h \
serialportmanager.h

FORMS += \
mainwindow.ui


Načítá se…
Zrušit
Uložit