实时读取另一个串口发来的返回数据
目录
实时读取另一个串口发来的返回数据
在您提供的代码基础上,我们可以直接在
StepperDriver
类中实现解析回零状态和电机状态标志位的功能,并将解析结果展示在txtBack
中。以下是具体的实现方案:1. 修改
StepperDriver
类1.1 添加状态解析方法
在
StepperDriver
类中,我们已经有了readZeroReturnStatus
和readMotorStatusFlags
方法,这些方法已经实现了状态解析功能。我们需要确保它们的解析结果能够正确显示在txtBack
中。1.2 修改
readZeroReturnStatus
方法确保
readZeroReturnStatus
方法将解析结果追加到txtBack
中:bool StepperDriver::readZeroReturnStatus(char slaveAddress, QTextEdit *txtBack) { // 构建查询指令 QByteArray command; command.append(slaveAddress); command.append(0x3B); command.append(0x6B); // 显示发送指令 txtBack->append(QStringLiteral("[发送] 零点回归状态查询指令: ") + command.toHex(' ').toUpper()); // 发送指令 serialPort->write(command); if (!serialPort->waitForBytesWritten(1000)) { txtBack->append(">> 错误:指令发送超时"); return false; } // 等待并读取响应 QByteArray response; while (serialPort->waitForReadyRead(500)) { response += serialPort->readAll(); if (response.length() >= 4) break; // 最小响应长度4字节 } // 显示原始响应 txtBack->append(QStringLiteral("[接收] 原始响应数据: ") + response.toHex(' ').toUpper()); // 基础响应验证 if (response.size() < 4) { txtBack->append(">> 错误:响应数据长度不足"); return false; } // 地址和功能码验证 if (static_cast<quint8>(response[0]) != static_cast<quint8>(slaveAddress) || static_cast<quint8>(response[1]) != 0x3B) { txtBack->append(">> 错误:响应头验证失败"); return false; } // 解析状态字节(第3字节) const quint8 statusByte = static_cast<quint8>(response[2]); txtBack->append(QStringLiteral("零点回归状态字节: 0x%1") .arg(statusByte, 2, 16, QLatin1Char('0'))); // 标志位解析 const bool encoderReady = (statusByte & 0x01); const bool calibrationReady = (statusByte & 0x02); const bool zeroingActive = (statusByte & 0x04); const bool zeroingFailed = (statusByte & 0x08); txtBack->append(QStringLiteral("编码器就绪: %1").arg(encoderReady ? "是" : "否")); txtBack->append(QStringLiteral("校准表就绪: %1").arg(calibrationReady ? "是" : "否")); txtBack->append(QStringLiteral("正在归零: %1").arg(zeroingActive ? "是" : "否")); txtBack->append(QStringLiteral("归零失败: %1").arg(zeroingFailed ? "是" : "否")); // 校验结果状态(第4字节) const quint8 resultCode = static_cast<quint8>(response[3]); switch (resultCode) { case 0x02: txtBack->append(">> 操作成功:零点回归状态读取成功"); return true; case 0xE2: txtBack->append(">> 操作失败:条件不满足"); return false; case 0xEE: txtBack->append(">> 错误:无效指令"); return false; default: txtBack->append(QStringLiteral(">> 未知响应码: 0x%1").arg(resultCode, 2, 16, QLatin1Char('0'))); return false; } }
1.3 修改
readMotorStatusFlags
方法确保
readMotorStatusFlags
方法将解析结果追加到txtBack
中:bool StepperDriver::readMotorStatusFlags(char slaveAddress, QTextEdit *txtBack) { // 构建查询指令 QByteArray command; command.append(slaveAddress); command.append(0x3A); command.append(0x6B); // 显示发送指令 txtBack->append(QStringLiteral("[发送] 电机状态标志查询指令: ") + command.toHex(' ').toUpper()); // 发送指令 serialPort->write(command); if (!serialPort->waitForBytesWritten(1000)) { txtBack->append(">> 错误:指令发送超时"); return false; } // 等待并读取响应 QByteArray response; while (serialPort->waitForReadyRead(500)) { response += serialPort->readAll(); if (response.length() >= 4) break; // 最小响应长度4字节 } // 显示原始响应 txtBack->append(QStringLiteral("[接收] 原始响应数据: ") + response.toHex(' ').toUpper()); // 基础响应验证 if (response.size() < 4) { txtBack->append(">> 错误:响应数据长度不足"); return false; } // 地址和功能码验证 if (static_cast<quint8>(response[0]) != static_cast<quint8>(slaveAddress) || static_cast<quint8>(response[1]) != 0x3A) { txtBack->append(">> 错误:响应头验证失败"); return false; } // 解析状态字节(第3字节) const quint8 statusByte = static_cast<quint8>(response[2]); txtBack->append(QStringLiteral("电机状态标志字节: 0x%1") .arg(statusByte, 2, 16, QLatin1Char('0'))); // 标志位解析 const bool enableStatus = (statusByte & 0x01); // bit0: 使能状态 const bool positionReached = (statusByte & 0x02); // bit1: 位置到达 const bool stallDetected = (statusByte & 0x04); // bit2: 堵转检测 const bool stallProtection = (statusByte & 0x08); // bit3: 堵转保护 txtBack->append(QStringLiteral("使能状态: %1").arg(enableStatus ? "有效" : "无效")); txtBack->append(QStringLiteral("位置到达: %1").arg(positionReached ? "是" : "否")); txtBack->append(QStringLiteral("堵转检测: %1").arg(stallDetected ? "触发" : "正常")); txtBack->append(QStringLiteral("堵转保护: %1").arg(stallProtection ? "激活" : "关闭")); // 校验结果状态(第4字节) const quint8 resultCode = static_cast<quint8>(response[3]); switch (resultCode) { case 0x02: txtBack->append(">> 操作成功:状态标志读取成功"); return true; case 0xE2: txtBack->append(">> 操作失败:设备未就绪"); return false; case 0xEE: txtBack->append(">> 错误:无效状态查询指令"); return false; default: txtBack->append(QStringLiteral(">> 未知响应码: 0x%1").arg(resultCode, 2, 16, QLatin1Char('0'))); return false; } }
2. 测试功能
2.1 发送读状态命令
在程序中调用
readZeroReturnStatus
和readMotorStatusFlags
方法,例如:// 读取回零状态 stepperDriver->readZeroReturnStatus(0x01, ui->txtBack); // 读取电机状态 stepperDriver->readMotorStatusFlags(0x01, ui->txtBack);
2.2 预期结果
假设设备返回以下数据包:
回零状态:
01 3B 03 6B
电机状态:
01 3A 05 6B
则
txtBack
中显示:[发送] 零点回归状态查询指令: 01 3B 6B [接收] 原始响应数据: 01 3B 03 6B 零点回归状态字节: 0x03 编码器就绪: 是 校准表就绪: 是 正在归零: 否 归零失败: 否 >> 操作成功:零点回归状态读取成功 [发送] 电机状态标志查询指令: 01 3A 6B [接收] 原始响应数据: 01 3A 05 6B 电机状态标志字节: 0x05 使能状态: 有效 位置到达: 否 堵转检测: 是 堵转保护: 否 >> 操作成功:状态标志读取成功
3. 扩展功能
3.1 添加时间戳
在显示状态信息时,添加时间戳:
QString timestamp = QDateTime::currentDateTime().toString("hh:mm:ss"); txtBack->append(QString("[%1] ").arg(timestamp) + message);
3.2 支持错误命令返回
在解析逻辑中添加对错误命令返回的处理:
if (static_cast<quint8>(response[2]) == 0xEE) { txtBack->append(">> 错误:无效命令"); return false; }
4. 完整代码示例
StepperDriver.h
class StepperDriver : public QObject { Q_OBJECT public: explicit StepperDriver(QObject *parent = nullptr); QSerialPort *getSerialPort() const; void on_btnOpenPort_clicked(); bool sendCommand(const QByteArray &command, const QString &desc, QString successMsg, QTextEdit *txtBack); bool enableMotor(char slaveAddress, char enableStatus, QTextEdit *txtBack); bool setPositionControl(char slaveAddress, char direction, uint16_t speed, char acceleration, uint32_t pulseCount, char mode, char multiSync, QTextEdit *txtBack); bool emergencyStop(char slaveAddress, char multiSync, QTextEdit *txtBack); bool readZeroReturnStatus(char slaveAddress, QTextEdit *txtBack); bool forceAbortZeroReturn(char slaveAddress, QTextEdit *txtBack); bool triggerZeroReturn(char slaveAddress, char zeroReturnMode, char multiSync, QTextEdit *txtBack); bool readMotorCurrentPosition(char slaveAddress, QTextEdit *txtBack); bool readMotorStatusFlags(char slaveAddress, QTextEdit *txtBack); private: QSerialPort *serialPort; };
MainWindow.cpp
void MainWindow::on_btnReadZeroReturnStatus_clicked() { stepperDriver->readZeroReturnStatus(0x01, ui->txtBack); } void MainWindow::on_btnReadMotorStatus_clicked() { stepperDriver->readMotorStatusFlags(0x01, ui->txtBack); }
通过以上修改,您的程序可以解析并显示回零状态和电机状态标志位的内容。如果仍有问题,请提供具体的错误信息或日志,以便进一步分析。