Qt串口通信

一、什么是串口通信

串口通信是一种通过串行接口按顺序逐位传输数据的通信方式。串行接口通过单条数据线(或差分线对)依次发送和接受数据,适用于设备间的远距离或简单数据传输。

典型的串口通信使用3根线完成,分别是地线、发送、接收。由于串口通信是异步的,所以端口能够在一根线上发送数据同时在另一根线上接收数据。串口通信最重要的参数是波特率、数据位、停止位和奇偶的校验。对于两个需要进行串口通信的端口,这些参数必须匹配,这也是能够实现串口通讯的前提。

二、串口通信参数介绍

  1. 波特率:

    定义:波特率是指单位时间内传输的码元个数(在串口通信中,每个码元通常对应1位二进制数据),单位为“波特”,它决定了数据传输的速度。发送方和接收方必须使用相同的波特率,否则会因采样时间不匹配导致数据解析错误。

    常用的波特率有 9600、115200、38400 等。例如,9600 波特率表示每秒传输 9600 位数据(包括数据位、校验位、停止位)。

    波特率越高,传输速度越快,但对传输线路的稳定性要求也越高(易受噪声干扰)。

   bool setBaudRate(qint32 baudRate,QSerialPort::Directions directions = AllDirections)//设置波特率

​   qint32 baudRate(QserialPort::Directions directions = AllDirections)// 返回波特率

2.数据位个数

定义:数据位是串口通信中实际传递的有效二进制数据位数,用于表示一个字符(如 ASCII 码字符)。它决定了单次传输的有效数据范围。

常见值:多为7位(可以表示0~127,对应ASCII码)或8位(0~255,可涵盖扩展ASCII码或二进制数据),其中8位是最常见的。

bool setDataBits(QSerialPort::DataBits dataBits) //设置数据位个数

QSerialPort::DataBits dataBits()//返回数据位个数

3.停止位个数

定义:停止位是数据帧末尾的空闲位,用于标记一个数据帧的结束,并为下一个数据帧的传输留出准备时间。接收方通过检测停止位来确认一个完整数据帧的结束,避免数据帧之间的混淆。

常见值:通常为1位(最常用,适用于大多数常规通信场景)、1.5位(较少见,主要用于某些特定的低速的通信协议)或2位(在传输速率较低或者线路噪声较大时使用,提供更长的间隔时间)。

bool setStopBits(QSerialPort::StopBits stopBits)//设置停止位个数

QSerialPort::StopBits stopBits()//返回停止位个数

4.奇偶校验位

定义:奇偶校验位是一个额外的校验位,用于简单检测数据传输过程中是否发生错误(如噪声导致的位翻转)。

工作原理:根据数据位中的“1”的个数,校验位会被设置位0或1,使“数据位+校验位”中“1”的总数总是满足预设的奇偶规则,奇/偶校验(数据位+校验位中“1”的总数为奇/偶数)、无校验、标记校验(校验位固定为1)、空格校验(校验位固定为0)。

bool setParity(QSerialPort::Parity parity)//设置奇偶校验位

QSerialPort::Parity parity()//返回奇偶校验位

一个完整的串口数据帧格式通常为: 起始位(1位) + 数据位(7/8位) + 校验位(0/1位) + 停止位(1/1.5/2位)

三、串口初始化

