news 2026/10/31 1:10:34

芯片烧录ISP、ICP、IAP全解析:从研发到量产的实战指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
芯片烧录ISP、ICP、IAP全解析:从研发到量产的实战指南

1. 芯片烧录到底在烧什么?先把概念理清楚

刚入行那会儿,我第一次听到“烧录”这个词,脑子里浮现的是拿烙铁往电路板上烫东西。后来才知道,烧录跟温度没半点关系,它指的是把编译好的固件代码写进芯片的存储器里,让芯片能按我们写的逻辑跑起来。你可以把它理解成给芯片“装系统”——芯片出厂时里面是空的,或者只有厂家预置的引导程序,真正让它干活的代码,得靠烧录这一步灌进去。

芯片烧录在嵌入式开发里属于最基础也最关键的环节。不管你是做消费电子、工业控制、汽车电子还是物联网设备,只要用到MCU、SoC、Flash存储芯片,就绕不开烧录这道工序。对于新手来说,烧录常常是“卡脖子”的第一步——代码写完了,编译也过了,但就是不知道怎么弄进板子里。而对于有经验的工程师,烧录方案的选择直接影响产线效率、产品可维护性和后期升级的便利性。

这篇文章要讲清楚的ISP、ICP、IAP,就是芯片烧录领域三个最核心的概念。它们分别对应不同的烧录场景和技术路径,理解了这三者的区别和联系,你基本就能应对绝大多数烧录需求了。不管你是刚接触单片机的学生,还是正在做产品量产的工程师,这篇文章都会给你一套可以直接参考的实操框架。

2. ISP、ICP、IAP三条路线,到底怎么选

2.1 先搞明白这三个缩写分别代表什么

ISP全称In-System Programming,中文叫“在系统编程”。它的核心特点是:芯片已经焊在电路板上了,你不需要把它拆下来,直接通过预留的调试接口就能把固件写进去。这个接口通常是SWD、JTAG或者芯片厂商自定义的串行接口。ISP最典型的应用场景就是研发阶段的反复调试——你改一版代码,编译完直接通过调试器烧进去,板子不用动。

ICP全称In-Circuit Programming,中文叫“在电路编程”。它跟ISP听起来很像,实际使用中很多人也混着叫。但严格来说,ICP更强调通过电路板上的特定接口对芯片进行编程,这个接口可能是生产时预留的测试点,也可能是专用的编程座。ICP在产线量产阶段用得最多,因为可以配合自动化烧录设备实现批量写入。

IAP全称In-Application Programming,中文叫“在应用编程”。这个跟前两个有本质区别:IAP是芯片自己运行一段程序,通过这段程序去修改自己内部的另一段程序。说白了就是“自己给自己升级”。你设备卖出去了,装在客户现场,发现固件有bug或者要加新功能,不可能把设备拆回来重新烧录,这时候IAP就是唯一的出路。通过预留的通信接口(串口、CAN、以太网、无线模块等)接收新固件,然后在芯片内部完成自我更新。

2.2 三者的核心差异对比

对比维度ISPICPIAP
编程时机研发调试、小批量产线量产现场部署后
是否需要拆芯片不需要不需要不需要
依赖外部工具需要调试器/编程器需要编程器/烧录机不需要,芯片自己完成
接口要求SWD/JTAG/BOOT引脚专用编程接口/测试点任意通信接口
固件来源外部工具传入外部工具传入芯片内部/外部存储
典型工具J-Link、ST-Link离线烧录器、在线烧录机Bootloader程序
适用阶段开发验证批量生产售后升级

这张表建议你存下来,遇到具体项目时对照着看,基本能快速定位该用哪种方案。

2.3 为什么要有这么多“P”,一种不够用吗

这个问题我当初也问过。答案很简单:不同阶段的需求完全不同,用一种方案硬扛所有场景,要么效率低,要么根本做不到。

