Qt:DIY属于你的串口调试助手
tips: 前面是一些很基础的操作, 对qt有了解可以直接看后面代码,不想看着代码写也可以在博客的最后下载完整qt工程
1、开发环境介绍 :
软件工具: Qt 5.12.7(带有Qt Creator)
win10 ( Qt是支持跨平台的, 所以在其他平台的话, 不需要改代码, 直接原工程编译一下即可 )
2、新建工程 :
打开之后可以直接点击界面的New按钮新建一个工程
或者
① 文件(F)--->新建文件或项目(N)
② 新建Widget应用
③ 工程命名及路径选择
④ 选择继承的类(我们使用widget类即可, mainwindow杂七杂八的东西太多, 用不到)
前面那个Build System直接默认qmake下一步即可
⑤ 选择GCC编译器(这个要自己安装的, 如果安装过VS的话应该会装过这个)
直接下一步到完成即可, 我没有截图的步骤都是默认
⑥ 工程简介
.pro 文件是这个工程的配置
.ui文件是进行图形界面设计的
⑦ 加入串口模块
因为我们要做串口助手, 所以需要添加串口所需要的东西, 在.pro文件中添加串口模块即可
QT += serialport printsupport
准备工作做完了就可以正式开工了, 下面先进行图形界面的设计
3、界面设计 :
双击widget.ui进入设计界面(Qt designer)
以上图为参考, 设计界面布局
下面分区来进行布局并介绍
-
①数据接收区
-
图中数据接收区这几个字右侧有一条不太显眼的灰色的线, 这个是QGroupBox控件
-
-
-
然后在左侧空间栏找到Text Browser空间拖动到数据接收区那个group box里面, 可以手动调整框框的大小
-
在右侧给这个文本浏览框重命名, 便后续程序编写(或者在文本框处右键改变对象名称)如下图所示
+
-
-
②数据发送区
-
控件使用:QGroupBox + QTextEdit
-
QTextEdit的那个框框改名称为textEdit_send
-
-
③串口操作区域
-
QLable + QComboBox + QPushButton
-
给QComboBox对象名称改变一下
-
-
组合框候选项设置
+ -
下面同理设置数据位、停止位、奇偶校验
-
-
放置3个button
-
**注:**16进制显示,黑底,时间戳就不做了
-
④数据发送区按钮
Tips: 双击按钮可以改变按钮显示的字符
-
⑤数据发送区功能框
-
- 控件改名
-
定时发送: checkBox_timer_send
-
十六进制发送: checkBox_hex_send
-
Send后面那个label:label_send_number
-
Receive后面那个label:label_receive_number
-
清空记录:pushButton_clear_log
-
-
⑥系统时间
-
-
控件为QGroupBox + QTextBrowser
-
系统时间: textBrowser_time
-
4、程序设计 :
在widget.cpp中写程序
系统时间显示函数 + 头函数对显示时间这个函数以及定时器变量进行声明
先运行一下代码看看效果
qt制作上位机大概如此, 一下为h和c文件的程序
下面的private slot函数里面,有一些是pushbutton clicked和currentIndexChanged等等,是在ui界面在对应的控件右键转到槽之后,在h文件自动生成的
头文件的程序为:
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QWidget>
#include <QTimer>
#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>
#include <QMenuBar>
#include <windows.h>
#include <QDebug>
#include <QString>
#include <QDateTime>
#include <QLabel>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private slots:
void timerUpdate(void);
void on_pushButton_open2close_clicked();
void on_pushButton_send_clicked();
void on_pushButton_clearRcv_clicked();
void on_pushButton_clearSend_clicked();
void on_pushButton_clear_log_clicked();
void on_pushButton_detect_serial_clicked();
void on_comboBox_serialName_currentIndexChanged(const QString &arg1);
void on_comboBox_baud_currentIndexChanged(const QString &arg1);
void on_comboBox_dataBits_currentIndexChanged(int index);
void on_comboBox_stopBits_currentIndexChanged(int index);
void on_comboBox_parity_currentIndexChanged(int index);
void on_checkBox_timer_send_stateChanged(int arg1);
private:
Ui::Widget *ui;
QTimer *timer;// 用以显示系统时间的定时器
QSerialPort *serialPort; //串口
bool detectFlag = 0; // 扫描串口标志位
int sendNumber=0; // 统计发送的字节数
int receiveNumber=0; // 统计接收的字节数
// 一些用到的子函数
void serialPortOpen();
void serialPortDetect();
void serialPortSend();
void serialPortReceive();
};
#endif // WIDGET_H
C文件代码
#include "widget.h"
#include "ui_widget.h"
#include <string>
#include <QAction>
#include <QMessageBox>
#include <QStatusBar>
#include <QDialog>
#include <QMenuBar>
#include <QMenu>
#include <QMainWindow>
#include <qdatetime.h> // 用于获取系统时间
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QTimer *timer1 = new QTimer(this);
connect(timer1, SIGNAL(timeout()), this, SLOT(timerUpdate()));
timer1->start(1000);
this->timer = new QTimer(this);// 这个定时器用以串口定时发送功能
QObject::connect(this->timer, &QTimer::timeout, this, &Widget::serialPortSend);
this->serialPortDetect(); // 串口检测
this->serialPort = NULL;
}
Widget::~Widget()
{
delete ui;
}
void Widget::timerUpdate(void)
{
QDateTime time = QDateTime::currentDateTime();
QString str = time.toString("yyyy-MM-dd hh:mm:ss dddd"); // 设置时间日期显示格式 年-月-日 时:分:秒 星期
ui->textBrowser_time->setTextColor(Qt::blue);
//ui->textBrowser_time->setTextBackgroundColor(Qt::yellow);
ui->textBrowser_time->setText(str);
}
// Open 按钮按下 打开串口
void Widget::on_pushButton_open2close_clicked()
{
this->serialPortOpen(); // 转到打开串口操作的子函数
}
// 发送按钮按下 发送信息
void Widget::on_pushButton_send_clicked()
{
// 如果串口已经连接并打开
if(this->serialPort!=NULL)
{
this->serialPortSend(); // 执行串口发送对应子函数
}
}
// 串口打开的操作
void Widget::serialPortOpen()
{
if(this->serialPort==NULL)
{
this->serialPort = new QSerialPort(this);
this->serialPort->setPortName(ui->comboBox_serialName->currentText());
this->serialPort->setBaudRate(ui->comboBox_baud->currentText().toInt());
switch(ui->comboBox_dataBits->currentText().toInt())
{
case 8:
this->serialPort->setDataBits(QSerialPort::Data8);break;
case 7:
this->serialPort->setDataBits(QSerialPort::Data7);break;
case 6:
this->serialPort->setDataBits(QSerialPort::Data6);break;
case 5:
this->serialPort->setDataBits(QSerialPort::Data5);break;
default:
break;
}
switch(ui->comboBox_parity->currentIndex())
{
case 0:
this->serialPort->setParity(QSerialPort::NoParity);
break;
case 1:
this->serialPort->setParity(QSerialPort::OddParity);
break;
case 2:
this->serialPort->setParity(QSerialPort::EvenParity);
break;
default:
break;
}
switch (ui->comboBox_stopBits->currentIndex())
{
case 0:
this->serialPort->setStopBits(QSerialPort::OneStop);
break;
case 1:
this->serialPort->setStopBits(QSerialPort::OneAndHalfStop);
break;
case 2:
this->serialPort->setStopBits(QSerialPort::TwoStop);
break;
default:
break;
}
if(!serialPort->open( QIODevice::ReadWrite ))
{
//ui->textEdit->append("open faild");
delete serialPort;
this->serialPort=NULL;
ui->pushButton_open2close->setText("Open");
}
else
{
ui->pushButton_open2close->setText("Close");
QObject::connect(this->serialPort,&QSerialPort::readyRead,this,&Widget::serialPortReceive);
}
}
else
{
serialPort->close();
delete serialPort;
serialPort=NULL;
ui->pushButton_open2close->setText("Open");
}
}
// 串口扫描函数 扫描打开的串口
void Widget::serialPortDetect()
{
this->detectFlag=1;
QList<QSerialPortInfo> serialPortList(QSerialPortInfo::availablePorts());
QSerialPort tempSerial;
ui->comboBox_serialName->clear();
for(int i=0;i<serialPortList.size();i++)
{
tempSerial.setPort(serialPortList.at(i));
//if(tempSerial.open(QIODevice::ReadWrite))
//{
ui->comboBox_serialName->addItem(serialPortList.at(i).portName());
tempSerial.close();
//}
}
this->detectFlag=0;
}
// 串口发送对应槽函数
void Widget::serialPortSend()
{
if(ui->checkBox_hex_send->checkState()==Qt::Unchecked)
{
this->serialPort->write(ui->textEdit_send->toPlainText().toLocal8Bit());
this->sendNumber+=ui->textEdit_send->toPlainText().toLocal8Bit().size();
}
else
{
this->serialPort->write(QByteArray::fromHex( ui->textEdit_send->toPlainText().toLocal8Bit() ));
this->sendNumber+=QByteArray::fromHex( ui->textEdit_send->toPlainText().toLocal8Bit() ).size();
}
ui->label_send_number->setText(QString::number(this->sendNumber));
}
// 串口接收对应的处理函数
void Widget::serialPortReceive()
{
QByteArray temp(this->serialPort->readAll());
QString tempStr;
if(ui->checkBox_hex_show->checkState()==Qt::Unchecked)
{
tempStr=QString::fromLocal8Bit(temp);
}
else
{
tempStr=temp.toHex();
}
if(!temp.isEmpty())
{
ui->textBrowser_receive->moveCursor(QTextCursor::End);
ui->textBrowser_receive->insertPlainText(tempStr);
// 上面两句跟下面的append效果一样
//on_checkBox_white_stateChanged(Qt::Checked);
//ui->textEdit_receive->append(tempStr);
}
this->receiveNumber+=temp.size();
ui->label_receive_number->setText(QString::number(this->receiveNumber));
temp.clear();
tempStr.clear();
}
// 清除接收按钮对应的槽函数
void Widget::on_pushButton_clearRcv_clicked()
{
ui->textBrowser_receive->clear();
}
// 清除发送按钮 对应槽函数
void Widget::on_pushButton_clearSend_clicked()
{
ui->textEdit_send->clear();
}
// 清除统计的Send 和 Receive 数量
void Widget::on_pushButton_clear_log_clicked()
{
this->sendNumber=0;
this->receiveNumber=0;
ui->label_receive_number->setText(QString::number(0));
ui->label_send_number->setText(QString::number(0));
}
// 扫描串口按钮按下
void Widget::on_pushButton_detect_serial_clicked()
{
this->serialPortDetect();
}
// 串口名字下标选择`
void Widget::on_comboBox_serialName_currentIndexChanged(const QString &arg1)
{
if(this->serialPort&&!this->detectFlag)
{
this->serialPort->close();
delete serialPort;
this->serialPort=NULL;
//this->serialPort->setPortName(arg1);
this->serialPortOpen();
}
}
// 波特率 选项框的备选项设计
void Widget::on_comboBox_baud_currentIndexChanged(const QString &arg1)
{
if(this->serialPort)
{
this->serialPort->setBaudRate(arg1.toInt());
}
}
// 数据位选项框备选项
void Widget::on_comboBox_dataBits_currentIndexChanged(int index)
{
if(this->serialPort)
{
switch(index)
{
case 0:
this->serialPort->setDataBits(QSerialPort::Data8);break;
case 1:
this->serialPort->setDataBits(QSerialPort::Data7);break;
case 2:
this->serialPort->setDataBits(QSerialPort::Data6);break;
case 3:
this->serialPort->setDataBits(QSerialPort::Data5);break;
default:
break;
}
}
}
// 停止位 选项框的备选项
void Widget::on_comboBox_stopBits_currentIndexChanged(int index)
{
if(this->serialPort)
{
switch (index)
{
case 0:
this->serialPort->setStopBits(QSerialPort::OneStop);
break;
case 1:
this->serialPort->setStopBits(QSerialPort::OneAndHalfStop);
break;
case 2:
this->serialPort->setStopBits(QSerialPort::TwoStop);
break;
default:
break;
}
}
}
// 奇偶校验位 选项框的备选项
void Widget::on_comboBox_parity_currentIndexChanged(int index)
{
if(this->serialPort)
{
switch(index)
{
case 0:
this->serialPort->setParity(QSerialPort::NoParity);
break;
case 1:
this->serialPort->setParity(QSerialPort::OddParity);
break;
case 2:
this->serialPort->setParity(QSerialPort::EvenParity);
break;
default:
break;
}
}
}
// 勾选定时发送
void Widget::on_checkBox_timer_send_stateChanged(int arg1)
{
if(this->serialPort)
{
if(arg1==Qt::Checked)
{
this->timer->start(ui->lineEdit_send_time->text().toInt());
}
if(arg1==Qt::Unchecked)
{
this->timer->stop();
}
}
}
**注:**完整QT项目点击蓝字下载
,但是上述描述足以做完, 有疑惑可以在下面评论; 一起学习
愿将来所有的一切,都值得现在的等待和付出。 加油!
Author : 李光辉
date : Sun May 3 21:55:46 CST 2020
blog ID: Kevin_8_Lee
blog site : https://blog.csdn.net/Kevin_8_Lee