目录

实时读取另一个串口发来的返回数据

实时读取另一个串口发来的返回数据

在您提供的代码基础上,我们可以直接在 StepperDriver 类中实现解析回零状态和电机状态标志位的功能,并将解析结果展示在 txtBack 中。以下是具体的实现方案:


1. 修改 StepperDriver

1.1 添加状态解析方法

StepperDriver 类中,我们已经有了 readZeroReturnStatusreadMotorStatusFlags 方法,这些方法已经实现了状态解析功能。我们需要确保它们的解析结果能够正确显示在 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 发送读状态命令

在程序中调用 readZeroReturnStatusreadMotorStatusFlags 方法,例如:

  
// 读取回零状态
  
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);
  
}
  

通过以上修改,您的程序可以解析并显示回零状态和电机状态标志位的内容。如果仍有问题,请提供具体的错误信息或日志,以便进一步分析。