Qt串口异步通信案例(主机线程)

串口线程类

MasterThread(主机线程)

目的:主动向从机发送请求,并等待接收响应。
关键行为:
    启动后,根据配置的串口号、等待超时时间以及请求内容向从机发送请求。
    发送请求后,等待读取响应。
    成功读取响应后,通过信号 response(QString) 发送响应内容。
    如果在等待读取响应或写请求时超时,同样会触发 timeout(QString) 信号。
同步机制:除了使用 QMutex 外,还使用了 QWaitCondition (m_cond)。在处理完一个事务后,线程不会立即退出循环,而是通过 m_cond.wait() 进入等待状态,直到新的事务请求通过

m_cond.wakeOne() 唤醒它。这种方式允许更精细的控制何时继续执行下一个事务,提高了资源利用效率。

MasterThread (主机线程) 示例

在智能工厂的生产线上,有一套自动化测试系统,该系统需要定期向各个测试工位的嵌入式控制器发送指令,收集测试结果,并根据结果调整生产线的速度或发出警报。

场景描述:

任务:主设备(MasterThread实例)周期性地向各个测试工位发送测试开始指令,要求工位执行特定的检测流程。
流程:MasterThread先配置好要发送的测试指令和目标工位(串口号),然后主动通过串口发送测试指令。它会等待每个工位的响应(可能是测试结果或确认信号),根据收到的信息调整后续指令或更新生产线状态。
特点:此场景中,MasterThread主动发起通讯,控制流程的推进,根据从属设备的反馈做出决策,体现了主控角色。

在串口采集CAN总线数据并进行解析的场景中,通常的逻辑取决于你的系统架构和通信需求,但通常更接近于使用一个主机线程(MasterThread)的模式:

主机线程(MasterThread)角色:

在CAN总线数据采集与解析的应用中,如果你的设备(如PC或主控制器)需要主动请求CAN数据,那么这个设备扮演的是主控角色。它通过串口向CAN适配器(或其他设备,如CAN-to-USB转换器)发送指令,要求读取CAN总线上的数据。
主机线程负责周期性或按需发送查询命令到CAN适配器,然后等待并处理响应(即接收到的CAN数据包)。这通常涉及设置读取命令、等待响应超时、处理接收到的数据等操作,这些特点符合MasterThread的行为模式。

从机线程(SlaveThread)角色:

如果你的设备主要是被动接收来自CAN总线的数据,并不需要主动发送请求,而是始终监听并响应数据的到来,那么它更像是一个从机。然而,在大多数CAN总线应用中,数据采集设备往往需要根据请求或预定的协议来操作,而非纯粹的被动接收。
在一些特定的系统设计中,如果CAN适配器本身带有足够的智能,能主动通过串口推送数据到你的设备,这时你的设备可能只需要监听串口并解析这些数据,这种情况下,虽然逻辑上更偏向于被动接收,但实际上仍可以通过主控线程设计实现,只是监听逻辑更加简化。

总结:
通常,采集CAN总线数据时,你的设备(尤其是如果它负责发起数据读取操作)会更适合设计成一个主机线程。你需要编写代码去初始化串口通信、发送查询指令到CAN适配器、读取数据并进行解析。即使是在等待数据到达的阶段,也是在主控逻辑中通过循环或事件驱动的方式实现,保持对串口数据的监听和处理。

#ifndef MASTERTHREAD_H
#define MASTERTHREAD_H

#include <QMutex>          // 包含用于线程同步的互斥锁类
#include <QThread>         // 包含用于实现线程基础功能的类
#include <QWaitCondition>  // 包含用于线程间同步的等待条件类


class MasterThread : public QThread
{
   
    Q_OBJECT             // 必须包含,用于启用Qt的信号和槽机制

public:
    // 构造函数,可选传入父对象指针,默认为nullptr
    explicit MasterThread(QObject *parent = nullptr);
    
    // 析构函数,清理资源,确保线程安全结束
    ~MasterThread();

    // 发起一次事务处理,包含串口号、等待超时时间及请求内容
    void transaction(const QString &portName, int waitTimeout, const QString &request);

signals:
    // 发射响应信号,携带响应字符串
    void response(const QString &s);
    
    // 发射错误信号,携带错误信息字符串
    void error(const QString &s);
    
    // 发射超时信号,携带超时信息字符串
    void timeout(const QString &s);

private:
    // 重写了QThread的run方法,定义线程执行的具体任务
    void run() override;

    // 存储串口号
    QString m_portName;
    
    // 存储请求内容
    QString m_request;
    
    // 存储等待超时时间
    int m_waitTimeout = 0;

    // 用于线程间同步的互斥锁
    QMutex m_mutex;
    
    // 用于线程间同步的等待条件
    QWaitCondition m_cond;
    
    // 标记线程是否应终止
    bool m_quit = false;
};


#endif // MASTERTHREAD_H
#include "masterthread.h"
#include <QSerialPort>      // 包含QSerialPort类,用于串口通信
#include <QTime>           // 包含QTime类,用于获取当前时间,便于生成超时消息

MasterThread::MasterThread(QObject *parent) :
    QThread(parent)       // 初始化基类QThread,传递父对象指针以实现对象树管理
{
   
}

//! [0]
MasterThread::~MasterThread() {
   
    m_mutex.lock();       // 加锁以保护共享资源
    m_quit = true;       // 设置退出标志,指示线程应该停止运行
    m_cond.wakeOne();     // 唤醒可能等待的线程,通知退出
    m_mutex.unlock();    // 解锁
    wait();              // 等待线程安全结束
}
//! [0]

//! [1] //! [2]
void MasterThread::transaction(const QString &portName, int waitTimeout, const QString &request) {
   
//! [1]
    const QMutexLocker locker(&m_mutex); // 自动加锁并在作用域结束时解锁,保护内部操作
    m_portName = portName;            // 更新串口名称
    m_waitTimeout = waitTimeout;       // 更新等待超时时间
    m_request = request;             
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值