QT实现串口通信的完整步骤
麦子穗 人气:0要实现串口通信,需要知道串口通信需要的信息
主要参数有:波特率、校验位、数据位、停止位、控制流
主要操作有:串口的打开和关闭、刷新设备串口、接发数据、开关显示灯等。
实现效果如图:
界面设计如下:
每个控件类名如下:
LED灯是QLable控件,设置它的长宽都是24px,然后鼠标右击,选择“样式表”,在样式表中添加代码。
最后附赠完整源码
第一步:在头文件中引入 QtSerialPort 类的两个头文件(必须引入)
// 引入串口通信的两个头文件(第一步) #include <QtSerialPort/QSerialPort> // 提供访问串口的功能 #include <QtSerialPort/QSerialPortInfo> // 提供系统中存在的串口信息
第二步:在工程文件中添加以下代码
# 引入串口工程类型(第二步) QT += serialport
第三步:在头文件中定义全局的串口对象
QSerialPort *serial; // 定义全局的串口对象(第三步)
第四步:参数设置,在头文件中定义初始化参数的函数和参数变量名,在.cpp文件中实现函数
public: void SerialPortInit(); // 串口初始化(参数配置) private: // 参数配置 QStringList baudList; //波特率 QStringList parityList; //校验位 QStringList dataBitsList; //数据位 QStringList stopBitsList; //停止位 QStringList flowControlList; //控制流
// 串口初始化(参数配置) void MainWindow::SerialPortInit() { serial = new QSerialPort; //申请内存,并设置父对象 // 获取计算机中有效的端口号,然后将端口号的名称给端口选择控件 foreach(const QSerialPortInfo &info,QSerialPortInfo::availablePorts()) { serial->setPort(info); // 在对象中设置串口 if(serial->open(QIODevice::ReadWrite)) // 以读写方式打开串口 { ui->PortBox->addItem(info.portName()); // 添加计算机中的端口 serial->close(); // 关闭 } else { qDebug() << "串口打开失败,请重试"; } } // 参数配置 // 波特率,波特率默认选择57600 ,禁止用户点击 ui->BaudBox->addItem("57600"); serial->setBaudRate(QSerialPort::Baud57600); ui->BaudBox->setDisabled(true); // 校验,校验默认选择无 ui->ParityBox->addItem("无"); serial->setParity(QSerialPort::NoParity); // 数据位,数据位默认选择8位 ui->BitBox->addItem("8"); serial->setDataBits(QSerialPort::Data8); // 停止位,停止位默认选择1位 ui->StopBox->addItem("1"); serial->setStopBits(QSerialPort::OneStop); // 控制流,默认选择无 ui->ControlBox->addItem("无"); serial->setFlowControl(QSerialPort::NoFlowControl); // 刷新串口 RefreshSerialPort(0); // 信号 connect(serial,&QSerialPort::readyRead,this,&MainWindow::DataReceived); // 接收数据 connect(ui->SendWordOrder,&QPushButton::clicked,this,&MainWindow::DataSend); // 发送数据 connect(ui->SendButton,&QPushButton::clicked,this,&MainWindow::DataSend); // 发送数据 connect(ui->SendEditBtn1,&QPushButton::clicked,this,&MainWindow::DataSend); // 发送数据 connect(ui->SendEditBtn2,&QPushButton::clicked,this,&MainWindow::DataSend); // 发送数据 connect(ui->SendEditBtn3,&QPushButton::clicked,this,&MainWindow::DataSend); // 发送数据 }
第五步:刷新串口,及时更新可用的串口
// 刷新串口 void MainWindow::RefreshSerialPort(int index) { QStringList portNameList; // 存储所有串口名 if(index != 0) { serial->setPortName(ui->PortBox->currentText()); //设置串口号 } else { ui->PortBox->clear(); //关闭串口号 ui->PortBox->addItem("刷新"); //添加刷新 foreach(const QSerialPortInfo &info,QSerialPortInfo::availablePorts()) //添加新串口 { portNameList.append(info.portName()); } ui->PortBox->addItems(portNameList); ui->PortBox->setCurrentIndex(1); // 当前串口号为COM1 serial->setPortName(ui->PortBox->currentText()); //设置串口号 } }
第六步:发送数据和接收数据
// 接收数据,使用read () / readLine () / readAll () void MainWindow::DataReceived() { char BUF[512] = {0}; // 存储转换类型后的数据 QByteArray data = serial->readAll(); // 读取数据 if(!data.isEmpty()) // 接收到数据 { QString str = ui->DataReceived->toPlainText(); // 返回纯文本 str += tr(data); // 数据是一行一行传送的,要保存所有数据 ui->DataReceived->clear(); // 清空之前的数据 ui->DataReceived->append(str); // 将数据放入控件中 qDebug() << "str info: " << ui->DataReceived->toPlainText(); // 清除之前的数据,防止追加,因为每次获取的数据不一样 int index = str.indexOf("\r\n"); // 找到,返回索引值,找不到,返回-1 if(index != -1) { snprintf(BUF,500,"%s", str.left(index + 2).toUtf8().data()); // QString转为char * 类型 qDebug() << "BUF info: " << BUF; // 数据类型转换成功 str.remove(0,index + 2); // 处理获取到的数据,将其放入对应的控件中 // ..... } } } // 发送数据,write () void MainWindow::DataSend() { serial->write(ui->DataSend->toPlainText().toLatin1()); // 串口发送数据 }
第七步:打开串口和关闭串口,当打开串口后,显示绿灯;关闭串口后,显示红灯
// 串口开关 void MainWindow::on_OpenSerialButton_clicked() { if(serial->isOpen()) // 如果串口打开了,先给他关闭 { serial->clear(); serial->close(); // 关闭状态,按钮显示“打开串口” ui->OpenSerialButton->setText("打开串口"); // 关闭状态,允许用户操作 ui->BaudBox->setDisabled(false); ui->ParityBox->setDisabled(false); ui->BitBox->setDisabled(false); ui->StopBox->setDisabled(false); ui->ControlBox->setDisabled(false); // 禁止操作“发送字符操作” ui->SendWordOrder->setDisabled(true); ui->SendButton->setDisabled(true); // 关闭状态,颜色为绿色 ui->OpenSerialButton->setStyleSheet("color: green;"); // 关闭,显示灯为红色 LED(true); // 清空数据 ui->DataReceived->clear(); ui->DataSend->clear(); } else // 如果串口关闭了,先给他打开 { //当前选择的串口名字 serial->setPortName(ui->PortBox->currentText()); //用ReadWrite 的模式尝试打开串口,无法收发数据时,发出警告 if(!serial->open(QIODevice::ReadWrite)) { QMessageBox::warning(this,tr("提示"),tr("串口打开失败!"),QMessageBox::Ok); return; } // 打开状态,按钮显示“关闭串口” ui->OpenSerialButton->setText("关闭串口"); // 打开状态,禁止用户操作 ui->BaudBox->setDisabled(true); ui->ParityBox->setDisabled(true); ui->BitBox->setDisabled(true); ui->StopBox->setDisabled(true); ui->ControlBox->setDisabled(true); // 允许操作“发送字符操作” ui->SendWordOrder->setDisabled(false); ui->SendButton->setDisabled(false); // 打开状态,颜色为红色 ui->OpenSerialButton->setStyleSheet("color: red;"); // 打开,显示灯为绿色 LED(false); } } // 开关显示灯 void MainWindow::LED(bool changeColor) { if(changeColor == false) { // 显示绿色 ui->LED->setStyleSheet("background-color: qradialgradient(spread:pad, cx:0.5, cy:0.5, radius:0.5, fx:0.5, fy:0.5, stop:0 rgba(0, 229, 0, 255), stop:1 rgba(255, 255, 255, 255));border-radius:12px;"); } else { // 显示红色 ui->LED->setStyleSheet("background-color: qradialgradient(spread:pad, cx:0.5, cy:0.5, radius:0.5, fx:0.5, fy:0.5, stop:0 rgba(255, 0, 0, 255), stop:1 rgba(255, 255, 255, 255));border-radius:12px;"); } }
第八步:相关槽函数
// 控件中添加 指令“###” void MainWindow::on_SendButton_clicked() { on_ClearButton_clicked(); ui->DataSend->append("###"); } // 清空控件 void MainWindow::on_ClearButton_clicked() { ui->DataSend->setText(""); } // 清空接收到的数据 void MainWindow::on_ClearShowButton_clicked() { ui->DataReceived->setText(""); } // 点击发送后,获取串口信息并展示在接受控件中 void MainWindow::on_SendEditBtn1_clicked() { on_ClearButton_clicked(); QString EditText = ui->Edit1->text(); //获取发送框内容 ui->DataSend->setText(EditText); //将文本内容放在发送栏中 } void MainWindow::on_SendEditBtn2_clicked() { on_ClearButton_clicked(); QString EditText = ui->Edit2->text(); //获取发送框内容 // qDebug() << "Edit1 text: " << EditText; ui->DataSend->append(EditText); //将文本内容放在发送栏中 } void MainWindow::on_SendEditBtn3_clicked() { on_ClearButton_clicked(); QString EditText = ui->Edit3->text(); //获取发送框内容 // qDebug() << "Edit1 text: " << EditText; ui->DataSend->append(EditText); //将文本内容放在发送栏中 } void MainWindow::on_SendWordOrder_clicked() { on_SendButton_clicked(); }
源码:
工程文件.pro文件源码:
QT += core gui # 引入串口工程类型(第二步) QT += serialport greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++11 # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ mainwindow.cpp HEADERS += \ mainwindow.h FORMS += \ mainwindow.ui # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target
头文件源码:
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> // 引入串口通信的两个头文件(第一步) #include <QtSerialPort/QSerialPort> // 提供访问串口的功能 #include <QtSerialPort/QSerialPortInfo> // 提供系统中存在的串口信息 QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); // 串口功能 void SerialPortInit(); // 串口初始化(参数配置) void RefreshSerialPort(int index); // 刷新串口 public slots: // 串口槽函数 void DataReceived(); // 接收数据 private slots: // 串口槽函数 void DataSend(); // 发送数据 void on_OpenSerialButton_clicked(); // 串口开关 void on_SendButton_clicked(); // 控件中添加 # void on_ClearButton_clicked(); // 清空控件中的所有 # void on_ClearShowButton_clicked(); // 清空接收到的数据 void LED(bool changeColor); // 开关显示灯 // 点击发送,接收数据 void on_SendEditBtn1_clicked(); void on_SendEditBtn2_clicked(); void on_SendEditBtn3_clicked(); void on_SendWordOrder_clicked(); private: Ui::MainWindow *ui; // 串口变量 QSerialPort *serial; // 定义全局的串口对象(第三步) // 参数配置 QStringList baudList; //波特率 QStringList parityList; //校验位 QStringList dataBitsList; //数据位 QStringList stopBitsList; //停止位 QStringList flowControlList; //控制流 }; #endif // MAINWINDOW_H
.cpp文件源码:
#include "mainwindow.h" #include "ui_mainwindow.h" #include <QDebug> #include <QMessageBox> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); SerialPortInit(); } // 串口初始化(参数配置) void MainWindow::SerialPortInit() { serial = new QSerialPort; //申请内存,并设置父对象 // 获取计算机中有效的端口号,然后将端口号的名称给端口选择控件 foreach(const QSerialPortInfo &info,QSerialPortInfo::availablePorts()) { serial->setPort(info); // 在对象中设置串口 if(serial->open(QIODevice::ReadWrite)) // 以读写方式打开串口 { ui->PortBox->addItem(info.portName()); // 添加计算机中的端口 serial->close(); // 关闭 } else { qDebug() << "串口打开失败,请重试"; } } // 参数配置 // 波特率,波特率默认选择57600 ,禁止用户点击 ui->BaudBox->addItem("57600"); serial->setBaudRate(QSerialPort::Baud57600); ui->BaudBox->setDisabled(true); // 校验,校验默认选择无 ui->ParityBox->addItem("无"); serial->setParity(QSerialPort::NoParity); // 数据位,数据位默认选择8位 ui->BitBox->addItem("8"); serial->setDataBits(QSerialPort::Data8); // 停止位,停止位默认选择1位 ui->StopBox->addItem("1"); serial->setStopBits(QSerialPort::OneStop); // 控制流,默认选择无 ui->ControlBox->addItem("无"); serial->setFlowControl(QSerialPort::NoFlowControl); // 刷新串口 RefreshSerialPort(0); // 信号 connect(serial,&QSerialPort::readyRead,this,&MainWindow::DataReceived); // 接收数据 connect(ui->SendWordOrder,&QPushButton::clicked,this,&MainWindow::DataSend); // 发送数据 connect(ui->SendButton,&QPushButton::clicked,this,&MainWindow::DataSend); // 发送数据 connect(ui->SendEditBtn1,&QPushButton::clicked,this,&MainWindow::DataSend); // 发送数据 connect(ui->SendEditBtn2,&QPushButton::clicked,this,&MainWindow::DataSend); // 发送数据 connect(ui->SendEditBtn3,&QPushButton::clicked,this,&MainWindow::DataSend); // 发送数据 } // 刷新串口 void MainWindow::RefreshSerialPort(int index) { QStringList portNameList; // 存储所有串口名 if(index != 0) { serial->setPortName(ui->PortBox->currentText()); //设置串口号 } else { ui->PortBox->clear(); //关闭串口号 ui->PortBox->addItem("刷新"); //添加刷新 foreach(const QSerialPortInfo &info,QSerialPortInfo::availablePorts()) //添加新串口 { portNameList.append(info.portName()); } ui->PortBox->addItems(portNameList); ui->PortBox->setCurrentIndex(1); // 当前串口号为COM1 serial->setPortName(ui->PortBox->currentText()); //设置串口号 } } // 接收数据,使用read () / readLine () / readAll () void MainWindow::DataReceived() { char BUF[512] = {0}; // 存储转换类型后的数据 QByteArray data = serial->readAll(); // 读取数据 if(!data.isEmpty()) // 接收到数据 { QString str = ui->DataReceived->toPlainText(); // 返回纯文本 str += tr(data); // 数据是一行一行传送的,要保存所有数据 ui->DataReceived->clear(); // 清空之前的数据 ui->DataReceived->append(str); // 将数据放入控件中 qDebug() << "str info: " << ui->DataReceived->toPlainText(); // 清除之前的数据,防止追加,因为每次获取的数据不一样 int index = str.indexOf("\r\n"); // 找到,返回索引值,找不到,返回-1 if(index != -1) { snprintf(BUF,500,"%s", str.left(index + 2).toUtf8().data()); // QString转为char * 类型 qDebug() << "BUF info: " << BUF; str.remove(0,index + 2); // 处理获取到的数据,将其放入对应的控件中 // .... } } } // 发送数据,write () void MainWindow::DataSend() { serial->write(ui->DataSend->toPlainText().toLatin1()); // 串口发送数据 } // 开关显示灯 void MainWindow::LED(bool changeColor) { if(changeColor == false) { // 显示绿色 ui->LED->setStyleSheet("background-color: qradialgradient(spread:pad, cx:0.5, cy:0.5, radius:0.5, fx:0.5, fy:0.5, stop:0 rgba(0, 229, 0, 255), stop:1 rgba(255, 255, 255, 255));border-radius:12px;"); } else { // 显示红色 ui->LED->setStyleSheet("background-color: qradialgradient(spread:pad, cx:0.5, cy:0.5, radius:0.5, fx:0.5, fy:0.5, stop:0 rgba(255, 0, 0, 255), stop:1 rgba(255, 255, 255, 255));border-radius:12px;"); } } MainWindow::~MainWindow() { delete ui; } // 串口开关 void MainWindow::on_OpenSerialButton_clicked() { if(serial->isOpen()) // 如果串口打开了,先给他关闭 { serial->clear(); serial->close(); // 关闭状态,按钮显示“打开串口” ui->OpenSerialButton->setText("打开串口"); // 关闭状态,允许用户操作 ui->BaudBox->setDisabled(false); ui->ParityBox->setDisabled(false); ui->BitBox->setDisabled(false); ui->StopBox->setDisabled(false); ui->ControlBox->setDisabled(false); // 禁止操作“发送字符操作” ui->SendWordOrder->setDisabled(true); ui->SendButton->setDisabled(true); // 关闭状态,颜色为绿色 ui->OpenSerialButton->setStyleSheet("color: green;"); // 关闭,显示灯为红色 LED(true); // 清空数据 ui->DataReceived->clear(); ui->DataSend->clear(); } else // 如果串口关闭了,先给他打开 { //当前选择的串口名字 serial->setPortName(ui->PortBox->currentText()); //用ReadWrite 的模式尝试打开串口,无法收发数据时,发出警告 if(!serial->open(QIODevice::ReadWrite)) { QMessageBox::warning(this,tr("提示"),tr("串口打开失败!"),QMessageBox::Ok); return; } // 打开状态,按钮显示“关闭串口” ui->OpenSerialButton->setText("关闭串口"); // 打开状态,禁止用户操作 ui->BaudBox->setDisabled(true); ui->ParityBox->setDisabled(true); ui->BitBox->setDisabled(true); ui->StopBox->setDisabled(true); ui->ControlBox->setDisabled(true); // 允许操作“发送字符操作” ui->SendWordOrder->setDisabled(false); ui->SendButton->setDisabled(false); // 打开状态,颜色为红色 ui->OpenSerialButton->setStyleSheet("color: red;"); // 打开,显示灯为绿色 LED(false); } } // 控件中添加 # void MainWindow::on_SendButton_clicked() { on_ClearButton_clicked(); ui->DataSend->append("###"); } // 清空控件 void MainWindow::on_ClearButton_clicked() { ui->DataSend->setText(""); } // 清空接收到的数据 void MainWindow::on_ClearShowButton_clicked() { ui->DataReceived->setText(""); } // 点击发送后,获取串口信息并展示在接受控件中 void MainWindow::on_SendEditBtn1_clicked() { on_ClearButton_clicked(); QString EditText = ui->Edit1->text(); //获取发送框内容 ui->DataSend->setText(EditText); //将文本内容放在发送栏中 } void MainWindow::on_SendEditBtn2_clicked() { on_ClearButton_clicked(); QString EditText = ui->Edit2->text(); //获取发送框内容 // qDebug() << "Edit1 text: " << EditText; ui->DataSend->append(EditText); //将文本内容放在发送栏中 } void MainWindow::on_SendEditBtn3_clicked() { on_ClearButton_clicked(); QString EditText = ui->Edit3->text(); //获取发送框内容 // qDebug() << "Edit1 text: " << EditText; ui->DataSend->append(EditText); //将文本内容放在发送栏中 } void MainWindow::on_SendWordOrder_clicked() { on_SendButton_clicked(); }
运行后效果:
总结
加载全部内容