当前位置:首页 » 《休闲阅读》 » 正文

QT:串口通信、串口发送与接收

23 人参与  2024年12月04日 12:01  分类 : 《休闲阅读》  评论

点击全文阅读


使用版本为Qt 5.9.8(Qt5.1以上6以下的版本适用)

目录

一、效果演示

二、ui设计

三、代码部分

四、完整代码

五*、功能优化

(1)清空接收区

(2)16进制显示

(3)16进制发送

(4)时间戳

(5)检测串口

一、效果演示

        这里用的虚拟串口COM1、COM2模拟串口通信。左边为QT设计的串口工具为COM2串口,右边串口助手为COM1,可以看到设计的串口工具可以完成简单的收发数据功能,此外可以对串口波特率等等参数进行设置。

二、ui设计

控件布局、控件名称如图所示:

波特率下拉栏添加了两个item:第一个115200,第二个9600。

数据位下拉栏添加了两个item:第一个8位,第二个6位。

校验位下拉栏添加了三个item:第一个无,第二个偶校验,第三个奇检验。

停止位下拉栏添加了三个item:第一个1位,第二个1.5位,第三个2位。

另外右下角红色指示灯实际上是一个Label(宽高:5*5),预设样式表代码为:

border-radius:5px;  //设置圆角半径background-color: rgb(255, 0, 0);  //设置背景颜色

三、代码部分

serial.pro 工程文件开头加入:

QT       += serialport

头文件mainwindow.h 开头加入:

#include <QSerialPort>     //提供访问串口的功能#include <QSerialPortInfo> //提供系统中存在的串口信息#include <QDebug>          //debug用

头文件mainwindow.h 内,在 private:中加入:用于定义一个串口对象

QSerialPort  *serial; //定义串口对象

mainwindow.cpp窗口构造函数中加入以下代码:(三部分功能见注释)

//获取可用串口名到下拉栏QList<QSerialPortInfo> list = QSerialPortInfo::availablePorts();    for(int i=0; i<list.size(); i++)    {        ui->comboBox_port->addItem(list.at(i).portName());    }//创建串口对象serial = new QSerialPort;//连接信号与槽(接收数据)QObject::connect(serial,&QSerialPort::readyRead,this,&MainWindow::ReadData);

        关键部分是写点击“打开串口”按钮的槽函数:打开还是关闭串口是通过判断按钮文本进行的。整体设计框架为:(具体代码见部分四:完整代码)

如果按钮文本为“打开串口”:    依次设置:串口名、波特率、数据位、校验位、停止位、流控制。    再打开串口。    如果成功打开:指示灯变绿、禁用下拉栏、改变按钮文本为“关闭窗口”。    如果打开失败:QDebug报错如果按钮文本为“关闭串口”:    关闭串口、指示灯变红、恢复下拉栏使能、改变按钮文本为“打开串口”。*****************************************************************************************void MainWindow::on_Button_openserial_clicked()//点击打开串口按钮{    if(ui->Button_openserial->text() == "打开串口")    {        //设置串口为下拉栏所选串口名        //设置波特率        //设置数据位数        //设置校验位        //设置停止位        //设置流控制        //打开串口 同时判断是否成功        bool info = serial->open(QIODevice::ReadWrite);        if(info == true)        {            qDebug()<<"success";            //改变label颜色(指示灯)            //关闭下拉栏设置使能            //改变按钮文本为"关闭串口"        }        else        {            qDebug()<<"fail";        }    else    {           //关闭串口        //改变label颜色(指示灯)        //恢复下拉栏设置使能        //改变按钮文本为"打开串口"    }}

接着写点击接收数据的函数(读数据):

void MainWindow::ReadData()//读取接收到的信息{    QByteArray buf = serial->readAll();    ui->textBrowser->append(buf);}

最后写点击“发送”按钮的槽函数:

void MainWindow::on_Button_send_clicked()//点击发送按钮{    //检查串口是否打开    if (serial->isOpen())    {        //获取要发送的数据:lineEdit_send内容        QString sendData = ui->lineEdit_send->text()+"\r\n";        //将字符串转为QByteArray        QByteArray data = sendData.toUtf8();        //发送数据        serial->write(data);    }    else    {        qDebug()<<"serial is not open";    }}

四、完整代码

头文件mainwindow.h

