赞
踩
目录
串口通信大致分为四个部分:打开串口、发送数据、接收数据、关闭串口,总的来说并不难,本文是结合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
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。