news 2026/9/27 1:38:55

RK3506工业开发板Qt GUI开发实战:交叉编译、环境搭建与开机自启动配置

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
RK3506工业开发板Qt GUI开发实战:交叉编译、环境搭建与开机自启动配置

瑞芯微RK3506工业开发板Qt GUI开发实战:从环境搭建到自启动配置

做工业人机界面这块,我这两年大部分时间都泡在ARM开发板上,从裸机点灯到跑完整套Qt界面,踩坑踩到怀疑人生。最近用瑞芯微RK3506工业开发板做完一个HMI项目,从交叉编译环境搭建到界面开发,再到最后的开机自启动配置,整个流程走下来,觉得这套组合在工业场景里确实挺有代表性。今天就把完整过程拆开揉碎写出来,从零开始讲清楚每一步怎么操作、为什么这么操作,以及哪些地方是你最容易掉进去的坑。

RK3506这块芯片定位很明确,就是冲着工业控制和人机交互来的,价格实在,供货稳定,外设接口齐全,跑Qt做中小型HMI屏幕绰绰有余。如果你正准备用RK3506做项目,或者手里有类似规格的ARM开发板想跑Qt,这篇文可以帮你少走很多弯路。我会把环境搭建、Qt编译、界面开发、程序部署、自启动配置这五块,按实际项目的推进顺序完整过一遍,中间会穿插大量我在现场调试时遇到的实际问题和对应的解决思路。

1. 整体方案设计:为什么选RK3506跑Qt,以及需要准备哪些料

1.1 RK3506在工业HMI场景里的定位

先说结论:RK3506不是一颗消费级跑分芯片,它就是为工业控制、电力设备、物联网网关这类场景设计的。核心优势不在浮点运算多强,而在接口丰富、实时性好、工作温度宽、生命周期长。做工业产品最怕什么?最怕芯片停产,方案还没量产芯片先没了。瑞芯微在工规市场的供货策略相对稳定,这一点对做产品选型的人来说分量非常重。

我实际用下来,RK3506配合Qt做图形界面,运行是非常流畅的。常见场景比如:

  • 设备状态监控面板,几个仪表盘加趋势曲线,实时刷新
  • 工业参数设置页,表单加下拉框,跳转切换
  • 简单的数据采集和报警弹窗

这些内容的负载对RK3506来说完全没有压力。再加上芯片本身支持丰富的GPIO、UART、CAN、以太网等接口,直接和PLC、传感器、变频器联动非常方便,不需要额外挂一颗MCU做中转。

当然它也有一颗改动的地方:别拿它和四核A72级别的处理器比3D渲染,Qt开发时尽量选Widgets或简单的QML场景,不要做复杂的粒子特效、复杂动画转场,这些都是RK3506在工业项目里不适用的方向,也是新人特别容易踩的性能误区。

1.2 技术路线选型:整体架构和材料清单

整个项目的技术路线,我把架构拆成四层:

  • 硬件层:RK3506工业开发板,外加一块LVDS或RGB接口的显示屏,推荐7寸或10.1寸,分辨率1024x600或1280x800,配电容触摸
  • 系统层:Linux系统,一般用厂家提供的Buildroot或Debian镜像
  • 图形层:Qt 5.15.2 LTS版本,这是目前工业场景里用得最稳的版本,比Qt 6的兼容性压力小
  • 应用层:用Qt Widgets写主界面程序,通过串口或Modbus协议和底层设备通信

这套方案的优点是每一层都有成熟的社区方案兜底,出了问题网上资料好找。很多朋友会纠结要不要用Qt 6,我的建议是:除非你有新特性刚需,否则在嵌入式Linux上继续用Qt 5.15.2,稳定胜过一切。

动手之前,需要把以下材料准备齐:

  • 装有Ubuntu 20.04或22.04的PC一台,虚拟机也行,但建议磁盘留足80GB
  • RK3506开发板一块,配套的电源、串口线、网线、屏幕模组
  • 厂家提供的交叉编译工具链和Linux系统镜像
  • Qt源码包,版本选择5.15.2
  • 一个能联网的终端环境,用于下载依赖

