QSerialPort使用详解

SerialPort 是 Qt 框架中 Qt Serial Port 模块的核心类,用于在跨平台(Windows , Linux, macOS, QNX 等)环境下进行串行端口(COM 口/TTY)的读写操作。

它提供了同步和异步两种操作模式,但在 Qt 开发中,强烈推荐使用基于信号与槽的异步模式,以避免阻塞主线程(UI 线程)。

以下是 QSerialPort 的详细功能解析、常用配置及最佳实践:


1. 核心功能概览
功能类别主要方法/信号说明
生命周期open()close()isOpen()打开/关闭串口,检查状态
参数配置setBaudRate()setDataBits()setParity()setStopBits()setFlowControl()设置波特率、数据位、校验位、停止位、流控
信息获取portName()baudRate()error()errorString()获取当前配置或错误信息
数据写入write()waitForBytesWritten()发送数据(异步),或等待发送完成(同步,慎用)
数据读取read()readAll()bytesAvailable()waitForReadyRead()读取数据(通常配合 readyRead 信号使用)
控制信号setDataTerminalReady()setRequestToSend()控制 DTR/RTS 引脚(常用于复位单片机或控制继电器)
关键信号readyReaderrorOccurredbytesWritten数据到达、发生错误、数据发送完成
2. 标准初始化 流程 (代码片段)

这是最标准的异步使用方式:

#include <QSerialPort>
#include <QSerialPortInfo>
#include <QDebug>
 
// 1. 创建对象
QSerialPort *serial = new QSerialPort(this);
 
// 2. 设置端口名 (例如 Windows 的 "COM3", Linux 的 "/dev/ttyUSB0")
serial->setPortName("COM3");
 
// 3. 打开端口 (读写模式)
if (!serial->open(QIODevice::ReadWrite)) {
    qWarning() << "打开失败:" << serial->errorString();
    delete serial;
    return;
}
 
// 4. 配置通信参数
serial->setBaudRate(QSerialPort::Baud9600);       // 波特率 9600
serial->setDataBits(QSerialPort::Data8);          // 8 位数据
serial->setParity(QSerialPort::NoParity);         // 无校验
serial->setStopBits(QSerialPort::OneStop);        // 1 位停止位
serial->setFlowControl(QSerialPort::NoFlowControl); // 无流控
 
// 5. 连接信号 (异步处理的核心)
connect(serial, &QSerialPort::readyRead, this, [=]() {
    QByteArray data = serial->readAll();
    qDebug() << "收到数据:" << data.toHex(' ');
    // 在这里处理数据解析逻辑
});
 
connect(serial, QOverload<QSerialPort::SerialPortError>::of(&QSerialPort::errorOccurred),
        this, [=](QSerialPort::SerialPortError error) {
    if (error == QSerialPort::NoError) return;
    qWarning() << "串口错误:" << serial->errorString();
});
 
// 6. 发送数据
serial->write("Hello World"); 
// 注意:write 是异步的,数据放入缓冲区后函数立即返回
3. 关键参数详解
A. 波特率 (BaudRate)

支持标准值:Baud1200 到 Baud115200,甚至更高(如 Baud230400Baud921600),具体取决于硬件驱动支持。

serial->setBaudRate(QSerialPort::Baud115200);
// 或者使用整数值 (Qt 5.1+)
serial->setBaudRate(115200); 
B. 数据位、校验位、停止位
  • DataBits: Data5 ~ Data8 (常用 Data8)
  • Parity: NoParity (无), EvenParity (偶), OddParity (奇), SpaceParity, MarkParity
  • StopBits: OneStop, OneAndHalfStop, TwoStop
     
C. 流控制 (FlowControl)

防止数据丢失的重要机制:

  • NoFlowControl: 无流控(最常用,适用于短距离或低速)。
  • HardwareControl: 硬件流控 (RTS/CTS),需要接线支持。
  • SoftwareControl: 软件流控 (XON/XOFF)。
4. 常见痛点与解决方案
痛点 1:数据接收不完整 (粘包/拆包)

readyRead 信号触发时,操作系统内核缓冲区可能有 1 个字节,也可能有 100 个字节,不一定刚好是一帧完整的数据

解决方案:建立应用层缓冲区和状态机。

// 伪代码示例:假设协议以 0xAA 开头,0x55 结尾
QByteArray m_buffer;
 
void onReadyRead() {
    m_buffer.append(serial->readAll()); // 追加到缓冲区
    
    while (true) {
        int start = m_buffer.indexOf(0xAA);
        if (start == -1) {
            m_buffer.clear(); // 没找到头,丢弃(或根据策略保留)
            break;
        }
        
        int end = m_buffer.indexOf(0x55, start);
        if (end == -1) {
            break; // 还没收完,等待下一次 readyRead
        }
        
        // 提取完整帧 [start, end]
        QByteArray frame = m_buffer.mid(start, end - start + 1);
        processFrame(frame); // 处理这一帧
        
        // 从缓冲区移除已处理的数据
        m_buffer.remove(0, end + 1);
    }
}
痛点 2:界面卡顿

如果在 readyRead 槽函数中进行了复杂的耗时计算(如大量数据解析、绘图、数据库写入),会阻塞 UI。

解决方案

  1. 快速读取:在槽函数中只执行 readAll() 并将数据存入队列。
  2. 异步处理:发射一个自定义信号,让其他对象(或工作线程)处理数据。
  3. 多线程:将 QSerialPort 对象 moveToThread 到一个专门的 Worker 线程中运行。
痛点 3: DTR/RTS 引脚控制

很多单片机(如 Arduino)通过 DTR 引脚复位,或者某些工业设备需要 RTS 信号使能。

// 拉低 DTR (常用于复位 Arduino)
serial->setDataTerminalReady(false); 
QThread::msleep(100);
serial->setDataTerminalReady(true);
 
// 控制 RTS
serial->setRequestToSend(true); 
痛点 4: 枚举可用串口

不要硬编码 "COM3",因为插拔顺序会变。

#include <QSerialPortInfo>
 
const auto infos = QSerialPortInfo::availablePorts();
for (const QSerialPortInfo &info : infos) {
    qDebug() << "端口名:" << info.portName();
    qDebug() << "描述:" << info.description();
    qDebug() << "制造商:" << info.manufacturer();
    // 可以根据 vendorIdentifier 和 productIdentifier 过滤特定设备
}
5. 进阶:Qt Serial Bus (针对 Modbus 等)

如果你需要做 Modbus RTUCAN Bus 等工业协议 ,不要手动解析 QSerialPort 的字节流。Qt 提供了更上层的模块 Qt Serial Bus

  • QModbusRtuSerialMaster
  • 优势: 自动处理地址校验、CRC 校验、超时重发、帧拼接。
  • 依赖QT += serialbus
6. 调试技巧
  • 虚拟串口: 使用 com0com (Windows) 或 socat (Linux) 创建一对虚拟串口(如 COM3 <-> COM4),用两个程序或一个程序的两个实例互发数据测试。
  • 十六进制显示: 调试二进制协议时,务必使用 data.toHex(' ') 打印,不要直接 qDebug() << data,否则不可见字符会导致困惑。
  • 错误码: 遇到 ResourceError 通常意味着端口被其他程序占用(如串口助手没关);PermissionError 在 Linux 下通常是用户组权限问题。
     
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值