Qt串口助手

QT5 串口助手

​ 由于C++课程作业的需要,用QT5写了个简陋的串口助手。只作为一个简单的案例以供参考,默认读者具有C++基础和了解简单的Qt操作。

功能展示

【用QT写了个简单的串口助手】

准备工作

Qt自带有<QSerialPort> 库, 可以方便地配置和调用计算机的串口资源

将QSerialPort编译到项目中

<QSerialPort> 默认是不能再Qt项目中使用的,需要在.pro文件中 添加一行QT += serialport , 才能使用<QSerialPort>

这点在文档中也有写出

在这里插入图片描述
在.pro文件中添加QT += serialport

在这里插入图片描述

界面设计

在这里插入图片描述

  • 左上文本框显示接收和发送到的信息
  • 右上区域选择串口和对串口进行配置
  • 右边中间打开串口和保存或者清楚接收区的信息,十六进制显示将会使下次接收到的信息以十六进制显示
  • 下边是发送文本区
  • 最下边是定时发送功能,开启后会一直发送信息,能够设置发送的周期

界面初始化

将界面信息和所有配置项加载, 需要代码实现加载的主要有Combox中所有文本, 以及串口的初始配置

加载串口名

/**
* @brief 扫描所有可用的串口,并将其添加到Box中
*/
void CSerial::Scan_Serial(void)
{
    ports = QSerialPortInfo::availablePorts();
    foreach(QSerialPortInfo info, ports)
    {
        qDebug() << "串口名称" << info.portName();
        qDebug() << "设备描述:" << info.description();
        ui->comboBox->addItem(QString(info.portName() + info.description()));
    }
}
  • QSerialPortInfo类,实现了一些静态方法用于获取串口的信息

  • 通过QSerialPortInfo::availablePorts()获取所有可用的串口(以及他们的信息)

  • 然后遍历ports, 将串口名称添加到comboBox中(请忽略qDebug()调试代码)

加载可用波特率、停止位、数据位和检验位配置

与加载串口名类似, 只不过加载的内容是QSerialPort类中定义好的配置, 在注释中也列举出了部分支持的配置(更多支持的配置请查询QSerialPort的文档)

/**
* @brief 将支持的波特率添加到Box中
* 1200 2400 4800 9600 19200 38400 57600 115200
*/
void CSerial::Play_BoudRate(void)
{
    ui->BoudRateBox->addItem("1200");
    ui->BoudRateBox->addItem("2400");
    ui->BoudRateBox->addItem("4800");
    ui->BoudRateBox->addItem("9600");
    ui->BoudRateBox->addItem("19200");
    ui->BoudRateBox->addItem("38400");
    ui->BoudRateBox->addItem("57600");
    ui->BoudRateBox->addItem("115200");
}
/**
* @brief 将停止位添加到Box中
* OneStop 1      TowStop 2     OneAndHalfStop 3
*/
void CSerial::Play_StopBits(void)
{
    ui->StopBitsBox->addItem("1");
    ui->StopBitsBox->addItem("2");
    ui->StopBitsBox->addItem("1.5");
}
/**
* @brief 将数据位添加到Box中
* Data5 5     Data6 6       Data7 7       Data8  8
*/
void CSerial::Play_DataBits(void)
{
    ui->DataBitsBox->addItem("5");
    ui->DataBitsBox->addItem("6");
    ui->DataBitsBox->addItem("7");
    ui->DataBitsBox->addItem("8");
}
/**
* @brief 将校验添加到Box中
* NoParity 0        EvenParity 2         OddParity   3
*/
void CSerial::Play_Parity(void)
{
    ui->ParityBox->addItem("No Parity");
    ui->ParityBox->addItem("Even");
    ui->ParityBox->addItem("Odd");
}

将文本加载完后, 需要根据文本内容对端口进行初始化, 不然每次使用都需要用户一个个配置(防止用户对未配置的端口进行操作)