#ifndef MAINWINDOW_H#define MAINWINDOW_H#include <QMainWindow>#include <QSerialPort>     //提供访问串口的功能#include <QSerialPortInfo> //提供系统中存在的串口信息#include <QDebug>          //debug用namespace Ui {class MainWindow;}class MainWindow : public QMainWindow{    Q_OBJECTpublic:    explicit MainWindow(QWidget *parent = nullptr);    ~MainWindow();private slots:    void on_Button_openserial_clicked();//点击打开串口按钮    void ReadData();//串口读数据(接收数据)    void on_Button_send_clicked();//点击发送按钮private:    Ui::MainWindow *ui;    QSerialPort *serial;//定义串口对象};#endif // MAINWINDOW_H

mainwindow.cpp文件

#include "mainwindow.h"#include "ui_mainwindow.h"MainWindow::MainWindow(QWidget *parent) :    QMainWindow(parent),    ui(new Ui::MainWindow){    ui->setupUi(this);    //获取可用串口名到下拉栏    QList<QSerialPortInfo> list = QSerialPortInfo::availablePorts();        for(int i=0; i<list.size(); i++)        {            ui->comboBox_port->addItem(list.at(i).portName());        }    //创建串口对象    serial = new QSerialPort;    //连接信号与槽(接收数据)    QObject::connect(serial,&QSerialPort::readyRead,this,&MainWindow::ReadData);}MainWindow::~MainWindow(){    delete ui;}void MainWindow::on_Button_openserial_clicked()//点击打开串口按钮{    if(ui->Button_openserial->text() == "打开串口")    {        //设置串口为下拉栏所选串口名        serial->setPortName(ui->comboBox_port->currentText());        //设置波特率        switch (ui->comboBox_baud->currentIndex())        {            case 0: serial->setBaudRate(QSerialPort::Baud115200); break;//115200            case 1: serial->setBaudRate(QSerialPort::Baud9600);   break;            default: break;        }        //设置数据位数        switch (ui->comboBox_databit->currentIndex())        {            case 0:serial->setDataBits(QSerialPort::Data8); break;//1位            case 1:serial->setDataBits(QSerialPort::Data6); break;            default: break;        }        //设置校验位        switch (ui->comboBox_parity->currentIndex())        {            case 0:serial->setParity(QSerialPort::NoParity);   break;//无校验位            case 1:serial->setParity(QSerialPort::EvenParity); break;            case 2:serial->setParity(QSerialPort::OddParity);  break;            default: break;        }        //设置停止位        switch (ui->comboBox_stopbit->currentIndex())        {            case 0:serial->setStopBits(QSerialPort::OneStop); break;//1位            case 1:serial->setStopBits(QSerialPort::OneAndHalfStop); break;            case 2:serial->setStopBits(QSerialPort::TwoStop); break;            default: break;        }        //设置流控制        serial->setFlowControl(QSerialPort::NoFlowControl);//无流控制        //打开串口 同时判断是否成功        bool info = serial->open(QIODevice::ReadWrite);        if(info == true)        {            qDebug()<<"success";            //改变label颜色(指示灯)            ui->label_light->setStyleSheet("background-color:rgb(0,255,0);border-radius:5px;");            //关闭下拉栏设置使能            ui->comboBox_port->setEnabled(false);            ui->comboBox_baud->setEnabled(false);            ui->comboBox_databit->setEnabled(false);            ui->comboBox_parity->setEnabled(false);            ui->comboBox_stopbit->setEnabled(false);            //改变按钮文本为“关闭串口”            ui->Button_openserial->setText(tr("关闭串口"));        }        else        {            qDebug()<<"fail";        }    }    else    {   //关闭串口        serial->clear();        serial->close();        //改变label颜色(指示灯)        ui->label_light->setStyleSheet("background-color:rgb(255,0,0);border-radius:5px;");        //恢复下拉栏设置使能        ui->comboBox_port->setEnabled(true);        ui->comboBox_baud->setEnabled(true);        ui->comboBox_databit->setEnabled(true);        ui->comboBox_parity->setEnabled(true);        ui->comboBox_stopbit->setEnabled(true);        //改变按钮文本为“打开串口”        ui->Button_openserial->setText(tr("打开串口"));    }}void MainWindow::ReadData()//接收数据函数(并显示){    QByteArray buf = serial->readAll();    ui->textBrowser->append(buf);}void MainWindow::on_Button_send_clicked()//点击发送按钮{    //检查串口是否打开    if (serial->isOpen())    {        //获取要发送的数据:lineEdit_send内容        QString sendData = ui->lineEdit_send->text();        //将字符串转为QByteArray        QByteArray data = sendData.toUtf8();        //发送数据        serial->write(data);    }    else    {        qDebug()<<"serial is not open";    }}

五*、功能优化

        以上代码仅仅实现了简单的收发功能,但还可以做一些使用功能上的优化:

(1)清空接收区

        接收显示的数据过多需要清空,可以设计点击按钮实现清空的功能,因此只需要添加一个按钮控件,编写点击按钮的槽函数即可:

void MainWindow::on_pushButton_2_clicked()//点击清空接收区按钮{    ui->textBrowser->clear();}

(2)16进制显示

        要接收数据以16进制显示,且每个字节用空格隔开便于查看。方法为添加一个checkBox控件,在接收数据函数内判断checkBox勾选情况,执行不同的操作,接收数据函数修改如下:

void MainWindow::ReadData()//读取接收到的信息{    QByteArray buf = serial->readAll();    if(ui->checkBox->isChecked()==true)//已经被勾选    {         QString hexData= buf.toHex().toUpper();//将数据转换为16进制字符串并大写         QString spacedData;//用于存储每个字节隔开一个空格的字符串         for(int i=0;i<hexData.length();i+=2)//在每个字节后添加一个空格         {             spacedData += hexData.mid(i,2);             spacedData += " ";         }         ui->textBrowser->append(spacedData);//将转换后的数据显示    }    else     {         ui->textBrowser->append(buf);//未勾选则直接显示    }}

(3)16进制发送

        前面已经实现了输入内容点击按钮发送,但是发送的是字符串,如果想要直接发送16进制数(如输入1a2b,发送出去16进制数1a2b),可用设计一个16进制发送功能,将符合16进制格式的字符串转换为QByteArray形式进行发送。方法为添加一个checkBox控件,在点击发送按钮槽函数内判断checkBox勾选情况,执行不同的操作,具体如下:

1.mainwindow.h文件public:中    定义static函数(实现符合16进制格式的QString数据转QByteArray数据)***************************************************************************static QByteArray hexStringToByteArray(const QString &hexString)    {        QByteArray byteArray;        QString sanitizedHex = hexString;//确保字符串长度是偶数        if (sanitizedHex.length() % 2 != 0){            sanitizedHex.prepend('0');//如果长度是奇数,前面补零        }        for (int i=0; i<sanitizedHex.length(); i+=2)        {            QString byteString = sanitizedHex.mid(i,2);//取两位            bool ok;            byteArray.append(static_cast<char>(byteString.toInt(&ok,16)));//转为字节            if (!ok){                qDebug() << "Invalid hex byte:" << byteString;//字符串非16进制格式,转换报错            }        }        return byteArray;//返回转换结果    }
2.修改点击发送按钮槽函数如下:****************************************************************************void MainWindow::on_Button_send_clicked()//点击发送按钮{    //检查串口是否打开    if (serial->isOpen())    {        if(ui->checkBox_2->isChecked()==true)//16进制发送被选中        {            //获取要发送的数据:lineEdit_send内容            QString sendData = ui->lineEdit_send->text();            //将字符串转换为QByteArray形式(调用了hexStringToByteArray函数)            QByteArray data  = hexStringToByteArray(sendData);            //发送数据            serial->write(data);        }        else        {            //获取要发送的数据:lineEdit_send内容            QString sendData = ui->lineEdit_send->text();            //将字符串转为QByteArray            QByteArray data  = sendData.toUtf8();            //发送数据            serial->write(data);        }    }    else { qDebug()<<"serial is not open"; }}

如图:勾选16进制发送后,输入16进制数发送内容与即为接收方接收结果,所键即所得。

(4)时间戳

        时间戳功能就是显示接收数据时,一并显示接收时间,需要添加一个头文件,并且在接收数据函数内加入第二段代码(添加到 “ui->textBrowser->append(xxx)” 上方):

#include <QDateTime> //获取当前时间
QString currentTime = QDateTime::currentDateTime().toString("[yyyy-MM-dd hh:mm:ss]");//定义字符串 = 当前时间并转换为字符串ui->textBrowser->append(currentTime);//设置标签内容

(5)检测串口

        当打开程序后,可用串口会自动添加到下拉栏,但如果可用串口增加或减少时,可用串口选项并不会发生变化,因此可设置一个按钮进行手动刷新(另外也可以用定时器实现定时刷新),点击按钮的槽函数与构造函数内获取可用串口是一样的:

void MainWindow::on_Button_check_clicked()//点击检测串口按钮{    //获取可用串口名到下拉栏    QList<QSerialPortInfo> list = QSerialPortInfo::availablePorts();    for(int i=0; i<list.size(); i++)    {        ui->comboBox_port->addItem(list.at(i).portName());    }}

如图:当发现没有可用串口时可点击检测窗口按钮刷新可用串口


点击全文阅读


本文链接:http://m.zhangshiyu.com/post/196410.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1