Qt6串口通信(实时接收数据、刷新串口号)

本文介绍了如何使用Qt库结合QML进行串口通信,包括设置波特率、数据位、校验位等参数,以及发送协议数据和异或校验的方法。同时,文章展示了如何实时刷新串口列表,并通过设置读缓冲区大小来优化接收完整协议数据的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

一、打开串口

二、发送数据

三、接收数据

四、关闭串口


串口通信大致分为四个部分:打开串口、发送数据、接收数据、关闭串口,总的来说并不难,本文是结合qml界面实现完整功能,以下是部分代码:

CMake:

find_package(Qt6 REQUIRED COMPONENTS SerialPort) 
target_link_libraries(mytarget PRIVATE Qt6::SerialPort)

qmake:

 QT += serialport

一、打开串口

//连接串口
bool SerialPort::connectSerial(QString port)
{
    qint32 baud_rate = 9600;  //自定义波特率

    m_serial.setPortName(port);                            //设置串口名称
    m_serial.setBaudRate(baud_rate);                       //设置波特率
    m_serial.setDataBits(QSerialPort::Data8);              //设置数据位8
    m_serial.setParity(QSerialPort::NoParity);             //校验位设置为0
    m_serial.setStopBits(QSerialPort::OneStop);            //停止位设置为1
    m_serial.setFlowControl(QSerialPort::NoFlowControl);   //设置为无流控制

    m_serial.setReadBufferSize(1);  //设置内部读缓冲区的大小(如果不设置默认最大是4096字节)

    if(!m_serial.open(QIODevice::ReadWrite))
    {
        qDebug() << "Serial port open error!";
        return false;
    }

    qDebug() << "Serial port open success!";
    return true;
}

注意:

1.函数传参port为需要打开的串口号,用一个下拉框接收识别到的所有串口号并实时刷新,参考如下代码:

新建一个serialportmanager.h文件

#ifndef SERIALPORTMANAGER_H
#define SERIALPORTMANAGER_H

#include <QObject>
#include <QSerialPortInfo>
#include <QTimer>

class SerialPortManager : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QStringList availablePorts READ availablePorts NOTIFY availablePortsChanged)

public:
    explicit SerialPortManager(QObject *parent = nullptr) : QObject(parent)
    {
        updateAvailablePorts();

        // 定期检查可用串口列表
        m_timer.setInterval(1000); // 每秒检查一次
        connect(&m_timer, &QTimer::timeout, this, &SerialPortManager::updateAvailablePorts);
        m_timer.start();
    }

    QStringList availablePorts() const
    {
        return m_availablePorts;
    }

signals:
    void availablePortsChanged();

private:
    void updateAvailablePorts()
    {
        m_availablePorts.clear();

        const QList<QSerialPortInfo> ports = QSerialPortInfo::availablePorts();
        for (const QSerialPortInfo &portInfo : ports) {
            m_availablePorts.append(portInfo.portName());
        }
        emit availablePortsChanged();
    }

private:
    QStringList m_availablePorts;
    QTimer m_timer;
};


#endif // SERIALPORTMANAGER_H

在main.cpp里实例化

#include <QApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "serialport.h"
#include "serialportmanager.h"

...
...
...

QQmlApplicationEngine engine;

SerialPortManager serialPortManager;
engine.rootContext()->setContextProperty("SerialPortManager", &serialPortManager);

qml的下拉框代码

import QtCharts 2.15

...    

    //串口下拉框
    ComboBox{
        id: portComboBox
        width: 80
        height: 40
        font.family: "楷体"
        model: SerialPortManager.availablePorts

        //设置默认选中的串口号
        onModelChanged: {
            if (SerialPortManager.availablePorts.length > 0)
                currentIndex = 0;
        }

        // 更新串口列表槽函数
        Connections {
            target: SerialPortManager
            function onAvailablePortsChanged() {
                // 更新串口列表
                portComboBox.model = SerialPortManager.availablePorts;
            }
        }
    }

2.m_serial.setReadBufferSize(1)设置内部读缓冲区的大小,一般不需要设置,在下面实时接收数据再详细解释这里为什么设置成1;

二、发送数据

//串口发送
void SerialPort::sendData()
{
    // 构造协议数据
    QByteArray protocolData;
    protocolData.append('\x01');
    protocolData.append('\x11');
    protocolData.append('\x02');
    protocolData.append('\x22');
    protocolData.append('\x03');

    // 计算并添加异或校验位
    quint8 checksum = xorChecksum(protocolData);
    protocolData.append(checksum);

    // 发送协议数据
    qint64 bytesWritten = m_serial.write(protocolData);
    if (bytesWritten == -1) {
        qDebug() << "Failed to write data to serial port:" << m_serial.errorString();
    }
    qDebug() << "发送字节数:" << bytesWritten;
}


//计算异或校验位
quint8 SerialPort::xorChecksum(QByteArray processedData)
{
    quint8 checksum = 0;
    for (int i = 0; i < processedData.size(); ++i) {
        checksum ^= processedData.at(i);
    }
    return checksum;
}

串口发送直接使用write()函数就行,不过串口通信一般需要做校验,以上代码是奇偶校验的一个方法,最终应该会发送一串16进制的数:01 11 02 22 03 33

三、接收数据

在构造函数里建立信号和槽

// 读取串口数据
connect(&m_serial, SIGNAL(readyRead()), this, SLOT(receiveData()));
//接收数据
void SerialPort::receiveData()
{
    receivedData.append(m_serial.readAll());
    ...
    数据处理
    ...
    数据处理完后可以用receivedData.clear()把缓冲区清除
    ...
}

如果串口设置了内部读缓冲区的大小为1,即m_serial.setReadBufferSize(1),这样每来一个字节数据就会触发一次readyRead()信号,这个方法对于需要接收一段完整协议来说非常适用。反之,只会触发一次readyRead()信号,readAll()就会把全部数据协议读出来,且最多4096个字节,超出的话会直接丢掉。所以当接收数据量多的时候推荐设置内部读缓冲区大小,这样不但数据不会丢失,而且响应速度也会更快。

四、关闭串口

//关闭串口
void SerialPort::closeSerial()
{
    if(m_serial.isOpen())
    {
        m_serial.close();
    }
}

以上就是串口通信的主要部分代码,下面附带一下.h文件给予参考:

#ifndef SERIALPORT_H
#define SERIALPORT_H

#include <QObject>
#include <QDebug>
#include <QCoreApplication>
#include <QSerialPort>
#include <QSerialPortInfo>
#include <QDataStream>

class SerialPort : public QObject
{
    Q_OBJECT

public:
    explicit SerialPort(QObject *parent = nullptr);
    ~SerialPort();

    quint8 xorChecksum(QByteArray processedData);
    bool connectSerial(QString port);
    void sendData();
    void closeSerial();
   
public slots:    
    void receiveData();

private:
    QSerialPort m_serial;
    QByteArray receivedData;

};

#endif // SERIALPORT_H
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值