【QT串口助手】

news2024/11/26 2:31:14

首先非常感谢CSDN吾爱技术圈分享的QT初体验:手把手带你写一个自己的串口助手,本教程重点参考

1. 前言

由于qt应用项目需求,前期也安装过QT(参考博客:【Qt安装与简易串口控制Arduino开发板小灯教程】),这次就好好来学习QT串口助手制作,该应用有基本串口设置和收发功能,可以深刻理解按键,数据交互的信号槽机制,不免有许多模块功能组件设计,最后还需要排版设计优化。本文记录一下用QT Creator 写一个基本功能齐全的串口助手的过程,整个工程只有几百行代码,跟着做下来对新手来说可以更快了解整个QT项目的开发过程和一些常用控件的使用方法。最好每个功能自己都试试增加自信心!
💕💕💕
先来看看作品:
在这里插入图片描述

2. 制作过程

2.1. 布局UI界面

(1) 创建QMainWindow工程。这一步就不赘述了,参考:【Qt安装与简易串口控制Arduino开发板小灯教程】

创建项目时项目名称可以设为Serial,基类可以选择QMainWindow。注意默认勾选“Generate form”,生成 ui 窗体文件 mainwindow.ui 后面要用到。完成后项目文件展示:

在这里插入图片描述

(2)双击mainwindow.ui打开UI布局界面,从左侧控件选择区找到需要的控件拖动到界面设计区的对应位置
(请注意:以下提到的摆放位置只放大概位置即可,因为必须借用布局工具才能规正)

  1. 找到Label控件,用于显示:
    在这里插入图片描述

用8个Lable控件分别按下图所示红框位置摆放,并且双击改显示的文字,或单击选择对应Lable后在其右边属性设置界面里的text属性更改

在这里插入图片描述

  1. 找到Combo Box控件:
    在这里插入图片描述

用5个Combo Box控件分别按下图绿色框所示位置摆放
在这里插入图片描述

  1. 找到Push Button控件,按键事件触发:
    在这里插入图片描述

用5个Push Button控件分别按下图紫色框所示位置摆放,并且双击按钮改显示的文字
在这里插入图片描述

  1. 找到Check Box控件,检查框设计模式配置属性:
    在这里插入图片描述

用6个Check Box控件分别按下图蓝色框所示位置摆放,并且双击更改显示的文字
在这里插入图片描述

  1. 用1个Spin Box控件分别按下图棕色框所示位置摆放并调整大小
    在这里插入图片描述

  2. 最后两个大的白色区域就是接收框和发送输入框,上面接收框用Plain Text Edit控件,下面输入框用Text Edit控件
    在这里插入图片描述

接收框用的Plain Text Edit控件需要更改属性为只读

在这里插入图片描述

2.2 添加下拉列表项

5个Combo Box控件分别双击添加列表项(端口对应的Combo Box不用改)

波特率:
(点击绿色加号即可添加)

在这里插入图片描述

数据位:

在这里插入图片描述

停止位:

校验位:
在这里插入图片描述

对于波特率和数据位的下拉列表控件还需要通过更改属性currentIndex属性,改变默认值。波特率默认9600,数据位默认8。

在这里插入图片描述

2.3 修改控件名称

下面对控件进行改名,以便对应程序中的对象名,用默认名不直观。

如何改名?
点击控件,找到界面右边属性栏的objectName。
在这里插入图片描述名称参考下图:

在这里插入图片描述

注意这一步一定要把对象名设置对,否则在编译程序时会有问题。不过建议大家根据自己的习惯命名,方便快速查找,下面会给出全部文件。

2.4. 利用布局工具

第一步放置控件的时候,想必就会发现根本很难通过鼠标拖动的方法完成对齐,这时还得用上方菜单栏的布局工具:
在这里插入图片描述

下图中的红框就是布局后才显示的:
在这里插入图片描述

操作方法是先手动把控件摆放到大概位置,然后鼠标左键拉一个框选定几个控件,再点击上面的布局工具。
接收设置和发送设置就是用了栅格布局,发送和清空发送按钮是垂直布局,串口设置中是上面部分是栅格布局,然后整体再用垂直布局。布局后的红框还可以调整大小。最后这4个框是Group Box控件,双击就可以改文字。为啥把这步放最后了是因为发现Group Box控件放上去后直接选不了里面的控件了,暂时不知道怎么操作。这里跟VS里不一样,VS就比较方便
在这里插入图片描述

3. 编写程序

main.cpp不需要修改,双击打开.pro文件

在这里插入图片描述

core gui后面添加serialport,即 QT += core gui serialport

QT       += core gui serialport

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++11

# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    main.cpp \
    mainwindow.cpp

HEADERS += \
    mainwindow.h

FORMS += \
    mainwindow.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

3.1 mainwindow.h文件源码:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QSerialPort>
#include <QString>
#include <QSerialPortInfo>
#include <QMessageBox>
#include <QTimer>
#include <QTime>
#include <QPainter>
#include <QDebug>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

    QSerialPort *serialPort;//定义串口指针


