Kaynağa Gözat

CRC校验和对报文的处理

master
鹏鹏 李 2 hafta önce
ebeveyn
işleme
ef240991f1
3 değiştirilmiş dosya ile 341 ekleme ve 169 silme
  1. +1
    -1
      modbus.pro.user
  2. +193
    -11
      widget.cpp
  3. +147
    -157
      widget.ui

+ 1
- 1
modbus.pro.user Dosyayı Görüntüle

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 4.0.3, 2025-07-24T09:24:34. -->
<!-- Written by QtCreator 4.0.3, 2025-07-24T14:53:28. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>


+ 193
- 11
widget.cpp Dosyayı Görüntüle

@@ -4,6 +4,9 @@
#include <QDebug>
#include <QSerialPort>
#include <QByteArray>
#include <QString>
#include <QVector>
#include <QMessageBox>
#include "crc.h"

Widget::Widget(QWidget *parent) :
@@ -69,6 +72,7 @@ void Widget::on_btnConnect_clicked()
else
{
serialPort->close();
qDebug() << "Serial close";
ui->btnConnect->setText("连接");
}

@@ -76,11 +80,106 @@ void Widget::on_btnConnect_clicked()

void Widget::on_pushWrite_clicked()
{
const char *sendData = ui->lineEdit->text().toStdString().c_str();
serialPort->write(sendData);
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<bool> 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<char>(byte));
}


quint16 temp = calculateCrc(SendCommand); //计算crc

SendCommand.append(temp%256); //加入计算的crc值
SendCommand.append(temp/256);

serialPort->write(SendCommand);
qDebug() << "SenOk" <<sendData;
}
case 3:
{
QString sendData = ui->lineEdit->text().trimmed();
if (sendData.isEmpty()) 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);
}

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<char>(values.size() * 2));
for (quint16 v : values)
{
SendCommand.append(static_cast<char>((v >> 8) & 0xFF));
SendCommand.append(static_cast<char>(v & 0xFF));
}

quint16 temp = calculateCrc(SendCommand); //计算crc

SendCommand.append(temp%256); //加入计算的crc值
SendCommand.append(temp/256);

serialPort->write(SendCommand);
qDebug() << "SenOk" <<sendData;
}

}
}


