news 2026/9/7 23:10:44

Qt串口助手开发实战:从串口通信原理到exe打包发布全攻略

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Qt串口助手开发实战:从串口通信原理到exe打包发布全攻略

简介:这是一份基于Qt框架开发的串口调试助手程序,面向需要快速完成串口数据收发测试的硬件工程师、嵌入式开发者及Qt初学者,同时也适合在设备联调、工控通信等场景下使用。压缩包共51个文件,除了可直接运行的主程序exe外,还包含Qt5运行所依赖的24个动态链接库、22个多语言界面翻译文件、卸载程序及辅助exe,以及少量cpp源码和编译中间文件,整体约23.53MB。已有130人学习或下载,适用于Windows平台下无需额外安装Qt开发环境的串口调试场景。包内自带完整运行库,启动主程序即可进行串口参数配置、数据收发与日志查看,便于快速排查设备通信异常。同时,cpp源文件与界面资源相关的编译文件可作为学习Qt串口编程、多语言翻译机制和程序打包发布流程的参考素材,对理解Qt项目构建与国际化配置也有实际帮助。 做了几年嵌入式上位机开发,手上经手的串口调试工具换了一茬又一茬,从最早拿别人的开源工具凑合用,到后面被各种奇葩需求逼着自研,最后沉淀下来的这套 Qt 串口助手 exe 程序方案,算是踩坑踩出来的。今天不整虚的,把这套工具从架构设计到打包发布的完整链路讲清楚,特别是那些官方文档里查不到、只有实际跑过才明白的坑,一次性倒出来。

这套程序的核心定位很明确:跨平台串口调试利器,用来替代功能残缺的商家自带工具,解决嵌入式开发、硬件调试、协议联调中“串口数据收发不可控、格式解析不灵活、可视化能力弱”的痛点,适合嵌入式工程师、上位机开发者、硬件爱好者参考,也适合那些想用 Qt 做上位机但不知道从哪下手的新手直接“抄作业”。

1. 串口助手的技术架构与功能拆解

1.1 核心功能需求分析

正经的串口助手不是简单地开个串口、发个数据就完事了。前期和几位搞 STM32、RS485 总线调试的朋友聊需求,整理下来核心功能至少得覆盖这几块:

  • 串口参数灵活配置:端口号、波特率、数据位、停止位、校验位、流控,缺一不可。实际调试中波特率要能随时切,比如 9600、115200、460800 甚至 921600,应用层不能有卡顿。
  • 收发数据双显:接收区要有 ASCII/Hex 切换,发送区要支持手动输入和定时自动发送。大部分场景下接收校验都靠 Hex 模式,所以进制切换的实时性要做到位。
  • 数据统计与日志:帧计数、字节计数、收发时间戳,调试 Modbus RTU 和自定义协议时这些数据能大幅缩减排查时间。日志要能落盘,不然掉电丢数据很恼火。
  • 可扩展协议解析:这是我自己加上去的需求。裸收发只是第一步,能把收到的二进制流按协议解析成具体物理量,或者把帧格式自定义下发,才算真正有用。

这套工具做下来,整个架构分成三层。顶层是 Qt Widgets 界面层,负责交互和显示;中间是 QSerialPort 通信层,负责串口数据读写下发;底层是协议解析与数据处理层,负责二进制流拆包、校验、格式转换。三层之间用信号槽解耦,界面卡死的问题大幅减少。

1.2 为什么选择 Qt 而不是其他框架

很多朋友问,串口助手用 Python、C#、甚至网页版都能做,为什么非要用 Qt?我的考量有三点。

第一,性能与实时性。串口调试讲究响应速度,数据量大的时候 460800 波特率下每秒约 46KB 数据流,Python 的 GIL 锁和解释器开销容易在接收缓冲区堆积时丢包。用 C++ 的 QSerialPort 走事件驱动,数据到达立即通过 readyRead 信号处理,实测下来稳妥。

第二,跨平台能力。日常主力 Windows,但偶尔要到 Linux 工位上调试,一套代码跑两边,不用维护两套工具。Qt 的 QSerialPort 模块封装了各平台串口 API 的差异,上层代码几乎不用改。

第三,界面和生态。QCustomPlot 这类绘图库让时域频域波形显示变成可能,配合 QSS 能做出现代化工控界面。这些都是 C# WinForms 和 Python Tkinter 做不到或者做起来极费劲的。