private slots:
    //    void on_button_openserial_clicked();

    /*手动连接槽函数*/
    void manual_serialPortReadyRead();

    void on_chkTimSend_stateChanged(int arg1);
    /*以下为mainwindow.ui文件中点击“转到槽”自动生成的函数*/
    void on_Serial_check_Bt_clicked();

    void on_open_serial_Bt_clicked();

    void on_send_Bt_clicked();

    void on_clear_recv_Bt_clicked();

    void on_clear_send_Bt_clicked();


private:
    Ui::MainWindow *ui;

    // 发送、接收字节计数
    long sendNum, recvNum;
    QLabel *lblSendNum;
    QLabel *lblRecvNum;
    QLabel *lblPortState;
    void setNumOnLabel(QLabel *lbl, QString strS, long num);

    // 定时发送-定时器
    QTimer *timSend;

};
#endif // MAINWINDOW_H

3.2 mainwindow.cpp文件源码:

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "QSerialPortInfo"
#include <QSerialPort>
#include <QMessageBox>
#include <QDateTime>
#include <QStatusBar>
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    QStringList serialNamePort;
    serialPort = new QSerialPort(this);
    connect(serialPort,SIGNAL(readyRead()),this,SLOT(manual_serialPortReadyRead()));/*手动连接槽函数*/

    /*找出当前连接的串口并显示到serailCb*/
    //foreach(const QSerialPortInfo &info,QSerialPortInfo::availablePorts())
    //{
    //serialNamePort<<info.portName();// 自动扫描当前可用串口,返回值追加到字符数组中
    //}
    //ui->serailCb->addItems(serialNamePort);// 可用串口号,显示到串口选择下拉框中
    ui->serial_Cb->clear();
    //通过QSerialPortInfo查找可用串口
    foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
    {
        ui->serial_Cb->addItem(info.portName());
    }

    // 发送、接收计数清零
    sendNum = 0;
    recvNum = 0;
    // 状态栏
    QStatusBar *sBar = statusBar();
    // 状态栏的收、发计数标签
    lblSendNum = new QLabel(this);
    lblRecvNum = new QLabel(this);
    lblPortState = new QLabel(this);
    lblPortState->setText("Connected");
    //设置串口状态标签为绿色 表示已连接状态
    lblPortState->setStyleSheet("color:red");

    // 设置标签最小大小
    lblSendNum->setMinimumSize(100, 20);
    lblRecvNum->setMinimumSize(100, 20);
    lblPortState->setMinimumSize(550, 20);
    setNumOnLabel(lblSendNum, "S: ", sendNum);
    setNumOnLabel(lblRecvNum, "R: ", recvNum);
    // 从右往左依次添加
    sBar->addPermanentWidget(lblPortState);
    sBar->addPermanentWidget(lblSendNum);
    sBar->addPermanentWidget(lblRecvNum);

    // 定时发送-定时器
    timSend = new QTimer;
    timSend->setInterval(1000);// 设置默认定时时长1000ms
    connect(timSend, &QTimer::timeout, this, [=](){
        on_send_Bt_clicked();
    });

}

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




void MainWindow::on_Serial_check_Bt_clicked()
{
    ui->serial_Cb->clear();
    //通过QSerialPortInfo查找可用串口
    foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
    {
        ui->serial_Cb->addItem(info.portName());
    }

}


