#include "widget.h" #include "ui_widget.h" #include #include #include #include #include #include #include #include "crc.h" Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui->setupUi(this); serialPort = new QSerialPort(this); connect(serialPort,&QSerialPort::readyRead,this,&Widget::on_SerialData_ReadyToRead); ui->comboBox_baudRate->setCurrentIndex(3); ui->comboBox_dataBit->setCurrentIndex(3); ui->comboBox_xiaoyan->setCurrentIndex(2); 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->btnConnect->setText("断开"); } else { qDebug() << "error"; } } else { serialPort->close(); qDebug() << "Serial close"; ui->btnConnect->setText("连接"); } } void Widget::on_pushWrite_clicked() { switch (ui->comboBox_gongnengma->currentIndex()) { case (2): //写多个线圈 { QString sendData = ui->lineEdit->text().trimmed(); if (sendData.isEmpty()) 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 coilCount = coils.size(); QByteArray SendCommand; //要发送的报文 SendCommand.append(ui->comboBox_stationAddress->currentText().toInt()%256); //加入站地址 SendCommand.append(0x0f); SendCommand.append(ui->lineEdit_stratAddress->text().toInt()/256); //加入起始地址 SendCommand.append(ui->lineEdit_stratAddress->text().toInt()%256); SendCommand.append(ui->lineEdit_length->text().toInt()/256); //加入长度 SendCommand.append(ui->lineEdit_length->text().toInt()%256); int byteCount = (coilCount + 7) / 8; SendCommand.append(byteCount); //字节数 for (int i = 0; i < byteCount; ++i) { quint8 byte = 0; for (int j = 0; j < 8; ++j) { int bitIndex = i * 8 + j; if (bitIndex < coils.size() && coils[bitIndex]) byte |= (1 << j); } SendCommand.append(static_cast(byte)); } quint16 temp = calculateCrc(SendCommand); //计算crc SendCommand.append(temp%256); //加入计算的crc值 SendCommand.append(temp/256); serialPort->write(SendCommand); qDebug() << "SenOk" <lineEdit->text().trimmed(); if (sendData.isEmpty()) 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); } QByteArray SendCommand; //要发送的报文 SendCommand.append(ui->comboBox_stationAddress->currentText().toInt()%256); //加入站地址 SendCommand.append(0x10); SendCommand.append(ui->lineEdit_stratAddress->text().toInt()/256); //加入起始地址 SendCommand.append(ui->lineEdit_stratAddress->text().toInt()%256); SendCommand.append(ui->lineEdit_length->text().toInt()/256); //加入长度 SendCommand.append(ui->lineEdit_length->text().toInt()%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)); } quint16 temp = calculateCrc(SendCommand); //计算crc SendCommand.append(temp%256); //加入计算的crc值 SendCommand.append(temp/256); serialPort->write(SendCommand); qDebug() << "SenOk" <readAll(); QString hexData = revMessage.toHex().toUpper(); qDebug() << hexData; ui->textEdit->append(hexData); //对接收的报文进行CRC校验 QByteArray payload = revMessage.left(revMessage.length() - 2); //分离接收值的crc校验位 quint8 receivedCrcLow = static_cast(revMessage.at(revMessage.length() - 2)); quint8 receivedCrcHigh = static_cast(revMessage.at(revMessage.length() - 1)); //计算返回的报文的crc quint16 crc = calculateCrc(payload); quint8 calcCrcLow = crc & 0xFF; quint8 calcCrcHigh = (crc >> 8) & 0xFF; //比较计算的crc值和接收到的crc值是否一致 if(calcCrcLow == receivedCrcLow && calcCrcHigh == receivedCrcHigh) { qDebug() << "接收成功"; switch (ui->comboBox_gongnengma->currentIndex()) { //解析读线圈的返回报文 case 0: { quint8 byteCount = static_cast(revMessage[2]); for (int byteIndex = 0; byteIndex < byteCount; byteIndex++) { quint8 byteValue = static_cast(revMessage[3 + byteIndex]); // 解析每个字节的8个位 for (int bitIndex = 0; bitIndex < 8; bitIndex++) { int coilIndex = byteIndex * 8 + bitIndex; if (coilIndex < ui->lineEdit_length->text().toInt()) { bool state = byteValue & (1 << bitIndex); qDebug() << coilIndex <<" " << state; ui->textEdit->append("线圈"+QString::number(coilIndex+1)+":"+QString::number(state)); } } } break; } //解析读寄存器的返回报文 case 1: { if (revMessage.size() >= 5 && revMessage.at(1) == 0x03) { int byteCount = revMessage.at(2); QByteArray data = revMessage.mid(3, byteCount); QVector registers; for (int i = 0; i < data.size(); i += 2) { quint16 value = (static_cast(data[i]) << 8) | static_cast(data[i+1]); registers.append(value); } for (int i = 0; i < registers.size(); i++) { qDebug() << "Register value:" << registers.at(i); ui->textEdit->append("寄存器"+QString::number(i)+":"+QString::number(registers.at(i))); } } break; } case 2: { if (revMessage.at(1) == '\x8f') { quint8 exCode = revMessage.at(2); qDebug() << "异常响应,异常码 =" << exCode; return; } } } } else { qDebug() << "接收失败"; } } //发送读线圈和寄存器报文 void Widget::on_btn_read_clicked() { QByteArray SendCommand; //要发送的报文 SendCommand.append(ui->comboBox_stationAddress->currentText().toInt()%256); //加入站地址 if (ui->comboBox_gongnengma->currentIndex() == 0) //读线圈 { SendCommand.append(0x01); } else if(ui->comboBox_gongnengma->currentIndex() == 1) //读寄存器 { SendCommand.append(0x03); } SendCommand.append(ui->lineEdit_stratAddress->text().toInt()/256); //加入起始地址 SendCommand.append(ui->lineEdit_stratAddress->text().toInt()%256); SendCommand.append(ui->lineEdit_length->text().toInt()/256); //加入长度 SendCommand.append(ui->lineEdit_length->text().toInt()%256); quint16 temp = calculateCrc(SendCommand); //计算crc SendCommand.append(temp%256); //加入计算的crc值 SendCommand.append(temp/256); qDebug() << SendCommand.toHex(); serialPort->write(SendCommand); //发送报文 }