ESP32-C3内置USB-JTAG调试:一根USB线实现日志、烧录与断点调试
有一段时间我在调一个基于ESP32-C3的设备控制板。功能逻辑其实不复杂就是启动过程中某个外设的初始化时序偶尔会翻车。没有逻辑分析仪也没有外置JTAG调试器我只能靠串口日志盲调加一行打印编译一次效率低到想摔板子。后来翻数据手册才发现这块板子一直藏着个内置的USB-JTAG调试通道。一根USB线日志输出、固件烧录、断点调试全都能干。这篇内容就按我实际摸了一周的路径完整写出来给还在跟串口打印死磕的人省点时间。先回答一个最直接的问题这个USB-JTAG到底能干什么跟以前那种外接四根线的调试方式有什么本质区别。1. 内置USB-JTAG是什么为什么值得折腾1.1 从外置调试器到内置调试通道网上讲ESP32调试多数资料还是老思路准备一个外部JTAG调试器把TCK、TMS、TDO、TDI四根信号线连到芯片的JTAG引脚再用OpenOCD做桥接。对于经典ESP32这确实是唯一路径因为芯片内部只有JTAG TAP没有把USB控制器接到调试总线上。外接调试器模块本身不贵但加上杜邦线、电平匹配、接触不良这些事够喝一壶的。尤其是去现场排查问题的时候还得多带一套线材和转接板包里乱七八糟。到了C3、S3以及后续的C6、H2这些新系列芯片直接集成了一个USB-Serial/JTAG控制器。这个东西厉害在两点一是USB物理层内置你只需要把USB D/D-连到芯片指定引脚不需要外部USB转串口芯片也不需要单独的JTAG适配器二是它的内部逻辑直接接到芯片调试总线上OpenOCD可以把它当成一个标准JTAG适配器来用。换句话说一颗芯片既是程序运行的目标又自带调试器的角色一根普通的USB数据线就能完成日志、烧录、调试三件事。我实际用下来的体感是以前去现场要带一堆线材现在只要一根能给数据的USB线其他全免。这个变化对排查“偶发启动失败”“外设时序异常”这类问题特别关键因为你可以在程序真正运行的现场停下来看寄存器、看调用栈、看变量而不是靠加打印、猜逻辑。串口日志只能回答“有没有走到这一步”断点调试能回答“这一步里的状态到底是什么”完全两个量级。1.2 哪些芯片支持哪些不支持先泼盆冷水不是所有ESP32都支持。经典ESP32和ESP32-S2就没有内置USB-JTAG。S2虽然带USB OTG但那个USB口不能直接当JTAG调试接口用想调试还是得外接适配器。判断一台板子能不能走这条路最快的方法是查芯片数据手册里有没有“USB Serial/JTAG Controller”这个外设模块。芯片内置USB-JTAG调试方式经典ESP32无GPIO12-15接外部JTAG调试器ESP32-S2无有USB-OTG但调试仍需外部JTAGESP32-C3有内置USB-JTAG/SerialESP32-S3有内置USB-JTAG/SerialESP32-C6、H2等新系列有内置USB-JTAG/Serial选型表仅供参考实际拿板子前最好插上USB看一眼设备枚举结果。另外提醒一句有些板子虽然芯片支持但板厂没有把USB座的D/D-引到对应引脚只做了USB转UART桥这种板子照样用不了内置调试。怎么分辨我会在第二节详细说。1.3 引脚与PCB注意事项内置USB-JTAG用的就是芯片的USB引脚。C3上是GPIO18D-、GPIO19DS3上是GPIO19D-、GPIO20DC6、H2等新系列请以对应数据手册为准。这组引脚在开发板上通常已经连到USB座了省心。但如果自己画板子有两个建议USB D/D-走线尽量短、尽量平行。虽然是全速USB等级不高但飞线太长或者两线间距太大还是会引入信号完整性问题轻则枚举不稳重则识别不到设备。这组GPIO不要再接其他外设。USB引脚一旦复用到别的功能USB-JTAG大概率失效。S3上这个问题尤其容易踩因为GPIO19/20同时和USB-OTG、部分外设功能有映射冲突。还有一个容易被忽略的点调试阶段不要把BOOT引脚按着不放。芯片进入下载模式后ROM引导程序会接管USB串口逻辑JTAG通道基本处于不可用状态。正常操作是先烧录完成等芯片复位进入正常启动流程再启动OpenOCD。记住这个顺序能省掉很多“为啥连不上”的疑惑。2. 环境准备工具链配置与板子走线2.1 先搞清板子的USB走线拿到开发板别急着连先确认那个USB口是直连芯片还是经过了一个UART桥。板上如果有CP2102、CH340这类芯片那么这个USB口跟芯片的USB-JTAG引脚没关系它只是把UART串口转成了USB。连这种口你再怎么折腾OpenOCD也搜不到自带调试设备。判断方法其实很简单插上USB在Linux下执行dmesg | tail或者打开Windows设备管理器。如果设备名里带“JTAG”字样比如“USB JTAG/serial”、/dev/ttyACM0说明是原生USB-JTAG通道。如果只出现“USB-SERIAL CH340”这类字符串那基本就是UART桥需要单独把USB线接到芯片D/D-或者找板子上的原生USB口。有些开发板把两个USB口都做了出来甚至带跳线切换选对就行。# Linux下常见确认命令 lsusb | grep -i 303a dmesg | tail -20提示看到/dev/ttyACM0不代表一定是原生USB-JTAG部分USB转串口芯片也会注册成ACM设备。最稳妥的判断是看USB厂商ID是否为0x303a或者看设备管理器里的设备名称。我手上这块板就是原生USB直连插上后Linux直接出现/dev/ttyACM0同时lsusb里能看到厂商ID 0x303a的USB设备。这一步确认清楚后面能省很多力气。2.2 ESP-IDF下启用调试我习惯用ESP-IDF开发调试链路最顺。环境装好后配置要点如下。先把目标芯片设对然后进菜单配置idf.py set-target esp32c3 idf.py menuconfig在Component config → ESP System Settings里找到Enable OpenOCD对应宏CONFIG_ESP_DEBUG_OCD把它打开。这个选项保证应用运行时保留JTAG调试能力并且让目标核心在收到调试器请求时能正确停顿。编译选项建议保持默认的Debug优化否则很多变量和行号信息会被优化掉GDB里print变量经常看不到值。配置完重新编译烧录一次idf.py build flash monitor烧录完成后先退出monitor再启动OpenOCD。ESP-IDF自带的OpenOCD在工具链目录里如果你在终端直接敲openocd提示找不到命令说明没把它加进PATH常见路径是$HOME/.espressif/tools/openocd-esp32/版本/openocd-esp32/bin/openocd。直接用自带的板级配置文件启动即可openocd -f board/esp32c3-builtin.cfg这里的builtin指的就是芯片内置USB-JTAG。如果用S3把文件名换成esp32s3-builtin.cfg。看到类似下面的日志就说明JTAG通道已经通了Info : esp_usb_jtag: VID 0x303a PID 0x1001 Info : clock speed 4000 kHz Info : JTAG tap: esp32c3.cpu tap/device found: ... Info : [esp32c3] Core was reset.不同版本日志会有差异但关键是能看到“tap/device found”和芯片型号而不是卡在“Error: device not found”。这步通过环境就算搭好了。2.3 PlatformIO与Arduino场景如果你用PlatformIO配置更简单在platformio.ini里指定使用内置调试器[env:esp32-c3-devkitm-1] platform espressif32 board esp32-c3-devkitm-1 framework arduino debug_tool esp-builtin debug_init_break tbreak setup然后从IDE启动调试任务PlatformIO会自己拉起OpenOCD和GDB。debug_init_break会在入口处自动停一下对验证调试链路通不通很有用。纯Arduino IDE用户要注意Arduino IDE本身不提供GDB断点调试功能。想用USB-JTAG调试要么把同样的代码迁移到PlatformIO或ESP-IDF环境要么只把USB串口当日志输出用。不要指望直接在Arduino IDE里按个按钮就能挂上调试器很多教程把这件事混在一起讲实际动手会踩坑。3. 实操完整跑通一次断点调试3.1 驱动与设备枚举检查Linux下插上板子后先确认设备lsusb | grep -i 303a dmesg | tail -20正常会看到厂商ID 0x303a的设备以及一个/dev/ttyACM0串口节点。如果只有/dev/ttyUSB0大概率是UART桥方向不对。Windows环境稍微啰嗦一点。设备装好后串口功能会表现为一个COM口而JTAG接口默认没有可用驱动。需要先用Zadig之类的工具把JTAG对应的USB接口驱动换成WinUSB或libusbOpenOCD才能通过libusb访问设备。操作时注意只替换JTAG接口别误改了CDC串口接口不然串口监视器会失灵重新装驱动就能恢复。# Linux下确认USB设备 Bus 001 Device 004: ID 303a:1001 Espressif USB JTAG/serial debug unit不同芯片的PID可能不同重点看厂商ID 0x303a就行。3.2 启动OpenOCD并连接GDB把OpenOCD跑起来之后另开一个终端进入编译产物目录用对应架构的GDB连接# ESP32-C3/C6/H2是RISC-V核心 riscv32-esp-elf-gdb build/blink.elf # ESP32-S3是Xtensa核心 xtensa-esp32s3-elf-gdb build/blink.elf进入GDB后依次执行target remote :3333 mon reset halt break app_main continue这里解释一下几个命令的意思。target remote :3333让GDB连接OpenOCD监听的本地端口默认就是3333如果发现端口被其他进程占用先查一下是谁占的别同时跑多个OpenOCD实例。mon reset halt会让OpenOCD复位芯片然后立刻停住这是把调试状态拉到干净起点的标准动作。break app_main在应用入口下断点continue让程序跑起来几秒后就会停在app_main开头。如果程序没能停在断点先检查烧录的固件和当前ELF文件是不是同一份重新idf.py flash即可。这里有个跟普通调试不一样的习惯我一般不会用GDB的load命令重新写Flash。ESP32的应用在Flash里跑OpenOCD虽然能写Flash但速度慢还容易在加载时干扰启动流程。日常节奏是“改代码-编译烧录-开OpenOCD-连GDB打断点”烧录交给esptool调试交给OpenOCD各干各的最不容易出幺蛾子。3.3 断点、单步、变量观察实战调试一个实际业务循环时操作大概是这样的(gdb) break blink_task # 在任务函数入口停 (gdb) continue # 跑到断点 (gdb) print counter # 看变量当前值 $3 42 (gdb) next # 单步跳过一行 (gdb) step # 进入函数内部 (gdb) info reg # 查看寄存器组 (gdb) x/10wx 0x3FC00000 # 查看内存地址内容 (gdb) bt # 查看调用栈遇到优化导致变量被内联、print看不到值的时候把编译优化等级调低或者用volatile修饰关键调试变量。还有个小技巧在关键路径上多设几个断点比死磕一个断点更有效。硬件断点数量有限这个限制在GDB里会以报错形式体现遇到“超出断点资源”的提示果断删掉不用的断点。我的实测感受是内置USB-JTAG的调试速度比外置专用调试器略慢但完成暂停、读寄存器、看调用栈这些日常操作完全没问题。不要把断点密集打在每条指令上正常业务逻辑调试体感基本不卡顿。4. 常见问题与排查手册4.1 只有串口没有JTAG设备这是问得最多的情况可能原因和排查思路整理成了一张表现象可能原因处理方式只有COM口没有JTAG设备板子是UART桥接找原生USB口或直接接D/D-设备管理器出现“未知设备”USB引脚被占、线材问题换线、检查引脚复用冲突设备正常枚举但OpenOCD找不到芯片处于下载模式松开BOOT复位后重试Windows下OpenOCD报访问错误JTAG接口没装WinUSB驱动用Zadig装WinUSB/libusb排查时别一上来就怀疑驱动先把“板子走线对不对”“芯片是否在正常启动状态”这两个基本前提确认掉能少走一半弯路。4.2 OpenOCD报错与USB权限Linux上最常见的是权限问题报错长这样Error: open failed libusb: error: LIBUSB_ERROR_ACCESS临时验证可以直接改设备节点权限sudo chmod 666 /dev/bus/usb/002/004长期使用加一条udev规则让所有用户都能访问该厂商的USB设备SUBSYSTEMusb, ATTRS{idVendor}303a, MODE0666, GROUPplugdev保存到/etc/udev/rules.d/50-esp.rules然后执行sudo udevadm control --reload-rules sudo udevadm triggerWindows上的对应问题就是前面说的驱动替换Mac较少遇到但同样记得别把串口接口和JTAG接口的驱动弄混。4.3 调试中目标频繁掉线或复位我遇到过几次“设好断点刚看两眼OpenOCD就报target lost”排查下来两个原因最常见。第一个是任务看门狗。断点停在某个任务里任务长时间不喂狗系统复位调试器自然掉线。开发阶段的调试固件最好把CONFIG_ESP_TASK_WDT临时关掉或者不要在一个任务里停太久。在中断里面下断点更要小心中断看门狗和中断嵌套很容易把芯片搞出异常行为。第二个是供电和USB线质量。换了根只能充电不能传数据的线OpenOCD一拉高JTAG速率就掉线。排查时先换一根标准的USB数据线排除物理层干扰再看能不能把JTAG时钟降下来openocd -f board/esp32c3-builtin.cfg -c adapter speed 1000另外OpenOCD准备启动时终端里的串口监视软件最好先退出。虽然USB串口和JTAG是两个USB接口原理上可以同时占用但某些平台的USB栈会在串口被占用时跟调试通道抢带宽。实测下来先关串口最稳。4.4 烧录和调试的相互影响烧录和调试共用同一个USB口几个细节要记牢idf.py flash monitor跑完之后monitor窗口一定要退出否则COM口被占用OpenOCD可能报设备忙。下载模式下芯片的JTAG通道不可用所以烧录完成后要让芯片正常复位运行再连调试器。GDB里的mon reset halt已经足够完成复位和暂停不需要手动按板子上的复位键。手动复位反而会让OpenOCD和目标状态错开出现“target not halted”之类的错误。这个板块的排查经验很多是我实际踩过坑之后才记住的。写出来是真希望后来的人别重复这些冤枉路。5. 进阶技巧与个人经验5.1 日志输出与断点共存的办法不少人会问CPU停住之后串口日志还能看吗实测结果是USB串口设备本身还在枚举状态但程序停住后应用层不再往发送FIFO写数据已经缓冲的日志会在停住的一瞬间吐完后面就是空白。想在看断点的同时保留现场日志建议在代码里维护一个内存环形缓冲区日志先写缓冲区必要时用GDB直接dump内存查看例如(gdb) x/64s 0x3FC00100这样即使断住了也能倒推程序是怎么一步步走到这里的。对我这种习惯“先看日志再决定断点下哪”的人这个办法比纯肉眼盯串口高效得多。5.2 低功耗场景调试注意如果项目里开了light sleep或deep sleepUSB-JTAG很容易在进入休眠后失联。USB物理层需要时钟和供电睡眠模式下外设被关掉调试器自然找不到目标。调试阶段我会在应用初始化时临时屏蔽休眠相关调用或者用一个编译宏控制只在特殊调试版本里把休眠禁掉功能验证完再恢复回来。另外Flash加密、安全启动这些安全特性开启后调试接口的使用会受到限制。调试和攻防本身就是冲突的量产固件不应该依赖调试口。开发板上练手无所谓但做产品时请把调试功能关干净别留后门。5.3 把调试搬到IDE里命令行GDB对新手确实不友好实际项目里我更推荐直接用VS Code的ESP-IDF扩展。在settings.json里配置好OpenOCD板级文件{ idf.adapterTargetName: esp32c3, idf.openOcdConfigFiles: [board/esp32c3-builtin.cfg], idf.port: /dev/ttyACM0, idf.debugAdapter: esp_idf }按F5启动调试断点、变量监视、调用栈操作全都有了。PlatformIO用户就在IDE调试面板里选对应的调试环境也能达到同样效果。工具链没变只是把GDB命令换成了图形界面上手成本低很多。最后再分享一个小经验。我踩坑最多的一次是在Windows上给一堆开发板装驱动COM口、JTAG口混在一起认不清。后来所有调试都走同一个流程先插USB看设备管理器确认枚举出来的名字和接口数量再决定要不要动驱动。这个习惯帮我省下了大量猜谜时间。内置USB-JTAG最大的价值不是让你秀操作而是把“调试”这件事的门槛降到了一个普通电子爱好者也能轻松上手的地步。放下串口打印试着打断点看寄存器你会发现之前那些晦涩的启动时序问题突然就变得清清楚楚了。

