Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

300 рядки
9.2 KiB

  1. #include "widget.h"
  2. #include "ui_widget.h"
  3. #include <QSerialPortInfo>
  4. #include <QDebug>
  5. #include <QSerialPort>
  6. #include <QByteArray>
  7. #include <QString>
  8. #include <QVector>
  9. #include <QMessageBox>
  10. #include "crc.h"
  11. Widget::Widget(QWidget *parent) :
  12. QWidget(parent),
  13. ui(new Ui::Widget)
  14. {
  15. ui->setupUi(this);
  16. serialPort = new QSerialPort(this);
  17. connect(serialPort,&QSerialPort::readyRead,this,&Widget::on_SerialData_ReadyToRead);
  18. ui->comboBox_baudRate->setCurrentIndex(3);
  19. ui->comboBox_dataBit->setCurrentIndex(3);
  20. ui->comboBox_xiaoyan->setCurrentIndex(2);
  21. QList<QSerialPortInfo> serialList = QSerialPortInfo::availablePorts();
  22. for(QSerialPortInfo serialInfo : serialList)
  23. {
  24. ui->comboBox_serialNum->addItem(serialInfo.portName());
  25. }
  26. }
  27. Widget::~Widget()
  28. {
  29. delete ui;
  30. }
  31. void Widget::on_btnConnect_clicked()
  32. {
  33. if (ui->btnConnect->text() == "连接")
  34. {
  35. //配置串口号
  36. serialPort->setPortName(ui->comboBox_serialNum->currentText());
  37. //配置波特率
  38. serialPort->setBaudRate(ui->comboBox_baudRate->currentText().toInt());
  39. //配置数据位
  40. serialPort->setDataBits(QSerialPort::DataBits(ui->comboBox_dataBit->currentText().toInt()));
  41. //配置校验位
  42. switch (ui->comboBox_xiaoyan->currentIndex())
  43. {
  44. case 0:
  45. serialPort->setParity(QSerialPort::NoParity);
  46. break;
  47. case 1:
  48. serialPort->setParity(QSerialPort::OddParity);
  49. break;
  50. case 2:
  51. serialPort->setParity(QSerialPort::EvenParity);
  52. }
  53. //配置停止位
  54. serialPort->setStopBits(QSerialPort::StopBits(ui->comboBox_stopBit->currentText().toInt()));
  55. //打开串口
  56. if (serialPort->open(QIODevice::ReadWrite))
  57. {
  58. qDebug() << "Serial open success";
  59. ui->btnConnect->setText("断开");
  60. }
  61. else
  62. {
  63. qDebug() << "error";
  64. }
  65. }
  66. else
  67. {
  68. serialPort->close();
  69. qDebug() << "Serial close";
  70. ui->btnConnect->setText("连接");
  71. }
  72. }
  73. void Widget::on_pushWrite_clicked()
  74. {
  75. switch (ui->comboBox_gongnengma->currentIndex())
  76. {
  77. case (2): //写多个线圈
  78. {
  79. QString sendData = ui->lineEdit->text().trimmed();
  80. if (sendData.isEmpty()) return;
  81. for (QChar ch : sendData) {
  82. if (ch != '0' && ch != '1') {
  83. QMessageBox::warning(this, "提示", "只允许输入 0 或 1!");
  84. return;
  85. }
  86. }
  87. QVector<bool> coils;
  88. for (QChar ch : sendData)
  89. {
  90. coils.append(ch == '1');
  91. }
  92. quint16 coilCount = coils.size();
  93. QByteArray SendCommand; //要发送的报文
  94. SendCommand.append(ui->comboBox_stationAddress->currentText().toInt()%256); //加入站地址
  95. SendCommand.append(0x0f);
  96. SendCommand.append(ui->lineEdit_stratAddress->text().toInt()/256); //加入起始地址
  97. SendCommand.append(ui->lineEdit_stratAddress->text().toInt()%256);
  98. SendCommand.append(ui->lineEdit_length->text().toInt()/256); //加入长度
  99. SendCommand.append(ui->lineEdit_length->text().toInt()%256);
  100. int byteCount = (coilCount + 7) / 8;
  101. SendCommand.append(byteCount); //字节数
  102. for (int i = 0; i < byteCount; ++i)
  103. {
  104. quint8 byte = 0;
  105. for (int j = 0; j < 8; ++j)
  106. {
  107. int bitIndex = i * 8 + j;
  108. if (bitIndex < coils.size() && coils[bitIndex])
  109. byte |= (1 << j);
  110. }
  111. SendCommand.append(static_cast<char>(byte));
  112. }
  113. quint16 temp = calculateCrc(SendCommand); //计算crc
  114. SendCommand.append(temp%256); //加入计算的crc值
  115. SendCommand.append(temp/256);
  116. serialPort->write(SendCommand);
  117. qDebug() << "SenOk" <<sendData;
  118. }
  119. case 3:
  120. {
  121. QString sendData = ui->lineEdit->text().trimmed();
  122. if (sendData.isEmpty()) return;
  123. QStringList sl = sendData.split(',');
  124. QVector<quint16> values;
  125. bool ok;
  126. for (const QString &s : sl)
  127. {
  128. quint16 v = s.toUShort(&ok, 16);
  129. if (!ok)
  130. {
  131. QMessageBox::warning(this, "提示", "请输入正确的十六进制值!");
  132. return;
  133. }
  134. values.append(v);
  135. }
  136. QByteArray SendCommand; //要发送的报文
  137. SendCommand.append(ui->comboBox_stationAddress->currentText().toInt()%256); //加入站地址
  138. SendCommand.append(0x10);
  139. SendCommand.append(ui->lineEdit_stratAddress->text().toInt()/256); //加入起始地址
  140. SendCommand.append(ui->lineEdit_stratAddress->text().toInt()%256);
  141. SendCommand.append(ui->lineEdit_length->text().toInt()/256); //加入长度
  142. SendCommand.append(ui->lineEdit_length->text().toInt()%256);
  143. SendCommand.append(static_cast<char>(values.size() * 2));
  144. for (quint16 v : values)
  145. {
  146. SendCommand.append(static_cast<char>((v >> 8) & 0xFF));
  147. SendCommand.append(static_cast<char>(v & 0xFF));
  148. }
  149. quint16 temp = calculateCrc(SendCommand); //计算crc
  150. SendCommand.append(temp%256); //加入计算的crc值
  151. SendCommand.append(temp/256);
  152. serialPort->write(SendCommand);
  153. qDebug() << "SenOk" <<sendData;
  154. }
  155. }
  156. }
  157. void Widget::on_SerialData_ReadyToRead()
  158. {
  159. QByteArray revMessage = serialPort->readAll();
  160. QString hexData = revMessage.toHex().toUpper();
  161. qDebug() << hexData;
  162. ui->textEdit->append(hexData);
  163. //对接收的报文进行CRC校验
  164. QByteArray payload = revMessage.left(revMessage.length() - 2);
  165. //分离接收值的crc校验位
  166. quint8 receivedCrcLow = static_cast<quint8>(revMessage.at(revMessage.length() - 2));
  167. quint8 receivedCrcHigh = static_cast<quint8>(revMessage.at(revMessage.length() - 1));
  168. //计算返回的报文的crc
  169. quint16 crc = calculateCrc(payload);
  170. quint8 calcCrcLow = crc & 0xFF;
  171. quint8 calcCrcHigh = (crc >> 8) & 0xFF;
  172. //比较计算的crc值和接收到的crc值是否一致
  173. if(calcCrcLow == receivedCrcLow && calcCrcHigh == receivedCrcHigh)
  174. {
  175. qDebug() << "接收成功";
  176. switch (ui->comboBox_gongnengma->currentIndex())
  177. {
  178. //解析读线圈的返回报文
  179. case 0:
  180. {
  181. quint8 byteCount = static_cast<quint8>(revMessage[2]);
  182. for (int byteIndex = 0; byteIndex < byteCount; byteIndex++)
  183. {
  184. quint8 byteValue = static_cast<quint8>(revMessage[3 + byteIndex]);
  185. // 解析每个字节的8个位
  186. for (int bitIndex = 0; bitIndex < 8; bitIndex++)
  187. {
  188. int coilIndex = byteIndex * 8 + bitIndex;
  189. if (coilIndex < ui->lineEdit_length->text().toInt())
  190. {
  191. bool state = byteValue & (1 << bitIndex);
  192. qDebug() << coilIndex <<" " << state;
  193. ui->textEdit->append("线圈"+QString::number(coilIndex+1)+":"+QString::number(state));
  194. }
  195. }
  196. }
  197. break;
  198. }
  199. //解析读寄存器的返回报文
  200. case 1:
  201. {
  202. if (revMessage.size() >= 5 && revMessage.at(1) == 0x03)
  203. {
  204. int byteCount = revMessage.at(2);
  205. QByteArray data = revMessage.mid(3, byteCount);
  206. QVector<quint16> registers;
  207. for (int i = 0; i < data.size(); i += 2)
  208. {
  209. quint16 value = (static_cast<quint8>(data[i]) << 8) | static_cast<quint8>(data[i+1]);
  210. registers.append(value);
  211. }
  212. for (int i = 0; i < registers.size(); i++)
  213. {
  214. qDebug() << "Register value:" << registers.at(i);
  215. ui->textEdit->append("寄存器"+QString::number(i)+":"+QString::number(registers.at(i)));
  216. }
  217. }
  218. break;
  219. }
  220. case 2:
  221. {
  222. if (revMessage.at(1) == '\x8f')
  223. {
  224. quint8 exCode = revMessage.at(2);
  225. qDebug() << "异常响应,异常码 =" << exCode;
  226. return;
  227. }
  228. }
  229. }
  230. }
  231. else
  232. {
  233. qDebug() << "接收失败";
  234. }
  235. }
  236. //发送读线圈和寄存器报文
  237. void Widget::on_btn_read_clicked()
  238. {
  239. QByteArray SendCommand; //要发送的报文
  240. SendCommand.append(ui->comboBox_stationAddress->currentText().toInt()%256); //加入站地址
  241. if (ui->comboBox_gongnengma->currentIndex() == 0) //读线圈
  242. {
  243. SendCommand.append(0x01);
  244. }
  245. else if(ui->comboBox_gongnengma->currentIndex() == 1) //读寄存器
  246. {
  247. SendCommand.append(0x03);
  248. }
  249. SendCommand.append(ui->lineEdit_stratAddress->text().toInt()/256); //加入起始地址
  250. SendCommand.append(ui->lineEdit_stratAddress->text().toInt()%256);
  251. SendCommand.append(ui->lineEdit_length->text().toInt()/256); //加入长度
  252. SendCommand.append(ui->lineEdit_length->text().toInt()%256);
  253. quint16 temp = calculateCrc(SendCommand); //计算crc
  254. SendCommand.append(temp%256); //加入计算的crc值
  255. SendCommand.append(temp/256);
  256. qDebug() << SendCommand.toHex();
  257. serialPort->write(SendCommand); //发送报文
  258. }