当前位置: 首页 > article >正文

Qt与下位机通信时,如何等待下位机回复和超时处理

在C++或Qt中实现与下位机(例如嵌入式设备、传感器等)的通信,并且需要等待对方回复,如果几秒后没有收到回复则执行下一步动作,可以使用多种方法来实现这种超时机制。以下是几种常见的实现方式:

1. 使用 QTimer 和 QEventLoopQTimer

结合 QEventLoop 可以方便地实现超时机制。QEventLoop 会阻塞当前线程,直到某个条件满足或超时发生。

示例代码

#include <QCoreApplication>
#include <QTimer>
#include <QEventLoop>
#include <QDebug>

void sendCommandAndWaitForResponse() {
    // 假设这里发送命令到下位机
    qDebug() << "Sending command to the device...";
    QEventLoop loop;
    QTimer timer;
    timer.setSingleShot(true);

    // 设置超时时间(例如5秒)
    int timeout = 5000;

    // 连接超时信号
    QObject::connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);
    timer.start(timeout);

    // 模拟接收响应
    bool responseReceived = false;  // 用于标记是否收到响应

    // 启动事件循环,等待响应或超时
    loop.exec();

    if (!responseReceived) {
        qDebug() << "Timeout: No response received within" << timeout / 1000 << "seconds.";
        // 执行下一步动作
    } else {
        qDebug() << "Response received successfully.";
    }
}

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    // 模拟异步响应
    QTimer::singleShot(3000, []() {
        qDebug() << "Simulating response from the device...";
        // 在实际应用中,这里会设置 responseReceived 为 true
    });

    sendCommandAndWaitForResponse();
    return a.exec();
}

2. 使用 QFuture 和 QFutureWatcher

QFuture 和 QFutureWatcher 可以用于异步操作,并且可以设置超时。

示例代码:

创建一个头文件 devicecommunication.h,并定义你的类:

#ifndef DEVICECOMMUNICATION_H
#define DEVICECOMMUNICATION_H

#include <QObject>

class DeviceCommunication : public QObject {
    Q_OBJECT

public:
    explicit DeviceCommunication(QObject *parent = nullptr);

    void sendCommandAndWaitForResponse();

signals:
    void responseReceived();

private slots:
    void onResponseReceived();
};

#endif // DEVICECOMMUNICATION_H

创建一个源文件 devicecommunication.cpp,实现你的类的方法:

#include "devicecommunication.h"
#include <QCoreApplication>
#include <QFuture>
#include <QFutureWatcher>
#include <QTimer>
#include <QtConcurrent/QtConcurrent>
#include <QDebug>

DeviceCommunication::DeviceCommunication(QObject *parent) : QObject(parent) {}

void DeviceCommunication::sendCommandAndWaitForResponse() {
    qDebug() << "Sending command to the device...";

    QFuture<void> future = QtConcurrent::run([this] {
        QThread::sleep(3);  // 模拟响应时间
        emit responseReceived();  // 发射信号表示响应已收到
    });

    QFutureWatcher<void> *watcher = new QFutureWatcher<void>(this);
    connect(watcher, &QFutureWatcher<void>::finished, [this, watcher, future] {
        if (future.isFinished()) {
            qDebug() << "Response received successfully.";
            watcher->deleteLater();
        }
    });

    watcher->setFuture(future);

    QTimer::singleShot(5000, [this, watcher] {
        if (!watcher->isFinished()) {
            qDebug() << "Timeout: No response received within 5 seconds.";
            watcher->deleteLater();
        }
    });
}

void DeviceCommunication::onResponseReceived() {
    qDebug() << "Response received, performing further actions...";
}
#include <QCoreApplication>
#include "devicecommunication.h"

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    DeviceCommunication communication;
    QObject::connect(&communication, &DeviceCommunication::responseReceived, &communication, &DeviceCommunication::onResponseReceived);

    communication.sendCommandAndWaitForResponse();

    return a.exec();
}

3. 使用 QSocketNotifier 或 QIODevice

如果你是通过串口、TCP/IP 或其他 I/O 设备进行通信,可以使用 QSocketNotifier 或 QIODevice 的 waitForReadyRead 方法来等待数据,并结合 QTimer 实现超时。

示例代码(使用 QSerialPort)

#include <QCoreApplication>
#include <QSerialPort>
#include <QTimer>
#include <QDebug>