有一点要提醒:Qt 版本选择上,如果你只需要串口功能,优先考虑 Qt 6.x LTS 版本和配套的 QSerialPort 模块;如果项目中依赖了老掉牙的第三方库,就老老实实用 Qt 5.15 LTS。工具选型不能追新,稳定压倒一切。

2. 串口通信基础与底层原理

2.1 串口通信的关键参数

串口通信看着简单,但很多人调试数据乱码、收发不对,基本都是参数不匹配导致的。串口通信本质是异步串行传输,关键是四个参数必须收发两端一致:

  • 波特率(Baud Rate):每秒传输的码元数。115200 意味着每秒传 115200 个比特,扣掉起始位、停止位、校验位(如果有),实际有效数据传输率远低于这个值。数据量大时,丢帧往往是因为应用层处理速度跟不上波特率。
  • 数据位(Data Bits):通常是 8 位,老一点设备可能是 7 位。这个参数决定了每个字节实际传输的有效比特数。
  • 停止位(Stop Bit):有 1 位、1.5 位、2 位三种。嵌入式设备常见 1 位停止位。
  • 校验位(Parity):None、Even、Odd,甚至 Mark/Space。Modbus RTU 协议通常用无校验或者偶校验。

这些参数组合起来,一个字节的传输时间可以精确算出来。例如 115200-8-N-1,一个字节 10 bits(1 起始 + 8 数据 + 1 停止),传输耗时约 86.8 微秒。计算这个有什么用?设计自动发送定时器时,如果每 10ms 发一帧 32 字节的数据,光传输就要 2.8ms,留给系统调度的余量非常有限,定时器的超时间隔必须留有足够余量,否则就会出现“发出去的数据对方收不全”的情况。

2.2 驱动层与系统适配

另一个高频翻车点在驱动上。USB 转串口芯片是嵌入式调试台上最繁忙的硬件之一,CH340、CH341、FTDI、CP2102 这几类芯片几乎占据了全部市场。驱动装不上、设备管理器中串口不出现、串口号乱跳,这些问题每天都在嵌入式群里发生。

针对 CH340/CH341 这类国产芯片,驱动安装有几个细节经验:

  • 驱动尽量从原厂官网下载,Windows 10/11 老版本系统可能自动识别,但新版本系统反而因为驱动签名策略导致安装失败。遇到驱动签名问题,要么禁用驱动强制签名重启,要么升级到官方最新版驱动。
  • 插上 USB 转串口模块后,设备管理器出现未知设备,大概率是驱动没有正确安装。右键更新驱动,手动指定到驱动解压目录,成功率比自动搜索高得多。
  • 串口号固定在 COM3 但被别的程序占用时,打开串口会报 “Access Denied”。排查按钮失效时,先关掉所有可能占用该串口的程序,或者换一个串口号。

FTDI 芯片相对稳定,但价格贵。新买的开发板如果板载的是 CH340,别犹豫,直接配好驱动再往下走。另外提一句,如果你的目标是做一个给客户用的工具,打包时一定要把驱动说明文档和驱动安装包一起分发,不然客户卡在驱动上会把你当客服用。

2.3 Qt 串口模块的核心 API

Qt 串口模块在 Qt 5.5 之后进入官方支持,类就两个:QSerialPort 和 QSerialPortInfo。前者负责串口读写,后者负责枚举可用串口。

枚举串口是动态获取端口列表的关键:

foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) { ui->comboPort->addItem(info.portName()); }

QSerialPort 打开串口的完整流程:

QSerialPort serial; serial.setPortName("COM3"); serial.setBaudRate(QSerialPort::Baud115200); serial.setDataBits(QSerialPort::Data8); serial.setParity(QSerialPort::NoParity); serial.setStopBits(QSerialPort::OneStop); serial.setFlowControl(QSerialPort::NoFlowControl); if (!serial.open(QIODevice::ReadWrite)) { qWarning() << "打开串口失败: " << serial.errorString(); }

读取数据用信号槽。这里有个极其关键的细节:readyRead 信号在 Windows 平台上的触发时机和 Linux 不同,在 Linux 下触发频率相对固定,Windows 下数据到达时立即触发。但这不意味着一定收到完整的一帧,串口协议没有帧边界,必须自己做数据拼接和拆包。