void MainWindow::on_open_serial_Bt_clicked()
{
    /*串口初始化*/
    QSerialPort::BaudRate baudRate;
    QSerialPort::DataBits dataBits;
    QSerialPort::StopBits stopBits;
    QSerialPort::Parity checkBits;

    // 获取串口波特率
    // baudRate = ui->baundrate_Cb->currentText().toInt();直接字符串转换为 int 的方法

    if(ui->baundrate_Cb->currentText()=="1200")
        baudRate=QSerialPort::Baud1200;
    else if(ui->baundrate_Cb->currentText()=="2400")
        baudRate=QSerialPort::Baud2400;
    else if(ui->baundrate_Cb->currentText()=="4800")
        baudRate=QSerialPort::Baud4800;
    else if(ui->baundrate_Cb->currentText()=="9600")
        baudRate=QSerialPort::Baud9600;
    else if(ui->baundrate_Cb->currentText()=="19200")
        baudRate=QSerialPort::Baud19200;
    else if(ui->baundrate_Cb->currentText()=="38400")
        baudRate=QSerialPort::Baud38400;
    else if(ui->baundrate_Cb->currentText()=="57600")
        baudRate=QSerialPort::Baud57600;
    else if(ui->baundrate_Cb->currentText()=="115200")
        baudRate=QSerialPort::Baud115200;

    // 获取串口数据位
    if(ui->databit_Cb->currentText()=="5")
        dataBits=QSerialPort::Data5;
    else if(ui->databit_Cb->currentText()=="6")
        dataBits=QSerialPort::Data6;
    else if(ui->databit_Cb->currentText()=="7")
        dataBits=QSerialPort::Data7;
    else if(ui->databit_Cb->currentText()=="8")
        dataBits=QSerialPort::Data8;

    // 获取串口停止位
    if(ui->stopbit_Cb->currentText()=="1")
        stopBits=QSerialPort::OneStop;
    else if(ui->stopbit_Cb->currentText()=="1.5")
        stopBits=QSerialPort::OneAndHalfStop;
    else if(ui->stopbit_Cb->currentText()=="2")
        stopBits=QSerialPort::TwoStop;

    // 获取串口奇偶校验位
    if(ui->checkbit_Cb->currentText() == "none"){
        checkBits = QSerialPort::NoParity;
    }else if(ui->checkbit_Cb->currentText() == "奇校验"){
        checkBits = QSerialPort::OddParity;
    }else if(ui->checkbit_Cb->currentText() == "偶校验"){
        checkBits = QSerialPort::EvenParity;
    }

    // 初始化串口属性,设置 端口号、波特率、数据位、停止位、奇偶校验位数
    serialPort->setPortName(ui->serial_Cb->currentText());
    serialPort->setBaudRate(baudRate);
    serialPort->setDataBits(dataBits);
    serialPort->setStopBits(stopBits);
    serialPort->setParity(checkBits);

    // 根据初始化好的串口属性,打开串口
    // 如果打开成功,反转打开按钮显示和功能。打开失败,无变化,并且弹出错误对话框。
    if(ui->open_serial_Bt->text() == "打开串口"){
        if(serialPort->open(QIODevice::ReadWrite) == true){
            //QMessageBox::
            ui->open_serial_Bt->setText("关闭串口");
            // 让端口号下拉框不可选,避免误操作(选择功能不可用,控件背景为灰色)
            ui->serial_Cb->setEnabled(false);
        }else{
            QMessageBox::critical(this, "错误提示", "串口打开失败!!!\r\n该串口可能被占用\r\n请选择正确的串口");
        }
        //statusBar 状态栏显示端口状态
        QString sm = "%1 OPENED, %2, 8, NONE, 1";
        QString status = sm.arg(serialPort->portName()).arg(serialPort->baudRate());
        lblPortState->setText(status);
        lblPortState->setStyleSheet("color:green");
    }else{
        serialPort->close();
        ui->open_serial_Bt->setText("打开串口");
        // 端口号下拉框恢复可选,避免误操作
        ui->serial_Cb->setEnabled(true);
        //statusBar 状态栏显示端口状态
        QString sm = "%1 CLOSED";
        QString status = sm.arg(serialPort->portName());
        lblPortState->setText(status);
        lblPortState->setStyleSheet("color:red");
    }

}


void MainWindow::on_send_Bt_clicked()
{
    QByteArray array;

    //Hex复选框
    if(ui->send_hex_Chb->checkState() == Qt::Checked){
        //array = QString2Hex(data);  //HEX 16进制
        array = QByteArray::fromHex(ui->textEdit_send->toPlainText().toUtf8()).data();
    }else{
        //array = data.toLatin1();    //ASCII
        array = ui->textEdit_send->toPlainText().toLocal8Bit().data();
    }

    if(ui->send_line_Chb->checkState() == Qt::Checked){
        array.append("\r\n");
    }
    // 如发送成功,会返回发送的字节长度。失败,返回-1。
    int a = serialPort->write(array);
    // 发送字节计数并显示
    if(a > 0)
    {
        // 发送字节计数
        sendNum += a;
        // 状态栏显示计数值
        setNumOnLabel(lblSendNum, "S: ", sendNum);
    }
}


void MainWindow::on_clear_recv_Bt_clicked()
{
    ui->textEdit_recv->clear();
    // 清除接收字节计数
    sendNum = 0;
    // 状态栏显示计数值
    setNumOnLabel(lblSendNum, "S: ", sendNum);
}


void MainWindow::on_clear_send_Bt_clicked()
{
    ui->textEdit_send->clear();
    // 清除发送字节计数
    sendNum = 0;
    // 状态栏显示计数值
    setNumOnLabel(lblSendNum, "S: ", sendNum);
}

// 定时发送开关 选择复选框
void MainWindow::on_chkTimSend_stateChanged(int arg1)
{
    // 获取复选框状态,未选为0,选中为2
    if(arg1 == 0){
        timSend->stop();
        // 时间输入框恢复可选
        ui->txtSendMs->setEnabled(true);
    }else{
        // 对输入的值做限幅,小于10ms会弹出对话框提示
        if(ui->txtSendMs->text().toInt() >= 10){
            timSend->start(ui->txtSendMs->text().toInt());// 设置定时时长,重新计数
            // 让时间输入框不可选,避免误操作(输入功能不可用,控件背景为灰色)
            ui->txtSendMs->setEnabled(false);
        }else{
            ui->autosend_Chb->setCheckState(Qt::Unchecked);
            QMessageBox::critical(this, "错误提示", "定时发送的最小间隔为 10ms\r\n请确保输入的值 >=10");
        }
    }
}