相关新闻

NPU与TPU架构解析:从脉动阵列到INT8量化部署实战

NPU与TPU架构解析:从脉动阵列到INT8量化部署实战

1. 从CPU的困境说起:为什么我们需要NPU和TPU如果你最近两年关注过手机芯片或者云端服务器的发布会,一定频繁听到两个词:NPU和TPU。厂商在PPT上把它们的算力标得一个比一个高,动辄几十上百TOPS,但很多人其实并不清楚——…

2026/10/14 16:50:00 阅读更多 →
C++知识地图:从语法到对象模型的系统学习路线

C++知识地图:从语法到对象模型的系统学习路线

1. 为什么我建议每个C学习者都该有一张自己的知识地图刚入行那几年,我学C的方式特别“野”:今天看两章《C Primer》,明天刷几道算法题,后天又去折腾模板元编程。结果就是——面试时被问到“虚函数表在多重继承下怎么布局”能答个七…

2026/10/14 16:50:00 阅读更多 →
集成与验证:模块对接到系统稳定与面试题精讲

集成与验证:模块对接到系统稳定与面试题精讲

收到你的信息。我注意到你给的输入里,“项目正文”“关键词”“摘要描述”都是空的,我手头能用的只有标题“第07讲:集成、验证与面试题精讲”,以及对应对的人群和平台理解。所以我没法凭空捏造你原本想写的内容细节。有两个选择&a…