处理粘包和半包的标准姿势:

connect(&serial, &QSerialPort::readyRead, this, [&]() { QByteArray data = serial.readAll(); buffer.append(data); while (buffer.size() >= FRAME_MIN_LEN) { // 按协议帧格式解析,取出完整帧后再从 buffer 中剔除 } });

这个思路和 TCP 拆包类似,但实现简单得多,因为串口帧一般较短,Modbus RTU 的帧最长也就 256 字节。

3. 界面设计与交互逻辑实现

3.1 主界面布局规划

Qt 串口助手的界面布局直接决定使用效率。我最初做的一版把所有功能塞在一个窗口里,结果找发送按钮要找半天。后来重新设计,遵循“三区一栏”布局:

  • 左侧参数配置区:串口选择下拉框、波特率下拉框、数据位/停止位/校验位下拉框、打开/关闭串口按钮。
  • 右侧接收区:带行号显示的 QPlainTextEdit 或者 QTextEdit,支持 ASCII/Hex 切换,带接收时间戳和字节计数。
  • 中下方发送区:发送内容编辑框、发送按钮、定时发送勾选框及间隔设置。
  • 最底部状态栏:显示串口状态、收发总字节数、错误信息。

这个布局的关键在于接收区要能支撑高频刷新。Qt 自带的 QTextEdit 在高频 append 文本时会卡界面,实测 115200 波特率下连续接收 5 万行数据,主线程直接假死。解决方案是设置最大阻塞块数,或者定期截断显示内容,再或者用 QPlainTextEdit 并做延迟刷新:

if (ui->textReceive->document()->blockCount() > MAX_BLOCK_COUNT) { ui->textReceive->clear(); // 防止内存无限增长 }

更好的做法是引入显示缓冲区。数据到达时先加入 QByteArray 缓冲区,通过 QTimer 每 50ms 刷一次 UI,界面流畅度和内存占用都会健康很多,而且还能顺带解决高频信号触发 UI 刷新导致的性能瓶颈。

3.2 数据收发核心代码逻辑

发送逻辑相对简单。手动发送把编辑框内容按当前选中的进制模式转成 QByteArray 然后用 write() 发出去。定时发送用 QTimer,间隔单位毫秒,实际应用中发现定时器的精度受系统影响,Windows 下默认 timer 精度约 15ms,想要更高精度的定时发送,需要用 multimedia 定时器或者QElapsedTimer做辅助校准,但通用调试场景下 QTimer 精度完全够用。

接收逻辑要重点说。串口数据是不定长、无边界的数据流,需要设计一个接收状态机来处理半包、粘包。以 Modbus RTU 为例,帧格式是:地址码 + 功能码 + 数据域 + CRC16 校验。解析流程:

// 假设 buffer 中已经累积了收到的原始字节 while (buffer.size() >= 8) { // Modbus RTU 最短帧 8 字节 if (buffer[0] == expectedAddr) { int len = 6 + buffer[1]; // 根据功能码和数据长度计算完整帧长 if (buffer.size() < len) break; // 半包,等下一批数据 QByteArray frame = buffer.left(len); // 校验 CRC16,通过后解析报文 buffer.remove(0, len); } else { buffer.remove(0, 1); // 帧头不匹配,丢弃一个字节 } }

注意不要在 readyRead 信号处理函数里做耗时解析和 UI 更新。正确做法是信号到了只做 readAll 和缓冲,解析丢到工作线程或者用 QtConcurrent::run 异步执行,解析完成后通过信号把结果传回 UI 线程。

4. 打包发布 exe 的完整流程

4.1 windeployqt 打包步骤

开发调试完,要交付给别人用,这时候“打包 exe”这个需求就迎面而来了。Qt 程序不是把 release 目录下的 exe 直接拷走就能跑的,必须要带上 Qt 运行时库和平台插件,否则目标机器上会报一个很有名的错误:“No Qt platform plugin could be initialized”。

这个报错是 Qt 打包最常见的问题,根源在于 platform 插件(qwindows.dll)缺失或者路径不对。手工拷贝容易漏,官方工具 windeployqt 就是干这个的。操作步骤:

  1. 用 Release 模式编译工程,生成 xxx.exe,放到一个干净的目录如D:\build\my_assistant\
  2. 打开 Qt 命令行工具(Qt 6.x 对应 “Qt 6.x.x (MinGW 11.2.0 64-bit)” 或者 MSVC 对应版本)。注意下载 Qt 时勾选编译器套件,我用的是 MinGW 64-bit。
  3. 命令行切到 exe 所在目录,执行:
cd /d D:\build\my_assistant windeployqt my_assistant.exe

执行完毕,目录下会多出 platforms、styles、libgcc_s_seh-1.dll、libstdc++-6.dll、libwinpthread-1.dll 等依赖文件,这就能直接拷去别的 Windows 机器跑了。

整个程序目录就是绿色便携版,不需要安装。实际项目里我还会额外带上一个drivers文件夹,里面放好 CH340 和 FTDI 驱动,这样客户拿到手,装上驱动、双击 exe 就能工作,体验和商业软件无异。

4.2 常见打包错误排查

打包这块坑确实不少,我挑三个高频问题讲讲。

第一个就是上面说的 platform plugin 错误,原因通常是:用的 windeployqt 和 exe 不是同一个编译套件(比如 exe 是 MinGW 编的,却用 MSVC 版 windeployqt),或者执行时工作目录不在 exe 目录下。解决办法是严格对应编译器版本。

第二个是找不到入口点或者闪退,多半是运行时库缺失或版本冲突。仔细观察 windeployqt 输出的日志,它能列出每个 DLL 的拷贝状态。缺失 libgcc_s_seh-1.dll 或 libstdc++-6.dll 时,MinGW 版 Qt 程序在无开发环境的机器上会直接闪退。确保这两个文件在 exe 同级目录。

第三个是杀毒软件误报或者拦截。C++ 程序打包后体积大了,又带了一堆 DLL,容易被 Windows Defender 或其他杀软误报木马。这个无解,能做到的是用官方 Qt 编译、不要加壳、写上公司签名信息,能降低误报率。个人开发者一个可行做法是用 Inno Setup 做安装包,部分杀软对带安装界面的程序误报率会低一些。

如果目标是更极致的单文件发布,可以研究静态编译 Qt。静态编译会把 Qt 库直接编进 exe,体积更大、但依赖为零,分发最省心。代价是需要自己编译 Qt 源码,耗时很长,新手不建议一上来就搞,先把 windeployqt 用熟练。

5. 进阶扩展:数据可视化与工业协议

5.1 QCustomPlot 时域转频域波形显示

串口助手只能看十六进制流,对搞信号采集和传感器数据分析的人来说远远不够。很多场景需要把串口收到的 ADC 采样值或者传感器数据实时显示成波形,还要能切换查看频谱。

这里用的是 QCustomPlot 开源绘图库,配合 kissfft 库做时域到频域的转换。时域波形是横轴时间、纵轴幅值的曲线,频域波形则是横轴频率、纵轴幅值,两者通过离散傅里叶变换(DFT)关联。实际实现中,取时域信号的一帧数据(1024 或 2048 个采样点),调用 kissfft 完成快速傅里叶变换(FFT),输出的频域幅值数据再用 QCustomPlot 的 QCPGraph 绘制。

关键代码片段:

// 帧数据填充 QVector<double> timeData(N); for (int i = 0; i < N; ++i) { timeData[i] = buffer[i]; } // FFT 变换 kiss_fft_cfg cfg = kiss_fft_alloc(N, 0, nullptr, nullptr); kiss_fft_cpx* in = new kiss_fft_cpx[N]; kiss_fft_cpx* out = new kiss_fft_cpx[N]; for (int i = 0; i < N; ++i) { in[i].r = timeData[i]; in[i].i = 0.0; } kiss_fft(cfg, in, out, nullptr); // 计算幅值谱 QVector<double> freqData(N / 2); double fs = baudRate / 10.0; // 估算采样率:10 bits/byte for (int i = 0; i < N / 2; ++i) { freqData[i] = sqrt(out[i].r * out[i].r + out[i].i * out[i].i) / N; }

有个细节要提醒:采样率的确定是频域分析的基础。串口数据是异步到达的,不是严格等间隔采样,直接做 FFT 会引入频谱泄漏。我采用的是“按接收字节的时间间隔换算采样率”方法,或者如果单片机那边能按固定采样率发数据,记住在发送端做好时间同步,上位机这边波形质量会好很多。频谱泄漏严重时可以加汉宁窗做平滑,但这在实时信号分析中究竟要不要加,取决于你对幅值精度的要求,频谱仅看趋势可以不加。

5.2 Modbus RTU 与 RS485 场景适配

工业现场大量使用 RS485 总线和 Modbus RTU 协议。串口助手如果做好 Modbus RTU 支持,调试工业设备效率会大幅提升。实现方式有两种思路。

一种是把自己的串口助手升级成“超级终端”,透传模式下用户自己编辑报文,CRC16 自动计算,这个适合通用调试。具体实现时在发送区增加“自动附加 CRC16”选项,在用户输入 Hex 数据后,程序检测帧末尾是否已有 CRC,没有就自动补上,并把校验字节显示出来。截图发群里跟人确认问题时,这个功能相当受欢迎。

另一种是做成“Modbus 调试模式”,图形化选择功能码(01/03/04/06/16 等),填寄存器地址和数量,自动生成请求帧并解析响应帧。响应帧解析时重点验证从站地址和 CRC,CRC 不对直接标红。这两个方向和网友需求的匹配度极高,值得重点投入。

RS485 和串口的区别主要在链路层是半双工,收发共用一对线,程序发送后要延时切换方向。在 USB 转 RS485 模块上,方向切换由驱动自动完成,上位机不需要特殊处理。但如果用的是自研 RS485 板卡,切换方向的控制引脚就要特别注意时序,发送完成后延迟 1~2ms 再切换到接收状态,否则会把回环数据当正常响应解析出来。

还有一个常见场景是 STM32 开发板的串口 DMA 接收和空闲中断。嵌入式端用 STM32F103 标准库做 MODBUS RTU 从站,经常需要 PC 端的串口助手配合验证。freemodbus v1.6 移植到 STM32 后,串口收发中断里要尽量少做耗时操作,否则波特率 115200 下中断频繁可能导致数据丢失。PC 端配合调试时,接收显示改成 Hex + 时间戳模式,能快速判断主站下发命令和从站响应之间的间隔,排查超时问题非常有效。

6. 常见问题与排查技巧实录

6.1 串口打不开或设备不识别

打开串口失败最典型的原因是驱动问题、端口被占用、权限不足。排查思路按这个顺序来:

  1. 打开设备管理器,看端口(COM 和 LPT)下有没有对应串口。没有就是驱动没装好,用 CH340/CH341/FTDI 官方驱动重新安装。
  2. 串口存在但打开失败,大概率是端口被占用。串口助手、逻辑分析仪软件、甚至某些 IDE 的调试工具都可能独占串口。全部关掉再试。
  3. 在某些精简版 Windows 系统上,缺失串口驱动或者系统服务被禁用也会导致打开失败。查看系统事件日志可以进一步定位。

写代码时也要做健壮性处理:打开串口失败后,用 QMessageBox 弹出具体的 errorString(),而不是干巴巴一句“打开失败”。错误提示比错误本身更重要。

6.2 接收丢失与乱码

接收丢数据的原因可以说五花八门。根据我的实测,最常见的两个原因:

  • 串口缓冲区和 FIFO 溢出。Windows 驱动默认的接收缓冲区是 4096 字节,波特率 921600 时每秒约 92KB 数据,缓冲区转瞬即满,应用层来不及读走,新数据直接丢弃。解决办法是调大系统串口 FIFO 缓冲,或者提高读串口的频次。
  • UI 刷新卡顿导致事件循环阻塞。这是自研工具最容易踩的坑,高频往 QTextEdit 里 append 文本会阻塞 Qt 事件循环,readyRead 信号派发不出来,数据就在系统缓冲区越积越多直到溢出。上文中提到的“缓冲 + 定时刷新 UI”就是在解决这个问题。

还有乱码问题。如果接收区 ASCII 模式下出现中文乱码,多半是编码不匹配。很多单片机通过串口发送的是 GBK/GB2312 编码的中文,而 Qt 默认按 UTF-8 处理,转换不匹配就会乱。处理方式是在 QTextEdit 里做编码转换,识别字节流中的汉字部分,用 QString::fromLocal8Bit 或者 QTextCodec 进行转换。但要注意,Hex 模式显示时不要做任何转换,直接按字节显示,否则会把汉字的多字节字符拆开显示得很奇怪。

6.3 定时发送精度与性能问题

QTimer 定时发送的精度在网络讨论里被吐槽不少。实测在 Windows 10 上,默认 timer 分辨率 15.6ms,想实现 1ms 周期的定时发送基本不现实。解决方案是,发送间隔要求高的时候换用多媒体定时器(timeBeginPeriod 调整精度)或者直接在独立线程里用循环 + QThread::msleep 实现,但后者精度也受系统调度影响。

还有一个实用技巧:做压测和稳定性测试时,串口助手的数据统计功能是核心参考。显示帧计数和字节计数时,注意用原子变量或者主线程直接累加,避免多线程数据竞争导致计数错乱。另外,清空回显缓冲区时不要 clear 整个 document,用QTextCursor::select( QTextCursor::Document )配合removeSelectedText()效率更高。

写在最后的一点心得

串口助手看着简单,把一个工具打磨到“自己愿意用、别人用着顺手”的程度,涉及的知识面其实很宽,串口协议、Qt 事件循环、UI 性能优化、Windows 打包分发,一个都不能少。我自己的经验是,先把第一版跑通,功能完整度其次,然后在实际调试中持续迭代,每踩一个坑就补一个对策,这套工具就会越来越顺手。如果后续你的项目有处理大批量高速数据、协议解析扩展、或者需要支持虚拟串口对测试的需求,也可以在这个基础上继续扩展,Qt 在这方面的上限非常高。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/7 23:07:07

SSH 远程管理与 apt 包管理实战:从握手原理到批量装包

SSH 远程管理与 apt 包管理实战&#xff1a;从握手原理到批量装包系列导读&#xff1a;《Linux 从入门到高阶&#xff1a;4 节点华为云 ECS 全实操》第 2 篇。 所有实验均在真实云主机执行&#xff0c;输出可复现。本篇聚焦"怎么安全可靠地连上远程机器"与"Ubun…

作者头像 李华
网站建设 2026/9/7 23:06:01

香港假冒客服电话诈骗的生成机理与治理路径研究

摘要电话诈骗已经成为香港社会治安领域最为突出的犯罪类型之一&#xff0c;其中假冒客户服务人员的诈骗手法占据核心位置。2026 年上半年数据显示&#xff0c;香港电话诈骗案件数量同比上升百分之四十五至四千八百三十宗&#xff0c;损失金额同比上升百分之五十六至九亿港元&am…

作者头像 李华
网站建设 2026/9/7 23:05:28

岭回归:从正则化原理到解决多重共线性的实战指南

开头做机器学习的朋友应该都遇到过这种场景&#xff1a;拿着线性回归跑训练集&#xff0c;R 漂亮得要命&#xff0c;结果一到验证集上预测值飘得没边&#xff0c;看回归系数更是离谱——某个特征的系数居然上千&#xff0c;另一个又是负的几百。最早我遇到这类问题时&#xff0…

作者头像 李华
网站建设 2026/9/7 23:04:57

用Playwright打造CSDN博客自动化发布机器人:从环境配置到定时备份

1. 先想清楚&#xff1a;Bot到底帮CSDN博主解决什么问题我最早对Bot产生兴趣&#xff0c;纯粹是因为"发一篇文章要在后台点太多次鼠标"。CSDN的Markdown编辑器虽然好用&#xff0c;但如果你同时维护好几个平台&#xff0c;文章要在CSDN、公众号、知乎各发一遍&#x…

作者头像 李华
网站建设 2026/9/7 23:04:51

10分钟跑通WeKnora:从Docker部署到自建知识库问答的完整路径

10分钟跑通WeKnora&#xff1a;从Docker部署到自建知识库问答的完整路径 【免费下载链接】WeKnora Open-source LLM knowledge platform: turn raw documents into a queryable RAG, an autonomous reasoning agent, and a self-maintaining Wiki. 项目地址: https://gitcode…

作者头像 李华
网站建设 2026/9/7 23:04:05

如何高效修改毕业论文文本与格式

如何高效修改毕业论文文本与格式 在完成毕业论文的过程中&#xff0c;修改文本和格式是一项不可避免的任务。作为一名正在奋战的大学生&#xff0c;我深知这个过程可能会让人感到疲惫和困惑。今天我想分享一些我在修改论文时总结的经验&#xff0c;希望能帮助大家提高效率&…

作者头像 李华