Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

264 строки
7.5 KiB

  1. #include "serialportmanager.h"
  2. #include <QSerialPortInfo>
  3. #include <QVBoxLayout>
  4. #include <QHBoxLayout>
  5. #include <QGroupBox>
  6. #include <QMessageBox>
  7. #include <QDebug>
  8. SerialPortManager::SerialPortManager(QWidget *parent)
  9. : QDialog(parent), m_serial(new QSerialPort(this))
  10. {
  11. setWindowTitle("串口连接设置");
  12. setFixedSize(450,200);
  13. // 连接串口信号
  14. connect(m_serial, &QSerialPort::readyRead, this, &SerialPortManager::handleReadyRead);
  15. connect(m_serial, &QSerialPort::errorOccurred, this, &SerialPortManager::handleError);
  16. // 主布局
  17. QVBoxLayout *mainLayout = new QVBoxLayout(this);
  18. // 创建单个GroupBox - 串口参数设置
  19. QGroupBox *settingsGroup = new QGroupBox("串口参数设置", this);
  20. QFormLayout *formLayout = new QFormLayout(settingsGroup);
  21. // 串口选择行
  22. m_portComboBox = new QComboBox(this);
  23. QPushButton *refreshButton = new QPushButton("刷新", this);
  24. QHBoxLayout *portComboLayout = new QHBoxLayout;
  25. portComboLayout->addWidget(m_portComboBox, 5);
  26. portComboLayout->addWidget(refreshButton, 1);
  27. formLayout->addRow("串口:", portComboLayout);
  28. // 波特率选择行
  29. m_baudComboBox = new QComboBox(this);
  30. populateBaudRates();
  31. formLayout->addRow("波特率:", m_baudComboBox);
  32. // 奇偶校验选择行
  33. m_parityComboBox = new QComboBox(this);
  34. populateParities();
  35. formLayout->addRow("奇偶校验:", m_parityComboBox);
  36. // 从站地址行
  37. m_stationSpinBox = new QSpinBox(this);
  38. m_stationSpinBox->setRange(1, 247);
  39. m_stationSpinBox->setValue(1);
  40. formLayout->addRow("从站地址:", m_stationSpinBox);
  41. // 添加到主布局
  42. mainLayout->addWidget(settingsGroup);
  43. // 按钮区域
  44. QHBoxLayout *buttonLayout = new QHBoxLayout;
  45. m_connectBtn = new QPushButton("连接", this);
  46. QPushButton *cancelButton = new QPushButton("取消", this);
  47. // 状态标签
  48. m_statusLabel = new QLabel("状态: 未连接", this);
  49. m_statusLabel->setStyleSheet("QLabel { color: red; }");
  50. buttonLayout->addWidget(m_statusLabel);
  51. buttonLayout->addStretch();
  52. buttonLayout->addWidget(m_connectBtn);
  53. buttonLayout->addWidget(cancelButton);
  54. // 添加到主布局
  55. mainLayout->addLayout(buttonLayout);
  56. // 连接信号
  57. connect(refreshButton, &QPushButton::clicked, this, &SerialPortManager::refreshPorts);
  58. connect(m_connectBtn, &QPushButton::clicked, this, &SerialPortManager::onConnectClicked);
  59. connect(cancelButton, &QPushButton::clicked, this, &QDialog::reject);
  60. // 初始刷新端口
  61. refreshPorts();
  62. }
  63. SerialPortManager::~SerialPortManager()
  64. {
  65. if (m_serial->isOpen()) {
  66. m_serial->close();
  67. }
  68. }
  69. // 串口操作接口实现
  70. bool SerialPortManager::isOpen() const
  71. {
  72. return m_serial->isOpen();
  73. }
  74. void SerialPortManager::openSerialPort()
  75. {
  76. if (!m_serial->isOpen()) {
  77. onConnectClicked();
  78. }
  79. }
  80. void SerialPortManager::closeSerialPort()
  81. {
  82. if (m_serial->isOpen()) {
  83. m_serial->close();
  84. updateConnectionState(false);
  85. }
  86. }
  87. QByteArray SerialPortManager::readAll()
  88. {
  89. return m_serial->readAll();
  90. }
  91. void SerialPortManager::write(const QByteArray &data)
  92. {
  93. if (m_serial->isOpen()) {
  94. m_serial->write(data);
  95. }
  96. }
  97. // 连接按钮槽函数
  98. void SerialPortManager::onConnectClicked()
  99. {
  100. if (m_serial->isOpen()) {
  101. // 如果已连接,则断开
  102. m_serial->close();
  103. updateConnectionState(false);
  104. return;
  105. }
  106. // 获取配置
  107. QString portName = m_portComboBox->currentData().toString();
  108. int baudRate = m_baudComboBox->currentData().toInt();
  109. QSerialPort::Parity parity = static_cast<QSerialPort::Parity>(m_parityComboBox->currentData().toInt());
  110. if (portName.isEmpty()) {
  111. QMessageBox::warning(this, "错误", "请选择有效的串口");
  112. return;
  113. }
  114. // 配置串口
  115. m_serial->setPortName(portName);
  116. m_serial->setBaudRate(baudRate);
  117. m_serial->setDataBits(QSerialPort::Data8);
  118. m_serial->setParity(parity);
  119. m_serial->setStopBits(QSerialPort::OneStop);
  120. if (m_serial->open(QIODevice::ReadWrite))
  121. {
  122. updateConnectionState(true);
  123. QString logMsg = QString("串口连接成功: %1, %2 bps, 从站地址: %3")
  124. .arg(portName)
  125. .arg(baudRate)
  126. .arg(m_stationSpinBox->value());
  127. emit logMessage(logMsg); // 发送统一日志
  128. }
  129. else
  130. {
  131. QString errorMsg = QString("串口连接失败: %1").arg(m_serial->errorString());
  132. emit logMessage(errorMsg); // 发送统一日志
  133. }
  134. }
  135. // 更新连接状态
  136. void SerialPortManager::updateConnectionState(bool connected)
  137. {
  138. if (connected) {
  139. m_connectBtn->setText("断开");
  140. m_statusLabel->setText("状态: 已连接");
  141. m_statusLabel->setStyleSheet("QLabel { color: green; }");
  142. } else {
  143. m_connectBtn->setText("连接");
  144. m_statusLabel->setText("状态: 未连接");
  145. m_statusLabel->setStyleSheet("QLabel { color: red; }");
  146. }
  147. }
  148. // 数据接收处理
  149. void SerialPortManager::handleReadyRead()
  150. {
  151. QByteArray data = m_serial->readAll();
  152. if (!data.isEmpty()) {
  153. QString hexString = data.toHex().toUpper(); // 转换为大写的十六进制
  154. emit logMessage("接收: " + hexString); // 发送统一日志
  155. }
  156. }
  157. // 错误处理
  158. void SerialPortManager::handleError(QSerialPort::SerialPortError error)
  159. {
  160. if (error != QSerialPort::NoError)
  161. {
  162. QString errorMsg = QString("串口错误: %1").arg(m_serial->errorString());
  163. emit logMessage(errorMsg); // 发送统一日志
  164. }
  165. }
  166. void SerialPortManager::populateBaudRates()
  167. {
  168. m_baudComboBox->clear();
  169. m_baudComboBox->addItem("4800", QSerialPort::Baud4800);
  170. m_baudComboBox->addItem("9600", QSerialPort::Baud9600);
  171. m_baudComboBox->addItem("19200", QSerialPort::Baud19200);
  172. m_baudComboBox->addItem("38400", QSerialPort::Baud38400);
  173. m_baudComboBox->addItem("57600", QSerialPort::Baud57600);
  174. m_baudComboBox->addItem("115200", QSerialPort::Baud115200);
  175. m_baudComboBox->setCurrentIndex(1); // 默认9600
  176. }
  177. void SerialPortManager::populateParities()
  178. {
  179. m_parityComboBox->clear();
  180. m_parityComboBox->addItem("无校验", QSerialPort::NoParity);
  181. m_parityComboBox->addItem("奇校验", QSerialPort::OddParity);
  182. m_parityComboBox->addItem("偶校验", QSerialPort::EvenParity);
  183. m_parityComboBox->setCurrentIndex(0); // 默认无校验
  184. }
  185. void SerialPortManager::refreshPorts()
  186. {
  187. m_portComboBox->clear();
  188. const auto ports = QSerialPortInfo::availablePorts();
  189. for (const QSerialPortInfo &port : ports) {
  190. QString description = port.description();
  191. if (description.isEmpty()) description = "未知设备";
  192. QString itemText = QString("%1 (%2)")
  193. .arg(port.portName())
  194. .arg(description);
  195. m_portComboBox->addItem(itemText, port.portName());
  196. }
  197. if (ports.isEmpty())
  198. {
  199. m_portComboBox->addItem("无可用端口", "");
  200. }
  201. }
  202. QString SerialPortManager::portName() const
  203. {
  204. return m_portComboBox->currentData().toString();
  205. }
  206. int SerialPortManager::baudRate() const
  207. {
  208. return m_baudComboBox->currentData().toInt();
  209. }
  210. QSerialPort::Parity SerialPortManager::parity() const
  211. {
  212. return static_cast<QSerialPort::Parity>(m_parityComboBox->currentData().toInt());
  213. }
  214. QSerialPort::StopBits SerialPortManager::stopBits() const
  215. {
  216. return QSerialPort::OneStop;
  217. }
  218. int SerialPortManager::stationAddress() const
  219. {
  220. return m_stationSpinBox->value();
  221. }