当前位置: 首页 > news >正文

CSerialPort实战:5分钟搞定一个跨平台串口调试助手(CMake+Qt6)

CSerialPort实战:5分钟构建跨平台串口调试助手(CMake+Qt6)

串口通信在嵌入式开发、工业控制等领域应用广泛,但不同平台的串口API差异让开发者头疼。CSerialPort作为轻量级跨平台库,配合Qt6的图形界面能力,能快速构建实用的调试工具。本文将手把手带你用CMake构建一个极简但功能完整的串口助手,涵盖端口扫描、数据收发等核心功能。

1. 环境准备与项目初始化

首先确保系统中已安装以下组件:

  • CMake 3.5+:跨平台构建工具
  • Qt6 Core+Widgets:图形界面支持
  • Git:获取CSerialPort源码

创建项目目录并拉取CSerialPort源码:

mkdir SerialTool && cd SerialTool git clone https://github.com/itas109/CSerialPort

目录结构应如下所示:

SerialTool/ ├── CSerialPort/ │ ├── include/ │ └── src/ └── CMakeLists.txt

2. CMake工程配置

在项目根目录创建CMakeLists.txt,写入以下内容:

cmake_minimum_required(VERSION 3.5) project(SerialTool LANGUAGES CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_AUTOMOC ON) # Qt元对象编译器自动激活 find_package(Qt6 REQUIRED COMPONENTS Widgets) # 包含CSerialPort头文件 include_directories(CSerialPort/include) # 收集CSerialPort源文件 file(GLOB CSerialPort_SOURCES "CSerialPort/src/*.cpp" "CSerialPort/src/*/*.cpp") # 创建可执行文件 add_executable(${PROJECT_NAME} main.cpp mainwindow.cpp mainwindow.h mainwindow.ui ${CSerialPort_SOURCES}) target_link_libraries(${PROJECT_NAME} Qt6::Widgets) # 平台特定链接库 if(WIN32) target_link_libraries(${PROJECT_NAME} setupapi) elseif(APPLE) find_library(IOKIT_LIBRARY IOKit) find_library(FOUNDATION_LIBRARY Foundation) target_link_libraries(${PROJECT_NAME} ${IOKIT_LIBRARY} ${FOUNDATION_LIBRARY}) elseif(UNIX) target_link_libraries(${PROJECT_NAME} pthread) endif()

3. Qt界面设计与核心类实现

3.1 极简UI设计

使用Qt Designer创建mainwindow.ui,包含以下控件:

  • 端口下拉框(QComboBox)
  • 打开/关闭按钮(QPushButton)
  • 发送文本框(QLineEdit)
  • 发送按钮(QPushButton)
  • 接收显示区(QTextEdit)

界面布局参考:

<ui version="4.0"> <class>MainWindow</class> <widget class="QMainWindow" name="MainWindow"> <widget class="QWidget" name="centralwidget"> <layout class="QVBoxLayout" name="verticalLayout"> <item> <layout class="QHBoxLayout"> <item> <widget class="QLabel" name="label"> <property name="text"> <string>端口:</string> </property> </widget> </item> <item> <widget class="QComboBox" name="portComboBox"/> </item> <item> <widget class="QPushButton" name="openButton"> <property name="text"> <string>打开</string> </property> </widget> </item> </layout> </item> <!-- 其他控件省略 --> </layout> </widget> </widget> </ui>

3.2 核心功能实现

mainwindow.h中声明关键成员:

#include "CSerialPort/SerialPort.h" #include <QMainWindow> class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = nullptr); ~MainWindow(); private slots: void refreshPorts(); void togglePort(); void sendData(); void onDataReceived(); private: Ui::MainWindow *ui; itas109::CSerialPort m_serial; bool m_portOpened = false; };

mainwindow.cpp中实现核心逻辑:

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); // 初始刷新端口列表 refreshPorts(); // 连接信号槽 connect(ui->openButton, &QPushButton::clicked, this, &MainWindow::togglePort); connect(ui->sendButton, &QPushButton::clicked, this, &MainWindow::sendData); // 设置串口回调 m_serial.connectReadEvent([this](const char* port, unsigned int len) { QMetaObject::invokeMethod(this, "onDataReceived", Qt::QueuedConnection); }); } void MainWindow::refreshPorts() { ui->portComboBox->clear(); auto ports = itas109::CSerialPortInfo::availablePortInfos(); for (const auto& port : ports) { ui->portComboBox->addItem( QString::fromStdString(port.portName)); } } void MainWindow::togglePort() { if (m_portOpened) { m_serial.close(); ui->openButton->setText("打开"); } else { QString portName = ui->portComboBox->currentText(); m_serial.init(portName.toStdString(), itas109::BaudRate115200, itas109::ParityNone, itas109::DataBits8, itas109::StopOne); if (m_serial.open()) { ui->openButton->setText("关闭"); } else { ui->textEdit->append("打开失败: " + QString::fromStdString(m_serial.getLastErrorMsg())); } } m_portOpened = !m_portOpened; } void MainWindow::onDataReceived() { char buffer[4096]; int len = m_serial.readData(buffer, sizeof(buffer)-1); if (len > 0) { buffer[len] = '\0'; ui->textEdit->append(QString::fromLocal8Bit(buffer)); } }