void sendCommandAndWaitForResponse(QSerialPort *serialPort) {
    // 发送命令
    serialPort->write("COMMAND\r\n");
    qDebug() << "Sending command to the device...";

    // 设置超时时间
    int timeout = 5000;
    QTimer timer;
    timer.setSingleShot(true);
    timer.start(timeout);

    // 等待响应
    while (true) {
        if (serialPort->waitForReadyRead(100)) {  // 100ms 轮询间隔
            QByteArray response = serialPort->readAll();
            qDebug() << "Response received:" << response;
            break;
        }

        if (timer.isActive()) {
            continue;
        }

        qDebug() << "Timeout: No response received within" << timeout / 1000 << "seconds.";
        // 执行下一步动作
        break;
    }
}

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    // 初始化串口
    QSerialPort serialPort;
    serialPort.setPortName("COM1");  // 根据实际情况设置端口号
    serialPort.setBaudRate(QSerialPort::Baud9600);
    serialPort.setDataBits(QSerialPort::Data8);
    serialPort.setParity(QSerialPort::NoParity);
    serialPort.setStopBits(QSerialPort::OneStop);
    serialPort.setFlowControl(QSerialPort::NoFlowControl);

    if (!serialPort.open(QIODevice::ReadWrite)) {
        qDebug() << "Failed to open serial port:" << serialPort.errorString();
        return -1;
    }

    sendCommandAndWaitForResponse(&serialPort);

    serialPort.close();

    return a.exec();
}

4. 使用多线程和 std::condition_variable

如果你更喜欢使用标准C++库,可以使用多线程和 std::condition_variable 来实现超时机制。

示例代码

#include <iostream>
#include <thread>
#include <chrono>
#include <condition_variable>
#include <mutex>

std::condition_variable cv;
std::mutex mtx;
bool responseReceived = false;

void waitForResponse() {
    std::unique_lock<std::mutex> lock(mtx);
    cv.wait_for(lock, std::chrono::seconds(5), []{ return responseReceived; });

    if (!responseReceived) {
        std::cout << "Timeout: No response received within 5 seconds." << std::endl;
        // 执行下一步动作
    } else {
        std::cout << "Response received successfully." << std::endl;
    }
}

void simulateDeviceResponse() {
    std::this_thread::sleep_for(std::chrono::seconds(3));  // 模拟响应时间
    {
        std::lock_guard<std::mutex> lock(mtx);
        responseReceived = true;
    }
    cv.notify_one();
}

int main() {
    std::cout << "Sending command to the device..." << std::endl;

    std::thread t1(waitForResponse);
    std::thread t2(simulateDeviceResponse);

    t1.join();
    t2.join();

    return 0;
}

当然Qt库里面提供了对应的 QWaitCondition

总结

•QTimer 和 QEventLoop:适用于简单的超时机制。
•QFuture 和 QFutureWatcher:适用于复杂的异步操作。
•QSocketNotifier 或 QIODevice:适用于基于I/O的通信。
•多线程和 std::condition_variable:适用于标准C++库的超时机制


http://www.kler.cn/news/355947.html

相关文章:

  • [IOI2018] werewolf 狼人(Kruskal重构树 + 主席树)
  • 高级交换基础
  • day48 图论章节刷题Part01(深搜理论基础、98. 所有可达路径、广搜理论基础)
  • Elixir 工具篇
  • Flink PostgreSQL CDC源码解读:深入理解数据流同步
  • Android一代整体壳简易实现和踩坑记录
  • Linux Ubuntu dbus CAPI ---- #include<dbus.h>出现“无法打开源文件dbus/xxx.h“的问题
  • 数据结构-5.8.由遍历序列构造二叉树
  • Python进阶--海龟绘图turtle库
  • Dungeon Crawler Grid Controller 地牢移动控制器
  • iOS模拟弱网步骤
  • 法律文书审查专项使用大模型实现
  • 在docker的容器内如何查看Ubuntu系统版本
  • Linux零基础教程学习(黑马)
  • Netty
  • MatrixOne助力江铜集团打造炉前智慧作业AIoT大数据系统
  • 分布式介绍
  • 框架一 Mybatis Spring SpringMVC(东西居多 后边的没怎么处理)
  • 05 django管理系统 - 部门管理 - 修改部门
  • Linux :at crontab简述