新闻详情

新闻详情

首页 / 资讯中心 / 详情

QSerialPort串口开发实战:从安装配置到半包粘包处理

发布时间:2026/9/28 12:38:32来源:尧图网络
QSerialPort串口开发实战:从安装配置到半包粘包处理
最近有个项目要从头做串口通信界面用QT Creator通信模块自然绕不开QSerialPort。之前我在几个工控项目里用的是第三方串口库后来发现光一个“程序退出时串口没释放导致下一轮打开失败”的问题就折腾了两天这次换到QSerialPort把从安装配置到收发数据的坑几乎踩了个遍。这篇文章就记录一下我这次串口开发的实际过程包括QSerialPort模块的正确安装方式、pro和CMake两种工程下的配置差异、数据读取时半包和粘包的完整处理策略以及一个很多人吐槽过的问题——QT Creator的代码对齐快捷方式到底该怎么用。如果你正准备用QT Creator做串口开发或者已经在串口通信上栽过跟头这篇应该能帮你省下不少排查时间。1. 串口开发为什么选QSerialPort吃过第三方库的亏才懂1.1 QSerialPort到底解决了什么问题做过串口开发的人应该都有体会Windows下操作串口传统路子是用CreateFile、ReadFile、WriteFile这套Win32 API再配合DCB结构体去配置波特率、数据位、校验位和停止位。Linux下则是对ttyS0、ttyUSB0这样的设备节点做open、read、write再用tcsetattr维护termios结构体。两套系统的API完全不同项目一旦要跨平台就得写两套底层逻辑还特别容易在平台差异上踩坑。QSerialPort就是Qt官方提供的跨平台串口类底层封装了各平台的串口实现对外暴露的是统一的API。也就是说你在Windows上写的串口打开逻辑到了Linux上不需要改代码只要重新编译就能跑。这个价值在工控类项目里非常直观——同一套上位机程序既要在开发机上连着USB转串口调试又要在现场工控机上通过板载串口通信没有QSerialPort的话就得维护两套串口适配层。另外一个实际的痛点是异步事件驱动。QSerialPort基于Qt的信号槽机制数据到达时自动触发readyRead信号你只需要在槽函数里读取即可避免了传统串口编程里一个线程死循环轮询等待数据的写法。轮询方式的问题在于CPU占用高、延迟不确定而且逻辑写起来很容易把状态机搞乱。1.2 三种串口方案的对比为什么不推荐自己封装我先把我评估过的三种方案摆出来方便后面看这篇文章的读者理解我为什么最后定在QSerialPort上。方案优点缺点适合场景Win32 API / Linux系统调用直接操作无依赖、性能上限高跨平台要写两套代码处理超时和异步非常繁琐单一平台、极简场景第三方跨平台串口库功能全、五六年没更新了还算稳定插件化通信库重、学习成本高、依赖解析问题多老项目维护、有历史包袱QSerialPort QSerialPortInfoQt官方维护、跨平台、与GUI事件循环天然集成只解决串口通信本身不处理协议解析多数新项目尤其是基于Qt的桌面/工控上位机第三方库我上一轮项目确实用过一开始挺顺利等到后面要做串口热插拔检测发现文档里描述的类方法和我实际编译出来的版本对不上去GitHub翻issue才知道维护者已经很久没跟进新版本了。那种“明明一个小功能却要找半天兼容性方案”的感觉做过的人应该懂。QSerialPort就不一样了它是随Qt主版本一起发布的Qt每个版本发布时都会对该模块做同步测试。再加上Qt本身在工业界和嵌入式领域的占有率这个模块长期维护是有保障的。对于上位机软件来说稳定、跨平台、有官方兜底这三点基本就把选择定死了。2. 安装阶段的坑模块没被编译进Qtpro和CMake全踩了一遍2.1 最常见的“找不到QSerialPort头文件”是怎么回事很多人在QT Creator里新建一个项目直接写上#include QSerialPort然后编译报错“No such file or directory”。第一反应是Qt没装好重装一遍还是没用。这个问题的根子在于Qt从5.x开始串口模块并不是默认编译进核心库的它在安装包中是作为一个独立组件存在的。如果你安装Qt时没有勾选Qt Serial Port组件那么即使Qt本身装得再完整也找不到QSerialPort头文件。windows上怎么确认自己到底装没装这个模块方法很简单打开Qt安装目录找到对应的编译器套件目录比如Qt/6.5.0/mingw_64。进入include目录翻翻有没有QtSerialPort这个文件夹。如果没有说明安装时漏选了。有的话再去看lib目录下有没有对应的库文件Windows下是Qt6SerialPort.dll和对应的导入库。我见过不少人在这一步反复重装Qt其实不用那么折腾。重新运行Qt Maintenance Tool选择“添加或移除组件”在Qt分类下找到对应版本勾选Qt Serial Port这个组件更新完成后就有这个模块了。Linux下如果是用apt安装的Qt通常需要单独执行一条类似sudo apt install libqt5serialport5-dev的命令具体包名根据发行版略有不同。2.2 .pro文件的三种写法别再复制粘贴出错用qmake管理项目时在.pro文件里加入串口模块常见的有三种写法我逐一说明坑在哪。第一种直接加QT serialport。这个最直观qmake会去Qt安装目录里找serialport模块的配置。要注意的是这一行必须放在项目文件里正确的位置不要在TEMPLATE app之前乱插也不要写进条件分支里把自己搞迷糊了。第二种加上network模块。这个坑我踩过一次。QSerialPort和QSerialPortInfo在部分Qt版本中依赖Qt Network模块如果你的项目里恰好没有引入network并且编译时提示一些莫名其妙的链接错误比如找不到qt_serialPort_需要链接的网络相关符号之类那就在.pro里加上QT serialport network第三种涉及多平台条件编译的写法比如在产品环境用的是Linux开发环境是Windows有人会写成win32 { QT serialport } unix { QT serialport }这么写本身没毛病但前提是两套环境下都装了串口组件。而且我建议别做这种无谓的区分直接QT serialport一行搞定Qt自己会处理平台差异。把简单问题复杂化后面维护起来很痛苦。2.3 CMake方式配置时容易忽略的链接细节如果项目采用的是CMake构建配置方式跟qmake完全不一样。我见过很多从qmake转过来的老手在CMakeLists.txt里只写了find_package(Qt6 REQUIRED COMPONENTS SerialPort)然后直接编译链接阶段疯狂报错原因是忘了一行关键代码target_link_libraries(你的项目名 PRIVATE Qt6::SerialPort)写完find_package只解决了头文件搜索路径的问题没有target_link_libraries的话链接器找不到QSerialPort的符号定义自然报“undefined reference”。这在Qt5和Qt6下都一样只是模块名从Qt5::SerialPort变成了Qt6::SerialPort。另外用CMake配置时还有一个容易被忽略的地方如果在Qt Creator里新建项目时用的是CMake默认生成的CMakeLists.txt里可能没有包含串口模块的find_package手动加的时候不要覆盖原来的find_package(Qt6 COMPONENTS Widgets)这一行正确做法是把它扩展成find_package(Qt6 REQUIRED COMPONENTS Widgets SerialPort)这样Qt会一次性找到Widgets和SerialPort两个模块后面再链接即可。2.4 版本兼容Qt5与Qt6的串口模块差异如果你还在用Qt 5.15和Qt 6在串口模块上有一个比较关键的区别需要注意。Qt 6把QSerialPort模块的重构做得更彻底一些内部实现从直接调用平台API改成了通过插件机制加载这意味着在部分Linux发行版上你除了安装Qt基础库还需要确保对应的串口插件存在。否则程序能编译通过运行时打开串口会得到一个“Resource unavailable”之类的错误。Qt 5和Qt 6在串口类本身的API上绝大部分是兼容的比如setBaudRate、setDataBits、setStopBits这些接口签名完全一致项目从Qt 5迁移到Qt 6这块改动量很小。但假如你在Qt 6里用了QSerialPortInfo的某些新方法又希望代码在Qt 5环境也能编译就要注意条件编译。稳妥的做法是在.pro或CMakeLists.txt里做版本判断必要时用#if QT_VERSION QT_VERSION_CHECK(6, 0, 0)对差异代码做隔离。3. 核心API的完整使用闭环枚举、配置、读写、关闭的每一个细节3.1 QSerialPortInfo枚举自动识别可用串口QSerialPortInfo这个类经常被新手忽略觉得它只是拿来看一眼串口列表的辅助工具。实际上用它来动态识别串口对用户体验的提升非常明显。传统的做法是让用户手动在界面上输入COM口号一旦换了一台机器用户就要自己去设备管理器里找端口号又麻烦又容易填错。我的做法是在界面上放一个“刷新串口”按钮槽函数里调用QSerialPortInfo的静态方法foreach (const QSerialPortInfo info, QSerialPortInfo::availablePorts()) { qDebug() Port: info.portName(); qDebug() Description: info.description(); qDebug() Manufacturer: info.manufacturer(); qDebug() Serial Number: info.serialNumber(); qDebug() Vendor ID: info.vendorIdentifier(); qDebug() Product ID: info.productIdentifier(); }强推这个类的理由是它暴露出来的一些信息非常实用。比如两个设备都接了USB转串口模块光看COM口号没法区分谁是谁这时可以通过Vendor ID和Product ID来区分不同的USB芯片型号。如果设备支持的话还能读序列号——当现场接了好几个同型号设备时靠序列号绑定串口是很可靠的办法。这里提一个我在工控项目里真实遇见过的场景设备上电后串口设备固件还没初始化完成这时候程序启动时枚举不到该串口用户又在界面上看不到新出现的COM口以为是设备坏了。后来我在“刷新”逻辑里加了自动重试机制每隔2秒枚举一次直到发现上一次不存在的串口号再提示用户选择这个小改动直接让现场的“插电没反应”投诉消失了大半。3.2 打开与配置参数波特率、数据位、校验位、停止位打开串口的流程完整代码应该是这样的QSerialPort *serial new QSerialPort(this); serial-setPortName(COM3); // Linux下可能写的是 /dev/ttyUSB0 if (!serial-open(QIODevice::ReadWrite)) { qDebug() 打开串口失败: serial-errorString(); return; } serial-setBaudRate(QSerialPort::Baud115200); serial-setDataBits(QSerialPort::Data8); serial-setParity(QSerialPort::NoParity); serial-setStopBits(QSerialPort::OneStop); serial-setFlowControl(QSerialPort::NoFlowControl);有几个容易出错的细节我逐一说明。第一setPortName和open的先后顺序。必须先设置端口名再调用open。有人为了代码简洁先new QSerialPort然后直接open程序倒是不会崩溃但打开的永远是上一次缓存的端口对象逻辑上根本不是你指定的那个设备。第二open失败时一定要处理errorString()。串口打开失败的常见原因包括端口已被其他程序占用、设备被拔掉、权限不足。Linux下非root用户打开/dev/ttyS*时经常遇到Permission denied这个在开发环境就能提前避开把用户加到dialout组或者用udev规则赋予设备节点权限。第三参数的设置时机。上面这段代码里参数设置放在open之后。有人习惯在open之前先setBaudRate那样的话部分版本的Qt会在open时使用系统默认参数把之前的配置覆盖掉导致你明明设置了115200实际打开后却跑在9600。保险的做法是先open再setBaudRate等所有参数。这个顺序问题文档里没有写得很直白但从Qt的源码实现来看open时会触一次底层设备的配置初始化所以先把设备打开再说后续参数是最稳的。3.3 数据写入的可靠姿势QSerialPort写数据的方式很直接调用write方法即可QByteArray data; data.append(ATSTATUS\r\n); qint64 bytesWritten serial-write(data); if (bytesWritten -1) { qDebug() 写入失败: serial-errorString(); } else { qDebug() 实际写入字节数: bytesWritten; }这里要说道说道write的返回值。bytesWritten -1表示写入失败失败原因可能是设备断连或者底层驱动出错小于传入数据长度但大于0说明部分数据被接受了等于传入长度则表示本次全部写入成功。但是write成功只代表数据进入了Qt内部的写缓冲区并不代表数据已经物理地发送到了串口线上。数据真正从串口发出去是在Qt的事件循环把写缓冲区的数据交给底层驱动之后。如果你想确认发送完成有两个办法一是连接bytesWritten信号connect(serial, QSerialPort::bytesWritten, this, [](qint64 bytes) { qDebug() 底层已发送字节数: bytes; });二是在连续发送多条数据之前调用serial-waitForBytesWritten(50)短暂等待底层把缓冲区清空。这里我不建议在GUI线程里大量调用waitFor系列函数因为它是阻塞式的。如果长时间阻塞等待界面会卡顿用户体验很差。3.4 关闭、释放与热插拔处理串口用完之后的关闭也藏着坑。常见的错误写法是直接delete serial这会导致两个问题一是如果底层还有数据没发送完暴力delete会把数据丢掉二是部分Windows下的USB转串口驱动对非正常关闭的设备会残留一个“设备被占用”的状态下次再打开时返回失败。标准化关闭步骤应该是// 断开信号连接防止槽函数里再用到这个对象 disconnect(serial, nullptr, this, nullptr); // 等待底层数据发送完成 serial-waitForBytesWritten(200); // 然后再关闭 serial-close(); // 最后再考虑是否delete serial-deleteLater();热插拔场景也是串口开发逃不开的需求。现场工人拔掉USB转串口线再插回Windows下COM口号很可能从COM3变成COM5。如果你在程序里硬编码了一个COM口号插拔后所有通信全部失效。处理思路是利用Qt的事件机制在程序中监听串口状态变化。QSerialPort在设备断开时会发出errorOccurred信号错误码为QSerialPort::ResourceError我在槽函数里侦测到这类错误就立即把串口对象关闭并置空等下一轮枚举发现设备再次出现时自动重连。4. 接收数据不完整、乱码、延迟这三个问题我用两条规则解决4.1 readyRead信号的触发时机为什么偶尔会漏数据QSerialPort的readyRead信号触发时机是“有新的数据到达缓冲区”。这听起来简单但实际开发中很多诡异问题都出在这个信号上。我的理解可以简化成一个生活类比串口数据到达底层缓冲区时相当于快递员把包裹放进了小区快递柜。readyRead等价于小区业主收到一条“你有新包裹”的短信。问题是快递员可能会分批放一次只放几个包裹放一会儿又放几个。如果你在收到第一条短信后只跑一趟快递柜把当时的包裹全取走就完事那后面陆续送到的包裹就没取等下一轮通知才能继续。放到串口场景中意思是一次readyRead信号并不代表“一帧完整数据已经到齐”只代表“缓冲区里有尚未读取的数据”。如果你在槽函数里做了“读一次”之后就认为读完了就很容易漏数据。正确的读取姿势应该是在槽函数里尽可能把缓冲区的数据全部读走哪怕多读几次。标准写法是void Widget::onReadyRead() { QByteArray data serial-readAll(); // 处理data }这里readAll本身会一次性读完当前缓冲区的所有数据但问题在于如果你只依赖“一次信号一次读取”高频大数据量的场景下下一次readyRead到来前新数据可能还没进入缓冲区数据被拆分成两段甚至多段你自己就得做数据拼包。4.2 半包与粘包用缓冲区定时器搭一个读取框架半包和粘包是串口开发中绕不开的问题。发送端一帧数据可能是“AA 55 01 02 03 04 FF”理论上应该一次性到达但实际传输中可能分两次到达这就是半包反过来接收端可能在一个极短时间窗口内连续收到多帧数据所有帧数据粘在一起这就是粘包。我这边采用的方案是“缓冲队列帧超时定时器”逻辑很清晰用QByteArray接收缓冲区。在onReadyRead里不断把readAll的结果追加到接收缓冲区。启动一个QTimer定时器比如200ms超时。每次有新数据写入接收缓冲区就把定时器重启。定时器一旦超时说明在一段时间内没有新数据到达则认为目前缓冲区里至少包含了一帧完整数据。此时再按协议解析。定时器的超时时间不是拍脑袋定的。要考虑波特率和单帧数据长度。拿115200波特率、一帧10字节来算每字节传输时间大约87微秒左右一帧不到1毫秒就能传完。但问题在于USB转串口的底层聚合策略Windows驱动通常会把短时间内的数据合并后再上报中间可能产生几毫秒到十几毫秒的延迟。200ms这个值对于大多数常规传感器上报帧来说足够保守同时又不至于让用户感觉到明显的交互延迟。当然这个方案只适用于“帧间间隔大于定时器周期”的协议。如果你处理的设备是连续流式数据比如每秒几百帧加速度数据那帧间隔远小于定时器周期超时方案就失效了。这时候得回到“帧头帧尾长度字段”这类协议解析方式上这就不是QSerialPort本身能解决的了。4.3 乱码和字节丢失的隐蔽根源数据乱码大家第一反应是波特率不对。这确实是常见原因但还有几个容易被忽略的坑。第一个坑是数据位配置错误。很多设备的出厂默认配置是7个数据位加偶校验而我们常用的Modbus RTU是8个数据位无校验。你的程序配置和设备的真实配置不一致时数据读出来往往就是乱的而且偶尔还会出现字节丢失。解决办法就是先想办法确认设备的真实串口参数不要凭经验猜。不要迷信9600和8N1是万能的很多工控表计的出厂配置五花八门。第二个坑是流控。QSerialPort默认的流控是NoFlowControl但有些老设备要求硬件流控RTS/CTS。硬件流控配置不当最典型的现象是设备发了一部分数据后就停止发送了接收端干等超时后认为设备没响应。排查这个问题的过程通常是配置明明都对收发单字节又正常一传长帧就卡。我碰过一次这个情况最后是把setFlowControl(QSerialPort::HardwareControl)之后才正常。第三个坑是硬件层的问题特别是USB转串口的廉价模块。CH340、CP2102这类芯片的兼容性大体过得去但个别质量差的线材在电磁干扰较强的工业现场就会出现偶发性字节丢失。这个靠软件代码很难彻底解决能用屏蔽线就用屏蔽线能缩短线距就缩短线距。真要是硬件问题不要死磕代码。4.4 排查链路从串口助手比对到驱动更新如果你在排一个非常诡异的串口问题我的建议是把排查链路拉直不要跳步。第一步永远是先用一个可靠的第三方串口调试工具比如友善串口调试助手或者AccessPort去和设备单独通信。这一步的核心目的是确认“设备本身能不能正常回数据”。如果串口工具也收不到那问题大概率在设备端或物理链路不在你的Qt代码。第二步用QT Creator跑一个最小的测试工程只包含QSerialPort开端口读取打印。代码越简单越好目标是把Qt这一层的变量隔离出来。如果最小工程也不通再检查波特率、数据位、校验位、停止位、流控这五个参数是否和串口助手里完全一致。第三步确认写操作的发送端行为。很多时候上位机收不到数据是因为上位机发送的消息格式有问题比如缺了回车换行符、帧尾校验错误等。用串口助手的“手动发送”功能对比你程序里发出的hex数据逐字节比对。我这套排查链路靠它解决过数不清的问题而且最大的好处是每一步都能准确定位“是哪一层出的错”。串口开发最忌讳一上来就改代码改来改去问题还在最后发现是没插线。5. QT Creator代码对齐快捷方式不好用我这边的优化方案5.1 快捷键失效的场景与原因回到标题里提到的那个高频槽点QT Creator的代码对齐快捷方式不好用。到底哪里不好用我总结了一下主要是这几个场景一是按快捷键没反应。QT Creator里最基础的代码格式化快捷键是CtrlI自动缩进Windows和Linux默认一致macOS则是CmdI。如果你按了没反应多半是快捷键冲突了可能是安装了什么全局热键工具把组合键抢走了。另外如果当前焦点在文本编辑器以外的地方比如焦点在项目树或者输出面板快捷键当然不会触发编辑器操作。二是选不中“正确的代码块”时对齐无效。很多人选中代码后按CtrlI发现只有第一行缩进变了后面的代码完全没动。这其实是选区没选全导致的QT Creator的自动缩进只对完全包含的代码块有效如果你少选了一个大括号它就对不上结构。所以选代码块时从第一个大括号开始选把整个逻辑块完整包进去。三是对齐了但格式不符合预期。QT Creator默认的自动缩进粒度是“按代码层级缩进”但对大括号的位置、操作符两边的空格、是否把多个变量声明对齐这些细节不做处理。5.2 几种对齐/格式化方案对比要真正解决“对齐不好用”的问题得结合你预期的格式标准来选方案。格式化方案触发方式能解决的问题局限QT Creator内置自动缩进CtrlI手动代码块层级缩进不对空格、换行、大括号风格做处理QT Creator内置Beautifier插件手动/保存时自动调用外部工具做整体格式化需要额外安装astyle/clang-formatClangFormat插件保存时自动代码风格统一空格、换行、排序都可定制版本匹配需注意配置复杂一些Aligned上用的较多的是clang-format它基于LLVM开发对C/C代码的格式化能力非常成熟。QT Creator自带一个Beautifier插件在“工具-选项-Beautifier”里可以启用。启用后你可以选择后端的格式化工具是Artistic Style还是clang-format也可以设置成保存文件时自动格式化。配置好的体验是代码写完之后一顿格式化缩进混乱、空格不统一、大括号位置不对全都自动修好根本不需要你手动去按对齐快捷键。5.3 我推荐的组合clang-format 保存时自动格式化我自己的习惯是新建项目后第一时间在项目根目录放一个.clang-format配置文件然后用QT Creator的Beautifier配置成“保存时自动格式化”。这样既能保证整个项目代码风格统一又省去了手动按键的麻烦。BasedOnStyle: Google IndentWidth: 4 ColumnLimit: 120 SortIncludes: true这个配置的意思是基础风格参照Google样式缩进宽度改为4单行最大长度120头文件按字母顺序排序。你完全可以根据团队规范调整。比如很多人习惯Allman风格的大括号另起一行那就在配置里加BreakBeforeBraces: Allman。需要注意的是Beautifier插件的clang-format后端路径需要明确指定。Windows下如果你的clang-format是随Qt一起安装的路径可能类似C:\Qt\Tools\QtCreator\bin\clang\bin\clang-format.exe。指定错误的话格式化工具不会生效而且界面上看不到明显报错会误以为配置没保存成功。这样处理之后文章开头提到的“代码对齐快捷方式不好用”就不再是问题了因为你根本不需要那个快捷键。保存文件时自动格式化格式问题在源头就被解决代码风格统一度极高。6. 三次量产级项目后的串口开发建议6.1 线程模型别用错UI卡顿的根源在这QSerialPort的使用和线程模型强相关。前面我说过QSerialPort依赖Qt的事件循环也就是说它默认工作在创建它的那个线程里。如果你在主线程GUI线程里 new 一个QSerialPort那么它的readyRead信号也会在主线程里回调。如果数据处理逻辑比较复杂比如要做CRC校验、协议解析、数据库写入主线程就容易被拖慢界面掉帧卡顿。常规做法是把串口对象放到一个独立的工作线程里用Qt的信号槽跨线程通信。具体实现可以这样创建一个继承QObject的类比如CommWorker在里面封装QSerialPort的创建、打开、读写逻辑。在主线程中创建一个QThread对象。把CommWorker通过moveToThread方法移动到该线程。线程启动后CommWorker里的串口操作全在该线程里执行。这样做的好处是串口数据收发和协议处理完全不影响UI响应哪怕接收缓冲区里堆积了几千帧数据界面照样流畅操作。我在一个高速数据采集项目里就是把串口接收放到了独立线程UI卡顿问题直接消失处理数据延迟也降了一个量级。6.2 日志记录是排查串口问题的第一生产力串口通信调试时最怕的就是问题复现不了。设备在现场偶发通信故障你不在现场光靠用户口头描述“好像卡了一下”根本没法定位。我强烈建议在串口通信代码里埋完整的日志至少包含以下几类信息串口的打开和关闭事件附带错误信息如果打开失败务必记录errorString。每一次发送数据的完整hex内容标注时间戳。每一次接收数据的完整hex内容标注时间戳。缓冲区超时被触发、协议解析失败等异常事件。日志输出到文件比输出到控制台更实用因为现场环境你不一定能看到控制台窗口而日志文件可以事后远程取回来分析。Qt提供了qInstallMessageHandler机制可以把日志重定向到自定义文件。我在日志里统一使用带毫秒的时间戳串口问题排查时几毫秒的先后顺序往往能直接分辨是发送端时序问题还是接收端解析问题。6.3 串口协议设计上的一点教训最后聊一下我在三次量产项目中积累的协议设计教训。早期做设备协议我倾向于定义很简短的命令比如A1表示查询状态A2表示启动调试时确实简单。但一旦设备量上去、交互指令变多这种无结构的协议维护起来非常痛苦新增一个功能就要改下位机与上位机两边的解析表还容易冲突。我现在设计的协议至少包含以下字段帧头、命令字、数据长度、数据区、校验位、帧尾。帧头用来做起始同步数据长度用来做半包判断校验位用来做传输误码检测。这套结构虽然多了几个字节但在排查通信问题时返回的信息量完全不同你看到一帧里数据长度不符合预期能立刻判断是半包看到校验失败能判断是硬件干扰或波特率偏差。另外设备上电后建议先发一小段握手帧确认下位机确实在位且协议版本匹配再进入正式通信流程。这个握手环节看起来多余但在现场联调时能省掉大量“是设备没上电还是协议不兼容”的争论时间。这套串口开发流程从QSerialPort模块的安装配置到API闭环从半包粘包处理到线程模型设计基本覆盖了我归结出来的所有高频坑。如果你正在做或准备做QT Creator串口开发直接照着这个思路走至少能少走一大半弯路。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

