|
- #include "widget.h"
- #include "ui_widget.h"
- #include <QSerialPortInfo>
- #include <QDebug>
- #include <QSerialPort>
- #include <QByteArray>
- #include <QString>
- #include <QVector>
- #include <QMessageBox>
- #include <synchapi.h>
-
- 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<QSerialPortInfo> 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<bool> 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<quint16> 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<bool> 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<quint16> 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);
- }
|