2026/10/14 16:50:00 阅读更多 →

最新新闻

IntelliJ IDEA 的Qoder CN 插件报错“暂时无法同步代码库索引选择”怎么解决?完整排查与修复指南

IntelliJ IDEA 的Qoder CN 插件报错“暂时无法同步代码库索引选择”怎么解决?完整排查与修复指南

摘要 本文针对在IDEA中使用Qoder CN时出现的报错,给出官方说明与实战解决步骤。官方指出需启用代码库索引:可点击“创建”手动启用,或切换“自动索引”。实战中,先登录Qoder CN且不要输入提示词,再进入设置—>Qode…

2026/10/14 17:36:00 阅读更多 →
PTZ-C8T6.zip 云台控制 C 工程解析:编译、协议与避坑指南

PTZ-C8T6.zip 云台控制 C 工程解析:编译、协议与避坑指南

简介:PTZ-C8T6.zip 是一份面向嵌入式开发初学者与 STM32 学习者的云台控制项目工程源码,基于 STM32F103 系列芯片与 HAL 库构建,适合用于课程设计、毕业设计或电赛类云台控制方案的参考与二次开发。压缩包共 98 个文件,约 675KB&a…

2026/10/14 17:36:00 阅读更多 →
Python 读取 Excel 并写入 zip:自动化报表打包实战

