嵌入式系统电源与时钟管理:PSC与PLLC实战配置与低功耗设计
1. 项目概述嵌入式系统的“心脏”与“脉搏”在嵌入式系统开发中尤其是涉及高性能处理器或复杂片上系统SoC时我们常常会面对两个看似基础却至关重要的子系统电源管理与时钟管理。你可以把它们想象成整个芯片的“心脏”与“脉搏”。电源管理控制器PSC负责为芯片内部各个功能模块如CPU、DMA、外设精准地“供电”或“断电”控制其生命活动而锁相环控制器PLLC则负责产生和分配稳定、精确的“时钟信号”即系统工作的节拍器确保所有数字逻辑能够协调一致地运行。为什么我们需要如此精细地控制它们原因很直接功耗和性能。一个典型的嵌入式设备其内部并非所有模块都需要时刻全速运转。例如一个用于数据采集的物联网传感器节点大部分时间可能只有ADC模数转换器和定时器在低速工作而强大的CPU核心和高速通信接口则处于休眠状态。如果让所有模块都保持上电并运行在最高时钟频率电池可能几小时就耗尽了。因此通过PSC动态地关闭闲置模块的电源和时钟通过PLLC动态调整工作频率是实现超低功耗设计的关键。本次我们聚焦于德州仪器TI某些系列处理器中的PSC与PLLC模块。虽然你提供的资料是具体的寄存器手册片段但我们的目标不是照本宣科而是解构其设计思想提炼出通用的配置逻辑、避坑指南和实战心得。无论你使用的是TI的Cortex-A、Cortex-R还是DSP平台甚至是其他厂商的ARM芯片其电源与时钟管理的核心理念都是相通的。掌握了这套“内功”你就能游刃有余地驾驭各种复杂的低功耗场景。2. 核心机制深度解析状态、控制与流程要玩转PSC和PLLC不能只停留在“配置某个寄存器位”的层面必须理解其背后的状态机模型和控制流程。这就像开车不仅要会踩油门和刹车写寄存器还要懂交规和路况状态转换条件。2.1 PSC模块的生命周期管理者PSC管理的核心对象是“模块”Module比如UART、SPI、EDMA等。每个模块在PSC眼中都有一个明确的状态这个状态由两个关键因素决定模块复位信号和模块时钟。你提供的资料中的表8-3清晰地定义了六种状态Enable使能复位释放时钟开启。模块正常工作状态。Disable禁用复位释放时钟关闭。用于省电模块内部状态保持。SyncReset同步复位复位有效时钟开启。一般用于硬件初始化软件很少主动设置。SwRstDisable软件复位禁用复位有效时钟关闭。上电后的常见默认状态软件需先将其切出此状态才能使用模块。Auto Sleep自动睡眠Auto Wake自动唤醒这两个是“智能省电”状态。模块时钟默认关闭但当有内部访问如CPU读/写该模块的寄存器时硬件会自动、临时地开启时钟Auto Wake会永久开启Auto Sleep则在访问后再次关闭。这里有一个极其重要的实战坑点资料中多次用“NOTE”强调当前芯片版本不支持将模块配置为Auto Sleep或Auto Wake模式。对于标记为“Auto Sleep/Wake Only”的模块如资料中的SCR1、SCR2等软件试图将其设置为Disable等状态是无效的PSC会强制将其保持在Enable状态。这意味着如果你在代码中试图关闭这些模块的时钟来省电实际上并不会成功功耗可能依然存在。正确的做法是对于需要省电的普通模块使用Disable状态对于“Auto Sleep/Wake Only”模块就让它保持Enable不要试图去动它。忽视这个NOTE是很多开发者功耗降不下来的一个隐性原因。2.2 PLLC系统节拍的指挥家PLLC的核心是锁相环它能够将外部较低频率的晶振时钟倍频到CPU、总线等所需的高频。你提供的资料片段展示了两个状态寄存器CKSTAT和SYSTAT。CKSTAT寄存器主要反映辅助时钟AUXCLK的开关状态。这个状态是由另一个寄存器CKEN中的AUXEN位控制的。CKSTAT是只读的用于查询当前状态确保软件操作符合预期。SYSTAT寄存器反映了SYSCLK1~SYSCLK7这7个系统时钟域的开关状态。每个位SYSnON直接对应一个时钟域是On还是Off。关键理解这些状态寄存器是“结果”的反映而不是“原因”。它们的值是由对应的控制寄存器如PLL的分频配置寄存器PLLDIVn中的使能位DnEN以及PSC对模块的时钟控制共同决定的。软件在操作时应该遵循“先配置控制寄存器再查询状态寄存器以确认操作完成”的流程。直接读写状态寄存器是无法改变时钟状态的。2.3 状态转换严谨的“握手”协议无论是PSC的模块状态转换还是PLLC的时钟配置变更都不是瞬间完成的。硬件需要时间进行内部同步和稳定。因此芯片设计了一套标准的“握手”流程资料中8.3.2节给出了完美示例等待就绪检查PTSTAT寄存器中的GOSTAT[x]位x代表电源域。必须等待其为0表示上一个状态转换命令已完成。这是死循环等待的常见位置务必添加超时判断防止硬件异常导致系统死锁。// 伪代码示例等待PSC0的域0转换完成带超时 uint32_t timeout 100000; // 超时计数 while ((PSC0-PTSTAT (1 0)) ! 0) { // 检查GOSTAT0 if (--timeout 0) { // 处理超时错误可能硬件或流程有问题 return ERROR_TIMEOUT; } }设置目标状态在目标模块的MDCTLn寄存器中配置NEXT位域指明下一个要切换到的状态如Enable,Disable等。这里可以一次性配置多个模块的NEXT状态提高效率。发起转换命令向PTCMD寄存器对应的GO[x]位写1正式向PSC发出“开始转换”的指令。只有执行了这一步之前设置的所有NEXT状态才会开始生效。等待转换完成再次循环检查PTSTAT.GOSTAT[x]位直到其变为0。此时所有模块才安全地进入了新的状态。为什么需要这么麻烦这保证了在复杂的电源时钟树中多个模块的状态转换是同步、有序进行的避免了因时序问题导致的系统崩溃或数据错误。跳过等待步骤直接操作后续寄存器是导致外设驱动初始化失败的一大根源。3. 寄存器配置实战与代码剖析理解了原理我们来看如何用代码操作。我们以使能一个UART模块和配置一个PLL输出时钟为例。3.1 PSC模块使能实战以UART0为例假设我们要启用PSC0控制的UART0根据表8-1它在LPSC 9。它的默认状态是SwRstDisable复位有效时钟关闭。我们需要将其切换到Enable状态。首先我们需要知道关键寄存器的基地址和结构。通常芯片头文件会定义好#define PSC0_BASE 0x01C10000U typedef struct { __IO uint32_t REVID; // 0x00 // ... 其他寄存器 __IO uint32_t PTCMD; // 0x120 __IO uint32_t PTSTAT; // 0x128 // ... 其他寄存器 __IO uint32_t MDCTL[16]; // 0xA00 - 0xA3C, 对应LPSC 0-15 } PSC_TypeDef; #define PSC0 ((PSC_TypeDef *)PSC0_BASE)使能UART0LPSC 9的代码如下int enable_uart0(void) { uint32_t timeout; // 1. 等待PSC0域0AlwaysON就绪 timeout 100000; while ((PSC0-PTSTAT (1 0)) ! 0) { if (--timeout 0) return -1; } // 2. 设置UART0LPSC9的下一个状态为 Enable (0x3) // MDCTL寄存器中NEXT状态位通常位于特定的比特位例如位[4:0] // 先清除旧状态再设置新状态。假设NEXT在[4:0]且当前值已知或可读取修改。 PSC0-MDCTL[9] ~(0x1F); // 清除低5位 PSC0-MDCTL[9] | 0x3; // 设置NEXT为Enable (0x3) // 3. 发起转换命令触发域0的状态转换 PSC0-PTCMD (1 0); // 写1到GO0位 // 4. 等待转换完成 timeout 100000; while ((PSC0-PTSTAT (1 0)) ! 0) { if (--timeout 0) return -2; } // 5. 可选但推荐确认模块状态已变为Enable // 读取MDSTAT9寄存器检查状态位例如[4:0]是否为0x3 // if ((PSC0-MDSTAT[9] 0x1F) ! 0x3) { return -3; } return 0; // 成功 }关键提示在实际项目中MDCTL和MDSTAT寄存器中状态位的具体位置需要查阅更详细的芯片手册。上述代码中的0x1F掩码和0x3值仅为示例务必替换成你所用芯片的实际定义。TI的芯片支持包如Processor SDK通常会提供完善的驱动库函数如PSCModuleControl()来封装这些底层操作在量产代码中建议优先使用库函数以保证可靠性和可移植性。3.2 PLLC时钟配置与状态检查假设我们需要确认SYSCLK2是否已经开启并查询AUXCLK的状态。// 假设PLLC寄存器基地址和结构已定义 #define PLLC_BASE 0xXXXX0000U typedef struct { // ... 其他寄存器 __I uint32_t CKSTAT; // 时钟状态寄存器 __I uint32_t SYSTAT; // 系统时钟状态寄存器 // ... 控制寄存器如PLLDIV2, CKEN等 } PLLC_TypeDef; #define PLLC ((PLLC_TypeDef *)PLLC_BASE) void check_clock_status(void) { uint32_t ckstat_val PLLC-CKSTAT; uint32_t systat_val PLLC-SYSTAT; // 检查AUXCLK状态假设AUXEN是CKSTAT的bit 0 if (ckstat_val 0x1) { printf(AUXCLK is ON.\n); } else { printf(AUXCLK is OFF.\n); } // 检查SYSCLK2状态SYS2ON是SYSTAT的bit 1 if (systat_val (1 1)) { printf(SYSCLK2 is ON.\n); } else { printf(SYSCLK2 is OFF. It may be controlled by PLLDIV2.D2EN or module power state.\n); } }重要心得SYSTAT显示时钟为Off不一定是你配置错了。可能的原因有1对应的PLLDIVn分频器未使能DnEN02使用该时钟的模块在PSC中处于Disable、SwRstDisable等关闭时钟的状态。因此调试时钟问题时需要PLLC和PSC的配置联合排查。4. 低功耗设计策略与陷阱规避掌握了基本操作我们来谈谈如何运用这些机制进行实际的低功耗设计。这不仅仅是关闭时钟那么简单而是一个系统级的策略。4.1 功耗域与模块的拓扑关系从资料表8-1和8-2可以看出芯片模块被划分到不同的电源域Power Domain。例如PSC0的PD0是AlwaysON域UART、SPI、EDMA等外设位于此域PD1PD_DSP则专门管理DSP及其内存。关键点AlwaysON域永远上电你无法通过软件关闭其电源PDCTL0寄存器相关位可能不可写或写无效。而像PD_DSP这样的伪/内部电源域其“关闭”实际上是指让内部RAM进入低功耗睡眠模式而非切断外部供电CVDD引脚始终供电。这意味着对于大多数外设我们只能通过PSC控制其时钟和复位来实现“软件断电”即Disable状态无法做到真正的物理断电。真正的物理断电通常需要在芯片设计时划分独立的供电引脚并由外部PMIC管理这超出了PSC的能力范围。4.2 实战低功耗流程设计一个典型的任务周期型低功耗应用如传感器每10秒采集一次数据并发送的流程如下系统初始化启动所有必要模块CPU、定时器、通信外设等到Enable状态。进入工作模式执行数据采集、处理、发送任务。准备休眠停止DMA传输关闭外设数据流。将不再使用的外设如高速SPI、ADC通过PSC设置为Disable状态。注意对于UART等可能由中断唤醒的模块需根据情况决定是否禁用。如果CPU核心如DSP支持可将其也通过PSC置于Disable状态这需要仔细处理上下文保存与恢复。配置一个在Disable状态下仍能运行的唤醒源如RTC定时器、GPIO中断。进入休眠CPU执行WFI等待中断或类似的低功耗指令。被唤醒唤醒源触发中断CPU恢复运行。恢复系统将需要工作的外设从Disable状态重新切换回Enable状态然后跳转到步骤2。4.3 常见陷阱与排查技巧外设无法正常工作检查顺序确认PSC模块状态已为Enable查询MDSTAT而不仅仅是设置了NEXT。必须完成完整的“等待-设置-触发-等待”流程。时钟溯源确认该外设的时钟源通过SYSCLKn已经开启查询SYSTAT和相应的PLLDIVn配置。复位状态有些外设从SwRstDisable切换到Enable后还需要在其自身的配置寄存器中解除复位或进行初始化。PSC的模块复位和有些外设的软件复位可能是独立的。功耗降不下去排查“Auto Sleep/Wake Only”模块用你的代码对照资料中的表8-1和8-2检查是否有模块被错误地尝试设置为Disable。这些模块必须保持Enable。检查时钟门控使用SYSTAT寄存器检查是否有本该关闭的SYSCLKn仍然处于开启状态。追溯其使能来源。测量静态电流在系统进入预设的低功耗模式后测量整板电流。如果仍然很高可能还有未受PSC管理的外部器件或IO口在漏电。仿真器IcePick连接异常资料第8.4和8.5节提到了PSC对IcePick仿真的支持。当使用JTAG仿真器调试时仿真器可能会通过IcePick命令强制模块保持上电或复位状态如Inhibit Sleep,Force Active。这会导致你的软件状态切换请求被“拒绝”并在MDSTAT中置位EMUIHB等标志触发PSC中断。现象你在代码中禁用了一个模块但用仿真器查看其寄存器发现它似乎还在工作或者状态寄存器显示有仿真事件挂起。应对在调试低功耗代码时如果可能尝试在不连接仿真器的情况下运行和测量功耗。如果必须连接需要了解并处理好PSC中断或者在仿真器软件中关闭相关的电源管理干预功能。5. 仿真、中断与高级调试对于复杂系统的调试理解PSC与仿真工具的交互以及其中断机制至关重要。5.1 PSC中断处理流程PSC中断PSCn_ALLINT主要用于通知CPU仿真器干预了电源/时钟/复位管理。处理流程如下基于资料8.5.3节使能中断在PSC端使能特定事件设置MDCTLn.EMUIHBIE等并在设备中断控制器中使能PSCn_ALLINT中断。中断服务例程ISR内定位源读取PERRPR电源错误挂起和MERRPR0/1模块错误挂起寄存器确定是哪个域或模块产生了事件。查明原因根据上述结果去读取对应的PDSTATn或MDSTATn寄存器检查EMUIHB仿真器心跳或EMURST仿真器复位位确定具体事件类型如被仿真器强制上电。清除标志向PERRCR和MERRCR0/1的相应位写1清除挂起状态。重新评估最关键的一步在退出ISR前向INTEVAL寄存器的ALLEV位写1。这会强制PSC重新评估所有中断条件。如果还有未处理的事件中断会再次触发确保你不会丢失任何事件。5.2 性能计数器EMUCNT的使用你提供的资料中提到了EMUCNT0和EMUCNT1这两个仿真性能计数器。它们以系统时钟的1/4频率计数用于性能剖析。使用要点启动对EMUCNT0寄存器执行一次写操作无论写何值即可启动计数器。计数器一旦启动只有上电复位才能停止。读取读取EMUCNT0会同时锁存快照EMUCNT0和EMUCNT1的当前值到影子寄存器。你随后读取的EMUCNT0和EMUCNT1的值实际上是这个快照值。顺序必须先读EMUCNT0再读EMUCNT1才能获得一个完整的64位计数值。顺序错误会导致快照更新不正确读到的数据是错的。用途可以在代码关键段前后读取计数器差值计算出该段代码执行所消耗的时钟周期数乘以4用于性能分析和优化。// 示例测量一段代码的执行周期 void start_performance_counter(void) { // 写入任意值启动计数器 PLLC-EMUCNT0 0; } uint64_t get_performance_counter(void) { uint32_t low, high; low PLLC-EMUCNT0; // 先读低32位触发快照 high PLLC-EMUCNT1; // 再读高32位 return ((uint64_t)high 32) | low; } void measure_code_section(void) { start_performance_counter(); // 要测量的代码段 my_time_critical_function(); // 结束测量 uint64_t cycles_elapsed get_performance_counter(); // 实际时钟周期 cycles_elapsed * 4 printf(Code section took %llu counter ticks (%llu system cycles).\n, cycles_elapsed, cycles_elapsed * 4); }电源与时钟管理是嵌入式系统底层软件的基石之一。它要求开发者不仅要有模块化的编程思维更要有系统级的硬件视角。从理解每个状态位的含义到遵循严格的状态转换协议再到将多个模块的功耗管理统筹进应用流程每一步都需要耐心和细致。我最深刻的体会是永远不要假设配置会立即生效查询状态寄存器和添加超时等待是编写稳健驱动代码的必要习惯。当系统功耗异常时一份清晰的、标注了各模块预期状态与实际状态的检查清单远比盲目地修改代码有效得多。希望这篇结合了原理、实战与陷阱分析的长文能帮助你在面对复杂的嵌入式电源时钟管理时心中更有章法。