研发阶段你关心的是“快”——改一行代码就能立刻烧进去看效果,所以ISP配合调试器是最优解。产线阶段你关心的是“稳”和“快”——一天要烧几千片板子,每片都要保证数据完整、校验通过,所以需要ICP配合自动化烧录设备。售后阶段你关心的是“可达”——设备可能装在深山老林的基站里,也可能装在客户密闭的机柜中,你只能通过通信链路把固件送进去,所以必须靠IAP。

我见过一些团队在量产时还在用J-Link一片一片手动烧,效率低不说,还容易因为人为操作失误导致漏烧、错烧。也见过产品设计时完全没预留IAP功能,后期发现bug只能召回设备,损失惨重。这些坑,本质上都是对ISP、ICP、IAP的适用场景理解不到位造成的。

3. ISP实战:从零开始烧第一片板子

3.1 ISP的硬件连接与接口选择

以最常见的ARM Cortex-M芯片为例,ISP通常通过SWD接口进行。SWD只需要两根信号线:SWCLK和SWDIO,加上电源和地,一共四根线就能完成烧录和调试。相比JTAG的五六根线,SWD在引脚资源紧张的项目里优势明显。

硬件连接时需要注意几个点。第一,调试器的电平必须和芯片的IO电平匹配,3.3V的芯片你用5V的调试器,轻则通信失败,重则烧坏引脚。第二,SWCLK和SWDIO的走线尽量短,如果板子上有干扰源(比如电机驱动、开关电源),最好加上拉电阻和滤波电容。第三,如果芯片的BOOT引脚有特殊配置,要确认当前状态是否允许通过SWD访问Flash。

我自己的习惯是,在画PCB的时候就把SWD接口做成标准的2x5排针,间距1.27mm或2.54mm都行,旁边丝印标清楚VCC、GND、SWCLK、SWDIO、RESET。这样不管是用J-Link、ST-Link还是DAPLink,直接插上去就能用,不用每次翻原理图找引脚。

3.2 用STM32CubeProgrammer完成一次完整烧录

这里以STM32系列为例,走一遍完整的ISP烧录流程。其他厂商的芯片操作逻辑类似,工具不同而已。

第一步,安装STM32CubeProgrammer。这个软件是ST官方出的,支持Windows、Linux、macOS,免费。安装完之后把ST-Link或J-Link插上电脑,打开软件。

第二步,选择连接方式。在软件右上角的下拉菜单里选ST-LINK,然后点“Connect”。如果连接成功,软件会读出芯片的型号、Flash大小、UID等信息。如果连不上,先检查驱动装没装、线接没接对、芯片有没有供电。

第三步,加载固件文件。点“Open File”,选择编译生成的.hex或.bin文件。.hex文件自带地址信息,.bin文件需要手动指定起始地址。一般来说,STM32的Flash起始地址是0x08000000。

第四步,配置烧录选项。在“Download”选项卡里,确认“Verify programming”和“Run after programming”都勾上。Verify会在烧录完成后自动校验数据,确保写入的内容和源文件一致。Run after programming让芯片烧完自动复位运行,省得你手动按复位键。

第五步,点“Start”开始烧录。烧录时间取决于固件大小和接口速度,一般几十KB的固件几秒钟就完事。烧录完成后软件会提示“Download verified successfully”,这时候板子应该已经跑起来了。

注意:如果烧录过程中报“No target connected”或者“Target not responding”,先别急着怀疑芯片坏了。检查一下芯片的复位引脚是不是被外部电路拉住了,或者BOOT0的电平是不是不对。我遇到过好几次都是因为板子上电时序问题导致芯片没进入调试模式,把电源重新插拔一下就好了。

3.3 ISP烧录的常见坑与排查思路

坑一:读保护导致连不上。有些芯片出厂时或者被误操作开启了读保护,SWD接口会被禁用。这时候需要用Mass Erase功能全片擦除,或者通过BOOT引脚进入系统存储器启动模式来解除保护。STM32CubeProgrammer里有个“Full chip erase”选项,勾上之后再连接,通常能解决。

坑二:低功耗模式导致调试器识别不到。如果芯片固件里进了Stop或Standby模式,调试器可能无法建立连接。解决办法是在连接设置里把“Connect under reset”打开,让调试器在芯片复位期间就接管SWD总线。

坑三:多芯片共用SWD总线冲突。有些板子上挂了多片MCU或者带SWD接口的器件,共用一组SWCLK和SWDIO。这时候需要确保其他芯片处于复位状态或者IO口设为高阻,否则总线会打架。我一般会在SWD线上加跳线帽,烧录哪片就短接哪片,避免互相干扰。

坑四:固件大小超过Flash容量。编译出来没注意看,固件比芯片Flash还大,烧录到一半报错。养成习惯,编译完先看map文件里的Flash占用,留出至少10%的余量给后续功能扩展。

4. ICP量产烧录:从手工到自动化的跃迁

4.1 ICP在产线上的典型部署方式

ICP的核心价值在于“批量”和“一致”。研发阶段你烧一片板子花30秒无所谓,产线上一天要出5000片,每片30秒就是41个小时,根本不可能。所以ICP方案必须解决两个问题:一是并行烧录,同时烧多片;二是自动化上下料,减少人工干预。

常见的ICP部署方式有三种。第一种是离线烧录器,比如把芯片放在烧录座的夹具里,一次烧一片或几片,适合小批量试产。第二种是在线烧录机,板子通过传送带流到烧录工位,探针压住测试点完成烧录,适合中大批量。第三种是嵌入式烧录方案,把烧录程序集成到产线测试设备里,功能测试和烧录一步完成。

我参与过的一个项目,月产量大概两万片,用的是四工位在线烧录机。板子从SMT线下来直接进烧录工位,四个探针同时压住四块板子的SWD测试点,烧录加校验一共12秒,一天产能完全跟得上。关键是烧录数据自动上传MES系统,每片板子的烧录时间、固件版本、校验结果都有记录,后期追溯很方便。

4.2 烧录文件的准备与校验机制

量产烧录最怕的就是烧错版本。研发阶段烧错了重新烧一遍就行,产线上烧错一批,可能几千片板子都要返工。所以烧录文件的版本管理和校验机制必须严格。

我的做法是:每次发布正式固件,文件名里必须包含版本号和日期,比如Firmware_v1.2.3_20240615.hex。烧录前用脚本自动计算文件的MD5或SHA256,和发布记录里的哈希值比对,一致才允许烧录。烧录完成后,烧录器会自动回读芯片内的数据,再次计算哈希值,和源文件比对。两次校验都通过,这片板子才算合格。

有些烧录器支持“加密烧录”功能,把固件加密后存储,烧录时由烧录器内部解密再写入芯片。这样即使烧录文件被拷贝走,没有对应的烧录器也烧不了。对于出货量大的产品,这个功能能有效防止固件泄露。

4.3 ICP烧录的效率优化技巧

技巧一:提高通信速率。SWD接口的默认速率通常是1MHz或2MHz,很多烧录器支持到10MHz甚至更高。在信号质量允许的前提下,把速率调高能显著缩短烧录时间。我实测过,同样大小的固件,2MHz烧录需要8秒,10MHz只需要2秒出头。

技巧二:只烧差异部分。如果两批固件之间只有少量改动,可以用差分烧录的方式,只写入变化的扇区。不过这个需要烧录器和芯片支持,不是所有平台都能用。

技巧三:优化固件体积。编译时开启优化选项,去掉不必要的调试信息和冗余代码,固件越小烧得越快。我见过一个项目,Debug版本固件有200KB,Release版本优化后只有80KB,烧录时间直接少了60%。

技巧四:并行烧录。如果烧录器支持多通道,尽量把通道用满。四通道比单通道效率提升接近四倍,但要注意电源供应要足够,别因为同时烧四片导致电压跌落。

提示:产线烧录工位的环境温度对烧录稳定性有影响。夏天车间温度高,有些烧录座接触电阻变大,容易出现校验失败。建议在烧录工位加个小风扇或者空调出风口,保持温度稳定。