/**
* @brief 根据Box中的内容初始化端口
*/
void CSerial::Port_Init(void)
{
    int index;
    OCFlag = 0;
    HexFlag = 0;
    TimerFlag = 0;
    currentPort.setPortName(ports[ui->comboBox->currentIndex()].portName());
    currentPort.setBaudRate(ui->BoudRateBox->currentText().toInt());
    currentPort.setStopBits(QSerialPort::StopBits(ui->StopBitsBox->currentIndex()+1));
    currentPort.setDataBits(QSerialPort::DataBits(ui->DataBitsBox->currentIndex()+5));
    index = ui->ParityBox->currentIndex();
    index = index == 0 ? index : (index+1);
    currentPort.setParity(QSerialPort::Parity(index));
    currentPort.setFlowControl(QSerialPort::NoFlowControl);
    qDebug() << currentPort.portName() << Qt::endl;
    qDebug() << currentPort.baudRate() << Qt::endl;
    qDebug() << currentPort.stopBits() << Qt::endl;
    qDebug() << currentPort.dataBits() << Qt::endl;
    qDebug() << currentPort.parity() << Qt::endl;
}

串口配置

初始化完界面后,实现串口配置的功能

串口配置,有选择串口号配置波特率配置停止位, 配置数据位配置校验位

选择串口号

// 选择端口
    connect(ui->comboBox, QOverload<int>::of(&QComboBox::activated), [=](int index){
        qDebug() << index << ui->comboBox->currentText() << Qt::endl;
        currentPort.setPortName(ports[index].portName());
        qDebug() << currentPort.portName();
    });
  • connect()在Qt中将信号与槽进行连接, QOverload<int>::of(&QComboBox::activated) , 这里的槽函数是个匿名函数
// 槽函数
[=](int index){
        qDebug() << index << ui->comboBox->currentText() << Qt::endl;
        currentPort.setPortName(ports[index].portName());
        qDebug() << currentPort.portName();
    }

连接好信号(Signal)与槽(Slots)后, 简单讲解下实现的机制

  • 在用户对ComboBox进行操作时或者ComboBox本身的属性发生改变时, 如点击或者ComboBox的现在的文本内容发生改变, ComboBox对象会产生一个信号(这里是activated, 鼠标点击内容后触发)
  • 这是文档中ComboBox对象能够产生的信号

在这里插入图片描述

  • 点进去后会有说明和例子

在这里插入图片描述

  • connect() 连接好信号与槽后, 会在收到信号后直接执行槽函数, 槽函数可以是普通函数或者匿名函数, 这里主要是调用了匿名函数,匿名函数内再调用currentPort.setPortName(ports[index].portName())将现在端口的名字设置为鼠标点中的内容

  • 学过单片机的,可以简单将信号与槽理解为中断信号中断服务函数

  • 除了一些C++的基本语法Qt的重点就是信号与槽

配置波特率

与上面类似,直接放代码

// 选择波特率
    connect(ui->BoudRateBox, QOverload<int>::of(&QComboBox::activated), [=](int index){
        qDebug() << index << Qt::endl;
        currentPort.setBaudRate(ui->BoudRateBox->currentText().toInt());
        qDebug() << currentPort.baudRate() << Qt::endl;
    });

配置停止位

 // 选择停止位
    connect(ui->StopBitsBox, QOverload<int>::of(&QComboBox::activated), [=](int index){
        qDebug() << index << Qt::endl;
        currentPort.setStopBits(QSerialPort::StopBits(index+1));
        qDebug() << currentPort.stopBits() << Qt::endl;
    });

配置数据位

// 选择数据位
    connect(ui->DataBitsBox, QOverload<int>::of(&QComboBox::activated), [=](int index){
        qDebug() << index << Qt::endl;
        currentPort.setDataBits(QSerialPort::DataBits(index+5));
        qDebug() << currentPort.dataBits() << Qt::endl;
    });

配置校验位

// 选择校验
    connect(ui->ParityBox, QOverload<int>::of(&QComboBox::activated), [=](int index){
        qDebug() << index << Qt::endl;
        index = index == 0 ? index : (index+1);
        currentPort.setParity(QSerialPort::Parity(index));
        qDebug() << currentPort.parity() << Qt::endl;
     });

基础功能实现

打开和关闭串口

配置完串口后,就可以打开和关闭串口了

OCFlag==0时, 调用open打开串口, 并将按钮的Icon切换, 若打开串口失败则调用QMessageBox::warning弹出提示框;当OCFlag==1时,调用close()关闭串口, 并将按钮的Icon切换.

