STM32F407 挂载 Si5324 时钟芯片配置程序全流程与避坑指南

简介:这份资源面向嵌入式开发与时钟系统设计人员,提供基于STM32F407平台配置Si5324时钟发生器的完整程序方案。Si5324作为可编程多输出频率合成器,支持LVPECL、HCSL、LVDS、LVCMOS等多种输出格式,常用于通信、数据中心与测试设备。资源包共6个文件,包含C语言配置源码、头文件、数据手册与参考手册PDF,以及官方DSPLLsim计算工具压缩包,整体约9.49MB。源码中封装了参考时钟源设置、分频系数计算、输出频率与电平配置等函数,配合数据手册可快速理解寄存器配置逻辑;DSPLLsim则用于自动计算分频参数,降低手动推导出错风险。已有3002人学习下载,适合需要掌握Si5324高级功能、搭建高精度低抖动时钟系统的开发者参考实践。

1. 从一块没输出的板子说起:Si5324 配置程序到底装什么

手上有一块自制的 STM32F407 板子,挂了一颗 Si5324 时钟发生器,上电后示波器探头搭在输出脚上,波形死活出不来。这种场景在时钟树调试里太常见了——Si5324 本身是一颗抖动衰减时钟芯片,出厂时内部寄存器全是默认值,不通过 I2C 把配置字写进去,它根本不会按你想要的频率输出。很多人第一次接触它,以为焊上去就能跑,结果卡在“芯片有电、总线有波形、就是没时钟”这个玄学状态里。

这套配置程序要装的东西其实不复杂:一个能编译 STM32F407 的工程环境,一份 Si5324 的寄存器配置数据,外加一条稳定的 I2C 读写链路。但坑在于,Si5324 的配置字不是随便填的,它依赖输入晶振频率、目标输出频率、环路带宽这些参数,算错一个分频比,输出要么偏频要么直接锁不住。这篇笔记面向的是正在 STM32F407 上挂 Si5324、需要把配置程序跑通的开发者,从工程搭建一路写到上板验证,中间踩过的坑我都会摊开讲。

2. 环境准备:STM32F407 工程与 Si5324 配置数据的落地

2.1 工具链版本选择与安装

STM32F407 的开发环境我一般用 STM32CubeIDE,版本选 1.14.0 之后的都行,它自带 ARM GCC 和 CubeMX 配置器,省得单独装编译器。如果你习惯 Keil MDK,那得注意 Si5324 的配置程序里会用到浮点运算来算分频参数,Keil 的 MicroLIB 对 printf 浮点支持有坑,建议在工程选项里勾选 Use Full Library 而不是 MicroLIB。

安装步骤不复杂,但有几个地方容易翻车:

# 以 STM32CubeIDE 为例,下载后直接解压安装 # Linux 下需要先给安装包执行权限 chmod +x st-stm32cubeide-1.14.0-linux-x86_64.sh sudo ./st-stm32cubeide-1.14.0-linux-x86_64.sh # 安装完成后,把 ST-Link 驱动规则拷进去,否则下载器识别不到 sudo cp ~/STMicroelectronics/STM32Cube/STM32CubeProgrammer/Drivers/rules/*.rules /etc/udev/rules.d/ sudo udevadm control --reload-rules

这段命令做两件事:一是给安装脚本执行权限并运行,二是把 ST-Link 的 udev 规则装到系统里。很多人装完 IDE 发现连不上板子,九成是 udev 规则没拷,Linux 下普通用户没权限访问 USB 设备。Windows 下相对省心,装完 ST-Link 驱动就能认。

提示:如果你用的是 macOS,STM32CubeIDE 对 Apple Silicon 的原生支持从 1.13 才开始,M1/M2 机器别去下老版本,否则编译时会出现工具链架构不匹配的报错。

2.2 Si5324 配置数据的来源与格式

Si5324 的配置程序核心是一张寄存器表。这颗芯片内部有 128 个寄存器,每个寄存器 8 位,配置流程就是按顺序把算好的值通过 I2C 写进去。配置数据通常有两种来源:一种是厂家提供的配置软件生成的头文件,另一种是自己按数据手册算。

我一般会把配置数据整理成一个 C 数组,放在单独的si5324_regs.h里,格式像这样:

// si5324_regs.h // Si5324 寄存器配置表,基于 114.285MHz 输入晶振、目标输出 156.25MHz 计算 // 每行两个字节:寄存器地址 + 寄存器值 const uint8_t si5324_init_seq[][2] = { {0x00, 0x54}, // 页选择,切到 Page 0 {0x01, 0xE4}, // 使能内部晶振,关闭输出直到配置完成 {0x02, 0x0F}, // 输入时钟选择,这里选 XA/XB // ... 中间省略若干分频与环路参数寄存器 {0x87, 0x00}, // 清除中断标志 {0x01, 0x00}, // 打开输出使能 };

这个数组的关键在于顺序不能乱。Si5324 上电后默认在 Page 0,但有些配置项在 Page 1 里,切页之前写的值会被覆盖。我见过有人把切页命令放在数组末尾,结果前面写的全白费,输出频率死活不对。另外,数组最后一定要留一个“打开输出”的寄存器操作,否则芯片配置完了但输出缓冲器没使能,示波器上还是平的。

2.3 I2C 底层驱动的适配

STM32F407 的硬件 I2C 外设出了名的容易卡死,尤其是总线被拉低之后。配置程序里我建议直接用 GPIO 模拟 I2C,虽然速度慢一点,但稳定,不会出现 HAL_I2C_Master_Transmit 超时返回 HAL_BUSY 的情况。

// 软件 I2C 写一个字节到 Si5324 // addr: 7 位从机地址,Si5324 默认 0x68 void si5324_write(uint8_t reg, uint8_t val) { i2c_start(); i2c_send_byte(0x68 << 1); // 从机地址 + 写标志 i2c_wait_ack(); i2c_send_byte(reg); // 寄存器地址 i2c_wait_ack(); i2c_send_byte(val); // 寄存器值 i2c_wait_ack(); i2c_stop(); delay_us(10); // 两次写之间留一点间隔,Si5324 需要处理时间 }

这段代码里0x68 << 1是因为 HAL 库和大部分软件 I2C 实现都要求把 7 位地址左移一位,最低位留给读写标志。delay_us(10)不是随便加的,Si5324 在收到每个寄存器写入后需要几个微秒的内部处理时间,连续写太快会导致后面的值被丢弃。如果你发现配置表写完了但读回校验对不上,先把延时加大到 50us 试试。

3. 配置程序编写:从寄存器表到可执行代码

3.1 配置流程的状态机设计

Si5324 的配置不是一次性写完就完事,它有一个内部锁定过程。正确的流程是:先写输入选择与分频参数,再写环路带宽,然后触发校准,最后等锁定标志置位再打开输出。我一般用一个简单的状态机来管理:

typedef enum { SI5324_STATE_IDLE, SI5324_STATE_CONFIG, SI5324_STATE_CALIBRATE, SI5324_STATE_WAIT_LOCK, SI5324_STATE_RUN } si5324_state_t; void si5324_task(void) { static si5324_state_t state = SI5324_STATE_IDLE; uint8_t reg_val; switch (state) { case SI5324_STATE_IDLE: state = SI5324_STATE_CONFIG; break; case SI5324_STATE_CONFIG: // 遍历配置表,逐条写入 for (int i = 0; i < sizeof(si5324_init_seq)/2; i++) { si5324_write(si5324_init_seq[i][0], si5324_init_seq[i][1]); } state = SI5324_STATE_CALIBRATE; break; case SI5324_STATE_CALIBRATE: // 写校准触发寄存器,地址 0x88,写 0x01 启动 si5324_write(0x88, 0x01); state = SI5324_STATE_WAIT_LOCK; break; case SI5324_STATE_WAIT_LOCK: // 读锁定状态寄存器 0x89,bit0 为 1 表示锁定 si5324_read(0x89, &reg_val); if (reg_val & 0x01) { si5324_write(0x01, 0x00); // 打开输出 state = SI5324_STATE_RUN; } break; case SI5324_STATE_RUN: // 正常运行,可在此监控失锁中断 break; } }

状态机的意义在于把“写配置”和“等锁定”分开。如果你把所有寄存器一口气写完就打开输出,芯片内部环路还没稳定,输出会有一段时间的杂波甚至完全无输出。SI5324_STATE_WAIT_LOCK里读的 0x89 寄存器是只读的,bit0 是 LOL(Loss of Lock)标志的反逻辑,为 1 表示已锁定。

3.2 分频参数的计算方法

Si5324 的输出频率由一组分频比决定,公式在数据手册里写得很清楚,但实际算的时候容易把 N1、N2、N3 搞混。我一般用下面这个简化流程:

参数含义典型取值(114.285MHz 输入,156.25MHz 输出)
N1输入分频比1
N2环路分频比8
N3输出分频比6
BW环路带宽1.2 kHz

计算时先确定 VCO 频率,Si5324 的 VCO 范围是 4.85GHz 到 5.67GHz,所以中间要经过一级倍频。实际写代码时,我建议把计算过程封装成一个函数,输入目标频率,输出寄存器值数组,这样换频率时不用手动改表。

// 根据目标输出频率计算 Si5324 分频寄存器值 // fin: 输入晶振频率(Hz),fout: 目标输出频率(Hz) // 返回 0 表示计算成功,-1 表示无法达到目标频率 int si5324_calc_div(uint32_t fin, uint32_t fout, uint8_t *regs) { // 先算 VCO 目标频率,取 5.0GHz 附近 uint32_t fvco = 5000000000UL; uint32_t n1 = 1; uint32_t n2 = fvco / (fin / n1); uint32_t n3 = fvco / fout; // 检查分频比是否在合法范围内 if (n2 < 4 || n2 > 1023 || n3 < 2 || n3 > 255) { return -1; } // 把 n1/n2/n3 拆成寄存器位域,这里省略具体位操作 // ... return 0; }

这段代码里fvco取 5.0GHz 是一个折中值,实际要根据输入频率和输出频率的公约数去调,让 N2 和 N3 都落在合法区间。如果算出来 N3 超过 255,说明输出频率太低,需要换一个 VCO 频点。我一般会写一个循环,从 4.85GHz 到 5.67GHz 步进 10MHz,找到第一组合法分频比就返回。

3.3 读写校验与回读机制

配置写完不代表写对了,Si5324 的 I2C 接口在总线干扰下可能丢数据。稳妥的做法是每写一个寄存器就回读一次,比对不上就重写,连续三次失败就报错。

// 带校验的寄存器写入 // 返回 0 成功,-1 失败 int si5324_write_verify(uint8_t reg, uint8_t val) { uint8_t readback; for (int retry = 0; retry < 3; retry++) { si5324_write(reg, val); si5324_read(reg, &readback); if (readback == val) { return 0; } } return -1; }

这个函数在调试阶段特别有用。我遇到过一块板子,I2C 上拉电阻用了 10k,上升沿太缓,写 10 次能对 7 次,换成 4.7k 之后一次通过。回读校验能帮你快速定位是配置数据算错了还是硬件链路有问题。

4. 避坑与排查:Si5324 配置过程中最常见的五个问题

4.1 现象:I2C 总线一直返回 NACK

原因:Si5324 的从机地址由芯片上的 ADDR 引脚决定,默认悬空是 0x68,但如果你的板子把 ADDR 拉高了,地址就变成 0x69。另外,芯片在复位期间不响应 I2C,如果复位引脚没接好,它一直处于复位态。

解决:先用示波器看 SDA 和 SCL 有没有波形,有波形但没 ACK,就换地址试。我一般写一个扫描程序,从 0x08 到 0x77 逐个发地址,看哪个有响应。复位引脚记得接 10k 上拉到 VCC,别悬空。

4.2 现象:配置写完了,输出频率偏差很大

原因:输入晶振频率填错了。Si5324 的配置表是按输入频率算的,如果你板子上焊的是 114.285MHz 但代码里按 100MHz 算,输出就会按比例偏。另一个可能是 N1 分频比没设对,输入路径上多分了一次频。

解决:拿频率计实测输入晶振的实际频率,别信标称值。晶振的负载电容不匹配时,实际频率可能偏几百 Hz,虽然不大,但 Si5324 的环路对输入频率敏感,偏一点输出就锁不上。代码里把fin改成实测值重新算一遍。

4.3 现象:锁定标志一直不置位

原因:环路带宽设得太窄,或者输入时钟抖动太大。Si5324 的锁定时间跟环路带宽成反比,带宽设 100Hz 时锁定可能要几百毫秒,设 1kHz 就快很多。另外,如果输入时钟本身质量差,芯片会反复失锁。

解决:先把环路带宽临时设大一点,比如 5kHz,看能不能锁上。能锁上再逐步调小到目标值。输入时钟用示波器看眼图,抖动超过 100ps 的话,Si5324 也救不回来,得先解决源端问题。

4.4 现象:输出有波形但抖动很大

原因:电源噪声。Si5324 对电源纹波很敏感,尤其是 VCO 的供电脚。如果和 STM32F407 共用一路 LDO,数字部分的开关噪声会串进来。

解决:给 Si5324 的模拟电源单独加一级 LC 滤波,或者换低噪声 LDO。我一般会在 VCO 供电脚旁边并一个 10uF 钽电容加一个 100nF 陶瓷电容,位置尽量靠近芯片引脚。

4.5 现象:程序跑一段时间后输出消失

原因:Si5324 的失锁中断没处理。如果输入时钟短暂丢失,芯片会失锁并关闭输出,但你的程序没去读中断标志,也没重新触发校准,它就一直停在那。

解决:在状态机的SI5324_STATE_RUN里定期读 0x89 寄存器,发现失锁就回到SI5324_STATE_CALIBRATE重新校准。另外,把 Si5324 的中断引脚接到 STM32 的外部中断上,失锁时直接进中断处理,比轮询快。

5. 上板验证:怎么确认 Si5324 真的按你的配置在跑

配置程序烧进去只是第一步,真正要确认它跑通,得从三个层面验证:I2C 通信正常、寄存器值正确、输出频率和抖动达标。

先做寄存器回读。写一个简单的测试函数,把配置表里的关键寄存器逐个读出来打印到串口:

// 验证配置是否写入成功 void si5324_dump_regs(void) { uint8_t val; // 只打印关键寄存器,避免刷屏 uint8_t key_regs[] = {0x01, 0x02, 0x03, 0x0B, 0x0C, 0x87, 0x89}; for (int i = 0; i < sizeof(key_regs); i++) { si5324_read(key_regs[i], &val); printf("REG[0x%02X] = 0x%02X\r\n", key_regs[i], val); } }

串口输出里重点看 0x89 的值,bit0 为 1 说明锁定。如果 0x89 读出来是 0x00,别急着改配置,先确认输入时钟有没有送到 Si5324 的 XA/XB 脚上。我习惯用示波器探头直接搭在晶振输出脚上,看到波形再往下查。

然后是频率实测。把 Si5324 的输出接到频率计或者示波器上,看实际频率和目标频率差多少。Si5324 的精度取决于输入晶振,如果输入是 114.285MHz 的 TCXO,输出偏差应该在 ±10ppm 以内。如果偏差超过 100ppm,回去检查分频比计算。

最后是抖动测试。没有专业相位噪声分析仪的话,用示波器看输出波形的过零点是否均匀,或者用 STM32 的定时器输入捕获功能测周期抖动。我一般会连续测 1000 个周期,算标准差,小于 50ps 就算合格。

注意:验证时别只测一个频点。Si5324 支持多路输出,如果你配置了多路,每一路都要单独测。我见过有人只测了 OUT1,结果 OUT2 的使能位没写,板子上另一路时钟一直没出来。

从那以后我每次配 Si5324,都强制走一遍“回读关键寄存器 → 实测频率 → 测抖动”这三步,少一步都不放心。希望帮到你。

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

相关新闻

国产AI芯片软件生态破局:从CUDA垄断到联合深度适配

国产AI芯片软件生态破局:从CUDA垄断到联合深度适配

上个月我们做国产算力选型评审&#xff0c;小组拿到一块新出的国产AI加速卡&#xff0c;硬件规格表相当漂亮——算力、显存、互连带宽都不弱于我们正在用的国际GPU。可真正把流行的开源大模型跑起来时&#xff0c;第一晚就栽在算子兼容性上报错。那一刻我突然意识到&#xff1a…

2026/10/20 13:03:57 阅读更多 →
STM32F407驱动Si5324时钟芯片:I2C配置程序与调试避坑指南

STM32F407驱动Si5324时钟芯片:I2C配置程序与调试避坑指南

简介&#xff1a;这份资源面向嵌入式开发与时钟系统设计人员&#xff0c;提供基于STM32F407平台配置Si5324时钟发生器的完整程序方案。Si5324作为高精度、低相位噪声的可编程频率合成器&#xff0c;广泛用于通信、数据中心与测试设备&#xff0c;资源围绕其寄存器配置、分频系数…

2026/10/20 13:03:57 阅读更多 →
context-mode:一种运行时上下文驱动的行为策略设计范式

context-mode:一种运行时上下文驱动的行为策略设计范式

1. “context-mode”不是新功能&#xff0c;而是开发者正在集体重构的底层认知最近在多个技术社区和开源项目讨论区里&#xff0c;“context-mode”这个词高频出现&#xff0c;但翻遍主流文档、API手册甚至GitHub仓库的README&#xff0c;几乎找不到它的官方定义。它既不是某个…

2026/10/20 13:02:56 阅读更多 →

最新新闻

开源AI智能体OpenClaw实操指南:普通人也能轻松部署

开源AI智能体OpenClaw实操指南:普通人也能轻松部署

说真的&#xff0c;能让“普通人也值得拥有”这七个字同时出现在标题里的AI项目&#xff0c;最近只有一个——OpenClaw&#xff0c;也就是被大家在聊天群里喊成“龙虾”的那个开源AI智能体。这个外号没啥高深来头&#xff0c;项目形象是一只举着钳子、看起来不太好惹的红色小龙…

2026/10/20 13:52:16 阅读更多 →
自适应哈夫曼编码:流式数据压缩中的动态树与同步机制

自适应哈夫曼编码:流式数据压缩中的动态树与同步机制

简介&#xff1a;这是一份自适应哈夫曼编码的C完整实现&#xff0c;适合正在学习数据压缩算法、哈夫曼树与动态编码原理的开发者。与静态哈夫曼编码不同&#xff0c;自适应版本在编码过程中根据字符频率变化实时更新哈夫曼树&#xff0c;特别适合流式数据或字符分布动态变化的场…

2026/10/20 13:52:16 阅读更多 →
MATLAB双目标定实战:从采集到三维重建的避坑指南

MATLAB双目标定实战:从采集到三维重建的避坑指南

简介&#xff1a;这份资源面向计算机视觉初学者与需要完成课程实验的学生&#xff0c;提供基于MATLAB工具箱的双目标定完整实践材料&#xff0c;帮助解决相机内外参数求解、几何失真校正与立体视觉入门问题。压缩包共182个文件&#xff0c;约15.71MB&#xff0c;以128张jpg标定…

2026/10/20 13:52:16 阅读更多 →
MCAL功能安全设计:从寄存器级防护到ASIL-D落地实践

MCAL功能安全设计:从寄存器级防护到ASIL-D落地实践

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

2026/10/20 13:52:16 阅读更多 →
宠物识别系统实战:基于Python与TensorFlow的图像分类毕设指南

宠物识别系统实战:基于Python与TensorFlow的图像分类毕设指南

每年毕设季&#xff0c;总会有人问我这样的问题&#xff1a;想做一个跟“人工智能”沾边的项目&#xff0c;但又怕难度太高hold不住。这里我直接给一个结论——如果你需要在2026年完成计算机方向的毕业设计&#xff0c;又希望项目既有技术含量、又能落地演示&#xff0c;“宠物…

2026/10/20 13:52:16 阅读更多 →
基于U-Net的道路裂缝检测:毕设级语义分割全流程实战

基于U-Net的道路裂缝检测:毕设级语义分割全流程实战

1. 项目概述与核心思路拆解1.1 为什么说这个选题是毕设的“安全牌”又带点含金量道路裂缝检测这个方向&#xff0c;在计算机视觉和深度学习的毕设题目里属于“进可攻退可守”的典型选择。进可攻——你可以往实例分割、多任务学习、轻量化部署方向延伸&#xff0c;做成一个能跑在…

2026/10/20 13:51:15 阅读更多 →

日新闻

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

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

2026/10/20 1:01:30 阅读更多 →
ESP32舵机控制指南:原理、多路驱动与避坑实战

ESP32舵机控制指南:原理、多路驱动与避坑实战

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

2026/10/20 1:01:30 阅读更多 →
位移法实现一阶低通滤波:单片机ADC采样降噪实战

位移法实现一阶低通滤波:单片机ADC采样降噪实战

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

2026/10/20 1:01:30 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型&#xff08;GMM&#xff09;的语音识别系统&#xff0c;很多人第一反应就是一堆数学公式&#xff0c;觉得门槛很高。但如果你真的在MATLAB里把它落地跑通&#xff0c;会发现核心其实就是三件事&#xff1a;把声音变成特征向量&#xff0c;用GMM给每个类别…

2026/10/20 10:02:13 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人&#xff0c;但落到具体操作上&#xff0c;无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程&#xff1a;对图像做反白、改调色板、彩色转灰度&#xff0c;最后把像素数据导出成txt文件。单看每一…

2026/10/19 17:32:41 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词&#xff0c;你会发现一个很有意思的现象&#xff1a;每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型&#xff0c;有人指的是运动控制系统&#xff0c;还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

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

2026/10/20 10:02:08 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

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

2026/10/20 9:50:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

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

2026/10/20 9:50:45 阅读更多 →