在您提供的代码基础上,我们可以直接在 `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);
}
```
通过以上修改,您的程序可以解析并显示回零状态和电机状态标志位的内容。如果仍有问题,请提供具体的错误信息或日志,以便进一步分析。
实时读取另一个串口发来的返回数据
可可乐不加冰2025-03-07 11:11
相关推荐
方白羽12 小时前
Android Gradle 缓存与文件目录深度解析曲幽16 小时前
Termux里的二进制和脚本,到底怎么运行才不踩坑?Termux-service 保活妙招!plainGeekDev17 小时前
单例模式 → object 声明程序员陆业聪17 小时前
读者点单·03|Compose 与传统 View 混用的 12 个真实坑程序员陆业聪17 小时前
读者点单·02|Android 启动优化实战:Trace 抓取→Application 编排→冷启动全流程拆解Coffeeee18 小时前
帮你快速理解AI Agent之我想招个Android实习生恋猫de小郭19 小时前
苹果 AirPods 协议,Android 也可以使用完整版 AirPods 能力黄林晴19 小时前
告别无效重建:Gradle 9.6.0 解决 CI 构建缓存失效痛点告别无效重建:Gradle 9.6.0 解决 CI 建筑缓存失效痛点张风捷特烈20 小时前
Flutter 类库大揭秘#01 | path_provider架构与设计_阿南_1 天前
Android文件读写和分享总结