干这行最邪门的经历之一就是我第一次给手头的ATmega328P烧引导程序时直接把芯片锁死了。当时用的就是Microchip Studio 7界面顺手、编译没毛病结果到了熔丝位这一关手一抖把时钟源选成了外部晶振而板子上根本没有晶振——芯片当场失联ISP识别不到任何器件那感觉就像手机突然黑屏再也开不了机。后面花了不少时间用外部时钟硬生生把芯片“救”回来才明白烧录AVR这件事真正决定成败的往往不是编译环节而是Hex文件怎么进去、熔丝位怎么配。这篇文章就把我用Microchip Studio 7烧录AVR单片机的完整流程拆开揉碎讲一遍从软件配置到硬件连接从Flash烧录到熔丝位细节再到各种能把人逼疯的恢复手段全部基于我踩过的坑和实测过的方案。无论你是刚入手AVR的新手还是正在被锁死的芯片折磨的老哥这篇都能让你少走不少弯路。1. 整体思路与工具选型1.1 为什么选Microchip Studio 7很多刚接触AVR的朋友都会纠结一个问题AVR的开发环境有这么多种Arduino IDE、Atmel Studio、Microchip Studio、AVRDUDE、PlatformIO到底该用哪个我的建议很直接如果你要碰裸机寄存器开发、要自己配熔丝位、要走JTAG/ISP调试Microchip Studio 7是最省心的选择。它其实就是原来的Atmel Studio被Microchip收购之后换了个马甲底层架构没变。最大的优势是官方IDW在线烧录、仿真、代码配置器ASF统统打包在一起而且对自家MCU的型号识别最准确烧录时能自动匹配器件签名降低选错芯片导致熔丝位被写错的风险。另外一点很实际Studio 7内置的Device Programming窗口就是专门用来管理熔丝位、锁定位、Flash和EEPROM的。你不需要额外装第三方编程软件也不用记一堆命令行参数界面里勾一勾、点一点就能完成烧录和配置。相比之下虽然AVRDUDE功能强大但纯命令行对新手不够友好一个参数拼错就可能出现莫名其妙的烧录失败。当然了Studio 7也有它的毛病安装包巨大、启动偏慢、某些旧版本存在USB驱动兼容问题。但在“烧录AVR”这个核心任务上它把官方该给的工具都给齐了我至今还是把它当作首选工具。1.2 烧录器硬件选型从入门到主流方案软件选好了硬件也不能随便凑合。AVR烧录器和STM32那套不太一样STM32常用SWD接口AVR则根据芯片型号和引脚资源主要有下面几种方案板载调试器EDBGMicrochip自家开发板上通常集成EDBG通过USB直连就能烧录调试相当于ST-Link和开发板二合一初学最推荐。它默认支持ISP和debugWIRE协议接上USB线就能在Studio 7里识别到工具。Atmel-ICE官方高级调试器支持JTAG、SWD、PDI、TPI、debugWIRE、ISP全协议覆盖AVR全系和ARM系列就是价格偏高。适合手头有多种芯片、需要硬件断点调试的玩家。AVR ISP mkII经典款ISP烧录器支持AVR全系ISP协议很多老教程都在用。但现在已经停产Studio 7新版本对它的驱动兼容性不如当年容易出现“USB驱动无法启动”的老问题。Arduino改烧录器把Arduino Uno的例程Upload via ISP编译进板子就能当USBasp或STK500兼容烧录器用。胜在便宜但速度慢、电压不稳适合应急。USBasp国内流玩家最普及的便宜方案基于ATmega8/48的ISP烧录器十几块钱就能买到。配合Studio 7需要装libusb驱动否则识别不了。我个人的建议是新手别一上来就买最便宜的USBasp虽然它能用但驱动问题、供电问题会让你分不清是自己操作错误还是硬件缺陷。预算允许的话直接上开发板自带EDBG或者二手Atmel-ICE省心烧出问题时至少硬件是靠谱的。2. 环境搭建与烧录前置配置2.1 安装Microchip Studio 7与驱动检查安装过程没有太多玄学去Microchip官网下载最新版Studio 7一路Next装完即可。但有几个细节需要注意第一Studio 7安装时会顺带安装Atmel USB Driver这个驱动如果没装上后面插上烧录器时系统会一直提示“无法识别的USB设备”。装完后可以打开设备管理器展开“端口”或者“通用串行总线设备”看到Atmel EDBG或ATMEL AVR ISP mkII之类字样就说明驱动正常。第二旧版本Studio 7在Windows 10/11上偶尔会出现Atmel USB驱动签名问题。解决办法是在开机时进入高级启动选项禁用驱动程序强制签名或者手动下载驱动进行安装。这条我实测在Win 11上有效卡在“USB device not recognized”时先别怀疑硬件。第三安装路径尽量别带中文否则某些插件容易出诡异问题。AVR工具链是装在安装目录下的如果路径有特殊字符GCC编译器的make阶段偶尔会抽风。2.2 建立工程并正确生成烧录文件新建工程时选择GCC C Executable然后选好自己的芯片型号Studio 7就会生成对应的makefile和基础框架。这里很多人会忽略工程属性里的Optimization等级会直接影响烧录后程序的运行行为。比如O0和Os编译出来的代码体积、执行速度都有差异如果芯片Flash快满了换成Os常常能救回来。编译通过后默认会在工程目录的Debug文件夹下生成hex和elf文件。烧录时Studio 7默认烧录的就是这个hex文件但它也允许你自己指定文件。我在实际操作中几乎不用Release配置因为Debug输出Hex已经足够用Release和Debug的差异主要在优化级别上Debug也完全可以改优化选项。如果工程里面引用了外部库、或者用了汇编文件需要检查工程属性里“Memory Settings”的Flash大小是否和芯片匹配。一旦链接脚本把代码段地址算错烧录进去的程序大概率直接跑飞。排查方式很简单查看Build Output窗口里最后生成的Program Memory Usage看占用是否异常高如果编译通过但占用为0多半是链接配置出问题了。生成Hex文件之后最好再手动打开看一眼第一行格式。标准的Intel HEX文件以冒号开头如果你发现是空文件或者明显缺少数据段就别急着烧录了先回到编译环境找原因。3. 全流程烧录实操步骤3.1 连接硬件与识别目标芯片硬件连接看起来简单但“接触不良”是烧录失败最隐蔽的原因。ISP接口标准是6针或10针其中MOSI、MISO、SCK、RESET、VCC、GND这六根信号线是必须的。接线时有一个高频翻车点RESET线没接好或者被禁用烧录器就无法对芯片复位进入编程模式。连接好后打开Studio 7先编译一次工程确保没有error然后点击菜单栏的Tools → Device Programming。这里有个小技巧先选择你的烧录器型号EDBG、Atmel-ICE等再点击Interface选择ISP接着点ApplyStudio 7会自动读取当前芯片的Device signature。如果你烧录器选了ISP但界面一直显示0x000000先检查接线再检查复位线大部分情况下是某个引脚接触不良。Device signature识别成功后Studio 7会进入可烧录状态。此时建议先在Fuses页签把当前熔丝位读一遍保存好原始值。这步很多人会跳过但一旦后面不小心把熔丝位改错你会发现连读回都做不到那时候就叫天天不应了。3.2 Flash烧录与EEPROM烧录的完整操作在Device Programming窗口切到Memories页签Flash下点击Browse选择你要烧录的hex文件勾选Erase chip before programming推荐勾上然后点Program。正常情况下下面的Output窗口会打印烧录进度完成后提示Programming complete。这里要重点说明一下Erase选项如果不勾选Studio 7只会对被修改的Flash页做编程但这在某些情况下会导致设置好的fuse值部分丢失产生“程序能烧但启动异常”的怪毛病。所以我的习惯是每次都勾上全片擦除再重新烧写。唯一例外是当你要保留EEPROM数据时才需要单独控制擦除范围。很多朋友还想顺便把EEPROM里的初始数据一起烧进去。EEPROM的烧录和Flash类似同样在Memories页签里选择eeprom文件勾选Program。千万注意别选错文件类型——EEPROM文件的扩展名通常也是hex或者eep如果错把Flash的hex文件烧到EEPROM里数据表和代码段会相互污染程序行为会变得神五神六的。烧录完成后不要立刻拔线先复查一遍Interface的状态。我遇到过一次烧录提示成功但程序完全没有运行最后发现是复位引脚一直被拉低导致芯片永远处于复位状态。烧完之后再读一下Device signature确认芯片还“活着”再做下一步。3.3 debugWIRE调试口的启用与禁用如果你用的是ATtiny系列它没有JTAG也没有ISP调试用的硬件断点只能靠debugWIRE这个单线调试接口。debugWIRE最大的坑是它是复用RESET引脚的所以一旦启用了debugWIREISP编程就失效了因为那根线被调试器占用了。具体现象就是你某次在Studio 7里点了Enable debugWIRE当时还能调试但下次插上普通ISP烧录器想烧引导程序发现工具识别不到芯片。这不是芯片坏了只是debugWIRE占用了复位线。解决办法也简单在Device Programming的debugWIRE页签里点Disable然后立刻切回ISP通常就能恢复正常烧录。这个坑我在ATtiny85上踩过两三次每次都以为是芯片锁死了最后发现只是debugWIRE没关。所以如果你是ATtiny用户在切换调试接口之前务必先想清楚当前用的是哪条通道。4. 熔丝位深度解析与避坑指南4.1 熔丝位的本质与字节构成熔丝位说白了就是芯片内部的一组硬件配置开关它们决定时钟源、启动延时、看门狗、BOD电压等底层参数。AVR的熔丝位是“烧进去就生效”的和Flash程序不一样程序可以反复擦写但熔丝位一旦设置成锁定某些功能特别是禁用ISP恢复起来就要费一番功夫。以ATmega328P为例熔丝位分三个字节低字节Low Byte、高字节High Byte、扩展字节Extended Byte。每个bit位都对应一项配置但每个芯片型号的位定义都有差异所以绝对不要拿A型号的熔丝位配置直接套到B型号上。Studio 7的Fuses窗口会按名称列出每一项并且在最下方显示出对应的原始字节值这比很多第三方工具要直观得多。在Studio 7的Fuses页签下默认会用勾选框显示每个熔丝位的状态但你要理解勾选框和数字之间的对应关系。通常界面上会标出“Checked 0 / Unchecked 1”之类的提示因为AVR熔丝位的逻辑和日常相反勾选往往表示该位被编程为0未勾选则为1。这导致很多新手一看默认值就蒙了。我的习惯是直接看底部的原始字节值以数值为准。4.2 最危险的熔丝位时钟源与SPIEN如果只能给你一条熔丝位避坑指令我要说改时钟源之前先确认板子上到底有没有对应频率的晶振或陶瓷谐振器。AVR默认出厂通常使用内部RC振荡器内部RC不需要外接任何元件就能跑虽然精度一般但至少能启动。一旦你把CKSEL配置成外部晶振而板上没有晶振芯片上电后就没有时钟源等于人没有心脏跳动整个系统直接瘫痪。另外还有一个高频坑RSTDISBL禁用复位引脚。ATtiny系列在引脚紧张时会把RESET引脚复用成普通IO把这个熔丝位编程后复位引脚就变成普通引脚了芯片将不再响应ISP的复位信号。解救办法通常需要高压编程器或者外接12V复位脉冲。如果你没有相应设备这颗芯片基本就废了所以这个熔丝位我是强烈建议不要碰。与恢复相关的还有SPIENSPI编程使能这个位一般保持默认它控制ISP接口是否可用。如果被误编程为禁用芯片就不接受普通ISP烧录了。好在多数AVR的SPIEN位在默认状态下是允许ISP的只要你不要脑抽去改它就行。4.3 看门狗与BOD的设置陷阱另一个容易引发怪问题的熔丝位是看门狗定时器WDTON。如果在熔丝位里把看门狗设为始终开启而你的程序从头到尾没有“喂狗”操作芯片就会周期性复位现象就是LED闪一下灭一下、忙乱重启。这种问题在烧录阶段看不出来往往要等跑程序时才暴露。BOD掉电检测熔丝位的作用是设定一个电压阈值当VCC低于该阈值时芯片强制复位防止低电压时运行产生不可预测逻辑。问题在于如果你的供电电压本身偏低比如3.3V系统选了个4.3V的BOD阈值芯片会反复复位看起来就像程序有bug。选择BOD阈值时一定要参考你的实际供电电压留出裕量。4.4 常用熔丝配置参考ATmega328P与ATtiny85为了让不同芯片的用户都有参照我把两个常见芯片的推荐熔丝配置整理如下。注意这只是推荐值实际要结合你板子上的晶振来微调芯片场景低字节CKSEL等高字节BOD/RST等扩展字节备注ATmega328P内部RC 8MHz0x620xD90xFF无需外部时钟ATmega328P外部16MHz晶振0xF70xD90xFD需在XTAL1/2接晶振ATtiny85内部RC 1MHz0x620xDF0xFF常见默认配置ATtiny85外部20MHz晶振0xE10xDD0xFE需注意启动延时这些数值不是拍脑袋写的是结合Studio 7的Fuses窗口逐位对应出来的。但再次强调不同批次、不同芯片的熔丝位定义细节可能微调所以烧录前务必在Studio 7里读回当前值和上表对照是否合理。如果你发现读到的默认值和上表差太多先别急着覆盖查一下手册。4.5 熔丝位锁死之后的紧急恢复方案说实话凡是用AVR写过引导程序的人多少都经历过芯片被熔丝位锁死。锁死不是烧毁一般情况下还能救只是救援过程有点折腾。恢复思路无非两种一是让芯片以已知时钟启动二是用高压编程器强制复位。对于时钟源锁死的情况可以用一个外部时钟发生器或者直接用一个Arduino Uno输出方波把时钟信号引到芯片的XTAL1引脚这样即使熔丝位要求外部晶振芯片也能获得时钟。然后再用ISP烧录器连上这时烧录器就能正常识别芯片重新把熔丝位改回去。这个方案我在ATmega328P上实测过一次救活一个。如果连ISP都无法识别那可能是把SPIEN锁死了。这时候就需要高压并行编程器或者HVSP也可以用一个简单的“复位引脚12V脉冲”方案给RESET引脚瞬间加12V使芯片进入高压编程模式。多数USBasp改装电路也有这个功能但操作起来有风险稍不小心会把片子打坏。如果你没有把握直接换新芯片可能是成本最低的选择。5. 常见问题与排查技巧实录5.1 烧录失败典型场景一览我把自己和网上社群里的典型烧录问题汇总成一张表方便你排查时对照现象大概率原因解决办法Device signature显示0x000000接线错误、RESET被禁用、目标未上电重新检查MOSI/MISO/SCK/RESET确认供电电压提示“Unable to enter programming mode”时钟源熔丝位配置异常或芯片处于低功耗模式尝试外部时钟救援或检查WDT熔丝位烧录成功但程序无反应没勾选Erase、复位引脚被拉低、Flash地址异常重新全片擦除再烧检查复位电路反复自动复位看门狗熔丝位开启但程序未喂狗关闭WDTON或在代码中喂狗芯片完全无法识别且发热供电电压错误或引脚接反立即断电检查硬件必要时更换芯片USB设备识别但Studio 7不显示工具驱动冲突或Studio版本过老重装Atmel USB Driver升级Studio版本5.2 从Output窗口精准定位错误Studio 7的Output窗口不是摆设很多问题光看弹窗根本看不出所以然但Output窗口里会把底层错误信息打出来。比如“Unable to locate the selected tool”和“Target voltage detected: 0.0V”的含义完全不同前者是驱动或工具识别层面的问题后者是目标板压根没供电。实际操作中如果烧录失败我会按这个顺序走一遍排查观察Output窗口里的错误码和电压读数确认目标板供电正常。用万用表量烧录器与目标板之间的GND是否连通——GND不共地是最容易被忽略的问题特别是你用的是外部供电而不是烧录器供电时。用示波器或者逻辑分析仪抓一下SCK、MOSI信号确认烧录器是否在发数据。USBasp这类便宜烧录器经常因为USB供电不足导致输出波形畸形。检查目标芯片型号选择是否正确。这个错误我犯过好几次——工程里是ATmega328P但Device Programming里却选了ATtiny85所读到的签名ID完全对不上自然会失败。5.3 把Studio 7烧录和命令行AVRDUDE结合起来虽然这篇文章的主题是Studio 7但实际工况里命令行工具往往能救命。比如你需要在无图形界面环境里刷一批芯片或者需要把烧录操作写进自动化脚本AVRDUDE就是最好的补充。AVRDUDE连USBasp的命令格式大致是avrdude -c usbasp -p m328p -U flash:w:main.hex:i这里-c指定编程器-p指定芯片型号-U指定烧录操作。熔丝位操作则是avrdude -c usbasp -p m328p -U lfuse:w:0x62:m -U hfuse:w:0xd9:m -U efuse:w:0xff:m注意熔丝位字节在AVRDUDE里的顺序低字节是lfuse高字节是hfuse扩展字节是efuse和Studio 7里的名称是对应的。如果你在Studio 7里改了一堆勾选但搞不清最终的字节值也可以用AVRDUDE的读取命令把当前值导出来两边交叉验证。5.4 烧录临时失败后的强制擦除与重试还有一种情况非常膈应人烧录时提示失败但芯片并没有完全锁死只是处于“半编程”状态。此时再直接Program往往还是失败因为Flash里残留的代码段和校验值对不上。我的处理办法是在Memories页签先单独点一次Erase不要同时勾选Program。等Erase完成后芯片内部就是空白状态然后再重新烧录。这套“先单独擦除、再单独烧录”的方案对付IMP联出现的编程失败成功率非常高。如果你用的是ISP接口但烧录供电不稳导致反复失败可以试试降低SPI时钟频率。Studio 7的Device Programming窗口里通常有Clock选项把它从4MHz降到250kHz信号完整性会好很多特别是杜邦线接得比较长的时候。别小看这一点我在一个大面包板上试过高频烧录必挂降频之后一次通过。6. 用Atmel-ICE对ATmega32U4刷写引导程序的全过程理论讲再多不如上实操例子。这里分享一个我最近做的案例用Atmel-ICE给一块自制的ATmega32U4板子刷Arduino Leonardo的引导程序。这块板子没有原生USB Bootloader出厂芯片是空的只能通过ISP接口写Bootloader。接线方式如下Atmel-ICE ISP接口ATmega32U4目标板1 (MISO)引脚14 / PB32 (VCC)VCC (5V)3 (SCK)引脚15 / PB14 (MOSI)引脚16 / PB25 (RESET)引脚RESET6 (GND)GND接好后打开Studio 7Tools → Device Programming选择Atmel-ICEInterface选ISPApply。读到的Device signature是0x1E9587确认无误后进入Memories页签选择要烧录的LeonardoBootloader.hex。这里有个细节ATmega32U4有多个Flash区段烧Bootloader时地址通常从0x0000开始但要确保链接脚本设置正确否则Bootloader会被放到错误的地址段。Studio 7在编程时如果报Address out of range多半就是文件本身的地址信息不对。烧录完成后我还特意检查了一遍熔丝位是否被正确设置。ATmega32U4的Bootloader需要在底部保留2KB空间所以BOOTSZ熔丝位必须设置为2048字节否则Bootloader和应用程序区会重叠USB下载程序时会出各种奇怪错误。这个坑不查手册根本发现不了。刷完Bootloader后拔掉ISP线插上USBWindows自动识别出Leonardo设备用Arduino IDE上传一个Blink程序测试一次成功。7. 结束前的几句心里话这篇文章从Software Studio 7的安装配置讲到硬件烧录器的选择再到完整的烧录流程、熔丝位深度解析和故障排查内容量其实挺大的。但说句实话能把AVR烧录这件事做好真正考验的不是你记住多少步骤而是你对器件底层工作机制的理解。我个人这几年用下来最大的感悟是烧录前多花两分钟把原始熔丝位读回来存好比什么高级技巧都管用。很多问题只要你能回退到初始状态就不算真正的问题真正难的是当你连回退的通道都被自己亲手切断时那种只能靠外部救援方案死磕的处境。另外还想提醒一点Studio 7里的“Fuses”窗口确实好用但千万别在不确定的情况下乱点勾选。你每次改动熔丝位都是在对芯片做一次硬件层面的重配置一个不起眼的勾选可能就决定了芯片是正常跑还是彻底罢工。最后再分享一个小技巧如果你手头有多颗同型号芯片第一次接触这个型号时先在废板上把所有熔丝位配置试一遍记录下每种配置下芯片的状态再上真正要用的板子。用一块废板换来的经验比任何文档都来得实在。
企业数字化 ERP 产品动态
相关推荐
基于MicroPython的ESP32小型应用平台:安装、启动器与文件系统实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:07:34
开源30MHz任意波形发生器:原理图、固件与调试波形全解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:07:34
LLC谐振变换器基本原理与工程设计实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:07:34
Spring Boot 2.6.13 + MySQL 8 + Flowable 6.8.1 集成部署与避坑实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:51:10
Console线选型与排障:CH340与FTDI芯片性能深度对比 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:51:10
从IEC 61499到Open61499:开源工业编程平台的进化与实践指南 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:51:10
BQ25570能量收集实战:从冷启动到VBAT_OK状态监控的完整指南 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:51:10
基于Simulink的永磁同步电机FOC控制建模与仿真实践 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:51:04
使用 Elixir、Phoenix 与 Absinthe 搭建 GraphQL 服务器:环境准备与项目初始化实战 【免费下载链接】howtographql The Fullstack Tutorial for GraphQL 项目地址: https://gitcode.com/gh_mirrors/ho/howtographql 点击查看 免费下载 本指南是 howtographql 教程 Elixir 后端路线中「Getting Started」章节的完整实战讲解。你将基于 Elixir、Phoen… · 2026/9/25 1:51:04
创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31
MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:37