#include <QCoreApplication>
#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>
#include <QDebug>
// 创建串口对象
QSerialPort serialPort;
​
// 设置串口名称
// 可以通过QSerialPortInfo::availablePorts()获取可用串口列表
serialPort.setPortName("COM3"); 
​
// 配置串口参数
bool configSuccess = true;
​
// 设置波特率
if (!serialPort.setBaudRate(QSerialPort::Baud115200)) {
    qDebug() << "设置波特率失败:" << serialPort.errorString();
    configSuccess = false;
}
​
// 设置数据位
if (!serialPort.setDataBits(QSerialPort::Data8)) {
    qDebug() << "设置数据位失败:" << serialPort.errorString();
    configSuccess = false;
}
​
// 设置奇偶校验
if (!serialPort.setParity(QSerialPort::NoParity)) {
    qDebug() << "设置奇偶校验失败:" << serialPort.errorString();
    configSuccess = false;
}
​
// 设置停止位
if (!serialPort.setStopBits(QSerialPort::OneStop)) {
    qDebug() << "设置停止位失败:" << serialPort.errorString();
    configSuccess = false;
}
​
// 设置流控制
if (!serialPort.setFlowControl(QSerialPort::NoFlowControl)) {
    qDebug() << "设置流控制失败:" << serialPort.errorString();
    configSuccess = false;
}

​四、打开和关闭串口 

// 打开串口
if (configSuccess) {
    if (serialPort.open(QIODevice::ReadWrite)) {
        qDebug() << "串口打开成功:" << serialPort.portName();
   // 连接信号槽处理串口数据
    QObject::connect(&serialPort, &QSerialPort::readyRead, [&]() {
        QByteArray data = serialPort.readAll();
        qDebug() << "收到数据:" << data;
    });
    
    // 连接信号槽处理串口错误
    QObject::connect(&serialPort, static_cast<void (QSerialPort::*)(QSerialPort::SerialPortError)>(&QSerialPort::error),
                     [&](QSerialPort::SerialPortError error) {
        if (error != QSerialPort::NoError) {
            qDebug() << "串口错误:" << serialPort.errorString();
        }
    });
    
    // 发送数据示例
    QByteArray sendData = "Hello, Serial Port!";
    qint64 bytesWritten = serialPort.write(sendData);
    if (bytesWritten == -1) {
        qDebug() << "发送数据失败:" << serialPort.errorString();
    } else if (bytesWritten < sendData.size()) {
        qDebug() << "部分数据发送失败";
    } else {
        qDebug() << "数据发送成功";
    }
    
} else {
    qDebug() << "串口打开失败:" << serialPort.errorString();
}
}
​
// 程序退出时关闭串口
QObject::connect(&a, &QCoreApplication::aboutToQuit, [&]() {
    if (serialPort.isOpen()) {
        serialPort.close();
        qDebug() << "串口已关闭";
    }
});

五、数据读写

打开一个串口后,就可以使用QSerialPort的各种读写函数来读写串口的数据。 串口数据读写有阻塞式和非阻塞(异步方式)两种方式,异步方式读写数据的相关函数如下

qint64 bytesAvailable()//返回缓冲区中等待读取的数据字节数
​
QByteArray read(qint64 maxSize)//读取maxSize个字节的数据
    
QByteArray readAll() //读取缓冲区内的全部数据
    
bool canReadLine()  //是否有可以按行读取的数据
    
QByteArray readLine(qint64 maxSize = 0) //读取一行数据,最多读取maxSize个字节,行数据以换行符结束
​
qint64 write(const char* data,qint64 maxSize); //将缓冲区的数据写入串口,最多写入maxSize个字节
​
qint64 write(const char* data);//将缓冲区data的数据写入串口,以\0结束一般用于写字符串数据

在使用异步读写数据时,QSerialPort有两个信号可以表示缓冲区的数据变化。

void readyRead()  //接收缓冲区有待读取的数据时,此信号被发射
​
void bytesWritten(qint64 bytes)//当发送缓冲区内的一批数据写入串口后,此信号被发射

使用函数write()向串口写入一个缓冲区的数据时,函数write()会立刻返回,不会阻塞等待。串口将缓冲区的数据发送完之后,QSerialPort会发射bytesWritten()信号,这就是异步方式。

此外,QSerialPort还有两个阻塞式的等待函数

bool waitForBytesWritten(int msecs = 30000) ; //最多等待mesecs ms,直到串口数据发送结束
​
bool waitForReadyRead(int msecs = 30000);//最多等待mesecs ms,直到串口接收到一批数据

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值