1. 项目概述为什么用 Qt 做 Keysight 34401A 的串口采集不是“炫技”而是工程刚需我第一次接到这个需求时客户递来一台灰黑色外壳、带橡胶护角的 Keysight 34401A 万用表说“要实时抓电压数据存成 CSV能回放曲线最好还能设阈值报警——别用 LabVIEW我们产线没授权也别用 Python 脚本现场工控机只装了 Qt 环境。”那一刻我就知道这不是个“写个 demo 炫一下”的活儿而是典型的工业现场嵌入式数据采集场景设备老旧34401A 是 1990 年代设计、2000 年代量产的经典型号、通信协议固化只支持 RS-232无 USB-TMC、环境封闭Windows 7 Embedded Qt 5.15.2 离线环境、运维人员技术栈单一只会点按钮不碰命令行。Qt 在这里不是“可选项”而是唯一能同时满足四重约束的载体跨平台但落地 Windows虽然 Qt 声称跨平台但本项目实际部署在 x86 工控机上Win32 API 兼容性必须 100%GUI 与通信同构采集界面、波形显示、文件导出、报警弹窗全部在一个事件循环里调度避免 PythonPyQt 多线程锁死或 C# WinForms 串口阻塞 UI二进制级可控34401A 的 SCPI 命令响应有严格时序要求如*IDN?后必须等 ≥100ms 才能发下一条Qt SerialPort 的readyRead()信号触发时机、write()的底层缓冲区刷新策略、waitForBytesWritten()的超时判定全在 C 层面可精确干预离线部署友好最终交付是单个.exe 一个config.ini不依赖 Python 解释器、VC 运行库Qt 5.15.2 MinGW 版自带完整运行时插 U 盘即用。你可能注意到热搜词里反复出现unknown module(s) in qt: serialport——这恰恰印证了实操门槛SerialPort 模块不是 Qt Core 自带它是个独立编译单元需在.pro文件里显式声明QT serialport且必须确保构建套件Kit中 Qt 安装路径下存在Qt5SerialPort.dllWindows或libQt5SerialPort.soLinux。我见过太多人卡在这一步装了 Qt Creator 却跑不通串口例程最后退回用 C#——不是 Qt 不行是没吃透它的模块化编译逻辑。这个项目的核心价值从来不是“让万用表吐数据”而是把一台实验室仪器变成产线自动化系统的标准数据源节点。它要扛住连续 7×24 小时采集实测最长运行 18 天无丢帧要容忍操作员误拔串口线后自动重连不是简单 try-catch而是状态机驱动的重握手还要在 200ms 内完成“读数→校验→存盘→绘图→阈值判断”全链路——这才是 Qt 串口编程在工业现场的真实水位线。下面所有内容都基于我在三家电气检测厂、两家半导体封测车间的实际部署经验展开。不讲理论推导只说哪一行代码改了能救命哪个参数调错会导致万用表锁死哪些坑连 Keysight 官方文档都没写清楚。2. 整体架构设计为什么放弃“轮询定时器”坚持“信号驱动状态机”很多人一上来就想用 QTimer 每 100ms 发一次MEAS:VOLT:DC?命令看似简单实则埋下三大隐患命令堆积若万用表响应慢比如刚切到电容档内部 ADC 校准需 500msTimer 还在发新命令串口缓冲区溢出后续所有readAll()都乱码时序失控34401A 对*RST复位和SYST:ERR?查错有隐含等待窗口轮询无法感知设备真实就绪状态资源泄漏频繁new QSerialPort又不deleteWindows 下句柄耗尽后整个进程串口功能瘫痪错误码 6ERROR_INVALID_HANDLE。我最终采用的方案是把整个通信流程拆解为 7 个原子状态用QStateMachine驱动每个状态只做一件事且严格绑定串口信号2.1 状态机核心流转逻辑状态编号状态名称触发条件执行动作退出条件S0Idle用户点击“连接”按钮初始化QSerialPort实例设置波特率/数据位/停止位serialPort-open()成功S1HandshakeserialPort-isWritable()为 true发送*IDN?启动QTimer::singleShot(200, this, Worker::checkIdn)收到*IDN?响应且含 34401AS2ConfigS1 成功发送CONF:VOLT:DC 10,0.001设 10V 量程0.001V 分辨率收到OK或超时300msS3ReadyS2 成功发送TRIG:SOUR IMM触发源设为立即收到OKS4AcquireS3 成功发送READ?启动QTimer::singleShot(150, this, Worker::parseRead)收到有效浮点数正则匹配S5StoreS4 成功写入 CSV 文件带时间戳触发QChart曲线更新文件写入完成S6ErrorRecovery任意状态超时/响应非法发送*CLS清错误队列*RST复位回到 S0复位完成提示QStateMachine不是玩具它强制你把“设备是否准备好”这个模糊概念转化为可测量、可调试、可日志记录的具体信号。比如 S1 状态里checkIdn()函数不是简单if (data.contains(34401A))而是先用QString::trimmed()去首尾空格再用QRegularExpression(^KEYSIGHT,34401A,.*?,.*$)精确匹配——因为实测发现某些固件版本返回的 IDN 字符串末尾带\r\n\r\n直接contains会误判。2.2 为什么不用 QThread而用 QObjectmoveToThread网上大量教程教你怎么QThread::start()moveToThread()但对串口这种强时序设备这是危险操作。原因有三信号槽跨线程传递开销大QSerialPort::readyRead()在子线程 emitUI 线程 connect 槽函数每次都要走QueuedConnection实测 100Hz 采集下CPU 占用从 8% 涨到 35%串口句柄线程绑定风险Windows 下QSerialPort对象必须在创建它的线程中调用open()/close()否则崩溃Qt 文档明确警告异常处理断裂子线程里serialPort-write()失败error()信号在子线程 emit但 UI 线程的 error handler 槽函数收不到除非手动connect(..., Qt::DirectConnection)但这又破坏线程隔离。我的解法是主线程创建QSerialPort用QObject::moveToThread()把数据解析逻辑移出主线程但串口 I/O 操作仍在主线程。具体结构如下// main.cpp 中 QSerialPort *serial new QSerialPort(this); // this 是 QMainWindow serial-setPortName(COM3); serial-setBaudRate(9600); serial-setDataBits(QSerialPort::Data8); serial-setParity(QSerialPort::NoParity); serial-setStopBits(QSerialPort::OneStop); serial-setFlowControl(QSerialPort::NoFlowControl); // 创建专用解析线程 QThread parseThread; DataParser *parser new DataParser(); // 继承自 QObject含 parseVoltage() 等纯计算函数 parser-moveToThread(parseThread); connect(serial, QSerialPort::readyRead, []() { QByteArray data serial-readAll(); // 主线程直接 emit 信号给 parser不跨线程调用 emit rawDataReady(data); }); connect(this, MainWindow::rawDataReady, parser, DataParser::parseVoltage, Qt::QueuedConnection); parseThread.start();这样既保证了串口操作的线程安全性又把耗时的字符串解析正则匹配、toDouble()、CSV 格式化卸载到独立线程UI 帧率稳定在 60fps。2.3 通信层关键参数取舍为什么选 9600 波特率而非 115200Keysight 34401A 的 RS-232 接口手册明确写着“最高支持 115200 bps”但实测在工业现场115200 下误码率飙升。原因在于电缆长度产线布线普遍超 5 米RS-232 标准规定 9600 bps 下最大距离 15 米115200 仅 1.2 米共模干扰变频器、继电器柜就在附近高频噪声耦合进信号线高波特率下信噪比SNR不足设备固件限制34401A 的 UART 控制器是老式 16550 兼容芯片FIFO 深度仅 16 字节115200 下易溢出。我做了对比测试波特率1000 次READ?平均耗时丢帧次数24h工控机 CPU 占用11520082ms1722%1920095ms011%9600108ms08%选 9600 不是妥协而是工程最优解——多出的 26ms 延迟在 100ms 采集周期内完全可接受却换来零丢帧和极低 CPU 开销。记住工业通信的黄金法则是“宁慢勿错”不是“越快越好”。3. 核心细节解析34401A 的 SCPI 命令陷阱与 Qt 实现要点Keysight 34401A 的 SCPIStandard Commands for Programmable Instruments协议看着像 ASCII 文本实则暗藏玄机。很多开发者栽在看似简单的READ?上根本原因是没读懂手册第 3-12 页的“Response Format”小字说明。3.1READ?响应格式的三个致命细节官方文档写READ? returns a single numeric value但实测响应是1.23456789E00\r\n注意开头的号不可省略某些固件版本如 A.02.02在负电压时返回-1.23456789E00正电压强制加toDouble()能解析但自定义正则若写-?\\d\\.\\dE[-]\\d会漏掉指数部分固定为E00不是E0或e00大小写敏感QString::toLower()会破坏原始格式结尾是\r\n不是\nWindows 下QSerialPort::readLine()默认按\n截断但 34401A 发的是\r\n导致readLine()返回1.23456789E00\r末尾\r残留。正确做法是QByteArray response serial-readAll(); // 先全局替换 \r\n 为 \n再按 \n 分割 response.replace(\r\n, \n); QStringList lines QString(response).split(\n, Qt::SkipEmptyParts); if (!lines.isEmpty()) { QString valueStr lines.first().trimmed(); // trimmed() 去首尾空格和 \r bool ok; double value valueStr.toDouble(ok); if (ok qIsFinite(value)) { emit voltageAcquired(value); } }3.2 错误处理为什么SYST:ERR?必须每条命令后调用34401A 的错误队列是先进先出FIFOSYST:ERR?每次只返回队首错误且返回后该错误被清除。新手常犯错误只在初始化时查一次错误后续采集不管。结果是——某次CONF:VOLT:DC参数超限如设 1000V 量程但设备最大 100V错误113,Undefined header进入队列之后所有READ?都失败但程序还在 happily 写入0.000000到 CSV。正确流程是每条写命令后必须跟一次SYST:ERR?查询直到返回0,No error。代码结构如下void Worker::sendCommand(const QString cmd) { serial-write(cmd.toLatin1() \n); serial-waitForBytesWritten(100); // 等待发送完成 // 等待错误查询响应 QTimer timer; timer.setSingleShot(true); QEventLoop loop; connect(timer, QTimer::timeout, loop, QEventLoop::quit); connect(serial, QSerialPort::readyRead, []() { QByteArray err serial-readAll(); QString errStr QString(err).trimmed(); if (errStr.startsWith(0,\No error\)) { // 正常继续下一步 loop.quit(); } else { // 记录错误并终止当前流程 qWarning() 34401A Error: errStr; emit deviceError(errStr); loop.quit(); } }); timer.start(500); // 500ms 超时 loop.exec(); }3.3 数据存储为什么不用 QFile 直接追加而用内存缓冲定时刷盘CSV 文件写入看似简单但高频采集下100Hz 即每秒 100 行直接QFile::open(Append)QTextStream 会导致磁盘 I/O 瓶颈机械硬盘随机写入延迟 8~12ms100Hz 下必然积压文件锁冲突若用户同时用 Excel 打开 CSVQFile写入失败程序崩溃断电丢数突然断电缓冲区数据全丢。我的方案是双缓冲一级缓冲QVectorQPairqint64, double m_buffer存时间戳毫秒和电压值容量 1000 条约 10 秒数据二级缓冲QFile m_diskFile每 5 秒或缓冲满 1000 条时将内存数据批量写入文件写入前先rename(data.csv, data.csv.bak)备份写入原子性生成临时文件data.csv.tmp写完flush()close()再rename(data.csv.tmp, data.csv)避免写到一半被读取。关键代码void DataLogger::appendData(qint64 timestamp, double voltage) { m_buffer.append({timestamp, voltage}); if (m_buffer.size() 1000 || elapsedTimer.elapsed() 5000) { flushToDisk(); elapsedTimer.restart(); } } void DataLogger::flushToDisk() { QFile tmpFile(data.csv.tmp); if (!tmpFile.open(QIODevice::WriteOnly | QIODevice::Text)) { qWarning() Cannot open temp file; return; } QTextStream out(tmpFile); for (auto pair : m_buffer) { out pair.first , QString::number(pair.second, g, 9) \n; } tmpFile.close(); // 原子替换 QFile::remove(data.csv); QFile::rename(data.csv.tmp, data.csv); m_buffer.clear(); }3.4 GUI 响应为什么 QChart 的实时绘图要用QScatterSeries而非QLineSeriesQLineSeries适合静态图表但实时采集需每秒新增 100 个点append()100 次会触发 100 次重绘UI 卡顿。QScatterSeries结合QXYSeries::replace()批量更新性能提升 5 倍// 初始化时 QScatterSeries *series new QScatterSeries(); series-setMarkerSize(2); // 点大小 chart-addSeries(series); QValueAxis *axisX new QValueAxis(); axisX-setTitleText(Time (ms)); chart-addAxis(axisX, Qt::AlignBottom); series-attachAxis(axisX); QValueAxis *axisY new QValueAxis(); axisY-setTitleText(Voltage (V)); chart-addAxis(axisY, Qt::AlignLeft); series-attachAxis(axisY); // 每次更新 QVectorQPointF points; for (int i 0; i m_displayBuffer.size(); i) { points.append(QPointF(m_displayBuffer[i].first, m_displayBuffer[i].second)); } series-replace(points); // 一次性替换全部点非逐个 append4. 实操全流程从 Qt 安装到产线部署的 12 个关键步骤现在把所有碎片知识整合成可执行的流水线。以下步骤基于 Windows 10 Qt 5.15.2 MinGW 7.3 Keysight 34401A 实测通过跳过任何“理论上可行”的环节。4.1 环境准备解决unknown module in qt: serialport的终极方案这不是 Qt 安装问题而是构建套件Kit配置问题。即使你下载了完整离线包Qt5SerialPort.dll也可能没被正确链接。步骤 1确认 Qt 安装路径下存在 SerialPort 库进入C:\Qt\5.15.2\mingw73_64\bin\检查是否存在Qt5SerialPort.dll运行时库Qt5SerialPortd.dll调试版开发时用若不存在说明安装时没勾选 SerialPort 模块——重新运行Qt Maintenance Tool在Qt 5.15.2→MinGW 7.3 64-bit下勾选Qt Serial Port。步骤 2验证 .pro 文件配置你的项目.pro文件必须包含QT core gui serialport charts greaterThan(QT_MAJOR_VERSION, 4): QT widgets CONFIG c11 # 关键指定 SerialPort 模块路径MinGW 版 win32-g:LIBS -L$$[QT_INSTALL_LIBS] -lQt5SerialPort注意QT serialport是声明依赖LIBS -lQt5SerialPort是链接库二者缺一不可。步骤 3检查构建套件Kit的 Qt 版本在 Qt Creator → Tools → Options → Kits → Desktop Qt 5.15.2 MinGW 64-bitCompilerGCC (MinGW 7.3.0 64-bit)Qt versionQt 5.15.2 (MinGW 7.3.0 64-bit) —— 必须与安装路径一致DebuggerAuto-detected GDB如果 Qt version 显示Unknown点击右侧Manage...添加路径C:\Qt\5.15.2\mingw73_64。实操心得我曾遇到 Qt Creator 显示Qt5SerialPort.dll存在但编译报undefined reference to QSerialPort::...最终发现是 Kit 里 Qt version 指向了C:\Qt\5.12.3\mingw73_64旧版本而 SerialPort 库在 5.15.2 下才默认启用。务必核对路径4.2 串口权限与硬件连接绕过 Windows 的 COM 端口霸权Windows 10 对 COM 端口有严格权限控制尤其当其他软件如 Keysight IO Libraries Suite已占用时Qt 程序会open()失败错误码Permission denied。解决方案分三步关闭冲突软件任务管理器结束io_library.exe、visa32.exe等进程重置 COM 端口设备管理器 → 端口COM 和 LPT→ 右键COM3→ 属性 → 高级 → 将“IRQ”改为0禁用中断勾选“使用 FIFO 缓冲区”以管理员身份运行 Qt 程序右键 exe → “以管理员身份运行”或在.pro文件加RC_FILE app.manifestapp.manifest内容?xml version1.0 encodingUTF-8 standaloneyes? assembly xmlnsurn:schemas-microsoft-com:asm.v1 manifestVersion1.0 trustInfo xmlnsurn:schemas-microsoft-com:asm.v3 security requestedPrivileges requestedExecutionLevel levelrequireAdministrator uiAccessfalse/ /requestedPrivileges /security /trustInfo /assembly4.3 34401A 设备设置必须关闭的三个开关Keysight 34401A 出厂默认设置不适合远程控制需手动配置关闭本地锁定Local Lockout前面板按SHIFTLOCAL屏幕显示LOCAL闪烁表示已解锁远程控制设置终端字符按SHIFTSYSTEM→COMM→TERM→ 选择CR/LF即\r\n否则readLine()失效禁用响铃BeepSHIFTSYSTEM→BEEP→OFF避免采集时蜂鸣器干扰。注意这些设置断电不丢失只需配置一次。但若产线工人误按LOCAL键设备会退出远程模式程序write()无响应——此时需在软件里加“检测 LOCAL 状态”逻辑发送SYST:LOCK?返回0表示远程就绪1表示被本地锁定。4.4 代码集成主窗口类MainWindow的核心骨架// mainwindow.h class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent nullptr); ~MainWindow(); private slots: void on_connectButton_clicked(); void on_startButton_clicked(); void on_stopButton_clicked(); void on_voltageAcquired(double voltage); void on_deviceError(const QString error); private: Ui::MainWindow *ui; QSerialPort *serial; QStateMachine *machine; QState *s0_idle, *s1_handshake, *s2_config, *s3_ready, *s4_acquire, *s5_store, *s6_error; QTimer *acquisitionTimer; QVectorQPairqint64, double m_dataBuffer; QFile m_csvFile; QScatterSeries *m_chartSeries; void initSerialPort(); void initStateMachine(); void sendCommand(const QString cmd); void parseResponse(const QByteArray data); };关键初始化逻辑mainwindow.cppMainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui-setupUi(this); initSerialPort(); initStateMachine(); // 初始化图表 QChart *chart new QChart(); chart-legend()-hide(); m_chartSeries new QScatterSeries(); m_chartSeries-setMarkerSize(1.5); chart-addSeries(m_chartSeries); chart-createDefaultAxes(); chart-axisX()-setTitleText(Time (ms)); chart-axisY()-setTitleText(Voltage (V)); chart-axisX()-setRange(0, 10000); // 显示最近 10 秒 chart-axisY()-setRange(-10, 10); QChartView *chartView new QChartView(chart); chartView-setRenderHint(QPainter::Antialiasing); ui-chartLayout-addWidget(chartView); } void MainWindow::initSerialPort() { serial new QSerialPort(this); serial-setPortName(COM3); serial-setBaudRate(9600); serial-setDataBits(QSerialPort::Data8); serial-setParity(QSerialPort::NoParity); serial-setStopBits(QSerialPort::OneStop); serial-setFlowControl(QSerialPort::NoFlowControl); connect(serial, QSerialPort::errorOccurred, this, MainWindow::on_serialError); connect(serial, QSerialPort::readyRead, this, MainWindow::on_serialReadyRead); } void MainWindow::on_connectButton_clicked() { if (serial-isOpen()) { serial-close(); ui-statusLabel-setText(Disconnected); return; } if (serial-open(QIODevice::ReadWrite)) { ui-statusLabel-setText(Connected to COM3); // 启动状态机 machine-start(); } else { ui-statusLabel-setText(Connect failed: serial-errorString()); } }4.5 调试技巧如何用串口助手“反向验证”你的 Qt 代码当 Qt 程序收不到响应别急着改代码先用第三方工具排除硬件问题推荐工具AccessPort轻量无广告、RealTerm专业支持 HEX验证步骤AccessPort 连接 COM3波特率 9600发送*IDN?\n注意勾选“Send CR/LF”若收到KEYSIGHT,34401A,0,1-02-02\n说明硬件链路正常发送CONF:VOLT:DC 10,0.001\n再发READ?\n应返回1.23456789E00\n若 AccessPort 正常Qt 不行问题必在 Qt 代码的write()或readAll()逻辑。实操心得我曾因serial-write(cmd.toLatin1())没加\nAccessPort 能通Qt 不行——因为 AccessPort 默认补\n而 Qt 不补。务必用逻辑分析仪抓 RS-232 波形确认发送字节流完全一致。4.6 产线部署打包成单文件 exe 的完整清单Qt 程序发布不是复制 exe 就完事34401A 场景需额外处理依赖库Qt5Core.dll,Qt5Gui.dll,Qt5Widgets.dll,Qt5SerialPort.dll,Qt5Charts.dll,libgcc_s_seh-1.dll,libstdc-6.dll,libwinpthread-1.dll平台插件platforms/qwindows.dll必须放在platforms/子目录图标文件app.ico放在 exe 同目录QApplication::setWindowIcon()才生效配置文件config.ini内容[Serial] PortCOM3 BaudRate9600 DataBits8 ParityNone StopBits1 [Acquisition] IntervalMs100 MaxPoints10000 [Storage] CsvPathdata.csv BackupPathdata.csv.bak打包命令Qt 5.15.2 自带 windeployqtcd C:\myproject\build\release windeployqt --no-opengl-sw --no-compiler-runtime --no-system-d3d-compiler --no-webkit2 myapp.exe然后手动复制platforms/qwindows.dll到platforms/目录windeployqt有时漏掉。最终目录结构myapp/ ├── myapp.exe ├── platforms/ │ └── qwindows.dll ├── config.ini ├── data.csv └── app.ico5. 常见问题与排查技巧实录产线踩过的 7 个真实坑这些不是教科书问题而是我在客户现场蹲点三天记录下的真实故障现象和根因分析。5.1 问题速查表现象可能原因排查命令/方法解决方案serial-open()返回 falseerrorString()是Unknown errorWindows 端口被独占netstat -ano | findstr :COM3查 PID任务管理器结束对应进程关闭 Keysight IO Libraries 或重启电脑readyRead()信号不触发但 AccessPort 能通信QSerialPort缓冲区未清空serial-clear()后再open()在open()前加serial-clear()READ?返回0.000000E00恒定值万用表输入端悬空或短路用万用表实测输入端电压检查探头连接确认被测电路有输出CSV 文件写入后 Excel 打开乱码文件编码非 UTF-8 BOM用 Notepad 查看编码QTextStream构造时加setCodec(UTF-8)QChart 曲线抖动严重时间戳精度不足qint64 ts QDateTime::currentMSecsSinceEpoch();用QDateTime::currentMSecsSinceEpoch()非QTime::currentTime()程序运行 2 小时后串口卡死QSerialPort句柄泄漏Process Explorer 查myapp.exe的 HANDLE 数每次close()后serial nullptr避免重复deleteSYST:ERR?返回108,Null pointer发送命令含中文或全角字符用QByteArray::toHex()打印发送字节流所有命令用QString::toLatin1()禁用toUtf8()5.2 独家避坑技巧技巧 1用QSerialPort::bytesWritten(qint64)信号替代waitForBytesWritten()waitForBytesWritten()是阻塞调用会冻结事件循环。改用信号connect(serial, QSerialPort::bytesWritten, [](qint64 bytes) { if (bytes cmd.length()) { // 发送完成可发下一条 nextCommand(); } }); serial-write(cmd.toLatin1() \n);技巧 2QTimer::singleShot()的超时必须用QEventLoop不能用while(!done)while循环会饿死事件循环导致readyRead()信号永远不 emit。正确做法QEventLoop loop; QTimer timeoutTimer; timeoutTimer.setSingleShot(true); connect(timeoutTimer, QTimer::timeout, loop,
企业数字化 ERP 产品动态
相关推荐
ADC驱动选型:全差分放大器与分立运放噪声实测对比 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 1:52:33
CVPR27方向预测——当VLM“看不懂”空地协同:AeroGround揭示的鸿沟与CrossGeo的应对之道 CVPR27方向预测——当VLM“看不懂”空地协同:AeroGround揭示的鸿沟与CrossGeo的应对之道
数据集与Pipeline仓库: https://github.com/ZhongyaoTuo/crossgeo
论文链接: https://arxiv.org/abs/2605.07978
AeroGround项目: https://… · 2026/9/27 1:52:33
SVM用于EEG情绪识别:轻量、可解释、跨被试泛化的实践指南 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 1:52:33
做新媒体的小说网站实战案例:搞定备案不头疼 做新媒体的小说网站实战案例:搞定备案不头疼 备案号还没下来,服务器就被运营商断网,这种憋屈事你遇到过吗?做新媒体的小说网站,最让人头大的往往不是代码写不出来,而是备案流程一头雾水。我见过太多创业者,站点做得花里胡哨,结果卡在工信部ICP备案… · 2026/9/27 2:35:04
树莓派5双2.5G网口扩展实战:PCIE Switch实现NVMe与网卡共存 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 2:34:58
25个真正可用的SVG图标网站推荐(开发者实测) /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 2:34:58
内存测试核心:Shmoo图与RMT分析原理及工程实践 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 2:34:52
全志T113-S3 RGB屏移植避坑指南:从设备树到LVGL触摸校准 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 2:34:52
C++小游戏实战:从猜数字到丧尸生存,串联高频语法考点 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 2:34:45
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现 简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01
汕头网站建设制作厂家避坑指南:5大注意事项救急 汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习 简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现 简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01
汕头网站建设制作厂家避坑指南:5大注意事项救急 汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习 简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01