QT串口助手(二):参数配置

作者:zzssdd2

E-mail:zzssdd2@foxmail.com

一、前言

开发环境:Qt5.12.10 + MinGW

主要实现功能

  • 串口参数的配置:波特率数据位停止位校验位
  • 本机串口设备的查询与添加显示
  • 串口设备的手动更新与打开关闭

涉及的知识点

  • 串口类QSerialPortQSerialPortInfo的使用
  • 自定义波特率的实现
  • QComboBox下拉列表自适应文本长度显示
  • 控件QPushButtonQComboBox的使用
    在这里插入图片描述

二、功能实现

下面开始逐步讲解以上列举的功能

2.1、串口设备的查询添加

创建一个串口设备信息列表和串口设备号列表,遍历本机可用串口然后添加到列表中,将设备信息列表显示在对应的QComboBox控件中,设备号列表用来后面打开串口设备使用。

/* 遍历可用串口设备 */
QStringList SerialPort_Name;
foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
{
    SerialPort_Name << info.portName()+':'+info.description();
    serialDevice << info.portName();
}
/* 添加到串口设备显示框 */
ui->SerialNum_Box->addItems(SerialPort_Name);

2.2、下拉列表自适应

此时已经将串口设备信息添加到下拉框中了,但是下拉框此时是固定长度,如果串口设备信息比较长则无法显示完全(以省略号展示),那么就需要实现下拉框根据设备信息字符串长度适配功能。原理就是遍历列表中所有设备信息字符串的长度,找出最大值然后将下拉框长度设置到能完全显示最大长度字符串。

/* 获取最长字符串 */
int maxlen = 0;
for (int index = 0; index < ui->SerialNum_Box->count(); index++)
{
    if (ui->SerialNum_Box->itemText(index).length() > maxlen)
    {
        maxlen = ui->SerialNum_Box->itemText(index).length();
    }
}
/*获取字体磅值转换为像素值*/
int fontsize = ui->SerialNum_Box->font().pointSize();//获取字体的磅值
ui->SerialNum_Box->view()->setFixedWidth(fontsize * maxlen * 0.75);//设置像素值

这里涉及字体磅与像素对应关系,因为setFixedWidth函数参数单位是像素。下面列出字号不同单位对照表:

中文字号英文字号(磅)毫米像素
1英寸72pt25.30mm95.6px
大特号63pt22.14mm83.7px
特号54pt18.97mm71.7px
初号42pt14.82mm56px
小初36pt12.70mm48px
一号26pt9.17mm34.7px
小一24pt8.47mm32px
二号22pt7.76mm29.3px
小二18pt6.35mm24px
三号16pt5.64mm21.3px
小三15pt5.29mm20px
四号14pt4.94mm18.7px
小四12pt4.23mm16px
五号10.5pt3.70mm14px
小五9pt3.18mm12px
六号7.5pt2.56mm10px
小六6.5pt2.29mm8.7px
七号5.5pt1.94mm7.3px
八号5pt1.76mm6.7px

由上表可知:1inch = 72pt,那么1pt = 1 / 72(inch),我们使用的9pt字号就是9 * (1 / 72) = 1 / 8(inch).

DPI(dots per inch)表示每英寸能够打印的格点数量(可以理解为像素点数),这个值一般默认值为96。在小字体模式下分辨率是96DPI(大字体模式下分辨率是120DPI),也就是说每英寸能显示96个像素,由此可以算出我们使用的9pt字号对应像素:96dpi / (1 / 8)inch = 12px,那么1px = 9pt / 12px = 0.75pt。

添加该功能后前后对比:
在这里插入图片描述

2.3、串口参数的配置

这部分功能实现串口参数的配置,主要有波特率、数据位、停止位、校验位等,根据下拉框选择的参数进行配置。

/* 设置波特率 */
switch (ui->Bandrate_Box->currentIndex())
{
    case 0:
        serial->setBaudRate(QSerialPort::Baud1200,QSerialPort::AllDirections);
        break;
    case 1:
        serial->setBaudRate(QSerialPort::Baud2400,QSerialPort::AllDirections);
        break;
    case 2:
        serial->setBaudRate(QSerialPort::Baud4800,QSerialPort::AllDirections);
        break;
    case 3:
        serial->setBaudRate(QSerialPort::Baud9600,QSerialPort::AllDirections);
        break;
    case 4:
        serial->setBaudRate(QSerialPort::Baud19200,QSerialPort::AllDirections);
        break;
    case 5:
        serial->setBaudRate(QSerialPort::Baud38400,QSerialPort::AllDirections);
        break;
    case 6:
        serial->setBaudRate(QSerialPort::Baud57600,QSerialPort::AllDirections);
        break;
    case 7:
        serial->setBaudRate(QSerialPort::Baud115200,QSerialPort::AllDirections);
        break;
    case 8:
        /*自定义波特率*/
    default:
        break;
}
/* 设置数据位 */
switch (ui->Databit_Box->currentIndex()) {
    case 0:
        serial->setDataBits(QSerialPort::Data5);
        break;
    case 1:
        serial->setDataBits(QSerialPort::Data6);
        break;
    case 2:
        serial->setDataBits(QSerialPort::Data7);
        break;
    case 3:
        serial->setDataBits(QSerialPort::Data8);
        break;
    default:
        break;
}
/* 设置停止位 */
switch (ui->Stopbit_Box->currentIndex()) {
    case 0:
        serial->setStopBits(QSerialPort::OneStop);
        break;
    case 1:
        serial->setStopBits(QSerialPort::OneAndHalfStop);
        break;
    case 2:
        serial->setStopBits(QSerialPort::TwoStop);
        break;
    default:
        break;
}
/* 设置校验位 */
switch (ui->Parity_Box->currentIndex()) {
    case 0:
        serial->setParity(QSerialPort::NoParity);
        break;
    case 1:
        serial->setParity(QSerialPort::EvenParity);
        break;
    case 2:
        serial->setParity(QSerialPort::OddParity);
        break;
    default:
        break;
}
/* 设置流控制 */
serial->setFlowControl(QSerialPort::NoFlowControl);