5. IAP升级:让设备自己给自己换系统

5.1 IAP的基本原理与Bootloader设计

IAP的本质是芯片运行一段特殊的程序(Bootloader),这段程序负责接收新固件、校验、写入、跳转。Bootloader通常放在Flash的最前面,上电后先运行。如果检测到升级条件(比如某个引脚被拉低、收到特定命令、或者应用程序区没有有效固件),就进入升级模式;否则直接跳转到应用程序区执行。

Bootloader的设计有几个关键点。第一,Bootloader本身不能被自己升级,否则升级失败就彻底变砖了。所以Bootloader要尽量简单、稳定,写完测试充分之后就不再改动。第二,Bootloader和应用程序的Flash分区要明确,通常Bootloader占前16KB或32KB,应用程序从后面开始。第三,要有固件有效性检查机制,比如在应用程序区的开头放一个标志字,Bootloader启动时检查这个标志字,无效就不跳转。

我一般会在Bootloader里实现一个简单的串口协议,支持“擦除”、“写入”、“校验”、“跳转”四个命令。上位机通过串口发送固件数据,Bootloader收到后写入指定地址,全部写完后计算CRC32,和上位机发来的校验值比对,一致就设置标志字并跳转。

5.2 双区升级与回滚机制

单区升级有个致命问题:升级过程中断电,应用程序区被擦除了一部分,新固件又没写完,设备就变砖了。解决这个问题有两种主流方案。

第一种是双区备份(A/B分区)。Flash里放两份应用程序区,一份是当前运行的,一份是升级备份。升级时先把新固件写到备份区,校验通过后修改启动标志,下次复位从备份区启动。如果升级失败,原来的应用程序区还在,可以回滚。这种方案可靠性最高,但Flash容量要翻倍。

第二种是外部存储辅助。芯片外挂一片SPI Flash或SD卡,新固件先存到外部存储,Bootloader从外部存储读取并写入内部Flash。这样内部Flash只需要一份应用程序区,成本更低。缺点是外部存储本身也可能出故障,而且读取速度慢一些。

我个人的选择是:如果Flash容量够(比如256KB以上),优先用双区方案,省心。如果Flash紧张(比如64KB),就用外部存储方案,但要在Bootloader里加多重校验,确保外部存储的数据可靠。

5.3 通过无线方式实现IAP OTA升级

OTA(Over-The-Air)升级是IAP在物联网设备上最常见的应用形态。设备通过WiFi、蓝牙、蜂窝网络等无线方式接收固件包,然后在本地完成升级。这里面的技术难点不在IAP本身,而在于无线链路的可靠性和固件包的完整性。

无线升级的流程一般是:设备向服务器请求升级,服务器下发固件包的URL和校验值;设备下载固件包到外部存储或内部备份区;下载完成后校验,校验通过则触发Bootloader执行写入;写入完成再次校验,通过后重启跳转到新固件。

这里面有几个容易出问题的地方。第一,无线链路可能不稳定,下载到一半断了,所以必须支持断点续传。第二,固件包可能被篡改,所以要有签名验证机制,比如用非对称加密算法对固件包签名,设备端用公钥验签。第三,升级过程中设备可能断电,所以要有掉电保护,确保任何时刻断电都不会导致设备无法启动。

我做过一个WiFi设备的OTA项目,固件包大概500KB,通过HTTP分片下载,每片4KB,下载完一片校验一片,全部下载完再做整体校验。升级成功率从最初的85%提升到99.5%以上,关键就是加了断点续传和分片校验。

6. 新手最容易踩的五个坑

6.1 坑一:把ISP和IAP混为一谈

这是概念性的错误,但影响很大。ISP是你用外部工具往芯片里写,IAP是芯片自己往自己里写。有些新手以为只要板子上留了SWD接口,产品卖出去之后也能通过SWD升级,这在实际部署中根本不现实——客户现场不可能给你接调试器。产品设计阶段就要想清楚:后期要不要升级?如果要,IAP方案必须提前规划。