相关新闻

GigaTIME项目:肿瘤免疫微环境多组学分析新突破

GigaTIME项目:肿瘤免疫微环境多组学分析新突破

1. 项目背景与核心价值肿瘤免疫微环境(TIME)研究一直是癌症治疗领域的前沿方向。传统研究方法往往受限于样本量小、技术手段单一等问题,难以全面揭示肿瘤与免疫系统相互作用的复杂机制。华盛顿大学与微软研究院联合团队近期发布的GigaTIME项目…

2026/10/14 8:51:23 阅读更多 →
AI系统应急响应预案:从风险分类到实战演练的完整指南

AI系统应急响应预案:从风险分类到实战演练的完整指南

1. 项目概述:为什么AI系统需要专属的应急响应预案?当AI系统从实验室的演示品,变成支撑核心业务的生产力工具时,它所面临的风险性质就彻底改变了。一次模型推理的异常输出,可能不再是简单的“答非所问”,而可…

2026/10/14 8:51:39 阅读更多 →
智能监控中的路径预测技术:从原理到实践

智能监控中的路径预测技术:从原理到实践

1. 项目概述:镜像视界路径预测系统的核心价值在智能监控和空间治理领域,我们正面临一个根本性挑战:传统系统只能告诉我们"目标现在在哪里",而实际决策更需要知道"目标即将去哪里"。这就是我们开发的"镜像…