把材料备齐后,下一步就是最磨人的环节:交叉编译环境的搭建。

2. Qt开发环境搭建:交叉编译与目标板部署

2.1 交叉编译工具链的选型与安装

这一步很多人会卡住,问题通常不是工具链本身多难装,而是“装完不知道对不对”。先说原理:普通PC上装的Qt,编译出来的程序跑在x86架构上,但RK3506是Arm架构,CPU指令集不同,所以需要一个能在x86 PC上运行、却能生成Arm机器码的编译器,这就是交叉编译工具链。

RK3506厂家通常会直接提供配套的交叉编译器,一般是基于gcc的arm-linux-gnueabihf或aarch64-linux-gnu系列。我的做法是:

# 解压工具链到 /opt 目录 sudo tar -xvf rk3506-gcc-toolchain.tar.bz2 -C /opt # 配置环境变量 export PATH=/opt/rk3506-gcc/bin:$PATH # 验证是否可用 arm-rockchip3506-linux-gnueabihf-gcc --version

如果厂家没有提供专用工具链,也可以用Linaro的通用arm工具链,但要确认glibc版本和内核的匹配度,这个坑后续我会重点讲。

注意:大多数交叉编译问题不是编译器本身出错,而是动态库不匹配。编译时链接了PC上的libstdc++,拷到板子上跑不起来,这类问题后面专门讲排查方法。

2.2 Qt源码交叉编译的完整过程

拿到工具链之后,重头戏是交叉编译Qt库。这里强调绝对不能偷懒用apt安装的Qt,那是给x86架构用的。我们要从源码编译一套Arm版Qt,然后部署到板子上。

我用的Qt版本是5.15.2,需要下载的包有:

  • qt-everywhere-opensource-src-5.15.2.tar.xz
  • 如果要用串口、网络等模块,确认源码包中是否包含qtserialport、qtnetwork等模块(一般都在)

配置这一步是核心技术难点,命令如下:

tar -xvf qt-everywhere-opensource-src-5.15.2.tar.xz cd qt-everywhere-opensource-src-5.15.2 mkdir build && cd build ../configure \ -prefix /opt/qt5.15.2-arm \ -xplatform linux-arm-gnueabi-g++ \ -release \ -opensource \ -confirm-license \ -no-opengl \ -no-gtk \ -no-sql-sqlite \ -nomake examples \ -nomake tests \ -skip qt3d \ -skip qtmultimedia \ -skip qtwebengine

几个关键参数逐一说一下:

  • -prefix:编译完的Qt库安装路径,后续部署到板子时,这个路径最好和板子上的实际路径保持一致,避免额外配置
  • -xplatform:指定目标的交叉平台配置。这里要注意,默认的linux-arm-gnueabi-g++可能对特定工具链不适用,瑞芯微的板子经常需要自己在qtbase/mkspecs下新建一个平台配置,或者修改现有配置里的编译器名称
  • -no-opengl:除非需要GPU加速,工业HMI一般用不上OpenGL,关掉可以减少依赖、降低编译体积
  • -skip qtwebengine:这个模块巨大而且难编译,嵌入式下几乎不用

配置完成后,执行编译:

make -j4 make install

编译Qt全套大约需要2到3个小时,视机器性能而定。这里强烈建议用make -j4而不是-j8或更高,因为Qt各模块之间存在依赖关系,并行度过高偶尔会触发隐藏的时序问题,排查起来非常痛苦。

2.3 将Qt运行库部署到开发板

编译安装之后,/opt/qt5.15.2-arm下面就是完整的Arm版Qt目录。部署到开发板时,有两种方式:

  • 整目录打包拷贝,优点是一次性省心,缺点是体积大
tar -czf qt5.15.2-arm.tar.gz /opt/qt5.15.2-arm # 拷贝到板子后解压到相同路径 tar -xzf qt5.15.2-arm.tar.gz -C /
  • 只拷贝运行所需的lib目录,优点是精简,适合存储空间紧张的板子