/**
* @brief 打开和关闭串口
*/
void CSerial::OpenAndClose_Port(void)
{
    if(OCFlag == 0)
    {
        if(currentPort.open(QIODevice::ReadWrite))
        {
            qDebug() << "串口已打开" << Qt::endl;
            ui->OpenSerial->setIcon(QIcon(":/Image/off.png"));
            ui->OpenSerial->setText("关闭串口");
            OCFlag = 1;
        }
        else
        {
            QMessageBox::warning(this, "Error", "Cannot Open Port:" + currentPort.errorString());
        }
    }
    else
    {
        currentPort.close();
        ui->OpenSerial->setIcon(QIcon(":/Image/On.png"));
        qDebug() << "串口已关闭" << Qt::endl;
        ui->OpenSerial->setText("打开串口");
        OCFlag = 0;
    }
}

槽函数写完,将其与一个按钮连接

// 打开关闭串口
    connect(ui->OpenSerial, &QPushButton::clicked, this, &CSerial::OpenAndClose_Port);
  • 第一个参数是信号发出的对象,第二个参数是需要连接的信号,第三个参数是调用槽函数的对象,第四个参数是槽函数

  • OpenSerial是一个QpushButton类的对象,俗称"按钮", clicked为鼠标点击信号, this表示对象为该对象(一个Cserial类的对象), 槽函数是OpenAndClose_Port(打开或者关闭串口)

  • 执行完上面这行代码后, OpenSerial(按钮)被按下后发出一个信号,被监测到后调用,检测器通知this,然后this再调用OpenAndClose_Port 执行槽函数

  • 而若用匿名函数,则不需要槽函数的发起对象,因为在一个匿名函数中,可以调用不同对象的不同的函数, 所以指定槽函数发起对象失去意义

发送数据

打开串口后,就能够发送数据了

OCFlag==1时(串口打开时),调用write()发送数据;若bytesWritten==-1,则数据发送失败,用QMessageBox打印错误信息, 并将发送的信息显示在接受区

OCFlag==0时(串口关闭时),调用QMessageBox提示用户打开串口

/**
* @brief 发送数据
*/
void CSerial::Send_Data(void)
{
    if(OCFlag)
    {
        QString SendString = ui->SendText->toPlainText();
        qDebug() << SendString << Qt::endl;
        QByteArray dataToSend = SendString.toLocal8Bit();
        // 发送数据
        qint64 bytesWritten =currentPort.write(dataToSend);
        if(bytesWritten == -1)
        {
            QMessageBox::warning(this, "Error", "数据发送失败!");
        }
        else
        {
            QString SendedData = QString::fromStdString(dataToSend.toStdString());
            ui->textEdit->append("Tx:"+SendedData);
        }
    }
    else
    {
        QMessageBox::warning(this, "Error", "请先打开串口!");
    }
}

槽函数写完,将其与一个按钮连接

// 发送数据
    connect(ui->SendData, &QPushButton::clicked, this, &CSerial::Send_Data);

接收数据

打开串口后,也可以接收到其他装置发送来的信息

接收到数据后,将数据显示到串口中, 若HexFlag==1,则以十六进制显示

/**
* @brief 接收数据
*/
void CSerial::Receive_Data(void)
{
    if(OCFlag)
    {
        QByteArray data = currentPort.readAll();
        QString text = QString::fromStdString(data.toStdString());
        qDebug() << text << Qt::endl;
        if(HexFlag == 0)
        {
            ui->textEdit->append("Rx:" + text);
        }
        else
        {
            ui->textEdit->append("Rx:" + data.toHex());
        }
    }
}

槽函数写完后,将其与信号连接, 该信号由串口产生; readRead在串口读取完数据后产生

// 接收数据
    connect(&currentPort, &QSerialPort::readyRead, this, &CSerial::Receive_Data);

保存接收区内容

收到数据后,可以将数据以.txt文件的形式保存到指定路径

通过QFileDialog::getSaveFileName()获取保存路径, 它的最后一个参数将保存文件类型限制为.txt

通过QFile对象打开文件,若打开失败则通过QMessageBox弹出错误信息窗口

通过textEdit对象的toPlainText()方法获取接收区数据并转换为纯文本

通过QFile对象write()方法将文本以utf-8的格式写入文件中

通过close()方法关闭文件,并弹出保存成功的提示窗口