Cadence Allegro 17.4保姆级安装教程:从License配置到报错排查 2026/9/28 16:59:20

Cadence Allegro 17.4保姆级安装教程:从License配置到报错排查

干PCB设计的同行应该都有同感,Cadence Allegro这套软件,学起来难,装起来更让人头大。尤其是17.4这个版本,网上教程鱼龙混杂,要么是16.6的老操作拿来硬套,要么是只说一半的截图教程,装到一半卡住…

阅读更多 →
16G显存跑Qwen 7B LoRA微调的实战指南 2026/9/28 16:59:20

16G显存跑Qwen 7B LoRA微调的实战指南

1. 为什么非得在16G显存上硬刚Qwen 7B的LoRA微调?“16G显存跑不动Qwen 7B微调”——这句话我去年在三个不同技术群都听人斩钉截铁地说过,语气像在宣布物理定律。结果呢?上周我用一台二手RTX 4090(24G显存但被公司IT策略锁死只允许…

阅读更多 →
STM32驱动ADS8866三线SPI模式高精度ADC采集实战 2026/9/28 16:59:20

STM32驱动ADS8866三线SPI模式高精度ADC采集实战

做高精度模拟量采集的项目,第一道坎往往不在算法上,而在ADC本身的选型和驱动。我之前手头一个项目要采集0~5V的传感器信号,精度要求1mV以内,换算下来至少要14位有效分辨率。STM32F103RCT6内部ADC是12位的,满…

阅读更多 →
BERT+BiLSTM-CRF中文NER全链路实战:从训练到HTTP服务部署 2026/9/28 16:59:20

BERT+BiLSTM-CRF中文NER全链路实战:从训练到HTTP服务部署

简介:本资源是一套面向自然语言处理初学者与进阶开发者的命名实体识别(NER)实战源码,聚焦BERT预训练模型与BiLSTM-CRF联合架构的工程实现,适用于信息抽取、智能客服、知识图谱构建等场景。压缩包共52个文件&#xff0c…

阅读更多 →
CLI-Anything:定义文件驱动的命令行工具生成器 2026/9/28 16:59:13

CLI-Anything:定义文件驱动的命令行工具生成器

1. 从"重复造轮子"到"一键命令行化":CLI-Anything的诞生动机做后端和运维的人都知道,日常里最烦的不是写代码,而是把代码变成工具那一段路。你可能已经有一套健壮的HTTP API,或者一堆写好的Python函数&#x…

阅读更多 →
地铁警戒线检测数据集:YOLO与VOC格式详解及YOLOv8训练实战 2026/9/28 16:59:13

地铁警戒线检测数据集:YOLO与VOC格式详解及YOLOv8训练实战

简介:面向地铁场景目标检测任务,这套数据集以警戒线(warning_line)为唯一检测类别,提供清晰现场图片和1635个矩形标注框,覆盖真实环境下的地铁警戒线形态,适合作为YOLO、Faster R-CNN等模型训练…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