2.4、自定义波特率

在QT的源码文件qserialport.h中枚举了常用的波特率:

    enum BaudRate {
        Baud1200 = 1200,
        Baud2400 = 2400,
        Baud4800 = 4800,
        Baud9600 = 9600,
        Baud19200 = 19200,
        Baud38400 = 38400,
        Baud57600 = 57600,
        Baud115200 = 115200,
        UnknownBaud = -1
    };

但是如果没有列出我们用到的波特率,那么就需要实现自定义波特率(比如我以前参与的一个项目就要求串口使用500000bps波特率)。实现方式就是将波特率QComboBox列表最后一项设置为自定义波特率,当使用自定义波特率时则获取填写的自定义值并转换为qint32类型数值,然后将该参数设置为波特率,如下:

qint32 CustomBandrate = ui->Bandrate_Box->currentText().toUInt();
serial->setBaudRate(CustomBandrate, QSerialPort::AllDirections);

这里需要注意的是波特率列表自定义项之前的都是对应的固定波特率值,如果不是选择自定义波特率应当设置为不可编辑状态,只有选择自定义波特率时才可以编辑。这里使用QComboBox的信号currentIndexChanged触发槽函数实现该功能:如果选择了自定义波特率,则将下拉框设为可编辑,否则设为不能编辑

/*下拉项改变信号槽:重载函数若有多种不同参数类型则使用信号槽连接时有必要指定参数类型*/
connect(ui->Bandrate_Box, QOverload<int>::of(&QComboBox::currentIndexChanged),[=](int index){
    if (index == 8) {
        ui->Bandrate_Box->setEditable(true);
        ui->Bandrate_Box->setCurrentText(NULL);
    } else {
        ui->Bandrate_Box->setEditable(false);
    }
});

参数配置列表完成如下:
在这里插入图片描述

2.5、串口打开与关闭

串口开关按钮点击信号对应的槽函数实现内容如下:

/*
    函   数:on_SerialPortSwitch_Bt_clicked
    描   述:开关串口按键点击槽函数
    输   入:无
    输   出:无
*/
void Widget::on_SerialPortSwitch_Bt_clicked()
{
    if (ui->SerialPortSwitch_Bt->text() == "打开")
    {
        /* 创建串口对象 */
        serial = new QSerialPort(this);
        /* 创建接收数据信号槽 */
        connect(serial, &QSerialPort::readyRead, this, &Widget::SerialPortReadyRead_slot);
        /* 设置串口号 */
        QString dev = serialDevice.at(ui->SerialNum_Box->currentIndex());
        serial->setPortName(dev);
        /* 设置波特率 */
        /* 设置数据位 */
        /* 设置停止位 */
        /* 设置校验位 */
        /* 设置流控制 */
        /* 打开串口 */
        if (serial->open(QIODevice::ReadWrite) != true)
        {
            QMessageBox::critical(this, "提示", "打开失败");
            return;
        }
        /*标记串口已打开*/
        global_struct.isSerialOpen = true;
        /*设置文本*/
        ui->SerialPortSwitch_Bt->setText("关闭");
    }
    else
    {
        /*关闭并删除串口对象*/
        serial->close();
        serial->deleteLater();
        /*标记串口已关闭*/
        global_struct.isSerialOpen = false;
        /*设置文本*/
        ui->SerialPortSwitch_Bt->setText("打开");
    }
}

2.6、串口设备的刷新

串口设备刷新按钮点击信号对应的槽函数功能实现如下:

/*
    函   数:on_ComFlush_BT_clicked
    描   述:串口设备刷新按钮槽函数
    输   入:无
    输   出:无
*/
void Widget::on_ComFlush_BT_clicked()
{
    ui->SerialNum_Box->clear();
    FindSerialPort();
}

/*
    函   数:FindSerialPort
    描   述:查找串口并添加到QComboBox
    输   入:无
    输   出:无
*/
void Widget::FindSerialPort(void)
{
    /* 遍历可用串口并添加到显示框 */
    QStringList SerialPort_Name;
    foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
    {
        SerialPort_Name << info.portName()+':'+info.description();
        serialDevice << info.portName();
    }
    ui->SerialNum_Box->addItems(SerialPort_Name);
    /*设置下拉框列表宽度*/
    int maxlen = 0;
    for (int index = 0; index < ui->SerialNum_Box->count(); index++)
    {
        if (ui->SerialNum_Box->itemText(index).length() > maxlen)
        {
            maxlen = ui->SerialNum_Box->itemText(index).length();
        }
    }
    int fontsize = ui->SerialNum_Box->font().pointSize();
    ui->SerialNum_Box->view()->setFixedWidth(fontsize * maxlen * 0.75);
}

三、总结

本篇文章主要是讲如何对串口参数进行配置及QComboBox等控件的一些基本操作。除此之外,还应该了解一定C++知识,比如类的继承、函数重载、Lambda表达式等;还有就是应该掌握QT信号槽的使用,因为这是QT框架中非常重要的通信机制,可以说使用QT开发必然离不开信号槽的应用。

  • 2
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值