diff --git a/communicationhistory.cpp b/communicationhistory.cpp new file mode 100644 index 0000000..6268949 --- /dev/null +++ b/communicationhistory.cpp @@ -0,0 +1,54 @@ +#include "communicationhistory.h" + +bool SaveDate(QWidget *parent, QTextEdit *edit) +{ + QString fileName = QFileDialog::getSaveFileName( + parent, + "保存文本", + QDir::homePath() + "/note.txt", + "文本文件 (*.txt);;所有文件 (*)"); + + if (fileName.isEmpty()) + return false; + + QFile file(fileName); + if (!file.open(QIODevice::Append | QIODevice::Text)) + { + QMessageBox::warning(parent, "错误", "无法打开文件"); + return false; + } + + if (file.size() > 0) + file.write("\n"); + + QTextStream out(&file); + out.setCodec("UTF-8"); + out << edit->toPlainText(); + file.close(); + return true; +} + +bool ReadDate(QWidget *parent, QTextEdit *edit) +{ + QString fileName = QFileDialog::getOpenFileName( + parent, + "打开文本", + QDir::homePath(), + "文本文件 (*.txt);;所有文件 (*)"); + + if (fileName.isEmpty()) + return false; + + QFile file(fileName); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) + { + QMessageBox::warning(parent, "错误", "无法读取文件"); + return false; + } + + QTextStream in(&file); + in.setCodec("UTF-8"); + edit->setPlainText(in.readAll()); + file.close(); + return true; +} diff --git a/communicationhistory.h b/communicationhistory.h new file mode 100644 index 0000000..c8b040c --- /dev/null +++ b/communicationhistory.h @@ -0,0 +1,17 @@ +#ifndef COMMUNICATIONHISTORY_H +#define COMMUNICATIONHISTORY_H + +#pragma once +#include +#include +#include +#include +#include +#include +#include + +bool SaveDate(QWidget *parent, QTextEdit *edit); + +bool ReadDate(QWidget *parent, QTextEdit *edit); + +#endif // COMMUNICATIONHISTORY_H diff --git a/crc.h b/crc.h index 2cf4052..d4c1d7b 100644 --- a/crc.h +++ b/crc.h @@ -1,9 +1,10 @@ #ifndef CRC_H #define CRC_H -#endif // CRC_H #include #include quint16 CalculateCrc(const QByteArray &data); bool CrcCheck(const QByteArray &data); + +#endif // CRC_H diff --git a/modbus.pro b/modbus.pro index 1425b43..e6da06e 100644 --- a/modbus.pro +++ b/modbus.pro @@ -16,10 +16,12 @@ TEMPLATE = app SOURCES += main.cpp\ widget.cpp \ crc.cpp \ - mymodbus.cpp + mymodbus.cpp \ + communicationhistory.cpp HEADERS += widget.h \ crc.h \ - mymodbus.h + mymodbus.h \ + communicationhistory.h FORMS += widget.ui diff --git a/modbus.pro.user b/modbus.pro.user index 3507302..c27cca7 100644 --- a/modbus.pro.user +++ b/modbus.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId diff --git a/mymodbus.cpp b/mymodbus.cpp index c3a7547..f0b9789 100644 --- a/mymodbus.cpp +++ b/mymodbus.cpp @@ -7,25 +7,25 @@ MyModbus::MyModbus() void MyModbus::Set(quint16 stationAddress, quint16 functionCode, quint16 startAdress, quint16 length) { - this->stationAddress = stationAddress; - this->functionCode = functionCode; - this->startAdress = startAdress; - this->length = length; + this->stationAddress_ = stationAddress; + this->functionCode_ = functionCode; + this->startAdress_ = startAdress; + this->length_ = length; } -void MyModbus::ReadColiAndReg() +void MyModbus::ReadCoilAndReg() { - sendCommand.clear(); - sendCommand.append(stationAddress%256); - sendCommand.append(functionCode%256); - sendCommand.append(startAdress/256); - sendCommand.append(startAdress%256); - sendCommand.append(length/256); - sendCommand.append(length%256); - quint16 temp = CalculateCrc(sendCommand); - sendCommand.append(temp%256); - sendCommand.append(temp/256); + sendCommand_.clear(); + sendCommand_.append(stationAddress_%256); + sendCommand_.append(functionCode_%256); + sendCommand_.append(startAdress_/256); + sendCommand_.append(startAdress_%256); + sendCommand_.append(length_/256); + sendCommand_.append(length_%256); + quint16 temp = CalculateCrc(sendCommand_); + sendCommand_.append(temp%256); + sendCommand_.append(temp/256); } void MyModbus::WriteCoil(QVector &coils) @@ -33,14 +33,14 @@ void MyModbus::WriteCoil(QVector &coils) quint16 coilCount = coils.size(); int byteCount = (coilCount + 7) / 8; - sendCommand.clear(); - sendCommand.append(stationAddress%256); - sendCommand.append(0x0f); - sendCommand.append(startAdress/256); - sendCommand.append(startAdress%256); - sendCommand.append(length/256); - sendCommand.append(length%256); - sendCommand.append(byteCount); + sendCommand_.clear(); + sendCommand_.append(stationAddress_%256); + sendCommand_.append(0x0f); + sendCommand_.append(startAdress_/256); + sendCommand_.append(startAdress_%256); + sendCommand_.append(length_/256); + sendCommand_.append(length_%256); + sendCommand_.append(byteCount); for (int i = 0; i < byteCount; ++i) { quint8 byte = 0; @@ -50,55 +50,55 @@ void MyModbus::WriteCoil(QVector &coils) if (bitIndex < coils.size() && coils[bitIndex]) byte |= (1 << j); } - sendCommand.append(static_cast(byte)); + sendCommand_.append(static_cast(byte)); } - quint16 temp = CalculateCrc(sendCommand); //计算crc - sendCommand.append(temp%256); //加入计算的crc值 - sendCommand.append(temp/256); + quint16 temp = CalculateCrc(sendCommand_); //计算crc + sendCommand_.append(temp%256); //加入计算的crc值 + sendCommand_.append(temp/256); } void MyModbus::WriteRegister(QVector &values) { - sendCommand.clear(); - sendCommand.append(stationAddress%256); - sendCommand.append(0x10); - sendCommand.append(startAdress/256); - sendCommand.append(startAdress%256); - sendCommand.append(length/256); - sendCommand.append(length%256); - sendCommand.append(static_cast(values.size() * 2)); + sendCommand_.clear(); + sendCommand_.append(stationAddress_%256); + sendCommand_.append(0x10); + sendCommand_.append(startAdress_/256); + sendCommand_.append(startAdress_%256); + sendCommand_.append(length_/256); + sendCommand_.append(length_%256); + sendCommand_.append(static_cast(values.size() * 2)); for (quint16 v : values) { - sendCommand.append(static_cast((v >> 8) & 0xFF)); - sendCommand.append(static_cast(v & 0xFF)); + sendCommand_.append(static_cast((v >> 8) & 0xFF)); + sendCommand_.append(static_cast(v & 0xFF)); } - quint16 temp = CalculateCrc(sendCommand); //计算crc - sendCommand.append(temp%256); //加入计算的crc值 - sendCommand.append(temp/256); + quint16 temp = CalculateCrc(sendCommand_); //计算crc + sendCommand_.append(temp%256); //加入计算的crc值 + sendCommand_.append(temp/256); } QByteArray MyModbus::SendCommand() { - return sendCommand; + return sendCommand_; } QByteArray MyModbus::Receive(const QByteArray &revMessage) { - receive.clear(); + receive_.clear(); if (CrcCheck(revMessage)) { - this->receive = revMessage; + this->receive_ = revMessage; } - return receive; + return receive_; } int MyModbus::ErrorCheck() { - if ((receive.at(1) & 0x80) == 0x80) + if ((receive_.at(1) & 0x80) == 0x80) { // MODBUS异常响应结构:地址 | 功能码+0x80 | 异常码 | CRC - quint8 exCode = receive.at(2); + quint8 exCode = receive_.at(2); return exCode; } else @@ -109,18 +109,18 @@ int MyModbus::ErrorCheck() QVector MyModbus::AnalReadCoil() { - quint8 byteCount = static_cast(receive[2]); + quint8 byteCount = static_cast(receive_[2]); QVector coil; for (int byteIndex = 0; byteIndex < byteCount; byteIndex++) { - quint8 byteValue = static_cast(receive[3 + byteIndex]); + quint8 byteValue = static_cast(receive_[3 + byteIndex]); // 解析每个字节的8个位 for (int bitIndex = 0; bitIndex < 8; bitIndex++) { int coilIndex = byteIndex * 8 + bitIndex; - if (coilIndex < length) + if (coilIndex < length_) { bool state = byteValue & (1 << bitIndex); coil.append(state); @@ -132,8 +132,8 @@ QVector MyModbus::AnalReadCoil() QVector MyModbus::AnalReadReg() { - int byteCount = receive.at(2); - QByteArray data = receive.mid(3, byteCount); + int byteCount = receive_.at(2); + QByteArray data = receive_.mid(3, byteCount); QVector registers; for (int i = 0; i < data.size(); i += 2) diff --git a/mymodbus.h b/mymodbus.h index 0f73496..2cf932f 100644 --- a/mymodbus.h +++ b/mymodbus.h @@ -9,17 +9,17 @@ class MyModbus { private: - quint16 stationAddress; - quint16 functionCode; - quint16 startAdress; - quint16 length; - QByteArray sendCommand; - QByteArray receive; + quint16 stationAddress_; + quint16 functionCode_; + quint16 startAdress_; + quint16 length_; + QByteArray sendCommand_; + QByteArray receive_; public: MyModbus(); - void Set(quint16 stationAddress,quint16 functionCode,quint16 startAdress,quint16 length); - void ReadColiAndReg(); + void Set(quint16 stationAddress_,quint16 functionCode_,quint16 startAdress_,quint16 length_); + void ReadCoilAndReg(); void WriteCoil(QVector &coils); void WriteRegister(QVector &values); QByteArray SendCommand(); diff --git a/widget.cpp b/widget.cpp index 246d093..8d22882 100644 --- a/widget.cpp +++ b/widget.cpp @@ -8,10 +8,9 @@ #include #include #include -#include -#include #include "crc.h" #include "mymodbus.h" +#include "communicationhistory.h" Widget::Widget(QWidget *parent) : QWidget(parent), @@ -30,18 +29,14 @@ Widget::Widget(QWidget *parent) : 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(); + QMessageBox::warning(this, "提示", "等待响应超时,请检查设备状态。"); + ui->btn_read->setEnabled(1); + ui->pushWrite->setEnabled(1); + timer.stop(); } }); @@ -61,6 +56,7 @@ Widget::Widget(QWidget *parent) : Widget::~Widget() { + delete modbus; delete ui; } @@ -69,13 +65,13 @@ 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: @@ -87,12 +83,11 @@ void Widget::on_btnConnect_clicked() 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); @@ -100,13 +95,11 @@ void Widget::on_btnConnect_clicked() } else { - qDebug() << "error"; QMessageBox::warning(this, "提示", "串口连接失败,请检查串口参数配置"); } } else { - delete modbus; serialPort->close(); ui->btn_read->setEnabled(0); ui->pushWrite->setEnabled(0); @@ -124,44 +117,42 @@ void Widget::on_pushWrite_clicked() { 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!"); + 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'); - } + 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(); + 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); + 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); + ui->textEdit_2->append("发送报文"+modbus->SendCommand().toHex().toUpper()); + serialPort->write(modbus->SendCommand()); + ui->btn_read->setEnabled(0); + ui->pushWrite->setEnabled(0); - comCount = 0; - Sleep(100); - timer.isActive(); - timer.start(1000); // 1 s 后触发超时 + comCount = 0; + timer.start(1000); // 1 s 后触发超时 - break; + break; } case 3: @@ -188,7 +179,7 @@ void Widget::on_pushWrite_clicked() } quint16 stationAddress = ui->comboBox_stationAddress->currentText().toInt(); - quint16 functionCode = 0x0f; + quint16 functionCode = 0x10; quint16 stratAddress = ui->lineEdit_stratAddress->text().toInt(); quint16 length = ui->lineEdit_length->text().toInt(); @@ -201,11 +192,8 @@ void Widget::on_pushWrite_clicked() ui->pushWrite->setEnabled(0); comCount = 0; - Sleep(100); - timer.isActive(); timer.start(1000); // 1 s 后触发超时 - qDebug() << "SenOk" <textEdit_2->append("接收报文"+hexData); - qDebug() << "接收成功"; int exCode = modbus->ErrorCheck(); if (exCode) { @@ -278,13 +264,14 @@ void Widget::on_SerialData_ReadyToRead() //解析读寄存器的返回报文 case 1: { - QVector registers = modbus->AnalReadReg(); + QVector registers = modbus->AnalReadReg(); + + ui->textEdit->append("寄存器的值:"); + for (int i = 0; i < registers.size(); i++) + { + ui->textEdit->append("寄存器"+QString::number(i+1)+":"+QString::number(registers.at(i))); + } - ui->textEdit->append("寄存器的值:"); - for (int i = 0; i < registers.size(); i++) - { - ui->textEdit->append("寄存器"+QString::number(i+1)+":"+QString::number(registers.at(i))); - } break; } @@ -305,7 +292,6 @@ void Widget::on_btn_read_clicked() quint16 functionCode; quint16 stratAddress = ui->lineEdit_stratAddress->text().toInt(); quint16 length = ui->lineEdit_length->text().toInt(); - QByteArray SendCommand; if (ui->comboBox_gongnengma->currentIndex() == 0) //读线圈 { @@ -317,7 +303,7 @@ void Widget::on_btn_read_clicked() } modbus->Set(stationAddress,functionCode,stratAddress,length); - modbus->ReadColiAndReg(); + modbus->ReadCoilAndReg(); serialPort->write(modbus->SendCommand()); //发送报文 ui->textEdit_2->append("发送报文"+modbus->SendCommand().toHex().toUpper()); @@ -325,64 +311,20 @@ void Widget::on_btn_read_clicked() ui->pushWrite->setEnabled(0); comCount = 0; - Sleep(100); - timer.isActive(); timer.start(1000); // 1 s 后触发超时 } -void Widget::on_pushButton_clicked() +void Widget::on_btn_SaveDate_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(); + SaveDate(this,ui->textEdit_2); } -void Widget::on_pushButton_2_clicked() +void Widget::on_btn_ReadDate_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(); + ReadDate(this,ui->textEdit_2); } -void Widget::on_pushButton_3_clicked() +void Widget::on_btn_ClearDate_clicked() { ui->textEdit_2->clear(); } @@ -392,3 +334,8 @@ void Widget::onReadyRead() recvBuffer.append(serialPort->readAll()); recvTimer->start(50); // 50ms 内无新数据即认为接收完成 } + +void Widget::on_btn_ClearRead_clicked() +{ + ui->textEdit->clear(); +} diff --git a/widget.h b/widget.h index 765a82b..a4781ae 100644 --- a/widget.h +++ b/widget.h @@ -27,14 +27,16 @@ private slots: void on_btn_read_clicked(); - void on_pushButton_clicked(); + void on_btn_SaveDate_clicked(); - void on_pushButton_2_clicked(); + void on_btn_ReadDate_clicked(); - void on_pushButton_3_clicked(); + void on_btn_ClearDate_clicked(); void onReadyRead(); + void on_btn_ClearRead_clicked(); + private: Ui::Widget *ui; QSerialPort *serialPort; diff --git a/widget.ui b/widget.ui index 0750755..29fa7e7 100644 --- a/widget.ui +++ b/widget.ui @@ -6,435 +6,474 @@ 0 0 - 787 - 543 + 700 + 486 Widget - + - 340 - 430 - 301 - 31 + 30 + 240 + 181 + 231 - - - - - 340 - 470 - 93 - 28 - - - - - - - - - - 40 - 280 - 251 - 191 - - - - true - - - - - - 200 - 470 - 93 - 28 - - - - - - - - - - 340 - 330 - 311 - 101 - - - - 写线圈时,使用1、0代表线圈的开关状态, -从左到右依次输入每个线圈的开关; -写寄存器时要写入所有寄存器的16进制数值, -相邻寄存器的值之间用英文","分离。 - - - - - - 40 - 10 - 72 - 15 - - - - 串口配置 - - - - - - 40 - 100 - 72 - 15 - - - + 从站配置 - - - - - 40 - 150 - 72 - 15 - - - - 状态通知 - - - - - - 42 - 32 - 406 - 58 - - - - - - - 串口 - - - - - - - - - - 波特率 - - - - - - + + + + 10 + 30 + 159 + 131 + + + + + - 1200 + 站地址 - - - - 2400 - - - - - 4800 - - - - - 9600 - - - - - 19200 - - - + + + + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + 7 + + + + + 8 + + + + + 9 + + + + + + - 38400 + 操作 - - - - - - - 数据位 - - - - - - + + + + + + + 读线圈 + + + + + 读寄存器 + + + + + 写线圈 + + + + + 写寄存器 + + + + + + - 5 + 起始地址 - - + + + + - 6 + 256 - - + + + + - 7 + 长度 - - + + + + - 8 + 1 - - + + + + + + + + 10 + 160 + 71 + 51 + + + + + + + + + + 90 + 160 + 71 + 51 + + + + + + + + + + + 30 + 19 + 181 + 211 + + + + 串口配置 + + + + + 10 + 20 + 161 + 181 + + + + + - NONE + 串口 - - - - - - - 校验位 - - - - - - + + + + + + + - 无校验(N) + 波特率 - - + + + + + + + 1200 + + + + + 2400 + + + + + 4800 + + + + + 9600 + + + + + 19200 + + + + + 38400 + + + + + + - 奇校验(O) + 数据位 - - + + + + + + + 5 + + + + + 6 + + + + + 7 + + + + + 8 + + + + + NONE + + + + + + - 偶校验(E) + 校验位 - - - - - - - 停止位 - - - - - - + + + + + + + 无校验(N) + + + + + 奇校验(O) + + + + + 偶校验(E) + + + + + + - 1 + 停止位 - - + + + + + + + 1 + + + + + 2 + + + + + + - 2 + 连接 - - - - - - - 连接 - - - - + + + + + + + + + 240 + 20 + 211 + 271 + + + + 数据读取 + + + + + 10 + 20 + 191 + 241 + + + + true + + + + + + + 470 + 20 + 221 + 271 + + + + 状态通知 + + + + + 10 + 20 + 201 + 241 + + + + true + + + + + + + 240 + 340 + 341 + 131 + + + + 写入数据 + + + + + 10 + 0 + 311 + 101 + + + + 写线圈时,使用1、0代表线圈的开关状态, +从左到右依次输入每个线圈的开关; +写寄存器时要写入所有寄存器的16进制数值, +相邻寄存器的值之间用英文","分离。 + + + + + + 10 + 90 + 301 + 31 + + + - 41 - 116 - 687 - 23 + 240 + 300 + 451 + 30 - + - 站地址 + 清空读取信息 - - - - 1 - - - - - 2 - - - - - 3 - - - - - 4 - - - - - 5 - - - - - 6 - - - - - 7 - - - - - 8 - - - - - 9 - - - - - - - - 操作 - - - - - - - - 读线圈 - - - - - 读寄存器 - - - - - 写线圈 - - - - - 写寄存器 - - - - - - + - 起始地址 + 清空收发信息 - + - 256 + 读取历史收发信息 - + - 长度 + 保存收发信息 - - - - 1 - - - - - - - - - 41 - 164 - 691 - 91 - - - - - - - - - - - - 清空收发信息 - - - - - - - 保存收发信息 - - - - - - - 读取历史收发信息 - - - - -