#include "widget.h" #include "ui_widget.h" #include #include #include #include #include #include #include #include Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { modbus = new MyModbus(); ui->setupUi(this); serialComm = new SerialCommunicator(this); // 初始化串口通信类 // 配置串口参数 serialComm->setMaxRetry(3); // 最大重发3次 serialComm->setRecvTimeout(50); // 接收超时50ms serialComm->setResendTimeout(1000); // 重发间隔1s // 连接信号槽(串口->界面) 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); ui->comboBox_xiaoyan->setCurrentIndex(2); ui->btn_read->setEnabled(0); ui->pushWrite->setEnabled(0); QList serialList = QSerialPortInfo::availablePorts(); for(QSerialPortInfo serialInfo : serialList) { ui->comboBox_serialNum->addItem(serialInfo.portName()); } } Widget::~Widget() { delete modbus; delete serialComm; delete ui; } //串口连接 void Widget::on_btnConnect_clicked() { if (ui->btnConnect->text() == "连接") { // 获取界面配置的串口参数 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: parity = QSerialPort::NoParity; break; case 1: parity = QSerialPort::OddParity; break; case 2: parity = QSerialPort::EvenParity; break; default: parity = QSerialPort::NoParity; } QSerialPort::StopBits stopBits = QSerialPort::StopBits(ui->comboBox_stopBit->currentText().toInt()); // 配置并打开串口 serialComm->setPortParams(portName, baudRate, dataBits, parity, stopBits); if (serialComm->open()) { ui->btnConnect->setText("断开"); ui->btn_read->setEnabled(true); ui->pushWrite->setEnabled(true); } else { QMessageBox::warning(this, "提示", "串口连接失败"); } } else { // 断开串口 serialComm->close(); ui->btnConnect->setText("连接"); ui->btn_read->setEnabled(false); ui->pushWrite->setEnabled(false); } } //写线圈和写寄存器 void Widget::on_pushWrite_clicked() { switch (ui->comboBox_gongnengma->currentIndex()) { case 2: //写多个线圈 { QString sendData = ui->lineEdit->text().trimmed(); if (sendData.isEmpty()) { QMessageBox::warning(this, "提示", "请至少输入一个数据"); return; } for (QChar ch : sendData) { if (ch != '0' && ch != '1') { QMessageBox::warning(this, "提示", "只允许输入 0 或 1!"); return; } } QVector coils; for (QChar ch : sendData) { coils.append(ch == '1'); } quint16 stationAddress = ui->comboBox_stationAddress->currentText().toInt(); quint16 functionCode = 0x0f; quint16 stratAddress = ui->lineEdit_stratAddress->text().toInt(); quint16 length = ui->lineEdit_length->text().toInt(); if (coils.size() != length) { QMessageBox::warning(this, "提示", "输入数据数与设置的长度不匹配"); return; } modbus->Set(stationAddress,functionCode,stratAddress,length); modbus->WriteCoil(coils); serialComm->sendData(modbus->SendCommand()); ui->btn_read->setEnabled(0); ui->pushWrite->setEnabled(0); break; } case 3: { QString sendData = ui->lineEdit->text().trimmed(); if (sendData.isEmpty()) { QMessageBox::warning(this, "提示", "请输入完整的寄存器数据"); return; } QStringList sl = sendData.split(','); QVector values; bool ok; for (const QString &s : sl) { quint16 v = s.toUShort(&ok, 16); if (!ok) { QMessageBox::warning(this, "提示", "请输入正确的十六进制值,或检查逗号是否是英文格式!"); return; } values.append(v); } quint16 stationAddress = ui->comboBox_stationAddress->currentText().toInt(); quint16 functionCode = 0x10; quint16 stratAddress = ui->lineEdit_stratAddress->text().toInt(); quint16 length = ui->lineEdit_length->text().toInt(); if (values.size() != length) { QMessageBox::warning(this, "提示", "输入数据数与设置的长度不匹配"); return; } modbus->Set(stationAddress,functionCode,stratAddress,length); modbus->WriteRegister(values); //要发送的报文 serialComm->sendData(modbus->SendCommand()); ui->btn_read->setEnabled(0); ui->pushWrite->setEnabled(0); break; } default: { QMessageBox::warning(this, "提示", "请将“操作”切换为写线圈或写寄存器"); break; } } } //发送读线圈和寄存器报文 void Widget::on_btn_read_clicked() { if (ui->comboBox_gongnengma->currentIndex() == 2 || ui->comboBox_gongnengma->currentIndex() == 3) { QMessageBox::warning(this, "提示", "请将“操作”切换为读线圈或读寄存器"); return; } quint16 stationAddress = ui->comboBox_stationAddress->currentText().toInt(); quint16 functionCode; quint16 stratAddress = ui->lineEdit_stratAddress->text().toInt(); quint16 length = ui->lineEdit_length->text().toInt(); if (ui->comboBox_gongnengma->currentIndex() == 0) //读线圈 { functionCode = 0x01; } else if(ui->comboBox_gongnengma->currentIndex() == 1) //读寄存器 { functionCode = 0x03; } modbus->Set(stationAddress,functionCode,stratAddress,length); modbus->ReadCoilAndReg(); serialComm->sendData(modbus->SendCommand()); ui->btn_read->setEnabled(0); ui->pushWrite->setEnabled(0); } void Widget::on_btn_SaveDate_clicked() { SaveDate(this,ui->textEdit_2); } void Widget::on_btn_ReadDate_clicked() { ReadDate(this,ui->textEdit_2); } void Widget::on_btn_ClearDate_clicked() { ui->textEdit_2->clear(); } void Widget::on_btn_ClearRead_clicked() { ui->textEdit->clear(); } void Widget::onSerialDataReceived(const QByteArray &data) { 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); }