由于项目需要使用到串口调试及测试,为了练手,使用 Qt 编写一个串口调试助手。本文按开发的过程进行简单介绍,同时也涉及部分用到的模块代码。详细代码参考源码仓库。
工具特性
具体功能
- 具备串口收发功能。
- 串口参数设置。默认115200,N,8,1
- 接收区清空,接收区十六进制显示,接收区时间戳。
- 发送区清空,十六进制发送,自动追加
\r\n
,定时发送。 - 收发计数显示及清零。
- 串口设备自动检测。运行前串口就绪则自动打开。运行中串口插入不会自动打开。运行过程中拔出设备则自动关闭串口。
已知 Bug
接收区时间戳显示不完善。
串口发送大量乱码时,程序会崩溃。乱码可能是真的乱码,也可能是波特率错误设置。
Qt 相关知识
- MainWindow设计。
- Qt串口类。
- 常用控件:按钮、复选框、文本编辑框、控件贴图。应用程序logo。
- Qt 检测设备热插拔(Windows)。
运行结果如图1所示:
开发过程
工程相关
Qt 使用的串口类为QSerialPort
,需要在工程文件中添加对应的库,如下:
1 | QT += core gui serialport |
logo图标,注意是 ico 格式:
1 | RC_ICONS = images/logo.ico |
图片资源文件:
1 | RESOURCES += \ |
USB 设备检测依赖的库:
1 | win32: LIBS += -lSetupAPI -luser32 |
信号与槽
在 Qt Creator 中添加的控件,可点击控件右键,选择“转到槽…”,选择适合的槽,点击“OK”,可自动添加槽函数声明,并自动跳转到槽函数实现代码。系统自动添加的形式为on_<控件对象名>_<控件事件名>
,如打开串口的按钮单击事件槽函数为on_btnOpen_clicked
。类似有on_cbPortName_currentTextChanged
(串口设备更改)、on_ckRecvHex_stateChanged
(接收十六进制复选框变更),等等。
此机制及操作方式,可类比于 MFC 的界面设计和消息响应。实际上,笔者喜欢将槽函数称为响应函数。
串口相关
串口类声明:
1 | #include <QSerialPort> |
枚举本机串口设备:
1 | QSerialPortInfo::availablePorts() |
串口参数设置:
1 | serial.setPortName("com4"); // 串口名称 |
注:Qt 似乎只有无流控、软件流控、硬件流控这三种,无法区分 RTS、DTR。
串口打开、关闭:
1 | serial.open(QIODevice::ReadWrite); |
串口数据发送:
1 | QByteArray sendData; |
串口数据接收:
1 | // 串口数据到来时,会触发QSerialPort::readyRead事件,添加相应的响应函数 |
注意,串口数据类型为QByteArray
。
自动检测 USB
鉴于目前大部分场合使用的是 USB 串口线,所以添加对 USB 设备的检测。这里检测到 USB 设备时,再使用QSerialPortInfo::availablePorts()
检测串口设备。
1 | #include <windows.h> |
响应nativeEvent
事件:
1 | bool MainWindow::nativeEvent(const QByteArray &eventType, void *message, long *result) |
这里使用自定义的信号sig_deviceChanged
,连接到函数on_deviceChanged
:
1 | QObject::connect(this, &MainWindow::sig_deviceChanged, this, &MainWindow::on_deviceChanged); |
界面逻辑
界面设计
界面使用设计师进行设计,如图2所示。
界面基本设置
在initMainWindow
函数中对窗口进行基本设置,如标题、窗口大小,最小化最大化按钮,等等。
1 | // 对主窗口的初始化 |
状态栏
状态栏主要用于调试信息、提示信息的显示,另外显示收发计数(及清零)。
状态栏相关函数和变量声明如下:
1 | void initStatusBar(); |
初始化函数如下:
1 | void MainWindow::initStatusBar() |
为响应状态栏控件事件,需要重载并实现函数eventFilter
:
1 | bool eventFilter(QObject *watched, QEvent *event); |
目前处理的事件有单击退出图标,以及点击清零计数QLabel。
控件贴图
新建资源文件 images.qrc,内容如下,再在 Qt Creator 中添加该文件:
1 | <RCC> |
也可以在 Qt Creator 新建资源文件,右键添加图片。效果一样。
以打开串口按钮为例,设置文字和图标代码如下:
1 | ui->btnOpen->setText(tr("打开串口")); |
注:资源文件 qrc 的前缀为/
,images为工程下的目录,使用 QIcon的参数形式为:images/xxx
。
QComboBox
串口参数使用 QComboBox 控件,为方便添加数据,使用 QStringList 类,再利用 addItems 添加数据项。其初始化如下:
1 | QStringList list; |
串口参数自动更新
为串口打开时,可以实时更改参数,但串口设备除外。响应 QComboBox 的currentTextChanged
或currentIndexChanged
事件。如下:
1 | // 串口设备直接用文本文字形式即可 |
QCheckBox
复选框用于发送、显示的特性设置。如十六进制发送、显示,定时发送,等等。设计上使用标志变量,在进行发送、显示时加以判断。主要响应 QCheckBox 的 stateChanged
函数。
1 | void MainWindow::on_ckRecvHex_stateChanged(int arg1) |
定时器
重载timerEvent
函数:
1 | #include <QTimer> |
函数实现:
1 | void MainWindow::timerEvent(QTimerEvent *event) |
开启、停止定时器:
1 | m_sendTimerId = startTimer(ui->txtInterval->text().toInt()); |
由于本程序只使用一个定时器,故不用判断event->timerId()
。
十六进制
为方便调试,工具支持字符、十六进制数据的发送和显示。“十六进制字符串”转字符串等函数集如下:
1 |
|
其它
实际上,程序难度不大,特别是串口类的操作,因为QSerialPort
提供了十分友好、方便的接口进行串口的设置、收发。如果要说有难度,可能在于界面逻辑的设计。如定时发送与单次发送,控件提示文字和图标显示,十六进制与字符串之间的转换,等等。
笔者在此工具基础上实现了对 ESP8266 的操作,包括指示LED灯、继电器、出厂恢复以及运行态的功能测试验证等操作。由于与本文关联不大,不再展开。
代码仓库
代码以仓库为准,本文不一定全部囊括。本工程所有源码均可自由自主使用,包括但不限于添加、删除、修改,商用、自用。由此带来的成果/后果概与作者无关。限于水平能力,本程序无任何质量保证,本程序作者无提供服务之义务。
仓库地址在此 。