void Widget::on_SerialData_ReadyToRead()
{
QByteArray revMessage = serialPort->readAll();
@@ -88,30 +187,113 @@ void Widget::on_SerialData_ReadyToRead()
qDebug() << hexData;
ui->textEdit->append(hexData);

//对接收的报文进行CRC校验
QByteArray payload = revMessage.left(revMessage.length() - 2);

//分离接收值的crc校验位
quint8 receivedCrcLow = static_cast<quint8>(revMessage.at(revMessage.length() - 2));
quint8 receivedCrcHigh = static_cast<quint8>(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<quint8>(revMessage[2]);

for (int byteIndex = 0; byteIndex < byteCount; byteIndex++)
{
quint8 byteValue = static_cast<quint8>(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<quint16> registers;
for (int i = 0; i < data.size(); i += 2)
{
quint16 value = (static_cast<quint8>(data[i]) << 8) | static_cast<quint8>(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)
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)
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_stratAddress->text().toInt()%256);
SendCommand.append(ui->lineEdit_length->text().toInt()/256);
SendCommand.append(ui->lineEdit_length->text().toInt()/256); //加入长度
SendCommand.append(ui->lineEdit_length->text().toInt()%256);

quint16 temp = calculateCrc(SendCommand);
quint16 temp = calculateCrc(SendCommand); //计算crc

SendCommand.append(temp%256);
SendCommand.append(temp%256); //加入计算的crc值
SendCommand.append(temp/256);

qDebug() << SendCommand.toHex();
serialPort->write(SendCommand);
serialPort->write(SendCommand); //发送报文
}

+ 147
- 157
widget.ui Dosyayı Görüntüle

@@ -140,8 +140,8 @@
<widget class="QPushButton" name="btnConnect">
<property name="geometry">
<rect>
<x>480</x>
<y>30</y>
<x>340</x>
<y>60</y>
<width>93</width>
<height>28</height>
</rect>
@@ -224,200 +224,190 @@
<widget class="QLineEdit" name="lineEdit">
<property name="geometry">
<rect>
<x>420</x>
<y>70</y>
<width>231</width>
<height>21</height>
<x>340</x>
<y>250</y>
<width>301</width>
<height>31</height>
</rect>
</property>
</widget>
<widget class="QPushButton" name="pushWrite">
<property name="geometry">
<rect>
<x>660</x>
<y>60</y>
<x>340</x>
<y>290</y>
<width>93</width>
<height>28</height>
</rect>
</property>
<property name="text">
<string>发送</string>
<string></string>
</property>
</widget>
<widget class="QTextEdit" name="textEdit">
<property name="geometry">
<rect>
<x>420</x>
<y>100</y>
<width>251</width>
<height>151</height>
</rect>
</property>
</widget>
<widget class="QLabel" name="label_10">
<property name="geometry">
<rect>
<x>70</x>
<y>150</y>
<width>21</width>
<height>16</height>
</rect>
</property>
<property name="text">
<string>读</string>
</property>
</widget>
<widget class="QComboBox" name="comboBox_stationAddress">
<property name="geometry">
<rect>
<x>92</x>
<y>120</y>
<width>61</width>
<height>21</height>
</rect>
</property>
<item>
<property name="text">
<string>1</string>
</property>
</item>
<item>
<property name="text">
<string>2</string>
</property>
</item>
<item>
<property name="text">
<string>3</string>
</property>
</item>
<item>
<property name="text">
<string>4</string>
</property>
</item>
<item>
<property name="text">
<string>5</string>
</property>
</item>
<item>
<property name="text">
<string>6</string>
</property>
</item>
<item>
<property name="text">
<string>7</string>
</property>
</item>
<item>
<property name="text">
<string>8</string>
</property>
</item>
<item>
<property name="text">
<string>9</string>
</property>
</item>
</widget>
<widget class="QLabel" name="label_9">
<property name="geometry">
<rect>
<x>40</x>
<y>120</y>
<width>45</width>
<height>16</height>
<y>170</y>
<width>251</width>
<height>271</height>
</rect>
</property>
<property name="text">
<string>站地址</string>
</property>
</widget>
<widget class="QLineEdit" name="lineEdit_length">
<widget class="QPushButton" name="btn_read">
<property name="geometry">
<rect>
<x>90</x>
<y>210</y>
<width>51</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>00</string>
</property>
</widget>
<widget class="QLineEdit" name="lineEdit_stratAddress">
<property name="geometry">
<rect>
<x>100</x>
<y>180</y>
<width>51</width>
<height>21</height>
<y>460</y>
<width>93</width>
<height>28</height>
</rect>
</property>
<property name="text">
<string>00</string>
<string>读</string>
</property>
</widget>
<widget class="QLabel" name="label_12">
<widget class="QWidget" name="layoutWidget">
<property name="geometry">
<rect>
<x>40</x>
<y>210</y>
<width>41</width>
<height>16</height>
</rect>
</property>
<property name="text">
<string>长度</string>
</property>
</widget>
<widget class="QLabel" name="label_11">
<property name="geometry">
<rect>
<x>30</x>
<y>180</y>
<width>71</width>
<height>16</height>
</rect>
</property>
<property name="text">
<string>起始地址</string>
</property>
</widget>
<widget class="QComboBox" name="comboBox_gongnengma">
<property name="geometry">
<rect>
<x>90</x>
<y>150</y>
<width>61</width>
<height>21</height>
<y>115</y>
<width>672</width>
<height>23</height>
</rect>
</property>
<item>
<property name="text">
<string>线圈</string>
</property>
</item>
<item>
<property name="text">
<string>寄存器</string>
</property>
</item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label_9">
<property name="text">
<string>站地址</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBox_stationAddress">
<item>
<property name="text">
<string>1</string>
</property>
</item>
<item>
<property name="text">
<string>2</string>
</property>
</item>
<item>
<property name="text">
<string>3</string>
</property>
</item>
<item>
<property name="text">
<string>4</string>
</property>
</item>
<item>
<property name="text">
<string>5</string>
</property>
</item>
<item>
<property name="text">
<string>6</string>
</property>
</item>
<item>
<property name="text">
<string>7</string>
</property>
</item>
<item>
<property name="text">
<string>8</string>
</property>
</item>
<item>
<property name="text">
<string>9</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QLabel" name="label_10">
<property name="text">
<string>对象</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBox_gongnengma">
<item>
<property name="text">
<string>读线圈</string>
</property>
</item>
<item>
<property name="text">
<string>读寄存器</string>
</property>
</item>
<item>
<property name="text">
<string>写线圈</string>
</property>
</item>
<item>
<property name="text">
<string>写寄存器</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QLabel" name="label_11">
<property name="text">
<string>起始地址</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEdit_stratAddress">
<property name="text">
<string>00</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_12">
<property name="text">
<string>长度</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEdit_length">
<property name="text">
<string>00</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QPushButton" name="btn_read">
<widget class="QLabel" name="label_13">
<property name="geometry">
<rect>
<x>40</x>
<y>260</y>
<width>93</width>
<height>28</height>
<x>340</x>
<y>160</y>
<width>311</width>
<height>91</height>
</rect>
</property>
<property name="text">
<string>读</string>
<string>写线圈时,使用1、0代表线圈的开关,
从左到右依次输入每个线圈的开关;
写寄存器时,每个寄存器的值用16进制表示,
相邻寄存器的值之间用&quot;,&quot;分离。</string>
</property>
</widget>
</widget>


Yükleniyor…
İptal
Kaydet