/*手动实现接收数据函数*/
void MainWindow::manual_serialPortReadyRead()
{
    QByteArray recBuf = serialPort->readAll();

    QString str_rev;

    // 接收字节计数
    recvNum += recBuf.size();
    // 状态栏显示计数值
    setNumOnLabel(lblRecvNum, "R: ", recvNum);

    if(ui->recv_hex_Chb->checkState() == false){
        if(ui->recv_time_Chb->checkState() == Qt::Checked){
            QDateTime nowtime = QDateTime::currentDateTime();
            str_rev = "[" + nowtime.toString("yyyy-MM-dd hh:mm:ss") + "] ";
            str_rev += QString(recBuf).append("\r\n");
        }
        else{
            // 在当前位置插入文本,不会发生换行。如果没有移动光标到文件结尾,会导致文件超出当前界面显示范围,界面也不会向下滚动。
            //ui->recvEdit->appendPlainText(buf);

            if(ui->recv_autoline_Chb->checkState() == Qt::Checked){
                str_rev = QString(recBuf).append("\r\n");
            }
            else
            {
                str_rev = QString(recBuf);
            }
        }
    }else{

        // 16进制显示,并转换为大写
        QString str1 = recBuf.toHex().toUpper();//.data();
        // 添加空格
        QString str2;
        for(int i = 0; i<str1.length (); i+=2)
        {
            str2 += str1.mid (i,2);
            str2 += " ";
        }
        if(ui->recv_time_Chb->checkState() == Qt::Checked)
        {
            QDateTime nowtime = QDateTime::currentDateTime();
            str_rev = "[" + nowtime.toString("yyyy-MM-dd hh:mm:ss") + "] ";
            str_rev += str2.append("\r\n");
        }
        else
        {
            if(ui->recv_autoline_Chb->checkState() == Qt::Checked)
                str_rev += str2.append("\r\n");
            else
                str_rev = str2;

        }
    }
    ui->textEdit_recv->insertPlainText(str_rev);
    ui->textEdit_recv->moveCursor(QTextCursor::End);

}


// 状态栏标签显示计数值
void MainWindow::setNumOnLabel(QLabel *lbl, QString strS, long num)
{
    // 标签显示
    QString strN;
    strN.sprintf("%ld", num);
    QString str = strS + strN;
    lbl->setText(str);
}

