#include "widget.h" #include "ui_widget.h" #include #include #include #include #include #include #include #include #include #include #include "crc.h" #include "mymodbus.h" Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui->setupUi(this); serialPort = new QSerialPort(this); modbus = new MyModbus(); connect(serialPort,&QSerialPort::readyRead,this,&Widget::on_SerialData_ReadyToRead); QObject::connect(&timer, &QTimer::timeout, [&]{ if (comCount < 3) { ui->textEdit_2->append("通信超时,重新发送中"); serialPort->write(modbus->SendCommand()); Sleep(1000); timer.isActive(); timer.start(1000); comCount ++; } else { QMessageBox::warning(this, "提示", "等待响应超时,请检查设备状态。"); ui->btn_read->setEnabled(1); ui->pushWrite->setEnabled(1); timer.stop(); } }); 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 ui; } //串口连接 void Widget::on_btnConnect_clicked() { if (ui->btnConnect->text() == "连接") { //配置串口号 serialPort->setPortName(ui->comboBox_serialNum->currentText()); //配置波特率 serialPort->setBaudRate(ui->comboBox_baudRate->currentText().toInt()); //配置数据位 serialPort->setDataBits(QSerialPort::DataBits(ui->comboBox_dataBit->currentText().toInt())); //配置校验位 switch (ui->comboBox_xiaoyan->currentIndex()) { case 0: serialPort->setParity(QSerialPort::NoParity); break; case 1: serialPort->setParity(QSerialPort::OddParity); break; case 2: serialPort->setParity(QSerialPort::EvenParity); } //配置停止位 serialPort->setStopBits(QSerialPort::StopBits(ui->comboBox_stopBit->currentText().toInt())); //打开串口 if (serialPort->open(QIODevice::ReadWrite)) { qDebug() << "Serial open success"; ui->textEdit_2->append("串口连接成功"); ui->btnConnect->setText("断开"); ui->btn_read->setEnabled(1); ui->pushWrite->setEnabled(1); } else { qDebug() << "error"; QMessageBox::warning(this, "提示", "串口连接失败,请检查串口参数配置"); } } else { delete modbus; serialPort->close(); ui->btn_read->setEnabled(0); ui->pushWrite->setEnabled(0); qDebug() << "Serial close"; ui->btnConnect->setText("连接"); ui->textEdit_2->append("串口断开"); } } //写线圈和写寄存器 void Widget::on_pushWrite_clicked() { switch (ui->comboBox_gongnengma->currentIndex()) { case 2: //写多个线圈 { QString sendData = ui->lineEdit->text().trimmed(); if (sendData.isEmpty()) { QMessageBox::warning(this, "提示", "请至少输入一个数据,缺少的数据默认为0"); 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(); modbus->Set(stationAddress,functionCode,stratAddress,length); modbus->WriteCoil(coils); ui->textEdit_2->append("发送报文"+modbus->SendCommand().toHex().toUpper()); serialPort->write(modbus->SendCommand()); ui->btn_read->setEnabled(0); ui->pushWrite->setEnabled(0); comCount = 0; Sleep(200); timer.isActive(); timer.start(1000); // 1 s 后触发超时 qDebug() << "SenOk" <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 = 0x0f; quint16 stratAddress = ui->lineEdit_stratAddress->text().toInt(); quint16 length = ui->lineEdit_length->text().toInt(); modbus->Set(stationAddress,functionCode,stratAddress,length); modbus->WriteRegister(values); //要发送的报文 ui->textEdit_2->append("发送报文"+modbus->SendCommand().toHex().toUpper()); serialPort->write(modbus->SendCommand()); ui->btn_read->setEnabled(0); ui->pushWrite->setEnabled(0); comCount = 0; Sleep(200); timer.isActive(); timer.start(1000); // 1 s 后触发超时 qDebug() << "SenOk" <Receive(serialPort->readAll()); if (!revMessage.isEmpty()) { ui->btn_read->setEnabled(1); ui->pushWrite->setEnabled(1); timer.stop(); } else { return; } QString hexData = revMessage.toHex().toUpper(); qDebug() << hexData; ui->textEdit_2->append("接收报文"+hexData); qDebug() << "接收成功"; int exCode = modbus->ErrorCheck(revMessage); 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("异常\n错误码: 0x%1 (%2)") .arg(QString::number(exCode, 16).toUpper().rightJustified(2, '0')) .arg(errorMsg)); return; } switch (ui->comboBox_gongnengma->currentIndex()) { //解析读线圈的返回报文 case 0: { QVector coil = modbus->AnalReadCoil(revMessage); ui->textEdit->append("线圈状态:"); for (int i = 0; i < coil.size(); i++) { bool state = coil.at(i); ui->textEdit->append("线圈"+QString::number(i+1)+":"+QString::number(state)); } break; } //解析读寄存器的返回报文 case 1: { QVector registers = modbus->AnalReadReg(revMessage); ui->textEdit->append("寄存器的值:"); for (int i = 0; i < registers.size(); i++) { ui->textEdit->append("寄存器"+QString::number(i+1)+":"+QString::number(registers.at(i))); } 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(); QByteArray SendCommand; if (ui->comboBox_gongnengma->currentIndex() == 0) //读线圈 { functionCode = 0x01; } else if(ui->comboBox_gongnengma->currentIndex() == 1) //读寄存器 { functionCode = 0x03; } modbus->Set(stationAddress,functionCode,stratAddress,length); modbus->ReadColiAndReg(); serialPort->write(modbus->SendCommand()); //发送报文 ui->textEdit_2->append("发送报文"+modbus->SendCommand().toHex().toUpper()); ui->btn_read->setEnabled(0); ui->pushWrite->setEnabled(0); comCount = 0; Sleep(200); timer.isActive(); timer.start(1000); // 1 s 后触发超时 } void Widget::on_pushButton_clicked() { QString fileName = QFileDialog::getSaveFileName( this, "保存文本", QDir::homePath() + "/note.txt", "文本文件 (*.txt);;所有文件 (*.*)"); if (fileName.isEmpty()) return; QFile file(fileName); if (!file.open(QIODevice::Append | QIODevice::Text)) // { QMessageBox::warning(this, "错误", "无法打开文件"); return; } // 每次追加前换行 if (file.size() > 0) // 文件非空 file.write("\n"); // 先换行,再写内容 QTextStream out(&file); out.setCodec("UTF-8"); out << ui->textEdit_2->toPlainText(); // 追加写入 file.close(); } void Widget::on_pushButton_2_clicked() { QString fileName = QFileDialog::getOpenFileName( this, "打开文本", QDir::homePath(), "文本文件 (*.txt);;所有文件 (*.*)"); if (fileName.isEmpty()) return; QFile file(fileName); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { QMessageBox::warning(this, "错误", "无法读取文件"); return; } QTextStream in(&file); in.setCodec("UTF-8"); ui->textEdit_2->setPlainText(in.readAll()); file.close(); } void Widget::on_pushButton_3_clicked() { ui->textEdit_2->clear(); }