6.2 坑二:Bootloader占用的空间没预留够

我见过一个项目,Bootloader写完占了28KB,但规划的时候只预留了16KB,结果应用程序的起始地址要往后挪,所有中断向量表偏移都要改,折腾了好几天。建议Bootloader预留空间至少是实际大小的1.5倍,比如实际用了20KB,就预留32KB,给后续加功能留余地。

6.3 坑三:升级时没有做电源监测

IAP升级过程中如果电压不稳或者突然断电,Flash写入可能出错,导致应用程序区数据损坏。解决办法是在Bootloader里加电源电压检测,低于阈值就拒绝升级。另外,写入关键数据时可以采用“先擦后写再校验”的流程,每一步都确认成功再继续。

6.4 坑四:量产烧录没有防呆机制

产线上操作员可能拿错板子、放反方向、烧录座接触不良。如果没有防呆机制,这些错误可能流到客户手里。我的做法是:烧录前先读芯片UID,和工单上的序列号比对;烧录后自动功能测试,至少验证串口输出和关键IO电平;测试不通过的板子自动打标记,和合格品分开放置。

6.5 坑五:忽略Flash寿命

Flash的擦写次数是有限的,通常10万次左右。ISP和ICP阶段擦写次数少,问题不大。但IAP如果设计不当,比如每次升级都全片擦除,或者频繁记录日志到Flash,可能几年就把Flash写坏了。优化方法是:升级时只擦除需要修改的扇区,日志用RAM缓存后批量写入,或者外挂EEPROM专门存日志。

7. 工具链选型:不同场景下用什么工具

7.1 研发调试阶段

J-Link是首选,支持芯片型号最全,烧录速度快,配合J-Flash软件可以批量烧录。ST-Link适合STM32系列,价格便宜,但只支持ST的芯片。DAPLink是开源方案,成本低,适合个人开发者和小团队。我自己的桌面常年插着一个J-Link EDU和一个DAPLink,前者用于正式项目,后者用于快速验证。

7.2 小批量试产阶段

离线烧录器比较合适,比如XELTEK、河洛等品牌。把芯片放在烧录座里,一次烧一片或几片,操作简单,不需要板子留测试点。缺点是芯片要拆下来烧,烧完再焊回去,多一道工序。

7.3 大批量量产阶段

在线烧录机是标配,配合自动化产线使用。选型时重点看几个指标:烧录速度、并行通道数、支持的芯片型号、是否支持MES对接。国产的烧录机这几年进步很快,性价比比进口的高不少,中小批量完全够用。

7.4 现场升级阶段

IAP方案的工具链取决于通信方式。串口升级需要上位机软件,CAN升级需要CAN分析仪,无线升级需要服务器端和设备端的配合。这部分没有通用工具,基本都要自己开发。我的建议是尽量用成熟的协议栈,比如HTTP+HTTPS做无线升级,可靠性有保障,开发量也小。

8. 几个真实项目中的经验教训

8.1 案例一:ISP接口被误用导致量产效率低下

有个项目,研发阶段一直用J-Link通过SWD烧录,板子上也留了SWD测试点。到了量产阶段,产线直接拿J-Link一片一片烧,一天只能烧几百片,交期完全跟不上。后来改成在线烧录机,四工位并行,效率提升了十几倍。教训是:研发阶段就要考虑量产烧录方案,测试点的位置、间距、信号定义都要按烧录机的要求来设计。

8.2 案例二:IAP升级失败导致设备变砖

一个客户现场的设备,通过无线方式升级固件,升级到一半网络断了,设备重启后无法启动。原因是Bootloader设计时没有做双区备份,应用程序区被擦除后新固件没写完,Bootloader找不到有效固件,一直停在升级模式。后来改成双区方案,升级失败自动回滚,再也没出过问题。

8.3 案例三:Flash寿命耗尽导致批量故障