3.3 mainwindow.ui源文件

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>581</width>
    <height>541</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <widget class="QGroupBox" name="groupBox">
    <property name="geometry">
     <rect>
      <x>30</x>
      <y>30</y>
      <width>191</width>
      <height>311</height>
     </rect>
    </property>
    <property name="title">
     <string>串口配置</string>
    </property>
    <widget class="QWidget" name="gridLayoutWidget_2">
     <property name="geometry">
      <rect>
       <x>10</x>
       <y>20</y>
       <width>169</width>
       <height>281</height>
      </rect>
     </property>
     <layout class="QGridLayout" name="gridLayout_2">
      <item row="1" column="0">
       <spacer name="verticalSpacer">
        <property name="orientation">
         <enum>Qt::Vertical</enum>
        </property>
        <property name="sizeHint" stdset="0">
         <size>
          <width>20</width>
          <height>40</height>
         </size>
        </property>
       </spacer>
      </item>
      <item row="2" column="0">
       <widget class="QPushButton" name="Serial_check_Bt">
        <property name="minimumSize">
         <size>
          <width>93</width>
          <height>28</height>
         </size>
        </property>
        <property name="text">
         <string>检测串口</string>
        </property>
       </widget>
      </item>
      <item row="3" column="0">
       <widget class="QPushButton" name="open_serial_Bt">
        <property name="minimumSize">
         <size>
          <width>93</width>
          <height>28</height>
         </size>
        </property>
        <property name="text">
         <string>打开串口</string>
        </property>
       </widget>
      </item>
      <item row="0" column="0">
       <layout class="QGridLayout" name="gridLayout" rowstretch="0,0,0,0,0,0" columnstretch="0,0">
        <property name="sizeConstraint">
         <enum>QLayout::SetDefaultConstraint</enum>
        </property>
        <property name="leftMargin">
         <number>0</number>
        </property>
        <property name="topMargin">
         <number>0</number>
        </property>
        <property name="rightMargin">
         <number>0</number>
        </property>
        <property name="bottomMargin">
         <number>0</number>
        </property>
        <property name="horizontalSpacing">
         <number>6</number>
        </property>
        <property name="verticalSpacing">
         <number>0</number>
        </property>
        <item row="3" column="0">
         <widget class="QLabel" name="label_databit">
          <property name="minimumSize">
           <size>
            <width>72</width>
            <height>30</height>
           </size>
          </property>
          <property name="maximumSize">
           <size>
            <width>76</width>
            <height>30</height>
           </size>
          </property>
          <property name="text">
           <string>数据位:</string>
          </property>
         </widget>
        </item>
        <item row="4" column="0">
         <widget class="QLabel" name="label_parity">
          <property name="minimumSize">
           <size>
            <width>72</width>
            <height>30</height>
           </size>
          </property>
          <property name="maximumSize">
           <size>
            <width>76</width>
            <height>30</height>
           </size>
          </property>
          <property name="text">
           <string>校验位:</string>
          </property>
         </widget>
        </item>
        <item row="1" column="1">
         <widget class="QComboBox" name="serial_Cb">
          <property name="minimumSize">
           <size>
            <width>87</width>
            <height>22</height>
           </size>
          </property>
          <property name="maximumSize">
           <size>
            <width>76</width>
            <height>15</height>
           </size>
          </property>
         </widget>
        </item>
        <item row="5" column="0">
         <widget class="QLabel" name="label_stopbit">
          <property name="minimumSize">
           <size>
            <width>72</width>
            <height>30</height>
           </size>
          </property>
          <property name="maximumSize">
           <size>
            <width>76</width>
            <height>30</height>
           </size>
          </property>
          <property name="text">
           <string>停止位:</string>
          </property>
         </widget>
        </item>
        <item row="5" column="1">
         <widget class="QComboBox" name="stopbit_Cb">
          <property name="minimumSize">
           <size>
            <width>87</width>
            <height>22</height>
           </size>
          </property>
          <property name="maximumSize">
           <size>
            <width>76</width>
            <height>15</height>
           </size>
          </property>
          <item>
           <property name="text">
            <string>none</string>
           </property>
          </item>
          <item>
           <property name="text">
            <string>奇校验</string>
           </property>
          </item>
          <item>
           <property name="text">
            <string>偶校验</string>
           </property>
          </item>
         </widget>
        </item>
        <item row="4" column="1">
         <widget class="QComboBox" name="checkbit_Cb">
          <property name="minimumSize">
           <size>
            <width>87</width>
            <height>22</height>
           </size>
          </property>
          <property name="maximumSize">
           <size>
            <width>76</width>
            <height>15</height>
           </size>
          </property>
          <item>
           <property name="text">
            <string>1</string>
           </property>
          </item>
          <item>
           <property name="text">
            <string>1.5</string>
           </property>
          </item>
          <item>
           <property name="text">
            <string>2</string>
           </property>
          </item>
         </widget>
        </item>
        <item row="2" column="1">
         <widget class="QComboBox" name="baundrate_Cb">
          <property name="minimumSize">
           <size>
            <width>87</width>
            <height>22</height>
           </size>
          </property>
          <property name="maximumSize">
           <size>
            <width>76</width>
            <height>15</height>
           </size>
          </property>
          <property name="currentText">
           <string>9600</string>
          </property>
          <property name="currentIndex">
           <number>3</number>
          </property>
          <item>
           <property name="text">
            <string>1200</string>
           </property>
          </item>
          <item>
           <property name="text">
            <string>2400</string>
           </property>
          </item>
          <item>
           <property name="text">
            <string>4800</string>
           </property>
          </item>
          <item>
           <property name="text">
            <string>9600</string>
           </property>
          </item>
          <item>
           <property name="text">
            <string>19200</string>
           </property>
          </item>
          <item>
           <property name="text">
            <string>38400</string>
           </property>
          </item>
          <item>
           <property name="text">
            <string>57600</string>
           </property>
          </item>
          <item>
           <property name="text">
            <string>115200</string>
           </property>
          </item>
         </widget>
        </item>
        <item row="1" column="0">
         <widget class="QLabel" name="label_serialport">
          <property name="minimumSize">
           <size>
            <width>72</width>
            <height>30</height>
           </size>
          </property>
          <property name="maximumSize">
           <size>
            <width>76</width>
            <height>30</height>
           </size>
          </property>
          <property name="text">
           <string>端口号:</string>
          </property>
         </widget>
        </item>
        <item row="2" column="0">
         <widget class="QLabel" name="label_baudrate">
          <property name="minimumSize">
           <size>
            <width>72</width>
            <height>30</height>
           </size>
          </property>
          <property name="maximumSize">
           <size>
            <width>76</width>
            <height>30</height>
           </size>
          </property>
          <property name="text">
           <string>波特率:</string>
          </property>
         </widget>
        </item>
        <item row="3" column="1">
         <widget class="QComboBox" name="databit_Cb">
          <property name="minimumSize">
           <size>
            <width>87</width>
            <height>22</height>
           </size>
          </property>
          <property name="maximumSize">
           <size>
            <width>76</width>
            <height>15</height>
           </size>
          </property>
          <property name="currentText">
           <string>5</string>
          </property>
          <item>
           <property name="text">
            <string>5</string>
           </property>
          </item>
          <item>
           <property name="text">
            <string>6</string>
           </property>
          </item>
          <item>
           <property name="text">
            <string>7</string>
           </property>
          </item>
          <item>
           <property name="text">
            <string>8</string>
           </property>
          </item>
         </widget>
        </item>
       </layout>
      </item>
     </layout>
    </widget>
   </widget>
   <widget class="QGroupBox" name="groupBox_2">
    <property name="geometry">
     <rect>
      <x>30</x>
      <y>350</y>
      <width>191</width>
      <height>81</height>
     </rect>
    </property>
    <property name="title">
     <string>接收设置</string>
    </property>
    <widget class="QWidget" name="formLayoutWidget_2">
     <property name="geometry">
      <rect>
       <x>10</x>
       <y>20</y>
       <width>189</width>
       <height>56</height>
      </rect>
     </property>
     <layout class="QFormLayout" name="formLayout_2">
      <item row="0" column="0">
       <widget class="QPushButton" name="clear_recv_Bt">
        <property name="text">
         <string>清空接收</string>
        </property>
       </widget>
      </item>
      <item row="0" column="1">
       <widget class="QCheckBox" name="recv_hex_Chb">
        <property name="text">
         <string>Hex接收</string>
        </property>
       </widget>
      </item>
      <item row="1" column="0">
       <widget class="QCheckBox" name="recv_time_Chb">
        <property name="text">
         <string>时间戳</string>
        </property>
       </widget>
      </item>
      <item row="1" column="1">
       <widget class="QCheckBox" name="recv_autoline_Chb">
        <property name="text">
         <string>自动换行</string>
        </property>
       </widget>
      </item>
     </layout>
    </widget>
   </widget>
   <widget class="QGroupBox" name="groupBox_3">
    <property name="geometry">
     <rect>
      <x>30</x>
      <y>440</y>
      <width>191</width>
      <height>71</height>
     </rect>
    </property>
    <property name="title">
     <string>发送设置</string>
    </property>
    <widget class="QWidget" name="layoutWidget">
     <property name="geometry">
      <rect>
       <x>10</x>
       <y>20</y>
       <width>183</width>
       <height>49</height>
      </rect>
     </property>
     <layout class="QGridLayout" name="gridLayout_5">
      <item row="0" column="0">
       <widget class="QCheckBox" name="send_hex_Chb">
        <property name="text">
         <string>Hex发送</string>
        </property>
       </widget>
      </item>
      <item row="0" column="1" colspan="2">
       <widget class="QCheckBox" name="send_line_Chb">
        <property name="text">
         <string>发送新行</string>
        </property>
       </widget>
      </item>
      <item row="1" column="0">
       <widget class="QCheckBox" name="autosend_Chb">
        <property name="text">
         <string>自动发送</string>
        </property>
       </widget>
      </item>
      <item row="1" column="1">
       <widget class="QSpinBox" name="txtSendMs">
        <property name="minimumSize">
         <size>
          <width>60</width>
          <height>0</height>
         </size>
        </property>
        <property name="readOnly">
         <bool>false</bool>
        </property>
       </widget>
      </item>
      <item row="1" column="2">
       <widget class="QLabel" name="label_3">
        <property name="text">
         <string>ms</string>
        </property>
       </widget>
      </item>
     </layout>
    </widget>
   </widget>
   <widget class="QGroupBox" name="groupBox_4">
    <property name="geometry">
     <rect>
      <x>220</x>
      <y>30</y>
      <width>351</width>
      <height>481</height>
     </rect>
    </property>
    <property name="title">
     <string>数据交互</string>
    </property>
    <widget class="QWidget" name="formLayoutWidget">
     <property name="geometry">
      <rect>
       <x>0</x>
       <y>20</y>
       <width>341</width>
       <height>451</height>
      </rect>
     </property>
     <layout class="QFormLayout" name="formLayout">
      <item row="0" column="0">
       <widget class="QLabel" name="label_2">
        <property name="text">
         <string>发送数据</string>
        </property>
       </widget>
      </item>
      <item row="1" column="0" colspan="2">
       <widget class="QTextEdit" name="textEdit_send"/>
      </item>
      <item row="2" column="0">
       <widget class="QLabel" name="label">
        <property name="text">
         <string>接收数据</string>
        </property>
       </widget>
      </item>
      <item row="3" column="0" colspan="2">
       <widget class="QTextEdit" name="textEdit_recv">
        <property name="readOnly">
         <bool>true</bool>
        </property>
       </widget>
      </item>
      <item row="4" column="0" colspan="2">
       <layout class="QHBoxLayout" name="horizontalLayout_2">
        <item>
         <spacer name="horizontalSpacer">
          <property name="orientation">
           <enum>Qt::Horizontal</enum>
          </property>
          <property name="sizeHint" stdset="0">
           <size>
            <width>40</width>
            <height>20</height>
           </size>
          </property>
         </spacer>
        </item>
        <item>
         <widget class="QPushButton" name="send_Bt">
          <property name="text">
           <string>发送数据</string>
          </property>
         </widget>
        </item>
        <item>
         <spacer name="horizontalSpacer_2">
          <property name="orientation">
           <enum>Qt::Horizontal</enum>
          </property>
          <property name="sizeHint" stdset="0">
           <size>
            <width>40</width>
            <height>20</height>
           </size>
          </property>
         </spacer>
        </item>
        <item>
         <widget class="QPushButton" name="clear_send_Bt">
          <property name="text">
           <string>清空发送区</string>
          </property>
         </widget>
        </item>
        <item>
         <spacer name="horizontalSpacer_4">
          <property name="orientation">
           <enum>Qt::Horizontal</enum>
          </property>
          <property name="sizeHint" stdset="0">
           <size>
            <width>40</width>
            <height>20</height>
           </size>
          </property>
         </spacer>
        </item>
       </layout>
      </item>
     </layout>
    </widget>
   </widget>
  </widget>
 </widget>
 <resources/>
 <connections/>