我推荐第一次调试用整目录拷贝,因为后续调试过程中缺库、缺插件的情况非常常见,全量部署可以降低定位问题的难度。

部署完成之后,还需要在板子上设置Qt运行环境变量。在/etc/profile末尾添加:

export QT_ROOT=/opt/qt5.15.2-arm export PATH=$QT_ROOT/bin:$PATH export LD_LIBRARY_PATH=$QT_ROOT/lib:$QT_ROOT/plugins/platforms:$LD_LIBRARY_PATH export QT_QPA_PLATFORM_PLUGIN_PATH=$QT_ROOT/plugins/platforms export QT_QPA_FB_DRM=1

其中QT_QPA_PLATFORM_PLUGIN_PATH这个变量,是很多人一开始容易忽略的。Qt程序启动时必须找到libqlinuxfb.so或libqeglfs.so这类平台插件,找不到了就会直接报could not find or load the Qt platform plugin "linuxfb",这个错误到第5部分细聊。

3. GUI界面开发实战:一个最小可用的工业HMI程序

3.1 界面模块划分和架构设计

环境搭好之后,就可以进入真正的GUI开发了。工业HMI和普通APP开发有一个非常大的不同:界面往往不是核心,"数据链路"才是核心。界面只是数据的可视化呈现,底层实时采集、处理、上报才是命根子。所以从一开始,代码结构就不能是"一个MainWindow搞定一切"的思路,而是按模块划分:

project/ ├── main.cpp ├── mainwindow.h / mainwindow.cpp ├── modbusworker.h / modbusworker.cpp # 数据采集线程 ├── settingdialog.h / settingdialog.cpp # 参数设置界面 ├── alarmwidget.h / alarmwidget.cpp # 报警显示控件 └── ui/ ├── mainwindow.ui └── settingdialog.ui

数据采集用独立线程跑,主线程只负责刷新界面。这样有一个显著的好处:即使串口或网络偶尔阻塞,界面也不会卡死。用户在整个触摸点击流程之中,不会因为底层通信卡顿而觉得"屏死机了",这是工业设备体验感的关键。

3.2 用Qt Widgets完成主界面布局

我这边因为工期原因没有用QML,直接选用Qt Widgets。对于参数表格、表单、设备状态这类界面,Widgets开发效率极高,而且可以直接用Qt Designer拖拽排版,对不熟悉前端技术的嵌入式工程师非常友好。

设计一个典型主界面,从上到下分三个区:

  • 顶部:标题栏和当前时间,时间用QLCDNumber显示更协调
  • 中间:设备运行状态区,用QLabel加动态换色来显示运行/停止/报警三种状态
  • 底部:按钮区,放置"参数设置""历史数据""系统信息"等几个功能按钮