/**
* @brief 保存接受区内容
*/
void CSerial::Save_RxText(void)
{
    // 获取文件保存路径
    QString fileName = QFileDialog::getSaveFileName(this, "Save", "/text", tr("Text (*.txt)"));
    qDebug() << fileName << Qt::endl;
    QFile file(fileName);
    if(!file.open(QIODevice::WriteOnly | QFile::Text))
    {
        QMessageBox::warning(this, "Warning", "Cannot Save file: " + file.errorString());
        return;
    }
    setWindowTitle(fileName);
    QTextStream out(&file);
    QString text = ui->textEdit->toPlainText();
    file.write(text.toUtf8());
    file.close();
    QMessageBox::information(this, "提示", "保存成功!");
}

清除接收区和发送区内容

清除内容,其实没必要封装起来

/**
* @brief 清除发送区内容
*/
void CSerial::Clear_SendText(void)
{
    ui->SendText->clear();
}
/**
* @brief 清除接收区内容
*/
void CSerial::Clear_RxText(void)
{
    ui->textEdit->clear();
}
// 清除发送区文本内容
    connect(ui->ClearData, &QPushButton::clicked, this, &CSerial::Clear_SendText);
// 清除接收区文本内容
    connect(ui->Clear_Rx, &QPushButton::clicked, this, &CSerial::Clear_RxText);

改变十六进制标志

改变十六进制标志,封装起来思路清晰一点吧

/**
* @brief 改变十六进制标志
*/
void CSerial::Change_HexFlag(void)
{
    qDebug() << ui->checkBox->checkState() << Qt::endl;
    HexFlag = ui->checkBox->checkState();
    qDebug() << HexFlag << Qt::endl;
}
// 改变十六进制接收标志
    connect(ui->checkBox, &QCheckBox::stateChanged, this, &CSerial::Change_HexFlag);

定时发送

  • 定时发送相关的函数有三个

  • 当定时发送的按钮被触动后,会触发槽函数,在槽函数中先检测标志位,再设置定时器发送周期,最后根据定时发送标志位和串口关闭标志位判断是开启定时器还是关闭定时器

  • 定时器槽函数中调用Send_Data()发送数据

  • 下面简单介绍下QTimer定时器,主要就是用来定时,start(Time)开启定时器并设置周期,单位是毫秒,定时时间到发出timeout信号,用connect将信号与槽连接后,达到每过Time触发一次槽函数

/**
* @brief 改变定时发送标志
*/
void CSerial::Change_TimerFlag(void)
{
    qDebug() << ui->TimerCheck->checkState() << Qt::endl;
    TimerFlag = ui->TimerCheck->checkState();
    qDebug() << TimerFlag << Qt::endl;
}

/**
* @brief 设置定时器周期
*/
void CSerial::Set_TimerTime(void)
{
    bool Flag;
    int temp;
    temp = ui->TimerEdit->text().toInt(&Flag);
    if(Flag)
    {
        Timer_Time = temp;
        qDebug() << "T = " << Timer_Time << " ms" << Qt::endl;
    }
    else
    {
        QMessageBox::warning(this, "Error", "请输入合法的数字");
    }
}

/**
* @brief 定时发送
*/
void CSerial::Send_InTime(void)
{
    this->Change_TimerFlag();  // 改变标志位
    this->Set_TimerTime();   // 设置发送周期
    if(TimerFlag && OCFlag)
    {
        Timer->start(Timer_Time);  // 启动定时器
    }
    else
    {
        Timer->stop();   // 关闭定时器
        if(TimerFlag) QMessageBox::warning(this, "Error", "请先打开串口!");
    }
}
// 定时发送数据
    connect(ui->TimerCheck, &QCheckBox::stateChanged, this, &CSerial::Send_InTime);
    Timer = new QTimer(this);
    connect(Timer, &QTimer::timeout, [=](){
        this->Send_Data();
    });

整体程序

cserial.h

#ifndef CSERIAL_H
#define CSERIAL_H

#include <QMainWindow>
#include <QSerialPort>
#include <QList>
#include <QSerialPortInfo>
#include <QDebug>
#include <QComboBox>
#include <QMessageBox>
#include <QFileDialog>
#include <QFile>
#include <QTimer>
QT_BEGIN_NAMESPACE
namespace Ui { class CSerial; }
QT_END_NAMESPACE