</ui>

如果一切顺利的话,点击左下角的三角符号进行编译运行就可以测试效果了。
在这里插入图片描述

4. 打包可执行文件

当经过上面的步骤,编译后能成功运行。这时如果希望像我们平时用到的各种免安装的exe工具一样可以分享给其他小伙伴使用,就需要再打包一下才行。
传送门:【Qt安装与简易串口控制Arduino开发板小灯教程】

windeployqt Serial.exe

测试软件,点击运行启动app,电脑连接一个USB转TTL模块,TX接RX,勾选时间戳。然后点击检测串口,选择对应端口号打开串口,在输入文本框中输入12abc,点击发送,然后就可以收到数据啦😍😍😍👍

在这里插入图片描述

5. 总结

🥳🥳🥳现在,我们在本教程中,您学习了【QT串口助手】。🛹🛹🛹从而实现对外部世界进行感知,充分认识这个有机与无机的环境🥳🥳🥳科学地合理地进行创作和发挥效益,然后为人类社会发展贡献一点微薄之力。🤣🤣🤣

如果你有任何问题,可以通过下面的二维码加入鹏鹏小分队,期待与你思维的碰撞😘😘😘

参考文献:
相关好文推荐:

  1. QT初体验:手把手带你写一个自己的串口助手
  2. 【Qt安装与简易串口控制Arduino开发板小灯教程】

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1962469.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