一个数据采集设备,固件里每采集一次数据就往Flash里写一条日志,一天写几万次。用了不到两年,Flash写坏了,设备批量返修。后来改成RAM缓存加定时批量写入,每天写入次数降到几十次,寿命问题彻底解决。这个坑让我深刻理解了“Flash不是无限写的”这个道理。

9. 进阶话题:ISP Pipeline与图像处理芯片的烧录

9.1 ISP Pipeline对烧录的特殊要求

这里的ISP指的是Image Signal Processor,图像信号处理器。跟前面讲的In-System Programming是两个概念,但在芯片烧录的语境下经常一起出现。图像处理芯片的固件通常包含大量的参数配置,比如白平衡系数、伽马曲线、降噪参数等。这些参数在烧录时就要写入,而且不同批次的传感器可能参数不同,需要动态调整。

烧录这类芯片时,除了写固件,还要写参数区。参数区的数据通常由标定工序生成,比如用标准色卡拍一张照片,算法计算出最优参数,然后通过烧录工位写入芯片。这就要求烧录系统能和标定系统对接,实现数据自动流转。

9.2 去弹窗与固件配置

有些图像处理芯片在启动时会检测某些配置引脚,如果配置不对会弹出警告窗口或者进入异常模式。烧录时需要确保这些配置引脚的状态正确,或者在固件里把相关检测逻辑关掉。我遇到过STC系列ISP芯片的去弹窗问题,解决办法是在烧录前先通过串口发送特定命令,让芯片进入静默模式,再执行烧录。

9.3 图像处理芯片的量产烧录方案

图像处理芯片的烧录通常分两步:第一步烧基础固件,第二步烧标定参数。基础固件所有板子都一样,可以批量烧。标定参数每片板子不同,需要单独处理。产线布局上,标定工位和烧录工位要分开,标定完的板子带着参数数据流到烧录工位,烧录工位根据序列号从数据库拉取对应的参数写入。

这套流程的关键是数据追溯。每片板子的标定数据、烧录时间、烧录结果都要记录,后期如果发现图像质量问题,可以追溯到具体是哪一批参数、哪个烧录工位出的问题。

10. 写在最后:一些个人体会

芯片烧录这件事,说简单也简单,接上线点一下按钮就完事。说复杂也复杂,从研发到量产到售后,每个阶段都有不同的坑。我自己的经验是:前期多花一小时规划烧录方案,后期能省十天返工时间。

ISP、ICP、IAP这三个概念,新手最容易犯的错误是只盯着眼前的需求。研发阶段只想着怎么把代码烧进去,不考虑量产怎么办;量产阶段只想着怎么提高烧录速度,不考虑售后升级怎么办。等到问题暴露出来,改硬件、改架构的成本就高了。

所以我的建议是:项目启动阶段就把烧录方案定下来。研发用什么工具、量产用什么设备、售后用什么方式升级,这三个问题想清楚了再画板子。测试点怎么留、Flash怎么分区、Bootloader怎么写,这些细节在原理图评审的时候就要过一遍。

另外,烧录相关的文档和脚本一定要版本管理。烧录文件、烧录参数、校验脚本、产线作业指导书,这些东西和源代码一样重要。我见过太多团队源代码管得很好,烧录文件到处乱放,最后量产时烧错版本,查了半天才发现是文件拿错了。

这个领域的技术更新不算快,但细节很多。多动手、多踩坑、多总结,慢慢就有感觉了。

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

AUTOSAR DEM完全指南:DTC生命周期、状态位与工程实战

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

作者头像 李华
网站建设 2026/10/31 1:10:21

SCANLAB振镜不响应?五步配置法从供电到通信握手全打通

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

作者头像 李华
网站建设 2026/10/31 1:10:21

四面体Gauss积分全解析:积分点构造、权重缩放与有限元工程实践

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

作者头像 李华
网站建设 2026/10/31 1:09:56

RK3588双路视觉实时检测:丢旧帧背压机制原理与实现

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

作者头像 李华
网站建设 2026/10/31 1:08:13

CI-03脱机烧录失败根因与免唤醒精准配置指南

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

作者头像 李华