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

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


**1. 修改 `StepperDriver` 类**

**1.1 添加状态解析方法**

在 `StepperDriver` 类中,我们已经有了 `readZeroReturnStatus` 和 `readMotorStatusFlags` 方法,这些方法已经实现了状态解析功能。我们需要确保它们的解析结果能够正确显示在 `txtBack` 中。

**1.2 修改 `readZeroReturnStatus` 方法**

确保 `readZeroReturnStatus` 方法将解析结果追加到 `txtBack` 中:

```cpp

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>(response0) != static_cast<quint8>(slaveAddress) ||

static_cast<quint8>(response1) != 0x3B) {

txtBack->append(">> 错误:响应头验证失败");

return false;

}

// 解析状态字节(第3字节)

const quint8 statusByte = static_cast<quint8>(response2);

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>(response3);

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` 中:

```cpp

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>(response0) != static_cast<quint8>(slaveAddress) ||

static_cast<quint8>(response1) != 0x3A) {

txtBack->append(">> 错误:响应头验证失败");

return false;

}

// 解析状态字节(第3字节)

const quint8 statusByte = static_cast<quint8>(response2);

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>(response3);

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` 方法,例如:

```cpp

// 读取回零状态

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 添加时间戳**

在显示状态信息时,添加时间戳:

```cpp

QString timestamp = QDateTime::currentDateTime().toString("hh:mm:ss");

txtBack->append(QString("%1 ").arg(timestamp) + message);

```

**3.2 支持错误命令返回**

在解析逻辑中添加对错误命令返回的处理:

```cpp

if (static_cast<quint8>(response2) == 0xEE) {

txtBack->append(">> 错误:无效命令");

return false;

}

```


**4. 完整代码示例**

**StepperDriver.h**

```cpp

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**

```cpp

void MainWindow::on_btnReadZeroReturnStatus_clicked()

{

stepperDriver->readZeroReturnStatus(0x01, ui->txtBack);

}

void MainWindow::on_btnReadMotorStatus_clicked()

{

stepperDriver->readMotorStatusFlags(0x01, ui->txtBack);

}

```


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

相关推荐
小羊没烦恼!1 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
千里马学框架1 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台1 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone1 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
伞伞悦读1 天前
【第38期】Python 模块与包详解:import、from、模块搜索路径、包结构和 __init__
开发语言·python
致远ccc1 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
C语言小火车1 天前
C/C++ 为什么需要编译器?
开发语言·c++
霍霍的袁1 天前
【C++】map 和 set 的使用 | 从用法到底层
开发语言·c++·学习·visual studio
ttyyttemo1 天前
Kotlin 协程中的 Job 结构化并发与取消
android
孙启超1 天前
【AI开发之Rust】第 11 课:智能指针与内部可变性
开发语言·后端·rust