守护线程(Daemon Threads)详解:与非守护线程的区别

守护线程&#xff08;Daemon Threads&#xff09;详解&#xff1a;与非守护线程的区别 1、守护线程是什么&#xff1f;2、守护线程与非守护线程的区别2.1 JVM关闭行为2.2 任务性质2.3 线程设置2.4 示例代码 3、总结 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收…

人工智能学习笔记 - 初级篇Ⅱ - 图形可视化 - 第11节: 绘制带填充区域的图表

微信公众号&#xff1a;御风研墨 关注可了解更多。问题或建议&#xff0c;请公众号留言 文章目录 绘制带填充区域的图表应用背景准备工作操作步骤工作原理补充说明最后 绘制带填充区域的图表 应用背景 在数据可视化中&#xff0c;带填充区域的图表可以有效地表示数据范围、趋…

创客项目秀 | 基于 XIAO 开发板的语音向导

背景 柴火创客空间作为大湾区科技创新的窗口&#xff0c;每年到访空间的社区伙伴众多&#xff0c;为了更好的进行空间信息交互&#xff0c;我们希望有一个装置是可以解决&#xff1a;当空间管理员不在现场的时候&#xff0c;到访者可以通过装置获得清晰的介绍与引导。 为了解…

APP逆向 day24unidbg上

一.前言 今天开始讲app逆向最后一个也是最重要的unidbg&#xff0c;这已经是从初级进阶到中级的了&#xff0c;我会讲unidbg&#xff0c;讲三节课&#xff0c;分为上中下来和大家讲&#xff08;由简单到难逐步&#xff09;&#xff0c;这节课主要是和大家讲unidbg的介绍并且会…

详解工厂模式与抽象工厂模式有什么区别?【图解+代码】

目录 工厂模式&#xff0c;抽象工厂模式是什么&#xff1f; 两种设计模式的流程&#xff1a; 1、工厂模式 2、抽象工厂模式 两种模式的对比 共同点&#xff1a; 不同点&#xff1a; 总结 工厂模式&#xff0c;抽象工厂模式是什么&#xff1f; 我已经具体的写了这两种模…

我的「Java全栈高级架构师高薪就业课」适合什么样的人群学习?

我的《Java全栈高级架构师高薪就业课》上线了~ 这是一套Java全栈微服务架构、以实战项目驱动的课程&#xff01;包含34个模块&#xff0c;1514课时。对标阿里P7级别技术栈而研发&#xff0c;有着循序渐进的学习体系&#xff0c;助你开启Java进阶之旅。 我的这套《Java全栈高级…

海域感知与岸线监控实施方案:总体技术架构

文章目录 引言I 总体架构1.1 物理结构图1.2 功能逻辑结构图1.3 系统架构1.4 雷达光电船只检测系统拓扑图1.5 雷达光电船只联动跟踪效果图II 技术架构存储Geoserver视频see also引言 利用渔船现有的定位导航通讯设备等资源,实现岸线和近岸海域内违法船舶和可疑船舶预警、抓拍、…

系统学习渗透测试:从零到精通的全面指南

渗透测试&#xff0c;作为网络安全领域的一项重要技术&#xff0c;旨在通过模拟黑客攻击来评估计算机系统的安全性。对于想要系统学习渗透测试的人来说&#xff0c;这既是一条充满挑战的道路&#xff0c;也是一次深入了解网络安全的宝贵机会。本文将从基础知识、技能提升、实战…

