野火电子论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 7879|回复: 2

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

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

@TOC

简单串口编写

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多线程的使用记录中的方式二。

初始化ui界面参数

在开始工作前需要初始化ui界面的参数,如设置QCombobox的下拉框内容。因此需要创建一个void initUI(void);函数。打开mainwidget.h,添加我们需要创建的函数,并使用快捷键<kbd>alt</kbd>+<kbd>enter</kbd>,在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&lt;&lt;"1200"&lt;&lt;"2400"&lt;&lt;"4800"&lt;&lt;"9600"&lt;&lt;"19200"&lt;&lt;"38400"
                &lt;&lt;"57600"&lt;&lt;"115200";
     ui-&gt;comBaudRate-&gt;addItems(baudrateList); //将设置的Item加入到列表中
     ui-&gt;comBaudRate-&gt;setEditable(true); //设置可以手动输入波特率
     //限定波特率手动输入时只能输入数字且范围为(0, 1000000)即最高1M
     isBaudRateRange= new QIntValidator; //防止内存泄漏,关闭窗口时 delete aIntValidator;
     isBaudRateRange-&gt;setRange(0, 1000000);
     ui-&gt;comBaudRate-&gt;setValidator(isBaudRateRange);
     ui-&gt;comBaudRate-&gt;setCurrentIndex(3);  //设置默认显示第4个即9600(从0开始)

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

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

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

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

}

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

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

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

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

}

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

利用QSerialPortInfo得到串口号

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

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

实现步骤:

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

具体内容如下:

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

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

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

打开mainwidget.h,添加 #include < QMessageBox > , 然后重新封装函数 void message(const char str); ,并使用快捷键<kbd>alt</kbd>+<kbd>enter</kbd>,在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(); 函数仅在打开程序时运行一次,因此,这里需要增加更新端口号的方法。

实现方法:

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

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

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

具体内容如下:

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

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

}

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

回复

使用道具 举报

发表于 2021-10-30 14:23:54 | 显示全部楼层
可以写个定时器实时刷新串口号
回复 支持 反对

使用道具 举报

 楼主| 发表于 2021-11-9 10:10:35 | 显示全部楼层
Memory# 发表于 2021-10-30 14:23
可以写个定时器实时刷新串口号

懒得写定时器了 直接按钮
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-11-21 17:41 , Processed in 0.042425 second(s), 24 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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