目录
一 串口通信相关概念介绍
串口通信(Serial Communications)在上位机控制领域非常常用,其原理是按位(bit)发送和接收字节。相对于按字节(byte)发送的并行通信慢很多,然而串口却可以在使用一根线发送数据的同时用另一根线接收数据。其优点是能够实现远距离通信。
而对于串口而言,长度可达1200米。典型地,串口用于ASCII码字符的传输。通信使用3根线完成,分别是地线、发送、接收。由于串口通信是异步的,端口能够在一根线上发送数据同时在另一根线上接收数据。其他线用于握手,但不是必须的。串口通信最重要的参数是波特率、数据位、停止位和奇偶校验。对于两个进行通信的端口,这些参数必须匹配。
(1)波特率:
这是一个衡量符号传输速率的参数。
指的是信号被调制以后在单位时间内的变化,即单位时间内载波参数变化的次数,如每秒钟传送240个字符,而每个字符格式包含10位(1个起始位,1个停止位,8个数据位),这时的波特率为240Bd,比特率为10位*240个/秒=2400bps。一般调制速率大于波特率,比如曼彻斯特编码)。通常电话线的波特率为14400,28800和36600。波特率可以远远大于这些值.但是波特率和距离成反比。高波特率常常用于放置的很近的仪器间的通信,典型的例子就是GPIB设备的通信。
(2)数据位:
这是衡量通信中实际数据位的参数。
当计算机发送一个信息包,实际的数据往往不会是8位的,标准的值是6、7和8位。如何设置取决于你想传送的信息。
比如,标准的ASCII码是0~127(7位)。扩展的ASCII码是0~255(8位)。
如果数据使用简单的文本(标准 ASCII码),那么每个数据包使用7位数据。
每个包是指一个字节,包括开始/停止位,数据位和奇偶校验位。
由于实际数据位取决于通信协议的选取,术语“包”指任何通信的情况。
(3)停止位:
用于表示单个包的最后一位。典型的值为1,1.5和2位。
由于数据是在传输线上定时的,并且每一个设备有其自己的时钟,很可能在通信中两台设备间出现了小小的不同步。因此停止位不仅仅是表示传输的结束,并且提供计算机校正时钟同步的机会。适用于停止位的位数越多,不同时钟同步的容忍程度越大,但是数据传输率同时也越慢。
(4)奇偶校验位:
在串口通信中一种简单的检错方式。
有四种检错方式:偶、奇、高和低。当然没有校验位也是可以的。对于偶和奇校验的情况,串口会设置校验位(数据位后面的一位),用一个值确保传输的数据有偶个或者奇个逻辑高位。例如,如果数据是011,那么对于偶校验,校验位为0,保证逻辑高的位数是偶数个。如果是奇校验,校验位为1,这样就有3个逻辑高位。
高位和低位不真正的检查数据,简单置位逻辑高或者逻辑低校验。这样使得接收设备能够知道一个位的状态,有机会判断是否有噪声干扰了通信或者是否传输和接收数据是否不同步。
二 Qt开发串口通信程序
Qt开发串口通信,有一个专门的模块叫QtSerialPort ,在开发时需要在工程文件中添加后才能使用。如下:
CMake:
需要在CMakeLists中加入以下内容
find_package(Qt6 COMPONENTS SerialPort REQUIRED)
target_link_libraries(工程名称 PRIVATE Qt6::SerialPort)
Qmake:
需要在.pro文件中添加如下内容:
QT += serialport
详细实例: 使用虚拟串口实现互相发送消息的功能
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include<QSerialPort>
#include<QSerialPortInfo>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void sendData();//发送串口数据
void receiveData();//接收串口数据
void openSerialport();//串口开启/关闭控制
private:
Ui::MainWindow *ui;
QSerialPort *serialPort;
};
#endif // MAINWINDOW_H
mianwindow.cpp
#include "mainwindow.h"
#include "./ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
//设置窗口标题和大小
this->setWindowTitle("串口通信Demo");
this->resize(800,600);
//初始化串口对象
serialPort=new QSerialPort(this);
//获取所有可用端口列表
QList<QSerialPortInfo> serialPortList=QSerialPortInfo::availablePorts();
//如果没有可用串口,则在状态栏提示相应信息
if(serialPortList.isEmpty()){
this->statusBar()->showMessage("没有可用串口,请插入串口或重启电脑重试");
}else {
//有可用串口的情况下,把串口遍历显示到下拉框中
this->statusBar()->showMessage("可用串口数量为:"+QString::number( serialPortList.count()) );
//创建遍历迭代器,把串口遍历显示到下拉框中
QList<QSerialPortInfo>::Iterator nextSerialPort=serialPortList.begin();
while (nextSerialPort != serialPortList.end()) {
ui->comboBox->addItem(nextSerialPort->portName());
nextSerialPort++;
}
}
//绑定信号和槽
connect(serialPort,SIGNAL(readyRead()),this,SLOT(receiveData()));
connect(ui->send_data,SIGNAL(clicked(bool)),this,SLOT(sendData()));
connect(ui->open_serialport,SIGNAL(clicked(bool)),this,SLOT(openSerialport()));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::sendData()
{
//获取需要发送的文本
QString senData=ui->lineEdit->text().trimmed();
//使用字节数组处理输入的文本
QByteArray sendDataArray;
sendDataArray.append(senData.toUtf8().data());
//使用串口发送字节数组
serialPort->write(sendDataArray);
}
void MainWindow::receiveData()
{
//接收其他串口发送过来的数据
QByteArray serialData;
serialData.append(serialPort->readAll());
//把数据依次显示到文本控件上面去
ui->textEdit->append(serialData);
}
void MainWindow::openSerialport()
{
//判断串口是否已经打开,若打开则关闭,同时改变状态灯和按钮文字设置为“打开串口”
if(serialPort->isOpen()){
serialPort->clear();
serialPort->close();
ui->open_serialport->setText("打开串口");
ui->label->setStyleSheet("background-color: rgb(255, 0, 0);");
}else {
//若串口没有打开,则设置指示灯为绿色,设置按钮文字为“关闭串口”
ui->label->setStyleSheet("background-color:rgb(0,255,0);border-radius:12px;");
ui->open_serialport->setText("关闭串口");
serialPort->setPortName(ui->comboBox->currentText());
serialPort->open(QIODevice::ReadWrite);
serialPort->setBaudRate(QSerialPort::Baud115200);
serialPort->setDataBits(QSerialPort::Data8);
serialPort->setParity(QSerialPort::NoParity);
serialPort->setStopBits(QSerialPort::OneStop);
serialPort->setFlowControl(QSerialPort::NoFlowControl);
}
}
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
写好代码之后,需要先使用虚拟串口工具创建一对串口,然后在使用一个串口调试工具使用其中一个串口,然后我们自己写的程序使用另一个串口。
这里我是使用深蓝网络串口调试工具作为一端,使用的串口是com3, 自己编写的程序使用com4,
最后双方实现通信。
资源下载链接:
https://download.csdn.net/download/XiaoWang_csdn/87614078
运行效果:
下一篇博客:
Qt6教程之三(15) Modbus通信_折腾猿王申兵的博客-CSDN博客
上一篇博客: