【QT】编写一个简易的串口软件

简述

QT学了一点发现学不进去,索性看看能不能直接撸个程序,于是就有了这个简易的串口软件…


分析需求

这是XCOM串口收发软件,以此为例

【QT】编写一个简易的串口软件_第1张图片

目的很明确:

  1. 串口列表要能显示所有已经接上PC上的COM
  2. 以我们的配置115200-8-1-N打开串口
  3. 能收、发

新建一个Qt项目

既然用到串口,那么我们就要在.pro里增加串口的库

QT       += serialport  # 串口库

以及mainwindow.h里添加头文件

#include "qDebug.h"						  // 调试输出用
#include          // 提供访问串口的功能
#include      // 提供系统中存在的串口的信息

先拖控件把ui整出来

【QT】编写一个简易的串口软件_第2张图片

要注意的是,除了Label,其他的控件都记得命名呀,当然你用默认的也行…

打开串口功能

1. 选择串口功能

我们要打开的串口,并不希望他是临时变量,我们用到的地方多呢!所以就在头文件先定义一个私有成员变量

QSerialPort *serial;

我们希望他在打开的时候就能加载所有的COM,所以我们在MainWindow里做这一步,创建窗口的时候就初始化COM列表,顺带着我们为serial开辟空间

	// 我们在 ui->setupUi(this); 后面加入这些代码即可
	
    // 添加所有串口到comboBox里(串口号的名字叫comboBox_COMx)
    foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
    {
        ui->comboBox_COMx->addItem(info.portName()); //+':'+info.description()
    }
    serial = new QSerialPort(this);

我们用info去引用一个个的从串口的列表里取出COM的信息,如果有,我们就把他加入到【串口选择】的下拉栏里

这个时候如果我们运行,就会发现【串口选择】里已有了PC上已插入的COM设备。

2. 打开串口

首先为按钮【打开串口】添加槽,然后在槽函数里编写我们的代码:
打开了 总不能就一直开吧,所以我们做了一个开关,通过按钮上的字来判断是开还是关

 // 点击打开串口
    if(ui->pushButton_OpenSerial->text()==tr("打开串口"))
    {
        ui->pushButton_OpenSerial->setText(tr("关闭串口"));
    }
    else
    {
        ui->pushButton_OpenSerial->setText(tr("打开串口"));
        
    }

这个时候我们运行,会发现打开串口的按钮已经可以正常工作了,点击打开,会显示关闭按钮。点击关闭,会显示打开按钮。

按钮做完了,接着就要做功能了,如果要关闭,我们就可以调用serial->close();来关闭串口,如果要打开,我们就去打开,不过不知道能不能打开(可能别的程序正在使用),所以加个if判断一下。

    // 点击打开串口
    if(ui->pushButton_OpenSerial->text()==tr("打开串口"))
    {
        ui->pushButton_OpenSerial->setText(tr("关闭串口"));
        // 设置串口号(以当前显示的COM号为要打开的串口)
        serial->setPortName(ui->comboBox_COMx->currentText());
        // 以读写方式打开串口
        if(serial->open(QIODevice::ReadWrite))
        {
            qDebug() << "Open OK" << endl;
        }
        else
        {
            qDebug() << "Open Failed" << endl;
        }
    }
    else
    {
        ui->pushButton_OpenSerial->setText(tr("打开串口"));
        serial->close();
    }

现在我们运行一下,看调试信息知道目前都是正确的。能正确开关串口。

既然打开了串口,那么我们就配置一下串口的参数,因为只是一个简易的,所以就固定死串口为8-1-N,把一下代码放入成功打开串口的if内。

//设置波特率
            serial->setBaudRate(115200);
            //设置数据位
            serial->setDataBits(QSerialPort::Data8);
            //设置校验位
            serial->setParity(QSerialPort::NoParity);
            //设置流控制
            serial->setFlowControl(QSerialPort::NoFlowControl);
            //设置停止位
            serial->setStopBits(QSerialPort::OneStop);

这就完了吗?还没有,我们配置好了串口,如何进行接收呢?我们利用的是QT的信号与槽机制,当串口收到数据,就会发出readyRead()信号,所以我们利用这个信号,建立一个槽用来接收字符。

先在头文件定义private slots函数 void recv_data(void);

然后我们紧接着刚刚配置串口后面写上connect()来连接信号与槽

connect(serial, SIGNAL(readyRead()), this, SLOT(recv_data()));

这样我们点击打开信号与槽后,就会配置串口,激活信号与槽。

现在万事俱备,只欠东风,我们继续写槽函数recv_data()来接收串口的数据