2026/10/13 5:12:03 阅读更多 →

最新新闻

PS5游戏兼容层技术解析:系统调用翻译与图形API转换实战

PS5游戏兼容层技术解析:系统调用翻译与图形API转换实战

1. 这个项目到底在解决什么问题 第一次看到“让PS5游戏跑在PC上”这个说法,我第一反应是:又来了,每隔一段时间就会有类似的标题冒出来。但点进去仔细看完这个17.2K Star的项目之后,我发现它跟以前那些“模拟器”路子完全不一样&am…

2026/10/14 8:51:30 阅读更多 →
五级分支流道自动生成算法与工程优化

五级分支流道自动生成算法与工程优化

1. 项目背景与需求解析 在精密加工和流体控制领域,多级分支流道系统是许多工业设备的核心部件。这类结构常见于注塑模具、液压阀块、微流控芯片等场景,其设计质量直接影响流体传输效率和系统稳定性。传统设计流程中,工程师需要手动计算每个分…

2026/10/14 8:51:30 阅读更多 →
基于SSM框架的企业知识库管理系统开发实践

基于SSM框架的企业知识库管理系统开发实践

1. 项目概述与核心价值这个知识库管理系统是我去年为一家中型科技公司实施的内部文档协作平台。当时他们正面临技术文档分散在多个同事电脑、版本混乱、查找困难等问题。基于JavaWeb技术栈开发的这套系统,最终实现了公司近3000份技术文档的集中管理和高效协作。SSM&…