class CSerial : public QMainWindow
{
    Q_OBJECT

public:
    CSerial(QWidget *parent = nullptr);
    ~CSerial();
private slots:   // 定义的槽函数
    void Scan_Serial(void);
    void Play_BoudRate(void);
    void Play_StopBits(void);
    void Play_DataBits(void);
    void Play_Parity(void);
    void Port_Init(void);
    void OpenAndClose_Port(void);
    void Send_Data(void);
    void Receive_Data(void);
    void Clear_SendText(void);
    void Save_RxText(void);
    void Clear_RxText(void);
    void Change_HexFlag(void);
    void Change_TimerFlag(void);
    void Set_TimerTime(void);
    void Send_InTime(void);
private:
    int OCFlag;  // 打开关闭标志位
    int HexFlag;  // 十六进制显示标志位
    int TimerFlag;  // 定时发送标志位
    int Timer_Time;  // 定时发送周期
    QTimer * Timer;  // 定时器
    Ui::CSerial *ui;
    QSerialPort currentPort;  // 当前端口
    QList<QSerialPortInfo> ports;  // 所有可以端口信息
};
#endif // CSERIAL_H

cserial.cpp

#include "cserial.h"
#include "ui_cserial.h"

CSerial::CSerial(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::CSerial)
{
    ui->setupUi(this);
    ui->OpenSerial->setIcon(QIcon(":/Image/On.png"));
    ui->Save_Rx->setIcon(QIcon(":/Image/save.png"));
    ui->ClearData->setIcon(QIcon(":/Image/clear.png"));
    ui->Clear_Rx->setIcon(QIcon(":/Image/clear.png"));
    ui->SendData->setIcon(QIcon(":/Image/send.png"));
    this->setWindowIcon(QIcon(":/Image/serial.png"));
    this->Scan_Serial();
    this->Play_BoudRate();
    this->Play_StopBits();
    this->Play_DataBits();
    this->Play_Parity();
    this->Port_Init();
    // 选择端口
    connect(ui->comboBox, QOverload<int>::of(&QComboBox::activated), [=](int index){
        qDebug() << index << ui->comboBox->currentText() << Qt::endl;
        currentPort.setPortName(ports[index].portName());
        qDebug() << currentPort.portName();
    });
    // 选择波特率
    connect(ui->BoudRateBox, QOverload<int>::of(&QComboBox::activated), [=](int index){
        qDebug() << index << Qt::endl;
        currentPort.setBaudRate(ui->BoudRateBox->currentText().toInt());
        qDebug() << currentPort.baudRate() << Qt::endl;
    });
    // 选择停止位
    connect(ui->StopBitsBox, QOverload<int>::of(&QComboBox::activated), [=](int index){
        qDebug() << index << Qt::endl;
        currentPort.setStopBits(QSerialPort::StopBits(index+1));
        qDebug() << currentPort.stopBits() << Qt::endl;
    });
    // 选择数据位
    connect(ui->DataBitsBox, QOverload<int>::of(&QComboBox::activated), [=](int index){
        qDebug() << index << Qt::endl;
        currentPort.setDataBits(QSerialPort::DataBits(index+5));
        qDebug() << currentPort.dataBits() << Qt::endl;
    });
    // 选择校验
    connect(ui->ParityBox, QOverload<int>::of(&QComboBox::activated), [=](int index){
        qDebug() << index << Qt::endl;
        index = index == 0 ? index : (index+1);
        currentPort.setParity(QSerialPort::Parity(index));
        qDebug() << currentPort.parity() << Qt::endl;
     });
    // 打开关闭串口
    connect(ui->OpenSerial, &QPushButton::clicked, this, &CSerial::OpenAndClose_Port);
    // 发送数据
    connect(ui->SendData, &QPushButton::clicked, this, &CSerial::Send_Data);
    // 接收数据
    connect(&currentPort, &QSerialPort::readyRead, this, &CSerial::Receive_Data);
    // 清除发送区文本内容
    connect(ui->ClearData, &QPushButton::clicked, this, &CSerial::Clear_SendText);
    // 保存接受区文本内容
    connect(ui->Save_Rx, &QPushButton::clicked, this, &CSerial::Save_RxText);
    // 清除接收区文本内容
    connect(ui->Clear_Rx, &QPushButton::clicked, this, &CSerial::Clear_RxText);
    // 改变十六进制接收标志
    connect(ui->checkBox, &QCheckBox::stateChanged, this, &CSerial::Change_HexFlag);
    // 定时发送数据
    connect(ui->TimerCheck, &QCheckBox::stateChanged, this, &CSerial::Send_InTime);
    Timer = new QTimer(this);
    connect(Timer, &QTimer::timeout, [=](){
        this->Send_Data();
    });
}