Python 读取 Excel 并写入 zip:自动化报表打包实战

简介:这份资源面向需要处理表格数据的Python学习者与开发者,聚焦Excel文件的读取与写入这一常见任务,帮助解决数据分析、数据清洗与自动化报告中的表格操作问题。压缩包共4个文件,全部为py脚本,整体约6KB,涵…

2026/10/14 17:36:00 阅读更多 →
Terminus(Olares)RabbitMQ 中间件集成实战:用 OlaresManifest.yaml 声明式接入消息队列

Terminus(Olares)RabbitMQ 中间件集成实战:用 OlaresManifest.yaml 声明式接入消息队列

云原生后端运维 【免费下载链接】Terminus Open-Source Personal Cloud OS for Always-On Agents 项目地址: https://gitcode.com/gh_mirrors/terminus2/Terminus 点击查看 免费下载 本篇技术指南基于 Terminus 仓库中 RabbitMQ 集成文档 展开,讲解如何…

2026/10/14 17:36:00 阅读更多 →
九轴姿态解算实战:C语言实现Mahony互补滤波与四元数融合

九轴姿态解算实战:C语言实现Mahony互补滤波与四元数融合

简介:九轴姿态解算源代码是一套面向嵌入式开发、无人机及机器人等场景的C语言实现,融合加速度计、磁力计与陀螺仪数据,用于实时估计物体的横滚、俯仰与偏航角。资源包含4个文件,全部为2个C源文件和2个头文件,压缩包仅5…

2026/10/14 17:36:00 阅读更多 →
C#工业级图形面积周长计算:精度、鲁棒性与性能平衡

C#工业级图形面积周长计算:精度、鲁棒性与性能平衡

1. 项目概述:为什么一个“图形周长、面积计算”功能值得花时间深挖? 你可能第一眼看到“C# 图形周长、面积计算”这个标题,会下意识觉得:“不就是几个数学公式封装成方法吗?勾股定理、πr、底高2……抄一遍就完事。”我…

2026/10/14 17:34:59 阅读更多 →

日新闻

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/14 16:30:29 阅读更多 →
影刀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 阅读更多 →