怎麼使用ixbrowser指紋流覽器?

ixBrowser是一款指紋流覽器流覽器&#xff0c;利用指紋隔離技術確保在與Pixelscan等第三方檢測網站進行測試時具有出色的通過率&#xff0c;能夠輕鬆管理多個獨立帳戶。此外&#xff0c;ixBrowser能夠創建無限的獨立個人資料並邀請團隊成員。簡化了運營&#xff0c;降低了運營成…

转行要趁早!网络安全岗人才稀缺,前景广阔,收藏这一篇就够了

1 网络安全从业人员能力基本要求&#xff0c;您达标了吗&#xff1f; 引导 根据国家市场监督管理总局、国家标准化管理委员会发布中华人民共和国国家标准公告&#xff08;2023年第1号&#xff09;&#xff0c;由全国信息安全标准化技术委员会归口的《信息安全技术 网络安全从业…

设计模式15-门面模式

设计模式15-门面模式 "接口隔离"模式典型模式1. 适配器模式&#xff08;Adapter Pattern&#xff09;2. 装饰模式&#xff08;Decorator Pattern&#xff09;3. 桥接模式&#xff08;Bridge Pattern&#xff09;4. 代理模式&#xff08;Proxy Pattern&#xff09;5. …

分布式日志分析系统--ELK

文章目录 ELK概述ELK主要特点ELK应用架构 Elasticsearch原理JSON格式倒排索引 ES与关系型数据库ES相关概念ES安装说明1.环境初始化2.优化系统资源限制配置3.编辑ES服务文件elasticsearch. yml 优化ELK集群安装脚本scp的使用集群安装成功 Shell命令API使用创建索引创建Type创建分…

yocto系列讲解[实战篇]95 - 使用外部第三方交叉编译器toolchain

By: fulinux E-mail: fulinux@sina.com Blog: https://blog.csdn.net/fulinus 喜欢的盆友欢迎点赞和订阅! 你的喜欢就是我写作的动力! 目录 概述下载toolchain包部署toolchain下载yocto下载toolchain layer添加toolchain layer配置toolchain变量编译和测试验证返回总目录:Yo…

中控屏UI设计全解析:布局与交互技巧

在现代科技的浪潮中&#xff0c;中控屏已成为智能系统不可或缺的交互界面。无论是智能家居、车载系统还是工业控制&#xff0c;一个直观、易用且美观的中控屏 UI 设计对于提升用户体验至关重要。本教程将带领你深入探索中控屏UI设计的精髓&#xff0c;指导你如何打造出既专业又…

一些Kafka面试题

Kafka是如何保证消息不丢失&#xff1f; 1.生产者发送消息到Broker丢失&#xff1a; 设置异步发送&#xff1a;发送失败则使用回调进行记录或者重发 消息重试&#xff1a;参数配置&#xff0c;可以设置重试次数 2.消息在broker中存储丢失 发送确认机制acks acks0&#xf…

创新突破 | OpenCSG发布StarShip CodeReview v1.0.0 Beta版

1. 代码审查很关键但耗时耗力 在软件开发过程中&#xff0c;代码审查是确保代码质量的关键环节。代码审查有助于维护代码标准和发现潜在错误&#xff0c;但也常常耗费大量时间和精力。审查者不仅需要深入理解代码逻辑&#xff0c;还要在繁复的逻辑中识别Bug&#xff0c;这个过…

如何使用 Odoo 16 主生产调度程序规划生产

为了优化运营并提高生产力&#xff0c;企业需要生产管理软件。在当今竞争激烈的经济环境中&#xff0c;有效的资源管理对企业至关重要。为制造业务设计的软件经常用于控制收入增长和盈利能力。ERP&#xff08;企业资源规划&#xff09;系统是专门为制造业创建的&#xff0c;可以…

Java刷题: 丑数判断

题目 丑数 就是只包含质因数 2、3 和 5 的正整数。 给你一个整数 n &#xff0c;请你判断 n 是否为 丑数 。如果是&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 解题思路 我觉得刷题是为了扩宽思考的广度。看到这题的时候&#xff0c;我的大脑是发懵的…

技术成神之路:设计模式(十)备忘录模式

介绍 备忘录模式&#xff08;Memento Pattern&#xff09;是一种行为设计模式&#xff0c;它允许在不破坏封装性的前提下捕获和恢复对象的内部状态。通过备忘录模式&#xff0c;可以在程序运行过程中保存和恢复对象的某个状态&#xff0c;从而实现“撤销”等功能。 1.定义 备忘…

11 优化器

目录 1. 随机梯度下降系优化器&#xff1a;SGD 1.1 算法种类 1.2 优缺点 2 SGDM 即为SGD with momentum 动量 2.1 公式 2.2 动量的优缺点 优点 缺点 2.3 使用场景 3 AdaGrad 3.1 公式 3.2 AdaGrad的优缺点 优点 缺点 3.3 使用场景 3.4 Adam 3.4.1 Adam优化器的…