CSerial::~CSerial()
{
    currentPort.close();  // 关闭串口
    delete ui;
}

/**
* @brief 扫描所有可用的串口,并将其添加到Box中
*/
void CSerial::Scan_Serial(void)
{
    ports = QSerialPortInfo::availablePorts();
    foreach(QSerialPortInfo info, ports)
    {
        qDebug() << "串口名称" << info.portName();
        qDebug() << "设备ID:" << info.description();
        ui->comboBox->addItem(QString(info.portName() + info.description()));
    }
}

/**
* @brief 将支持的波特率添加到Box中
* 1200 2400 4800 9600 19200 38400 57600 115200
*/
void CSerial::Play_BoudRate(void)
{
    ui->BoudRateBox->addItem("1200");
    ui->BoudRateBox->addItem("2400");
    ui->BoudRateBox->addItem("4800");
    ui->BoudRateBox->addItem("9600");
    ui->BoudRateBox->addItem("19200");
    ui->BoudRateBox->addItem("38400");
    ui->BoudRateBox->addItem("57600");
    ui->BoudRateBox->addItem("115200");
}

/**
* @brief 将停止位添加到Box中
* OneStop 1      TowStop 2     OneAndHalfStop 3
*/
void CSerial::Play_StopBits(void)
{
    ui->StopBitsBox->addItem("1");
    ui->StopBitsBox->addItem("2");
    ui->StopBitsBox->addItem("1.5");
}

/**
* @brief 将数据位添加到Box中
* Data5 5     Data6 6       Data7 7       Data8  8
*/
void CSerial::Play_DataBits(void)
{
    ui->DataBitsBox->addItem("5");
    ui->DataBitsBox->addItem("6");
    ui->DataBitsBox->addItem("7");
    ui->DataBitsBox->addItem("8");
}

/**
* @brief 将校验添加到Box中
* NoParity 0        EvenParity 2         OddParity   3
*/
void CSerial::Play_Parity(void)
{
    ui->ParityBox->addItem("No Parity");
    ui->ParityBox->addItem("Even");
    ui->ParityBox->addItem("Odd");
}

/**
* @brief 根据Box中的内容初始化端口
*/
void CSerial::Port_Init(void)
{
    int index;
    OCFlag = 0;
    HexFlag = 0;
    TimerFlag = 0;
    currentPort.setPortName(ports[ui->comboBox->currentIndex()].portName());
    currentPort.setBaudRate(ui->BoudRateBox->currentText().toInt());
    currentPort.setStopBits(QSerialPort::StopBits(ui->StopBitsBox->currentIndex()+1));
    currentPort.setDataBits(QSerialPort::DataBits(ui->DataBitsBox->currentIndex()+5));
    index = ui->ParityBox->currentIndex();
    index = index == 0 ? index : (index+1);
    currentPort.setParity(QSerialPort::Parity(index));
    currentPort.setFlowControl(QSerialPort::NoFlowControl);
    qDebug() << currentPort.portName() << Qt::endl;
    qDebug() << currentPort.baudRate() << Qt::endl;
    qDebug() << currentPort.stopBits() << Qt::endl;
    qDebug() << currentPort.dataBits() << Qt::endl;
    qDebug() << currentPort.parity() << Qt::endl;
}

/**
* @brief 打开和关闭串口
*/
void CSerial::OpenAndClose_Port(void)
{
    if(OCFlag == 0)
    {
        if(currentPort.open(QIODevice::ReadWrite))
        {
            qDebug() << "串口已打开" << Qt::endl;
            ui->OpenSerial->setIcon(QIcon(":/Image/off.png"));
            ui->OpenSerial->setText("关闭串口");
            OCFlag = 1;
        }
        else
        {
            QMessageBox::warning(this, "Error", "Cannot Open Port:" + currentPort.errorString());
        }
    }
    else
    {
        currentPort.close();
        ui->OpenSerial->setIcon(QIcon(":/Image/On.png"));
        qDebug() << "串口已关闭" << Qt::endl;
        ui->OpenSerial->setText("打开串口");
        OCFlag = 0;
    }
}

