1. 项目概述
作为一名嵌入式开发者,我经常需要与各种串口设备打交道。在开发过程中,一个稳定可靠的串口调试工具是必不可少的。虽然市面上有很多现成的串口调试助手,但往往功能繁杂或者缺少某些特定需求。于是,我决定用QT框架从零开始打造一个属于自己的串口调试助手。
这个项目将分为多个阶段进行开发。在第一部分中,我们已经完成了QT开发环境的搭建。现在进入第二部分,主要实现以下核心功能:
- 自动识别系统可用串口
- 实现串口的打开和关闭功能
- 支持常见波特率设置
- 提供完整的源码下载
2. QT串口模块安装与配置
2.1 安装串口模块
QT默认安装并不包含串口模块,需要手动添加。以下是详细步骤:
-
找到QT维护工具:
- 打开QT安装目录(默认是
C:\Qt,如果你像我一样自定义了安装路径,比如D:\Qt,就进入对应的文件夹) - 找到并双击
MaintenanceTool.exe
- 打开QT安装目录(默认是
-
登录QT账号:
- 如果你之前安装QT时已经登录过账号,这里会自动保留登录状态
- 直接点击"下一步"即可
-
选择组件:
- 在组件列表中,找到与你当前项目使用的QT版本完全一致的版本
- 勾选"Qt Serial Port"模块
- 建议同时勾选"Qt Build Tools"和"Qt Logging"模块(虽然不是必须的,但对开发有帮助)
注意:安装过程可能会比较慢,特别是网络状况不佳时。我安装时大约花了30分钟,建议耐心等待。
2.2 验证安装
安装完成后,可以通过以下方式验证串口模块是否安装成功:
- 打开QT Creator
- 新建一个控制台应用项目
- 在.pro文件中添加:
qmake复制QT += serialport - 在main.cpp中添加:
cpp复制#include <QSerialPort> #include <QSerialPortInfo> - 编译运行,如果没有报错,说明安装成功
3. 串口调试助手UI设计
3.1 主界面布局
我们的串口调试助手需要包含以下基本元素:
-
串口参数设置区域:
- 串口号选择下拉框
- 波特率选择下拉框
- 数据位、校验位、停止位、流控选择下拉框
-
操作按钮:
- 打开/关闭串口按钮
- 发送数据按钮(下一阶段实现)
-
数据显示区域:
- 发送数据输入框
- 接收数据显示框
3.2 UI设计步骤
-
在QT Creator中新建一个Widgets Application项目
-
打开主窗口的.ui文件
-
从左侧控件栏拖拽需要的控件到主窗口:
- 多个Label用于参数说明
- ComboBox用于参数选择
- PushButton用于操作
- LineEdit用于发送数据输入
- PlainTextEdit用于接收数据显示
-
为控件设置合适的objectName,方便后续代码调用:
- 串口号下拉框:cbbSerialPort
- 波特率下拉框:cbbBaudRate
- 打开串口按钮:btnOpenSerial
- 发送数据按钮:btnSendData
- 发送数据输入框:leSendData
- 接收数据显示框:teRecvData
4. 核心代码实现
4.1 项目配置文件(.pro)
首先需要在项目配置文件中添加串口模块支持:
qmake复制QT += core gui serialport
TARGET = SerialPortTool
TEMPLATE = app
SOURCES += \
main.cpp \
mainwindow.cpp
HEADERS += \
mainwindow.h
FORMS += \
mainwindow.ui
关键点说明:
QT += serialport:添加串口模块支持- 其他配置保持QT默认生成的即可
4.2 主窗口头文件(mainwindow.h)
cpp复制#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QSerialPort>
#include <QSerialPortInfo>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void onBtnOpenSerialClicked();
void onBtnSendDataClicked();
void onSerialPortReadyRead();
private:
Ui::MainWindow *ui;
QSerialPort *serialPort;
void initSerialPortComboBox();
void initBaudRateComboBox();
void initParityComboBox();
void initDataBitsComboBox();
void initStopBitsComboBox();
void initFlowControlComboBox();
};
#endif // MAINWINDOW_H
4.3 主窗口实现文件(mainwindow.cpp)
4.3.1 构造函数与初始化
cpp复制#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include <QMessageBox>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
// 创建串口对象
serialPort = new QSerialPort(this);
// 初始化各下拉框
initSerialPortComboBox();
initBaudRateComboBox();
initParityComboBox();
initDataBitsComboBox();
initStopBitsComboBox();
initFlowControlComboBox();
// 连接信号与槽
connect(ui->btnOpenSerial, &QPushButton::clicked, this, &MainWindow::onBtnOpenSerialClicked);
connect(ui->btnSendData, &QPushButton::clicked, this, &MainWindow::onBtnSendDataClicked);
connect(serialPort, &QSerialPort::readyRead, this, &MainWindow::onSerialPortReadyRead);
}
4.3.2 下拉框初始化函数
cpp复制void MainWindow::initSerialPortComboBox()
{
ui->cbbSerialPort->clear();
// 获取系统可用串口
foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) {
ui->cbbSerialPort->addItem(info.portName());
}
if (ui->cbbSerialPort->count() == 0) {
ui->cbbSerialPort->addItem("无串口");
ui->btnOpenSerial->setEnabled(false);
}
}
void MainWindow::initBaudRateComboBox()
{
ui->cbbBaudRate->clear();
ui->cbbBaudRate->addItem("1200", QSerialPort::Baud1200);
ui->cbbBaudRate->addItem("2400", QSerialPort::Baud2400);
ui->cbbBaudRate->addItem("4800", QSerialPort::Baud4800);
ui->cbbBaudRate->addItem("9600", QSerialPort::Baud9600);
ui->cbbBaudRate->addItem("19200", QSerialPort::Baud19200);
ui->cbbBaudRate->addItem("38400", QSerialPort::Baud38400);
ui->cbbBaudRate->addItem("115200", QSerialPort::Baud115200);
ui->cbbBaudRate->setCurrentIndex(3); // 默认9600
}
4.3.3 串口操作函数
cpp复制void MainWindow::onBtnOpenSerialClicked()
{
if (serialPort->isOpen()) {
serialPort->close();
ui->btnOpenSerial->setText("打开串口");
QMessageBox::information(this, "提示", "串口已关闭");
return;
}
// 获取用户选择的参数
QString portName = ui->cbbSerialPort->currentText();
QSerialPort::BaudRate baudRate = static_cast<QSerialPort::BaudRate>(ui->cbbBaudRate->currentData().toInt());
QSerialPort::Parity parity = static_cast<QSerialPort::Parity>(ui->cbbParity->currentData().toInt());
QSerialPort::DataBits dataBits = static_cast<QSerialPort::DataBits>(ui->cbbDataBits->currentData().toInt());
QSerialPort::StopBits stopBits = static_cast<QSerialPort::StopBits>(ui->cbbStopBits->currentData().toInt());
QSerialPort::FlowControl flowControl = static_cast<QSerialPort::FlowControl>(ui->cbbFlowControl->currentData().toInt());
// 配置串口参数
serialPort->setPortName(portName);
serialPort->setBaudRate(baudRate);
serialPort->setParity(parity);
serialPort->setDataBits(dataBits);
serialPort->setStopBits(stopBits);
serialPort->setFlowControl(flowControl);
// 尝试打开串口
if (serialPort->open(QIODevice::ReadWrite)) {
ui->btnOpenSerial->setText("关闭串口");
QMessageBox::information(this, "提示",
"串口打开成功!\n串口:" + portName + "\n波特率:" + ui->cbbBaudRate->currentText());
} else {
QMessageBox::critical(this, "错误", "串口打开失败!\n原因:" + serialPort->errorString());
}
}
5. 常见问题与解决方案
5.1 串口无法打开
可能原因:
- 串口被其他程序占用
- 没有串口设备或设备未正确连接
- 权限问题(Linux/Mac系统)
解决方案:
- 关闭可能占用串口的其他程序
- 检查设备连接状态
- 在Linux/Mac下,可能需要使用sudo运行程序或修改设备权限
5.2 波特率设置无效
可能原因:
- 设备不支持设置的波特率
- 波特率设置代码有误
解决方案:
- 确认设备支持的波特率范围
- 检查代码中波特率设置是否正确:
cpp复制serialPort->setBaudRate(QSerialPort::Baud9600); // 明确指定枚举值
5.3 串口列表不更新
可能原因:
- 设备插拔后没有重新扫描串口
- 系统没有正确识别设备
解决方案:
- 实现一个刷新按钮,点击时重新调用
initSerialPortComboBox() - 检查设备管理器/系统日志,确认设备是否被正确识别
6. 开发心得与技巧
-
跨平台考虑:
- Windows下串口名称为COMx(如COM1)
- Linux下通常为/dev/ttySx或/dev/ttyUSBx
- MacOS下通常为/dev/tty.usbserial-xxx
- QT的QSerialPortInfo可以自动处理这些差异
-
错误处理:
- 一定要检查
serialPort->open()的返回值 - 使用
serialPort->errorString()获取详细的错误信息
- 一定要检查
-
性能优化:
- 对于高速串口通信,考虑使用缓冲区而不是每次收到数据就立即处理
- 可以使用定时器定期读取数据,而不是实时响应readyRead信号
-
调试技巧:
- 使用qDebug()输出调试信息
- 可以在接收数据处理函数中添加时间戳,方便分析通信时序
7. 下一步开发计划
-
实现数据收发功能:
- 完成发送数据按钮的功能
- 完善接收数据处理和显示
-
增加HEX/ASCII转换:
- 支持16进制发送和显示
- 支持ASCII码发送和显示
-
自动识别串口变化:
- 实现串口热插拔检测
- 自动更新串口列表,无需重启软件
-
增强功能:
- 添加发送历史记录
- 实现数据保存功能
- 增加通信统计(发送/接收字节数)
通过这个项目的开发,我深刻体会到QT框架在跨平台串口通信开发中的便利性。虽然目前功能还比较简单,但已经具备了串口调试助手的基本功能。在后续开发中,我会逐步完善各项功能,最终打造一个功能全面、稳定可靠的串口调试工具。