2026/10/14 8:51:30 阅读更多 →
五级分支流道系统参数化设计与算法实现

五级分支流道系统参数化设计与算法实现

1. 项目背景与核心需求在精密加工和流体控制领域,多级分支流道系统是常见的基础结构。这类系统通常用于分配液体或气体介质,要求各分支的流量均衡且压力损失可控。传统设计方法依赖CAD软件手动绘制,效率低下且难以保证参数化精度。这个项目的…

2026/10/14 8:51:30 阅读更多 →
代码出片:用Claude Opus 5.5和开源图形库生成视觉大片

代码出片:用Claude Opus 5.5和开源图形库生成视觉大片

1. 为什么选择“代码出片”,而不是视频模型1.1 视频生成模型的两道坎:可控性弱与风格迁移难这两年“文字生成视频”确实火,不用摄影棚、不用演员,一句话就能出一个看起来挺唬人的镜头。但真把它当生产力工具用,你会发现…

2026/10/14 8:51:30 阅读更多 →
Unity编辑器底层机制与运行时原理详解

Unity编辑器底层机制与运行时原理详解

1. 别被“基础”两个字骗了:为什么Unity新手常在第3小时就卡死在编辑器里很多人点开Unity安装包时,心里想的是“不就是拖拖拽扭、放放模型、点点播放键吗”,结果三小时后盯着控制台里一串红色报错发呆——“NullReferenceException: Object r…

2026/10/14 8:50:30 阅读更多 →

日新闻

AnyPS5通用适配层设计:兼容性与性能的工程取舍

AnyPS5通用适配层设计:兼容性与性能的工程取舍

1. 从"AnyPS5"这个名字说起:它到底想解决什么问题第一次看到"AnyPS5"这个标题,我脑子里冒出来的第一个念头是:这大概率是一个围绕"跨平台运行"或者"通用适配"做文章的项目。名字里的"Any"…

2026/10/14 0:00:41 阅读更多 →
Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

1. 项目概述:Flutter跨平台二手交易应用开发作为一名长期从事移动应用开发的工程师,我最近完成了一个基于Flutter框架的二手物品交易平台项目。这个项目最吸引我的地方在于它完美结合了Flutter的跨平台优势与HarmonyOS的生态特性,实现了"…

2026/10/14 0:00:41 阅读更多 →
DFS算法解决飞机降落调度问题实战

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:41 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 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/13 22:01:27 阅读更多 →
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/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练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/14 7:53:34 阅读更多 →