仔细思考一下,平时在用串口软件的时候,有新的数据发来会自动出现在旧的数据后面。
所以我们的做法是,先暂时保存显示的数据,然后把读到的数据加在后面,再清除显示的数据,把合成的数据再显示出来,就达到我们的效果了。

void MainWindow::recv_data(void)
{
    qDebug() << "Recv Data" << endl;
    QByteArray buf = serial->readAll();
    if(!buf.isEmpty())
    {
        QString str = ui->textEdit_ReceiveMsg->toPlainText();
        str+=tr(buf);
        ui->textEdit_ReceiveMsg->clear();
        ui->textEdit_ReceiveMsg->append(str);
    }
}

这个时候我们运行一下,打开串口,用单片机来发数据,实测已经可以正确显示在屏幕上了

3. 发送数据

对于发送数据,有了刚才的经验就比较简单了。
为UI的【发送】键添加一个槽函数,当我们点击【发送】时,串口就发送我们写入的信息。
所以我们在发送的槽函数内写入:

	// 先读取我们写入的文本
	QString str = ui->textEdit_SendMsg->toPlainText().toLatin1();
    qDebug() << str <<endl;
    // 写入
    serial->write(str.toLatin1());

串口的write函数的参数有两个

  1. 第一个是char *类型,所以我们要str转char *,用的.toLatin1()来转换。
  2. 第二个是传入字符最大数量(我选择不设置所以没填)

此时我们再运行,发现收发都正常了。

附上我的完整代码(不包含UI,看控件的英文名字应该能对上图片)

mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include 
#include          // 提供访问串口的功能
#include      // 提供系统中存在的串口的信息

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
    void on_pushButton_OpenSerial_clicked();
    void recv_data(void);

    void on_pushButton_SendMsg_clicked();

    void on_pushButton_ClearRecv_clicked();

private:
    Ui::MainWindow *ui;

    QSerialPort *serial;
};

#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "qDebug.h"
#include "QObject"
#include "QTimer"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    // 初始化
    // 添加所有串口到comboBox里(串口号的名字叫comboBox_COMx)
    foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
    {
        ui->comboBox_COMx->addItem(info.portName()); //+':'+info.description()
    }
    serial = new QSerialPort(this);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::recv_data(void)
{
    qDebug() << "Recv Data" << endl;
    QByteArray buf = serial->readAll();
    if(!buf.isEmpty())
    {
        QString str = ui->textEdit_ReceiveMsg->toPlainText();
        str+=tr(buf);
        ui->textEdit_ReceiveMsg->clear();
        ui->textEdit_ReceiveMsg->append(str);
    }
}

void MainWindow::on_pushButton_OpenSerial_clicked()
{
    // 点击打开串口
    if(ui->pushButton_OpenSerial->text()==tr("打开串口"))
    {
        ui->pushButton_OpenSerial->setText(tr("关闭串口"));
        // 开辟空间
        //serial = new QSerialPort(this);

        // 设置串口号
        serial->setPortName(ui->comboBox_COMx->currentText());

        // 以读写方式打开串口
        if(serial->open(QIODevice::ReadWrite))
        {
            qDebug() << "Open OK" << endl;
            // 此处写死为 8-1-N
            //设置波特率
            serial->setBaudRate(115200);
            //设置数据位
            serial->setDataBits(QSerialPort::Data8);
            //设置校验位
            serial->setParity(QSerialPort::NoParity);
            //设置流控制
            serial->setFlowControl(QSerialPort::NoFlowControl);
            //设置停止位
            serial->setStopBits(QSerialPort::OneStop);

            connect(serial, SIGNAL(readyRead()), this, SLOT(recv_data()));
        }
        else
        {
            qDebug() << "Open Failed" << endl;
        }

    }
    else
    {
        ui->pushButton_OpenSerial->setText(tr("打开串口"));
        serial->close();
    }
}

void MainWindow::on_pushButton_SendMsg_clicked()
{
    QString str = ui->textEdit_SendMsg->toPlainText().toLatin1();
    qDebug() << str <<endl;
    serial->write(str.toLatin1());
}

void MainWindow::on_pushButton_ClearRecv_clicked()
{
    ui->textEdit_ReceiveMsg->clear();
}

收尾

其实还有很多其他的功能可以加进去,我就多做了一个【清除接收】…
甚至还有BUG…就是只有打开软件的时候才加载已有COM口,所以还要加上点击下拉框的时候就扫描更新一遍。
此时的波特率、停止位啥的都是写死的,所以真正要做完的话,还需要把这些控件都做上
还有等等等等…
哈哈 主要功能做出来了,其他的往上添加就好了。
打包exe教程 https://blog.csdn.net/syzdev/article/details/80860619
over…



你可能感兴趣的:(QT)