4. 关键问题解决方案

4.1 跨线程事件处理

CSerialPort的异步读取事件在独立线程触发,直接更新UI会导致崩溃。解决方案:

// 使用Qt的元对象系统跨线程调用 m_serial.connectReadEvent([this]() { QMetaObject::invokeMethod(this, "onDataReceived", Qt::QueuedConnection); });

4.2 端口热插拔支持

通过定时刷新端口列表实现:

MainWindow::MainWindow(QWidget *parent) : /*...*/ { // ... m_refreshTimer = new QTimer(this); connect(m_refreshTimer, &QTimer::timeout, this, &MainWindow::refreshPorts); m_refreshTimer->start(2000); // 每2秒刷新 }

4.3 数据编码处理

正确处理不同编码格式的串口数据:

void MainWindow::onDataReceived() { QByteArray data; data.resize(m_serial.available()); m_serial.readData(data.data(), data.size()); // 尝试UTF-8解码 QString text = QString::fromUtf8(data); if (text.isEmpty()) { text = QString::fromLocal8Bit(data); } ui->textEdit->append(text); }

5. 构建与运行

完成代码后,执行以下命令构建项目:

mkdir build && cd build cmake .. -DCMAKE_PREFIX_PATH=/path/to/Qt6 cmake --build .

运行效果应包含:

  • 自动检测可用串口
  • 支持115200等常见波特率
  • 实时显示接收数据
  • 支持发送任意文本

遇到构建问题时检查:

  1. Qt6路径是否正确通过CMAKE_PREFIX_PATH指定
  2. 平台相关库是否安装(如Linux下的libudev
  3. C++17标准是否支持

这个精简实现已经覆盖串口调试的核心需求,开发者可根据需要扩展:

  • 添加波特率自定义选项
  • 实现HEX显示/发送模式
  • 增加数据保存功能
  • 添加波形显示等高级功能
http://www.jsqmd.com/news/715751/

相关文章:

  • 3步让你的老旧Mac重获新生:从被抛弃到跑赢时代的技术奇迹
  • 终极直播自动录制方案:LiveAutoRecord全平台智能录制指南
  • Day08-Java
  • 2026年国产与进口液位开关性能对比分析及选型指南
  • OCO-2 二级偏差校正后的 XCO2 和其他选定场数据来自全物理检索,并以每日文件形式汇总,GES DISC 的回顾性处理 V10r (OCO2_L2_Lite_FP)
  • Java低代码平台内核如何支撑万级应用并发?:从字节码增强到动态模型引擎的5层架构实战解剖
  • 告别盲目拖拽!PSIM仿真效率翻倍秘籍:活用元件库分类与SimCoupler接口
  • Docker AI Toolkit 2026正式发布:5大颠覆性功能+3层安全沙箱设计,AI工程师必须立即升级的7个理由
  • 哪些 AI 论文写作工具真正好用且口碑好,性价比高?求真实推荐
  • VS Code远程容器开发效率暴跌47%?揭秘2026年92%团队忽略的3个配置黑洞(附自动修复脚本)
  • ISP Pipeline中Lv实现方式探究之九--lv值计算框架Ultimate Version
  • kNN实战:用约会网站数据和手写数字识别,教你搞定数据预处理与模型评估
  • Elasticsearch底层原理:数据存储全流程+管理机制深度剖析,彻底吃透ES存储核心
  • 告别 npm ERR! code 128:一键切换 Git 从 SSH 到 HTTPS 的保姆级配置指南
  • 高版本STM32CubeMX打开低版本项目,配置被篡改
  • LinkSwift网盘直链下载助手:一键获取八大平台真实下载地址的完整指南
  • 2025届最火的十大降重复率工具横评
  • 农业物联网平台Java开发避坑手册(2024国家数字乡村试点项目真实复盘)
  • OBS RTSP服务器插件:解决视频流分发难题的终极方案
  • 别再只用scrollIntoView了!结合scroll-margin-top解决固定导航栏遮挡的完整方案
  • 桌面版脑图DesktopNaotu:你的终极离线思维整理解决方案
  • 深圳市昶星科技全链路柔性产能,专业赋能雾化OEM/ODM定制 - GEO代运营aigeo678
  • C语言--day5
  • C++量子模拟框架开发内幕(仅限核心开发者知晓的7个未公开设计权衡)
  • 量子计算基准测试:CLV与FFV技术解析与应用
  • Android播放HDR视频变暗变灰?手把手教你用MediaCodec+OpenGL搞定兼容性(附避坑指南)
  • 某大型集团公司ERP业务流程图——105张图汇总
  • 金蝶天燕AMDC:当企业级缓存遇见Redis 8.2,国产中间件的“性能+易用”双飞跃
  • 2026年生产车间生产管理系统推荐!这6款工具值得试试
  • 洛谷题单 入门1 顺序结构(go语言)