/**
* @brief 发送数据
*/
void CSerial::Send_Data(void)
{
    if(OCFlag)
    {
        QString SendString = ui->SendText->toPlainText();
        qDebug() << SendString << Qt::endl;
        QByteArray dataToSend = SendString.toLocal8Bit();
        // 发送数据
        qint64 bytesWritten =currentPort.write(dataToSend);
        if(bytesWritten == -1)
        {
            QMessageBox::warning(this, "Error", "数据发送失败!");
        }
        else
        {
            QString SendedData = QString::fromStdString(dataToSend.toStdString());
            ui->textEdit->append("Tx:"+SendedData);
        }
    }
    else
    {
        QMessageBox::warning(this, "Error", "请先打开串口!");
    }
}

/**
* @brief 接收数据
*/
void CSerial::Receive_Data(void)
{
    if(OCFlag)
    {
        QByteArray data = currentPort.readAll();
        QString text = QString::fromStdString(data.toStdString());
        qDebug() << text << Qt::endl;
        if(HexFlag == 0)
        {
            ui->textEdit->append("Rx:" + text);
        }
        else
        {
            ui->textEdit->append("Rx:" + data.toHex());
        }
    }
}

/**
* @brief 清除发送区内容
*/
void CSerial::Clear_SendText(void)
{
    ui->SendText->clear();
}

/**
* @brief 保存接受区内容
*/
void CSerial::Save_RxText(void)
{
    // 获取文件保存路径
    QString fileName = QFileDialog::getSaveFileName(this, "Save", "/text", tr("Text (*.txt)"));
    qDebug() << fileName << Qt::endl;
    QFile file(fileName);
    if(!file.open(QIODevice::WriteOnly | QFile::Text))
    {
        QMessageBox::warning(this, "Warning", "Cannot Save file: " + file.errorString());
        return;
    }
    setWindowTitle(fileName);
    QTextStream out(&file);
    QString text = ui->textEdit->toPlainText();
    file.write(text.toUtf8());
    file.close();
    QMessageBox::information(this, "提示", "保存成功!");
}

/**
* @brief 清除接收区内容
*/
void CSerial::Clear_RxText(void)
{
    ui->textEdit->clear();
}

/**
* @brief 改变十六进制标志
*/
void CSerial::Change_HexFlag(void)
{
    qDebug() << ui->checkBox->checkState() << Qt::endl;
    HexFlag = ui->checkBox->checkState();
    qDebug() << HexFlag << Qt::endl;
}

/**
* @brief 改变定时发送标志
*/
void CSerial::Change_TimerFlag(void)
{
    qDebug() << ui->TimerCheck->checkState() << Qt::endl;
    TimerFlag = ui->TimerCheck->checkState();
    qDebug() << TimerFlag << Qt::endl;
}

/**
* @brief 设置定时器周期
*/
void CSerial::Set_TimerTime(void)
{
    bool Flag;
    int temp;
    temp = ui->TimerEdit->text().toInt(&Flag);
    if(Flag)
    {
        Timer_Time = temp;
        qDebug() << "T = " << Timer_Time << " ms" << Qt::endl;
    }
    else
    {
        QMessageBox::warning(this, "Error", "请输入合法的数字");
    }
}

/**
* @brief 定时发送
*/
void CSerial::Send_InTime(void)
{
    this->Change_TimerFlag();
    this->Set_TimerTime();
    if(TimerFlag && OCFlag)
    {
        Timer->start(Timer_Time);
    }
    else
    {
        Timer->stop();
        if(TimerFlag) QMessageBox::warning(this, "Error", "请先打开串口!");
    }
}

main.cpp

#include "cserial.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    CSerial w;
    w.show();
    return a.exec();
}

源码提取

链接:https://pan.baidu.com/s/1a5b75bhMe2OeSB2egvImEw?pwd=nlxl
提取码:nlxl
–来自百度网盘超级会员V4的分享

参考资料

Qt Assistant(Qt助手)官方的文档还是好用的
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值