简介一份Linux平台可用的串口通信工具cuteCOM源码包面向嵌入式开发者、Linux运维及需要串口调试的工程师。该源码不仅覆盖常规的串口参数配置与收发数据功能还内置文件发送能力适合固件更新、数据采集等场景同时为学习串口编程提供了可阅读、可修改的完整工程。资源共5个文件以cpp源文件、h头文件为主搭配ui界面文件和pro工程文件结构精简便于直接编译与二次开发压缩包仅14KB。已有162人学习下载。由于是源码发布使用者可自行调整界面与传输逻辑并针对不同Linux发行版重新编译摆脱商业工具限制。对于正在研究Qt串口通信、需要快速搭建调试工具的开发者而言这是一份轻量而实用的参考实现。 刚在调一块板子需要往设备里发一个几百 KB 的固件升级包手头终端工具试了一圈都不顺手要么只能发文本要么对大文件支持稀烂。翻出以前编译过的 cuteCOM 源码改吧改吧二十分钟搞定。这工具虽然名字不起眼但源码结构干净串口收发、文件发送、UI 都齐特别适合拿来改造成自己的串口调试环境。今天就把这个源码的架构和文件发送部分的实现思路拆开讲讲也把编译和踩坑过程一起记录一下。1. 项目整体设计与技术选型思路1.1 为什么选择 cuteCOM 作为串口调试工具用过不少串口工具商业的、开源的、命令行的一抓一大把。但 cuteCOM 吸引我的是它“小而完整”的源码结构。它基于 Gtk 编写跨平台能力不错在 Linux 桌面环境下原生支持很好。相比 minicom 这种纯终端工具cuteCOM 有图形界面操作直观串口参数配置一目了然。而相比自己从零写一个串口工具基于 cuteCOM 做二次开发能省掉大量 UI 和底层收发逻辑的重复造轮子工作。另外一个很重要的点是cuteCOM 的源码对串口底层的封装不算复杂很适合用来学习 Linux 下串口编程的核心套路。它直接基于 POSIX 终端接口termios操作串口设备不依赖额外的串口库这对理解串口通信原理特别有帮助。如果你是想搞嵌入式开发、写自动化测试脚本或者单纯想把串口工具改成符合自己习惯的样子这个项目都很值得拿来看一看。1.2 源码结构的核心模块划分把 cuteCOM 的源码拉下来大致看一眼整个项目可以分成几个核心模块。第一个是主窗口模块负责构建 Gtk 界面、菜单、按钮布局第二个是串口配置模块包括设备节点选择、波特率、数据位、校验位、停止位、流控等参数设置第三个是串口收发模块处理数据的读取、显示和发送第四个就是我们要重点关注的“发送文件”功能模块它读取本地文件内容通过串口按指定规则发送出去。这样的模块划分非常清晰改动起来也方便。串口参数配置模块用了 GtkComboBox 来做下拉选择设备列表通过遍历 /dev/ttyS* 和 /dev/ttyUSB* 来生成基本覆盖了板卡自带串口和 USB 转串口这两种常见情况。收发模块则是通过一个独立的接收线程用 read() 阻塞读取串口数据再用 g_idle_add 回调到主线程刷新 UI 显示这套逻辑不复杂但足够稳定。我实际把整个源码过了一遍代码量不算大核心逻辑集中在一两个文件里非常适合阅读和修改。比那些动辄几万行、封装了一层又一层的大型串口工具cuteCOM 的代码反而更让人看得明白。1.3 技术选型的对比分析如果拿 cuteCOM 和另外几个常见的 Linux 串口方案对比会有更直观的认识。minicom 是命令行下的老牌工具功能强但无图形界面而且配置比较繁琐Picocom 更轻量适合快速测试但同样没有界面CuteCom 则是图形界面的代表使用体验最接近 Windows 下常用的串口调试助手。而如果自己写脚本比如用 Python 的 pyserial实现收发没问题但要做一个交互界面、文件发送进度显示工作量和 cuteCOM 的二次开发差不多。从二次开发的角度看cuteCOM 的好处在于它本身就是图形界面程序改造成本低它是 C 语言写的编译依赖少在绝大多数 Linux 发行版上都能直接编译运行它不依赖庞大的第三方框架交叉编译或者移植到嵌入式平台也相对容易。这些优势让它在“需要一个能改的、有界面的串口工具”这个场景下成了我很推荐的选择。2. 核心串口通信机制与文件发送原理2.1 Linux 串口设备与 termios 配置要点Linux 下一切皆文件串口设备也以文件节点的形式存在于 /dev 下面。老式的主板串口一般是 /dev/ttyS0、/dev/ttyS1USB 转串口则是 /dev/ttyUSB0、/dev/ttyUSB1还有一些嵌入式设备可能是 /dev/ttySAC 或者其他名字。cuteCOM 在扫描设备节点时其实做的就是遍历设备目录、按前缀过滤的操作。这个逻辑虽然简单但非常实用。对串口的控制核心在于 termios 结构体。cuteCOM 的源码里有一段很经典的配置代码先打开设备文件然后通过 tcgetattr 获取当前属性修改 c_cflag、c_iflag、c_oflag、c_lflag 这几个字段最后用 tcsetattr 写回。这里有几个关键点波特率要用 cfsetispeed 和 cfsetospeed 分别设置输入输出速率数据位、停止位、校验位是通过修改 c_cflag 中的 CS8、CSTOPB、PARENB 这些掩码来控制的这一点和很多人的直觉不太一样。流控配置也是在这里做的。硬件流控需要设置 CRTSCTS软件流控则要设置 IXON、IXOFF。cuteCOM 的界面里有流控选项对应的就是修改这几个标志位。还有一个很容易被忽略的地方是 raw mode。如果不把终端设置成原始模式串口数据中的某些字符会被终端驱动特殊处理比如换行符转换、CtrlC 信号等导致数据收发异常。cuteCOM 里会清掉 ICANON、ECHO 等标志位把串口设置成 raw mode这是保证串口通信数据“原样进出”的关键。2.2 串口数据的读取与显示流程cuteCOM 的数据接收流程值得展开讲讲。它在打开串口后创建一个接收线程线程里用一个 while 循环不断调用 read() 从串口文件描述符中读取数据。这个循环不是简单的死循环而是会先调用 select() 或者 poll() 检测串口是否有数据可读避免一直空转占用 CPU。读到数据之后追加到一个缓冲区里同时通过 Gtk 的 idle 回调机制通知主界面刷新显示区。这套设计有一个很实在的好处串口读数据是阻塞操作如果放在主线程里一读到数据就卡住整个界面就动弹不得了。cuteCOM 把读数据丢到独立线程UI 主线程只负责响应事件、刷新界面这样即使串口数据量很大界面也不会卡死。显示方面接收区用的是 GtkTextView。数据到达后通过 gtk_text_buffer_insert 把新内容追加到缓冲区末尾再用 gtk_text_view_scroll_to_mark 滚动到最底部保证始终显示最新数据。cuteCOM 的接收显示还区分了 ASCII 和 HEX 两种模式数据的转换和显示逻辑并不复杂就是在写入 TextView 之前把字节流转成对应的字符串。2.3 文件发送功能的实现思路cuteCOM 的文件发送功能是它的亮点也是读者问得最多的部分。这个功能的本质就是打开一个本地文件读取文件内容按照一定的速率和规则通过串口发送出去。但这里有几个细节决定了发送功能好不好用。第一个细节是二进制安全。如果文件是二进制文件比如固件包里面可能包含 0x00、0x0A、0x1A 这样的特殊字节。发送时不能把文件内容当字符串处理而必须按原始字节流发送。cuteCOM 的源码在文件发送路径上走的不是文本发送的接口而是直接把缓冲区里的字节写进串口中间不加任何转换。这一点在嵌入式固件升级场景下至关重要尤其是很多串口 loader 要求数据逐字节原样传输任何多余的转义都会让固件校验失败。第二个细节是分块读取与发送。一个文件动辄几百 KB如果一次性读进内存再发送内存占用太大而且串口速率有限一次性写入可能导致内核缓冲区塞满write() 返回的字节数小于请求的字节数。cuteCOM 的做法是每次读一小块比如 4KB 或者 8KB写入串口后检查实际写入长度如果没写完整就继续写剩余部分直到这一块全部写完再读下一块。这种分块机制很类似网络编程中的发送循环是保证大文件不丢数据的关键。第三个细节是发送延时的控制。不同的设备对串口数据接收速度的要求不一样有的设备内部缓冲区很小数据来得太快会溢出丢包。cuteCOM 在文件发送时会在块之间加入一个可配置的延时这个延时可以通过界面参数调整。比如发 AT 指令查询类的文本数据不需要延时而给某些老式单片机 bootloader 灌固件可能每一块之间需要几十毫秒的间隔让设备有足够时间把数据搬走。这个细节在实际调试中经常决定发送成功与否。2.4 发送进度反馈的实现cuteCOM 的文件发送界面里有一个进度条这个进度条的实现思路也很典型。发送循环每完成一个数据块就更新一次“已发送字节数”用已发送字节数除以文件总字节数得到百分比再调进度条控件的更新接口刷新显示。因为发送循环运行在独立线程里进度条的更新同样通过 Gtk 的 idle 回调回到主线程执行避免在线程里直接操作 UI 控件。这个进度反馈机制虽然简单但对使用者来说非常重要。串口发送大文件往往耗时几秒甚至几十秒如果没有进度显示用户没法判断程序是还在发送还是已经卡死了。cuteCOM 的做法算是教科书写法任何用 Gtk 或其他 GUI 框架做多线程串口工具的人都可以参考这个模式来设计自己的进度反馈。3. 编译过程与关键功能实操记录3.1 在 Linux 上编译 cuteCOM 的完整步骤先从源码编译说起。cuteCOM 的编译依赖不多主要需要 gcc、make、pkg-config以及 Gtk 2.0 的开发头文件。在 Ubuntu 或 Debian 系系统上可以先用下面这些命令把编译环境装好sudo apt update sudo apt install build-essential pkg-config libgtk2.0-dev然后拉取源码并编译git clone https://github.com/neundorf/CuteCom.git cd CuteCom make如果一切顺利当前目录下会生成可执行文件。需要注意的是CuteCom 仓库存在的时间比较长源码用的还是 Gtk 2 的 API在比较新的发行版上系统默认装的可能是 Gtk 3这时候需要确保 libgtk2.0-dev 已经安装不然编译时会报找不到 gtk/gtk.h 的错误。编译过程中最常见的报错有两类。一类是缺少头文件比如找不到 glib.h 或者 gtk.h这种直接用 apt 装对应的 -dev 包就能解决。另一类是某些函数的隐式声明警告这是因为新版 GCC 对 C 语言的检查更严格了但一般不致命只是编译警告。如果遇到因为警告被当成错误-Werror导致编译失败的情况可以改一下 Makefile把 -Werror 去掉。3.2 设备权限与串口工具的常见问题处理编译完成后运行 cutecom如果发现设备下拉列表里没有你的 USB 转串口或者像 /dev/ttyUSB0 这样的节点根本不存在大概率是两种情况。第一是 CH340、FTDI 这类 USB 转串口芯片的驱动没有加载插上设备后 dmesg 看一下内核日志如果有识别到 USB 设备但没有生成 ttyUSB 节点可能需要手动加载驱动模块。第二是权限不够普通用户默认没有访问串口设备的权限cuteCOM 打开设备时会报 permission denied。解决方法也很简单。把当前用户加入 dialout 组然后重新登录就能获得串口设备的访问权限sudo usermod -aG dialout $USER这个方法在 Ubuntu、Debian 系系统上几乎是标准操作。Fedora 系则是 lock 组或者 uucp 组名称略有不同但思路一样。如果你不想每次都用 sudo 运行 cutecom这个加入用户组的步骤一定要做。3.3 发送文件功能的实际操作示例文件发送功能的具体操作流程完全可以按这个路子来。打开 cuteCOM先选择串口设备比如 /dev/ttyUSB0然后设置波特率 115200、8 位数据位、1 位停止位、无校验。这些参数要跟设备端的 UART 配置保持一致否则收上来的全是乱码。然后打开文件发送对话框选择要发送的固件文件设置分块大小和块间延时点发送按钮。这里分享一个我实际调试中的经验。有一次给一块 STM32 板子发固件板子的 bootloader 要求每包 1024 字节包间延时 50ms。我把 cuteCOM 的文件发送参数按这个配置好发送过程稳定固件写入校验一次通过。还有一次发一个文本格式的配置文件板子没那么多讲究我把延时改成最小速度瞬间拉满几十 KB 的文件一秒多就传完了。这说明文件发送功能的关键参数不是越多越好而是要能匹配实际设备的需求cuteCOM 在这点上做得够用且直观。3.4 发送终端命令与脚本化使用技巧除了发文件cuteCOM 日常用得最多的场景之一就是发 AT 指令、调试命令这类短文本。界面上的发送输入框可以直接输入内容发送也支持勾选“以 Hex 格式发送”把输入内容按十六进制字节发送。这个特性在调试一些二进制协议时特别好用比如发 Modbus 报文、自定义串口协议帧可以直接把报文写成 Hex 字符串发出去直观又省事。更进一步cuteCOM 支持从文件读取内容作为发送来源这意味着你可以把一整套调试流程写成脚本文件通过文件发送功能一次性执行。比如准备一个文本文件里面按顺序写好各种初始化命令用延时参数控制每条命令的间隔这样就能实现半自动的设备初始化调试。虽然它不像专门的自动化测试工具那样灵活但对于大多数调试场景这个功能完全够用还省去了额外写脚本的成本。4. 常见问题排查与源码二次开发经验4.1 串口打不开或乱码的排查路径串口工具最常见的问题就是打不开设备或者收发乱码。打不开设备先确认设备节点存在再确认权限最后确认没有其他程序占用串口。lsof 命令可以查看谁在占用串口设备lsof /dev/ttyUSB0如果有程序占用要么关掉那个程序要么用 fuser -k /dev/ttyUSB0 强制释放。乱码问题则分两种情况一种是真的乱码像字符错乱、显示奇怪符号这多半是波特率不对或者数据位、停止位设置不匹配重新核对双方配置就行另一种是数据能收但不能显示或者显示不全这往往跟前面的终端模式设置有关cuteCOM 默认已经做了 raw mode 处理但如果你自己改过源码要留意有没有意外把某些终端标志位打开了。还有一个非常实用的小知识如果你不确定自己的串口参数配置是否正确可以用两个 USB 转串口模块对接一个发给另一个收在 cuteCOM 里开两个实例分别连两个串口就能自测收发链路是否正常。这个自测方法对于排查线序错误、驱动问题特别有效。4.2 文件发送过程中的常见问题文件发送也不是每次都一帆风顺。我遇到过几次比较典型的状况。第一种是发送中途界面就假死了这个八成是发送循环和 UI 更新的同步没做好如果修改过源码检查一下是不是直接把 UI 操作放在了发送线程里。第二种是发送速度很慢检查一下是不是块间延时设得太大或者分块太小导致频繁的系统调用开销过大一般来说 4KB 分块、块间延时 1ms 左右在大多数场景下已经很快了。第三种是收端收到的文件不完整这种大概率是串口流控没配对设备端开了硬件流控而工具端没开数据在高速发送时溢出丢失。增加发送超时和失败重试机制是我自己在修改 cuteCOM 源码时加的一个功能。串口发送在信号不好、线路干扰大的环境下可能遇到 write 超时或者写入失败原始的代码遇到这种情况可能直接退出发送循环导致发送中断。我在发送循环里加了错误判断如果 write 返回错误或超时延时一段时间后重试重试次数超过阈值才报错退出。这个改动在很多工业调试场景下非常管用比如在强电磁干扰的环境里给设备升级固件这个重试机制能让发送成功率从 80% 提升到接近 100%。4.3 二次开发实践增加自动应答与日志功能cuteCOM 的源码结构清晰为二次开发提供了很大的便利。我自己动手做过两个改动效果很好。第一个改动是增加自动应答功能。有一些设备上电后会主动发一些握手信息之前都需要手动在输入框输入响应指令我改动后在接收线程里加了一个字符串匹配逻辑如果收到的数据包含特定关键字就自动从预设列表中取出下一条指令发送出去。这样设备上电后工具能自动完成整个握手流程。第二个改动是增加日志记录功能。原始版本的数据显示都在界面上关了程序就没记录了。我在接收显示路径上加了一个文件写入操作把收发数据都追加到一个带日期的日志文件里同时把 HEX 格式和时间戳也包含进去。这个功能在调试长时间运行的设备时特别有用比如让设备跑一个晚上的老化测试第二天看日志文件就能排查问题不用全程守在电脑前看界面。这两个改动都不复杂核心就是找到收发数据的入口点按自己的需求插入处理逻辑。cuteCOM 的代码风格也比较规整每个功能块相对独立不影响整体结构的稳定性。4.4 从源码学习串口编程的收获最后聊聊从 cuteCOM 源码里学到的串口编程心得。串口编程听起来神秘其实核心就是几件事打开设备、配置参数、读写数据、关闭设备。Linux 下的串口编程和文件读写几乎一样区别就在于 ioctl 和 termios 那套配置逻辑。cuteCOM 把配置逻辑封装得通俗易懂照着读一遍再配合 man termios 查一下关键字段的含义基本就能掌握 Linux 串口编程的八成套路。遇到的几个特别容易踩坑的点在这里一起说一下。第一是 read() 和 write() 的返回值一定要检查串口不是理想管道读写可能不完全不检查返回值就会出现数据错乱或者发送丢失。第二是串口参数配置要完整不能只改波特率要一次性把所有相关标志位都设置好否则某个标志位残留会导致数据被奇怪地处理。第三是多线程编程时 UI 和串口读写一定要分离这一点 cuteCOM 的代码就是很好的范本。这几条经验我自己在写其他串口相关的程序时也在用确实少踩了不少坑。本文还有配套的精品资源点击获取