Qt串口通信开发教程:Linux下的串口调试工具实现

Qt串口通信开发教程:Linux下的串口调试工具实现

文章前言:

源码地址:https://github.com/haoxiliangluo/robot_control

不用做ros开发的可以将串口部分复制到新的项目中,也可以直接cmake使用,如果直接使用的话,请不要连接rosmaster,这可能会导致程序崩溃。

本项目是我大一下学期时候在Linux为调试串口方便写的,当时用的都是很简单的语法,也没有开多线程,所以在一些方面可能为有一些问题,等我抽出来空再将他分离出来,并进行优化。

1. 项目概述

本文介绍一个基于Qt5和ROS的串口通信工具,该工具提供了一套完整的串口通信解决方案,可用于各种串口设备的调试和数据传输。工具具有以下特点:

  • 自动检测和显示系统可用串口设备
  • 完整的串口参数配置(波特率、数据位、停止位、校验位)
  • 支持ASCII和十六进制数据的收发与显示
  • 大数据量自动清屏功能
  • 串口数据保存功能
  • 自动重连断开的串口
  • 添加时间戳功能

项目效果:

2. 开发环境配置

2.1 开发环境

  • 操作系统:Ubuntu 20.04
  • ROS版本:ROS Noetic
  • Qt版本:Qt 5.14.2(也可使用Qt 5.12或更高版本)
  • 编译器:GCC 9.3.0
  • 构建工具:CMake 3.16.3

2.2 依赖库

  • QtSerialPort:Qt提供的串口通信模块
  • QtWidgets:Qt图形界面库
  • ROS相关库(可选,用于ROS集成)

2.3 环境配置

  1. 安装Qt开发环境:

    bash 复制代码
    sudo apt-get install qt5-default qtcreator
  2. 安装Qt串口模块:

    bash 复制代码
    sudo apt-get install libqt5serialport5-dev
  3. 安装ROS(如果需要ROS集成):

    bash 复制代码
    # 按ROS官方指南安装ROS Noetic

3. 项目结构

serial/
├── CMakeLists.txt         # CMake构建脚本
├── package.xml           # ROS包配置文件
├── mainpage.dox          # 文档配置
├── resources/            # 资源文件目录
│   └── images.qrc        # Qt资源配置文件
├── ui/                   # UI文件目录
│   └── main_window.ui    # 主窗口UI设计文件
├── include/              # 头文件目录
│   └── serailDemo/       # 项目头文件
│       ├── main_window.hpp  # 主窗口类定义
│       └── qnode.hpp     # ROS节点类定义
└── src/                 # 源代码目录
    ├── main.cpp         # 主函数
    ├── main_window.cpp  # 主窗口类实现
    └── qnode.cpp        # ROS节点类实现

4. 核心功能实现

4.1 串口设备检测

使用QSerialPortInfo类获取系统可用串口设备列表:

cpp 复制代码
void MainWindow::report()
{
    ui.serial_port_2->clear(); //清空下拉菜单

    portList = QSerialPortInfo::availablePorts(); //获取端口列表

    //添加下拉菜单
    for (QSerialPortInfo &i : portList)
    {
        ui.serial_port_2->addItem(i.portName());
    }
}

4.2 串口参数配置

设置串口参数,包括波特率、数据位、停止位和校验位:

cpp 复制代码
void MainWindow::slot_open_serial()
{   
    //相当于sudo,pkexec一般用于图形化编程
    QString command = "pkexec chmod 666 /dev/" + portList.at(ui.serial_port_2->currentIndex()).portName();
    system(command.toUtf8());
    update_serial_date();
    serial.setParity(parity);
    serial.setBaudRate(baudRate);
    serial.setDataBits(dataBits);
    serial.setStopBits(stopBits);
    if (serial.open(QIODevice::ReadWrite)) {
        logMessage("串口打开成功!");
    } else {
        logMessage("串口打开失败!");
        qDebug() << serial.error();
    }
}

4.3 数据发送功能

实现数据发送,支持ASCII和十六进制格式:

cpp 复制代码
void MainWindow::sendMessge() {
    if (serial.isOpen()) {
        QString message = ui.textEdit->toPlainText();
        QByteArray data = message.toUtf8();
        if(ui.checkBox_3->isChecked())
        {
            message = data.toHex(' ').toUpper(); // 将数据转换为十六进制字符串,并用空格分隔
            serial.write(data);
        }
        else
        {
            serial.write(data);
        }
        receivedDataSize += data.size();
        // 检查是否需要200k清屏
        if(ui.checkBox_5->isChecked() && receivedDataSize >= 200 * 1024)
        {
            cleanAccept();
            receivedDataSize = 0;
        }
        logMessage("发送: " + message);
    } else {
        logMessage("串口并没有被打开.");
        QMessageBox::warning(this, "warning!", "串口并没有被打开,脑子不要可以捐了.");
    }
}

4.4 数据接收功能

使用QSerialPort::read方法读取串口数据,支持ASCII和十六进制显示:

cpp 复制代码
void MainWindow::readSerialData()
{
    while (serial.canReadLine()) {
        QByteArray data = serial.read(serial.bytesAvailable());
        receivedDataSize += data.size();
        if (ui.checkBox_5->isChecked() && receivedDataSize >= 200 * 1024) {
            cleanAccept();
            receivedDataSize = 0;
        }
        QString message;
        if (ui.checkBox_2->isChecked()) {
            message = toHex(data);
        } else  {
            message = QString::fromUtf8(data);
        }
        logMessage("接收: "+message);
    }
}

4.5 十六进制转换

实现数据与十六进制字符串之间的转换:

cpp 复制代码
QString MainWindow::toHex(const QByteArray &data)
{
    QString hexString;
    for (char byte : data) {
        hexString.append(QString("%1 ").arg(static_cast<unsigned char>(byte), 2, 16, QChar('0')).toUpper());
    }
    return hexString.trimmed();
}

4.6 自动重连功能

检测串口错误并自动尝试重新连接:

cpp 复制代码
void MainWindow::handleSerialError(QSerialPort::SerialPortError error) {
    if (error == QSerialPort::ResourceError) {
        logMessage("串口连接断开,尝试重新连接...");
        serial.close();
        QTimer::singleShot(1000, this, &MainWindow::slot_open_serial);
    }
}

4.7 保存数据功能

将接收的数据保存到文件:

cpp 复制代码
void MainWindow::save_data()
{
    QString filename = QFileDialog::getSaveFileName(this, tr("选择保存路径"), "");
    QFile file(filename);
    file.open(QIODevice::ReadWrite | QIODevice::Text);
    //获取日志信息
    QStringList saveData;
    for(int i=0; i<ui.listWidget->count(); i++)
    {
        QListWidgetItem* item = ui.listWidget->item(i);
        saveData << item->text();
    }

    // 将 QStringList 转换为单个 QString
    QString saveDataString = saveData.join("\n");

    // 写入日志信息
    if (file.write(saveDataString.toUtf8()) > 0) {
        // 弹出成功对话框
        QMessageBox::information(this, tr("保存数据"), tr("保存成功!"));
    } else {
        QMessageBox::warning(this, tr("保存数据"), tr("保存失败!"));
    }
}

5. CMake配置

项目使用CMake构建,以下是CMakeLists.txt的核心部分:

cmake 复制代码
cmake_minimum_required(VERSION 2.8.0)
project(serailDemo)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_PREFIX_PATH "/usr/lib/x86_64-linux-gnu/cmake/Qt5")
find_package(catkin REQUIRED COMPONENTS roscpp)
include_directories(${catkin_INCLUDE_DIRS})
find_package(Qt5 REQUIRED Core Widgets SerialPort)
set(QT_LIBRARIES Qt5::Widgets Qt5::SerialPort)
catkin_package()
file(GLOB QT_FORMS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ui/*.ui)
file(GLOB QT_RESOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} resources/*.qrc)
file(GLOB_RECURSE QT_MOC RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} FOLLOW_SYMLINKS include/serailDemo/*.hpp *.h)
QT5_ADD_RESOURCES(QT_RESOURCES_CPP ${QT_RESOURCES})
QT5_WRAP_UI(QT_FORMS_HPP ${QT_FORMS})
QT5_WRAP_CPP(QT_MOC_HPP ${QT_MOC})
file(GLOB_RECURSE QT_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} FOLLOW_SYMLINKS src/*.cpp)
add_executable(serailDemo ${QT_SOURCES} ${QT_RESOURCES_CPP} ${QT_FORMS_HPP} ${QT_MOC_HPP})
target_link_libraries(serailDemo ${QT_LIBRARIES} ${catkin_LIBRARIES})
install(TARGETS serailDemo RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION})

6. UI设计

通过Qt Designer创建界面,主要包含:

  1. 串口配置区域:用于选择串口设备和设置串口参数
  2. 接收区域:显示接收到的数据
  3. 发送区域:用于编辑和发送数据
  4. 控制按钮:打开/关闭串口、清空接收/发送区、保存数据等
  5. 选项设置:十六进制显示/发送、添加时间戳、自动清屏等

UI文件通过QT5_WRAP_UI命令转换为C++头文件,并在主窗口类中使用。

7. 编译与运行

7.1 使用catkin编译

bash 复制代码
# 在工作空间根目录下
catkin_make

7.2 运行程序

bash 复制代码
# 在工作空间根目录下
source devel/setup.bash
rosrun serailDemo serailDemo#用ros开发的
./build/devel/lib/serailDemo #原生linux开发的

8. 使用指南

  1. 选择串口设备:从下拉菜单中选择要使用的串口设备
  2. 配置串口参数:设置波特率、数据位、停止位和校验位
  3. 打开串口:点击"打开串口"按钮
  4. 发送数据:在发送区输入要发送的数据,点击"发送消息"按钮
  5. 接收数据:接收到的数据将显示在接收区
  6. 特殊功能
    • 勾选"16进制显示"可将接收到的数据以十六进制显示
    • 勾选"16进制发送"可将发送的数据以十六进制发送
    • 勾选"200k清屏"当接收数据量超过200KB时自动清空接收区
    • 勾选"添加时间头"在日志前添加时间戳
  7. 保存数据:点击"保存串口数据"按钮将接收到的数据保存到文件

9. 常见问题与解决方案

  1. 无法打开串口

    • 检查串口权限:确保当前用户有访问串口设备的权限
    • 检查串口是否被其他程序占用
    • 检查串口设备是否正确连接
  2. 数据接收显示乱码

    • 检查波特率设置是否正确
    • 检查数据位、停止位、校验位是否与设备匹配
    • 尝试以十六进制模式查看数据
  3. 程序闪退或卡死

    • 检查串口连接是否稳定
    • 减少高频率大数据量的传输
    • 启用自动清屏功能

10. 拓展与改进

本项目还可以进行以下改进:

  1. 添加数据绘图功能,实时显示串口数据
  2. 增加数据协议解析功能
  3. 支持多串口同时操作

11. 总结

本文介绍了一个基于Qt和ROS的串口通信工具的实现过程,包括环境配置、核心功能实现、UI设计和使用说明。该工具功能完善,界面友好,适用于各种串口设备的调试和开发工作。通过这个项目,我们可以了解Qt串口通信的基本原理和实现方法,为进一步的串口应用开发打下基础。

希望这篇教程对大家学习Qt串口通信开发有所帮助!如有问题欢迎在评论区留言讨论。


欢迎分享、点赞、收藏!如果您对这个项目有兴趣,可以到我的GitHub仓库查看完整代码。

相关推荐
ChineHe1 分钟前
Git基础篇 - Linux(CentOS)源码安装Git实例
linux·git·centos
请来次降维打击!!!5 分钟前
算法优选系列(1.双指针_下)
c++·算法
kevindanglu10 分钟前
CentOS7安装软件yum install 无法解析仓库URL
linux·服务器
Run_Teenage14 分钟前
C语言每日一练——day_4
c语言·开发语言
SongYuLong的博客20 分钟前
C# WPF 串口通信
开发语言·c#·wpf
熊峰峰32 分钟前
数据结构第六节:二叉搜索树(BST)的基本操作与实现
开发语言·数据结构·c++·算法
追寻向上36 分钟前
《JMeter自动化测试实战指南:从环境搭建到Python集成》
开发语言·python·jmeter
John_ToDebug37 分钟前
Chrome 浏览器性能优化全景解析
c++·chrome·性能优化
字节程序员44 分钟前
JMeter使用BeanShell断言
开发语言·python·jmeter
最爱で毛毛熊44 分钟前
JavaScript性能优化
开发语言·javascript·性能优化