关键代码大致是:

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { // 实例化中央控件 QWidget *central = new QWidget(this); QVBoxLayout *layout = new QVBoxLayout(central); // 状态指示区 m_statusLabel = new QLabel("设备状态:运行中", central); m_statusLabel->setStyleSheet("background-color: #4CAF50; color: white;" "font-size: 20px; padding: 20px;"); // 按钮区 QPushButton *btnSettings = new QPushButton("参数设置", central); connect(btnSettings, &QPushButton::clicked, this, &MainWindow::openSettingDialog); layout->addWidget(m_statusLabel); layout->addWidget(btnSettings); setCentralWidget(central); }

触摸按钮的大小,工业场景最好不小于60x60像素,太小了工人戴手套操作时容易误触。这个细节很多初做工业HMI的人注意不到,但现场用户反馈最多的就是"按键真难点"。

3.3 核心数据联动:串口通信与界面刷新

界面做出来了,下一步就是把数据接进来。RK3506最常用的工业通信方式就是UART串口,走Modbus RTU协议和PLC或传感器通信。Qt里使用QSerialPort模块非常方便。

在工程文件中添加串口支持:

QT += core gui widgets serialport

建立串口线程的代码注意点:

void ModbusWorker::run() { QSerialPort serial; serial.setPortName(m_portName); serial.setBaudRate(9600); serial.setDataBits(QSerialPort::Data8); serial.setParity(QSerialPort::EvenParity); serial.setStopBits(QSerialPort::OneStop); if (!serial.open(QIODevice::ReadWrite)) { emit errorOccurred(serial.errorString()); return; } while (m_running) { // 组帧 QByteArray frame; frame.append(0x01); // 从站地址 frame.append(0x03); // 功能码:读保持寄存器 frame.append(0x00); frame.append(0x10); // 起始地址 frame.append(0x00); frame.append(0x02); // 读取长度 // 计算CRC16(略) serial.write(frame); if (serial.waitForBytesWritten(100)) { if (serial.waitForReadyRead(500)) { QByteArray resp = serial.readAll(); // 解析数据 int value = parseValue(resp); emit dataReady(value); } } // 轮询周期 QThread::msleep(500); } }

主界面在槽函数里刷新仪表盘数值:

void MainWindow::onDataReady(int value) { m_statusLabel->setText(QString("当前温度:%1 ℃").arg(value / 10.0)); }

这条数据链路里最常见的坑有两个。

第一个是waitForReadyRead(500)这个参数。在重负载板子上,串口接收中断可能延迟,500ms不一定足够。稳妥的做法是用readyRead信号加状态机解析,而不是纯粹的阻塞等待轮询。我实测中改成信号槽方式后,数据丢包率明显下降。

第二个是串口缓冲区的"粘包"问题。有时候一次readAll()读到的不一定是完整的一帧,也可能是两帧拼接在一起。业界通用解法是维护一个接收缓冲区,先查帧头帧尾再截取完整帧,多余数据留在缓冲区里等下一帧。这个细节在Modbus通信中特别致命,不处理的话界面会出现偶发跳变数据。

3.4 编译发布和移植到ARM板

开发调试阶段,我习惯先在PC上用x86版Qt跑一遍,数据结构、界面交互都调好,然后切到交叉编译环境出ARM版。具体操作是在同一个pro文件上,用两套qmake分别生成Makefile:

# 先清理 make clean # x86调试版 /usr/bin/qmake project.pro make -j4 # 交叉编译ARM版 /opt/qt5.15.2-arm/bin/qmake project.pro make clean make -j4

二进制文件生成后,通过NFS或scp拷贝到开发板。这里给一个自动化部署的小脚本:

#!/bin/bash TARGET_IP=192.168.1.100 arm-rockchip3506-linux-gnueabihf-strip HMIApp scp HMIApp root@$TARGET_IP:/opt/app/ ssh root@$TARGET_IP "chmod +x /opt/app/HMIApp && /opt/app/HMIApp -platform linuxfb"

strip这一步经常被忽略,但非常有用。去掉调试符号后,可执行文件体积能缩小三分之一甚至更多,对存储和加载速度都是实打实的优化。

4. 开机自启动配置:三种方案与踩坑记录

4.1 用systemd服务管理自启动

程序开发完成后,最后一步也是最"工业"的一步,就是让软件跟随系统开机自动运行。工业设备不像手机电脑,没有专职运维人员盯着,断电重启后必须能自己恢复工作。这一步做不到位,前面所有开发都是白费。

RK3506的Linux系统默认就带systemd,这是我优先推荐的方式,可控性强、出错容易排查。先在板子上创建一个service文件:

[Unit] Description=Industrial HMI Application After=network.target [Service] Type=simple User=root Environment=DISPLAY=:0 Environment=QT_QPA_PLATFORM=linuxfb Environment=QT_ROOT=/opt/qt5.15.2-arm Environment=LD_LIBRARY_PATH=/opt/qt5.15.2-arm/lib:/opt/qt5.15.2-arm/plugins/platforms ExecStart=/opt/app/HMIApp Restart=always RestartSec=3 [Install] WantedBy=multi-user.target

配置中Restart=always和RestartSec=3这两个参数,堪称工业现场的救命稻草。一旦程序因为偶发异常崩溃,systemd会在3秒后自动拉起来,可以大大降低设备停机时间。很多设备在无人值守环境下运行几个月不出问题,靠的就是这行配置。

然后执行:

systemctl daemon-reload systemctl enable hmiapp.service systemctl start hmiapp.service

这里有三个高频问题:

  • 第一个:程序反复重启,循环刷日志。兜底方法是在service里加一个StartLimitIntervalSec=0和StartLimitBurst=0,防止无限重启消耗CPU
  • 第二个:环境变量在systemd环境里默认是清空的,Qt找不到库的问题90%都是这里引起的,所以service文件里必须显式指定所有依赖的Environment变量,不能指望/etc/profile
  • 第三个:如果程序的日志没有重定向,systemd启动时的输出会丢到journal里,查看方式用journalctl -u hmiapp -f

4.2 备选方案:inittab自启动

部分RK3506板子的出厂固件可能不带systemd,而是用BusyBox的init系统,这种情况下需要配置/etc/inittab:

::respawn:/opt/app/HMIApp -platform linuxfb

respawn的作用是程序退出后自动重新拉起,功能类似systemd的Restart字段。但有一个差别很大:respawn对"快速崩溃"没有限制。如果程序一启动就崩溃,然后又被恢复起来,如此循环会造成CPU占用飙高、日志刷屏。

另一种做法是官方固件经常提供的/etc/rc.local:

#!/bin/sh -e /opt/app/HMIApp -platform linuxfb & exit 0

rc.local方式要注意"可执行权限"——很多板子的rc.local默认没有执行权限,写进去根本不会跑。遇到自启动不生效时,先检查这个文件的权限。

4.3 触摸屏校准和屏幕常亮设置

和自启动配套的还有两个细节,不处理后面会很闹心。

第一个是触摸屏校准。电容屏一般出厂有校准参数,但如果你换过屏幕,触摸坐标就会偏移。可以在自启动前执行对应的校准工具,把校准数据写到指定配置文件中。debain系系统一般用xinput_calibrator,纯framebuffer环境则用tslib的ts_calibrate。

第二个是屏幕休眠。有些屏在系统空闲一段时间后会进入休眠或黑屏状态,这不是硬件坏了,而是内核的DRM/KMS或framebuffer没有设置关掉blanking。命令行下关掉:

# 在自启动脚本里加入 setterm -blank 0 -powersave off -powerdown 0

在Qt程序里也可以用:

// 阻止屏幕休眠 QProcess::execute("setterm -blank 0");

这块处理完之后,整机断电重启,Qt程序能自己拉起来,触摸校准可用,屏幕常亮不熄,一台基础的工业HMI产品就算成型了。

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

5.1 Qt平台插件加载失败

这是新手上路遇到次数最多的一个报错:

This application failed to start because no Qt platform plugin could be initialized. Available platform plugins are: linuxfb, minimal, offscreen.

排查思路按三步走:

  • 第一步,确认板子上$QT_ROOT/plugins/platforms目录存在,且里面有libqlinuxfb.so
  • 第二步,确认环境变量QT_QPA_PLATFORM_PLUGIN_PATH指向了正确的目录
  • 第三步,确认lib库依赖完整,用ldd检查:
ldd /opt/app/HMIApp | grep "not found"

如果有输出,说明缺少依赖库,到PC交叉编译工具链对应目录下拷贝对应的so到板子/lib或Qt的lib目录。

5.2 中文字体显示成方块

Qt程序在开发板上默认不包含中文字体,界面里中文全部显示为方块,这个是工业项目里必须解决的,因为HMI界面几乎都是中文。解决办法是准备一个或多个开源中文字体(如文泉驿微米黑、思源黑体),拷贝到板子/opt/qt5.15.2-arm/lib/fonts/目录,然后在程序里设置:

QFont font("WenQuanYi Micro Hei", 12); app.setFont(font);

或者放到系统字库目录并刷新字体缓存。字体问题不解决,界面就是半成品状态,根本没法交付。

5.3 触摸漂移和点击不准

触摸不准有时候不是校准问题,而是设备树的触摸参数不对。RK3506板子如果用GT911或GT928这类电容触摸芯片,内核里有对应寄存器配置。如果板厂提供的设备树触摸节点中的touchscreen-inverted-x、touchscreen-inverted-y等参数与实际屏幕安装方向不符,就会出现触摸坐标镜像或翻转。

排查方法是先用evtest工具直接读取原始触摸事件,对比手指位置和上报坐标,判断是偏移、翻转还是完全没有识别:

evtest /dev/input/event0

如果event正常但Qt响应不对,那问题出在tslib或Qt的输入配置;如果event本身就不对,问题就在内核驱动或设备树。

5.4 数据库模块与串口模块找不到

Qt项目在PC上编译运行正常,交叉编译后一运行就报qt.serialport: Unknown module(s) in QT: serialport。这种情况通常是交叉编译Qt时没有编译对应的模块,或者编译时模块路径不对。

解决办法分两个层面:

  • 编译层面:配置Qt时确认没有禁用serialport模块,官方默认开启,但如果使用了-skip参数需要检查
  • 运行层面:把libQt5SerialPort.so.5拷贝到板子Qt库目录。更稳妥的做法是写一个小脚本,用ldd检查程序依赖的所有Qt库,批量拷贝

另外,qmake的QT += serialport在pro文件里写清楚了,但交叉编译时用错了qmake,也可能导致报"unknown module"。这种情况多发生在系统里同时装了两套Qt时,最好在编译前which qmake确认路径。

5.5 性能优化:让界面响应更跟手

RK3506跑Qt Widgets是流畅的,但如果你把界面写得过于复杂,仍然会遇到掉帧、卡顿的情况。我的经验是几个关键优化点:

  • 避免频繁setStyleSheet动态改样式,宁可预置多套样式,在状态切换时一次性替换
  • 定时器刷新QImage或QPixmap时,尽量只更新局部update()区域,不要整个窗口repaint。实际经验是,10.1寸屏全画面更新一次比局部更新多花好几倍时间
  • 图片资源尽量打包进qrc,避免运行时频繁访问存储造成IO瓶颈
  • 不要在UI线程里做耗时的文件读写或网络请求,统一扔给工作线程,用完通过信号槽回传

这些优化做完,即使设备长期跑下来,界面响应依然跟手,设备切换页面、按压反馈都不会有"迟钝"或"假死"的体感。

6. 写在最后的几句实在话

整套流程走下来,我的体会是:RK3506开发板配合Qt做工业HMI,成本可控、开发效率高、稳定性也经得起现场考验。如果只是追求屏幕上出个界面,那确实不难,几天就能搞出来,但真正决定产品好坏的,往往是那些不起眼的地方——轮询数据会不会丢帧、程序崩溃了能不能自己拉起来、断电重启后能不能恢复到正常状态、触摸准不准、字体清不清晰。这些细节才是工业项目和实验室demo的本质差距。

如果你也是第一次在ARM板子上跑Qt,我的建议是:先不要追求界面的炫酷,先保证程序能稳定运行24小时不崩溃,再把开机自启和数据链路的可靠性做扎实,最后回过头来慢慢打磨界面的交互细节。按这个节奏推进,方向基本不会跑偏。

最后分享一个调试小技巧:在做自启动配置的时候,可以在程序里加一个启动参数--debug,判断到这个参数时输出更详细的日志,并且不进入全屏模式。这样在调试自启动问题时,你就能同时看到systemd的日志和程序的内部日志,排查问题的效率会翻倍。这个习惯我一直保留到现在,不管是RK3506还是其他板子,都特别实用。

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

NFC天线匹配实战:用VNA测准RLC参数调出13.56MHz心跳

/* 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:37:12

RK3588嵌入式SoC六大硬件单元状态监控与频率调优实操

/* 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:37:10

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 1:37:07

Android 15在米尔RK3576开发板上的实测:系统升级与部署全记录

/* 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:36:47

VC++聊天室课程设计:Socket编程与MFC线程避坑指南

/* 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:36:46

图盲去模糊实战:从图构建、核估计到图神经网络训练与避坑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华