野火电子论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 7345|回复: 1

QT5串口上位机——从零开始教你写03

[复制链接]
发表于 2021-10-29 22:46:24 | 显示全部楼层 |阅读模式
  • @




    [size=1.3em]简单串口编写3.线程类对象的添加和UI界面的参数设置 添加任务类对象和线程类对象

    打开工程,选择mainwidget.h,添加我们创建的类Serial和线程类QThread

    内容如下:

    #ifndef MAINWIDGET_H
    #define MAINWIDGET_H

    #include <QWidget>
    #include "serial.h"  //添加自定义类serial头文件
    #include <QThread>   //添加线程类QThread头文件

    QT_BEGIN_NAMESPACE
    namespace Ui { class MainWidget; }
    QT_END_NAMESPACE

    class MainWidget : public QWidget
    {
        Q_OBJECT

    public:
        MainWidget(QWidget *parent = nullptr);
        ~MainWidget();
        QThread *t1;    //1.创建子线程对象
        Serial *m_work; //2.创建任务类对象
       
    private:
        Ui::MainWidget *ui;

    };
    #endif // MAINWIDGET_H

    mainwidget.cpp中将创建的对象实例化,并将任务函数移入子线程。

    内容如下:

    #include "mainwidget.h"
    #include "ui_mainwidget.h"

    MainWidget::MainWidget(QWidget *parent)
        : QWidget(parent)
        , ui(new Ui::MainWidget)
    {
        ui->setupUi(this);
       
        //1.创建子线程对象,动态分配空间,指定父对象
        t1 = new QThread(this);
        //2.创建任务类对象,动态分配空间,不能指定父对象
        m_work = new Serial;//防止内存泄漏,关闭窗口时 delete m_work;
        //3.将任务对象移动到某个子线程中
        m_work->moveToThread(t1);
       
    }

    MainWidget::~MainWidget()
    {
        delete ui;
        delete m_work;  //关闭时释放内存空间
    }

    注:这里线程操作参考之前的文章Qt多线程的使用记录[1]中的方式二。

    初始化ui界面参数

    在开始工作前需要初始化ui界面的参数,如设置QCombobox的下拉框内容。因此需要创建一个void initUI(void);函数。打开mainwidget.h,添加我们需要创建的函数,并使用快捷键alt+enter,在mainwidget.cpp中定义void initUI(void);函数。

    设置内容如下:

    public:
        MainWidget(QWidget *parent = nullptr);
        ~MainWidget();
        QThread *t1;    //1.创建子线程对象
        Serial *m_work; //2.创建任务类对象
        void initUI();  //初始化UI界面参数,如设置QCombobox的item和设置QSS样式。

    其中 void initUI(); 函数内容如下。

    void MainWidget::initUI()
    {
         QStringList baudrateList; //设置波特率列表
         baudrateList<<"1200"<<"2400"<<"4800"<<"9600"<<"19200"<<"38400"
                    <<"57600"<<"115200";
         ui->comBaudRate->addItems(baudrateList); //将设置的Item加入到列表中
         ui->comBaudRate->setEditable(true); //设置可以手动输入波特率
         //限定波特率手动输入时只能输入数字且范围为(0, 1000000)即最高1M
         isBaudRateRange= new QIntValidator; //防止内存泄漏,关闭窗口时 delete aIntValidator;
         isBaudRateRange->setRange(0, 1000000);
         ui->comBaudRate->setValidator(isBaudRateRange);
         ui->comBaudRate->setCurrentIndex(3);  //设置默认显示第4个即9600(从0开始)

         QStringList databitsList; //设置数据位列表,根据串口中配置顺序设置。
         databitsList<<"5"<<"6"<<"7"<<"8";
         ui->comDataBits->addItems(databitsList); //将设置的Item加入到列表中
         ui->comDataBits->setCurrentIndex(3);  //设置默认显示第4个即8bit(从0开始)

         QStringList parityList; //设置校验位列表,根据串口中配置顺序设置。
         parityList<<"Even"<<"Mark"<<"None"<<"Odd"<<"Space";
         ui->comParity->addItems(parityList); //将设置的Item加入到列表中
         ui->comParity->setCurrentIndex(2);  //设置默认显示第3个即None(从0开始)

         QStringList stopbitsList; //设置停止位列表,根据串口中配置顺序设置。
         stopbitsList<<"1"<<"1.5"<<"2";
         ui->comStopBits->addItems(stopbitsList); //将设置的Item加入到列表中
         ui->comStopBits->setCurrentIndex(0);  //设置默认显示第1个即1bit(从0开始)

         QStringList encodeList; //设置编码格式列表,根据编码格式中配置顺序设置。
         encodeList<<"ASCII"<<"UTF8"<<"UTF16"<<"GBK"<<"Big5"<<"ShiftJIS";
         ui->comEncode->addItems(encodeList); //将设置的Item加入到列表中
         ui->comEncode->setCurrentIndex(0);  //设置默认显示第1个即ASCII(从0开始)

    }

    注:

    • 其中需要在mainwidget.h中添加   #include < QStringList > ;
    • 配置的item参数需要同之前switch设置的参数顺序相同。
    • 要在mainwidget.h中添加   #include < QIntValidator >;并创建一个私有成员,QIntValidator isBaudRateRange;*

    设置完成后在MainWidget中运行 initUI(); 函数

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

        //0.初始化ui界面;
        initUI();
        //1.创建子线程对象,动态分配空间,指定父对象
        t1 = new QThread(this);
        //2.创建任务类对象,动态分配空间,不能指定父对象
        m_work = new Serial;//防止内存泄漏,关闭窗口时 delete m_work;
        //3.将任务对象移动到某个子线程中
        m_work->moveToThread(t1);

    }

    至此,QCombobox 参数初始化完成。(后期仍会在 initUI() 中进行其他配置如设置QSS样式等)。

    利用QSerialPortInfo得到串口号

    这里我们会发现并没有设置串口的Item参数。主要原因是,电脑再识别设备的串口号时,会任意分配可用的端口号,因此这里我们通过使用QSerialPortInfo类来得到可用端口号,并设置到串口的Item中。

    首先,打开mainwidget.h,添加 #include < QSerialPortInfo> , 然后创建 void getportInfo(); 函数,并使用快捷键alt+enter,在mainwidget.cpp 中定义 void getportInfo(); 函数。

    实现步骤:

    首先检测可用的设备端口号,当存在可用的端口号时,通过遍历的方式,将可用的端口号保存在portStringList中。然后设置到串口的Item中。无可用端口号时,弹出信号框。

    具体内容如下:

    void MainWidget::getportInfo()
    {
        qint32 comCnt=0; //保存当前可用的串口数量
        QStringList portStringList; //保存当前可用的串口列表

        if(portStringList.length()!=0)
        {
          portStringList.clear();//检测portStringList内容当不为空时清除再次调用时使用
        }
        if(ui->comPortName->count()!=0)
        {
            ui->comPortName->clear();//检测comPortName的列表数量当不为空时清除再次调用时使用
        }
        //获取串口设备数量
        comCnt = QSerialPortInfo::availablePorts().length();
        if(comCnt!=0)
        {
           //获取串口信息
           foreach (const QSerialPortInfo &qspinfo, QSerialPortInfo::availablePorts())
           {
                portStringList+=qspinfo.portName();
           }
           ui->comPortName->addItems(portStringList);
        }
        else{   
            message("未检测到串口!");
            }
    }

    注:

    • 其中message();为自己重新封装的信号框函数,具体内容见下。

    打开mainwidget.h,添加 #include < QMessageBox > , 然后重新封装函数 void message(const char *str); ,并使用快捷键alt+enter,在mainwidget.cpp 中定义 void message(const char *str);函数。

    具体内容如下:

    void MainWidget::message(const char *str)
    {
        QMessageBox msgBox;
        msgBox.setText(QString::fromLocal8Bit(str));
        msgBox.exec();
    }

    然后在MainWidget中运行 getportInfo(); 函数

    这里要注意,在拔插串口设备时,可用的端口号会产生变化,但 getportInfo(); 函数仅在打开程序时运行一次,因此,这里需要增加更新端口号的方法。

    实现方法:

    • 添加检测拔插设备的函数,当设备变化时重新运行getportInfo();
    • 使用定时器,设定每100ms检测一次,当设备变化时重新运行getportInfo();
    • 增加按钮,当点击按钮时重新运行getportInfo();

    这里选择增加按钮的方法,主要原因是简单且不占用资源。

    增加按钮的信号与槽,当点击按钮时,重新运行getportInfo();

    具体内容如下:

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

        //0.初始化ui界面;配置qss样式
        initUI();
        //1.创建子线程对象,动态分配空间,指定父对象
        t1 = new QThread(this);
        //2.创建任务类对象,动态分配空间,不能指定父对象
        m_work = new Serial;//防止内存泄漏,关闭窗口时 delete m_work;
        //3.将任务对象移动到某个子线程中
        m_work->moveToThread(t1);
        //4.获取串口设备信息
        getportInfo();
            //添加更新按钮信号与槽,用于更新串口设备信息
            connect(ui->upBtn,&QPushButton::clicked,this,&MainWidget::getportInfo);

    }

    至此,利用QSerialPortInfo得到串口号完成。

    参考资料[1]

    Qt多线程的使用记录: https://blog.csdn.net/qq_39538318/article/details/120398160

回复

使用道具 举报

发表于 2021-10-30 14:24:40 | 显示全部楼层
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

联系站长|手机版|野火电子官网|野火淘宝店铺|野火电子论坛 ( 粤ICP备14069197号 ) 大学生ARM嵌入式2群

GMT+8, 2024-4-24 09:43 , Processed in 0.045959 second(s), 23 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表