新闻详情

新闻详情

首页 / 资讯中心 / 详情

ESP32-C3 无线管家:远程烧录与日志采集 RP2040 实战

发布时间:2026/9/25 1:13:29来源:尧图网络
ESP32-C3 无线管家:远程烧录与日志采集 RP2040 实战
1. 项目缘起与整体设计思路1.1 为什么会有这个“管家”需求手头同时有 ESP32-C3 和 RP2040 两块芯片的人不少但真正把两者组合起来做点事情的人其实不多。我最初接触这个组合是因为一个很实际的问题RP2040 的固件烧录和调试通常需要一台电脑通过 USB 连接用 BOOTSEL 模式拖拽 UF2 文件或者用调试探针走 SWD 接口。但很多部署场景下设备装进机箱、埋进设备内部之后再想插 USB 线就非常麻烦了。这时候 ESP32-C3 的价值就体现出来了。它自带 Wi-Fi 和蓝牙功耗控制得也不错关键是价格便宜、生态成熟。让它充当 RP2040 的“管家”——负责下载固件、控制启动模式、采集运行日志——这个思路就非常自然了。NEXDAP 这个项目正是基于这个思路展开的它把 ESP32-C3 做成一个中间层向上通过无线网络接收指令和固件数据向下通过 SWD 和 SPI 接口与 RP2040 交互。这个方案解决的核心问题是让 RP2040 摆脱对物理 USB 连接的依赖实现远程固件更新和日志回传。适合那些做嵌入式部署、远程设备维护、或者单纯想折腾双芯片协作的开发者参考。1.2 整体架构是怎么搭起来的整个系统的架构可以分成三层来理解。最上层是控制端可以是手机、电脑或者任何能发网络请求的设备中间层是 ESP32-C3它跑着 NEXDAP 固件负责协议转换和任务调度最下层是 RP2040它是被管理的目标芯片。ESP32-C3 和 RP2040 之间的连接主要走两条路一条是 SWD 接口用于烧录固件和调试另一条是 SPI 接口用于高速数据传输和日志采集。为什么选 SWD 而不是 JTAG因为 SWD 只需要两根线SWCLK 和 SWDIO引脚占用少而且 RP2040 对 SWD 的支持非常完善用起来稳定。SPI 则是因为它的速率可以做得比较高适合大量日志数据的搬运。这里有个设计取舍值得说明为什么不让 ESP32-C3 直接模拟 USB 设备去烧录 RP2040因为 RP2040 的 USB 启动模式需要特定的时序和枚举过程用 GPIO 模拟 USB 主机在 ESP32-C3 上实现起来复杂度很高而且稳定性难以保证。走 SWD 协议虽然需要自己实现一套时序但协议本身是确定的调试起来更可控。1.3 关键器件的选型考量ESP32-C3 的选型理由很直接RISC-V 内核主频 160MHz自带 Wi-Fi 和 BLEGPIO 数量够用而且乐鑫的 ESP-IDF 框架对 SPI 和 GPIO 的控制支持得很成熟。相比 ESP32-S3C3 少了一些引脚和外设但对于这个项目来说完全够用而且成本更低、功耗更优。RP2040 这边没什么好选的它就是被管理的目标。需要注意的是 RP2040 的 SWD 接口默认是启用的不需要额外的配置上电就能用。它的 SPI 接口可以配置为主机或从机在这个项目里我们让 RP2040 做 SPI 从机ESP32-C3 做主机这样 ESP32-C3 可以主动发起日志采集请求。还有一个细节ESP32-C3 的 GPIO 电平是 3.3VRP2040 的 IO 也是 3.3V所以两者可以直接连接不需要电平转换。这一点在布线的时候省了不少事。2. 核心细节解析与实操要点2.1 SWD 协议在 ESP32-C3 上的实现要点SWD 协议本质上是一个两线制的串行调试接口包含 SWCLK 和 SWDIO 两根信号线。SWCLK 由主机这里是 ESP32-C3产生SWDIO 是双向数据线。协议的核心在于时序的精确控制因为 SWD 的读写操作对时钟沿的配合要求很严格。在 ESP32-C3 上实现 SWD 主机不能用硬件 SPI 或者 I2C 外设直接搞定因为 SWD 的协议格式和这些标准外设不兼容。我的做法是用 GPIO 配合精确的延时函数来手动翻转电平。ESP32-C3 的主频是 160MHz一个时钟周期是 6.25ns通过esp_rom_delay_us或者忙等待循环可以做到微秒级的延时控制。具体来说SWD 的一次写操作包含以下几个阶段首先是 8 个时钟周期的包头包含起始位、APnDP 位、读写位、地址位和奇偶校验位然后是 4 个时钟周期的 Trn turnaround阶段用于切换数据线方向接着是 32 个时钟周期的数据阶段最后又是 Trn 阶段和空闲周期。注意SWDIO 在 Trn 阶段需要切换方向ESP32-C3 的 GPIO 必须配置为开漏输出或者动态切换输入输出模式。我实测下来用gpio_set_direction动态切换最稳定但切换本身有几百纳秒的延迟需要在时序计算时留出余量。另一个坑是上拉电阻。SWDIO 线上建议加一个 10kΩ 的上拉电阻到 3.3V否则在空闲状态下电平可能不稳定导致 RP2040 误识别。SWCLK 线不需要上拉但走线尽量短避免引入干扰。2.2 SPI 日志采集的配置与优化SPI 接口在这个项目里承担的是日志采集任务。RP2040 运行过程中会把日志数据写入一个环形缓冲区ESP32-C3 通过 SPI 定期读取这个缓冲区。这里 SPI 的配置有几个关键参数需要仔细调整。首先是时钟频率。ESP32-C3 的 SPI 主机最高可以跑到 80MHz但实际能跑多快取决于走线质量和 RP2040 从机的响应速度。我一开始设了 40MHz发现偶尔会丢数据后来降到 20MHz 就非常稳定了。如果你用的是短排线连接可以尝试 30MHz 左右如果是长线或者经过排针建议保守一点用 10MHz。其次是SPI 模式。RP2040 的 SPI 从机支持模式 0 到模式 3我选的是模式 0CPOL0CPHA0也就是空闲时时钟为低电平数据在时钟上升沿采样。这个模式最常用兼容性也最好。然后是片选信号。SPI 的片选CS可以用硬件片选也可以用软件片选。硬件片选由 SPI 外设自动控制时序更精确软件片选需要手动拉低拉高 GPIO灵活性更高但时序容易出问题。我建议用硬件片选因为 ESP32-C3 的 SPI 外设支持自动片选配置好之后基本不用操心。实操心得SPI 的 CS 信号在每次传输之间必须拉高至少一个时钟周期否则 RP2040 可能无法正确复位内部状态机。我在调试时遇到过连续读取时数据错位的问题后来发现就是 CS 没有正确拉高导致的。2.3 启动模式控制的电路设计RP2040 的启动模式由 BOOTSEL 引脚和 Flash 中的引导程序共同决定。正常启动时RP2040 会从 Flash 中加载固件运行如果 BOOTSEL 引脚在上电时被拉低它会进入 USB 大容量存储模式等待固件拖拽。在这个项目里ESP32-C3 需要能够控制 RP2040 的复位和 BOOTSEL 引脚以便在需要烧录新固件时让 RP2040 进入正确的模式。具体电路上ESP32-C3 的两个 GPIO 分别连接到 RP2040 的 RUN复位引脚和 BOOTSEL 引脚。控制逻辑是这样的要进入烧录模式时ESP32-C3 先拉低 BOOTSEL然后拉低 RUN 再拉高 RUNRP2040 就会在复位后检测到 BOOTSEL 为低电平进入 USB 启动模式。但这里有个问题——我们并不走 USB 烧录而是走 SWD 烧录。SWD 烧录不需要 RP2040 进入 USB 模式只需要 RP2040 的调试接口可用即可。所以实际上 BOOTSEL 的控制主要用于强制复位后从 Flash 启动确保 RP2040 不会因为 Flash 中的固件损坏而卡死。RUN 引脚的控制则是用于正常的复位操作。注意RP2040 的 RUN 引脚内部有上拉外部只需要一个开漏或者推挽输出即可控制。但如果你用的 GPIO 在上电瞬间有不确定状态建议加一个 10kΩ 下拉电阻确保 RP2040 不会意外复位。3. 实操过程与核心环节实现3.1 硬件连接与引脚分配先把硬件连起来。ESP32-C3 和 RP2040 之间的连线如下表所示ESP32-C3 引脚RP2040 引脚功能说明GPIO4SWCLKSWD 时钟线GPIO5SWDIOSWD 数据线GPIO6RUN复位控制GPIO7BOOTSEL启动模式控制GPIO10SPI0 RXSPI 主机输入GPIO11SPI0 CSnSPI 片选GPIO12SPI0 SCKSPI 时钟GPIO13SPI0 TXSPI 主机输出GNDGND共地这个引脚分配不是固定的你可以根据自己板子的实际情况调整。但有几个原则SWCLK 和 SWDIO 尽量分配到相邻的 GPIO方便走线SPI 的四根线尽量连续减少交叉RUN 和 BOOTSEL 用普通 GPIO 即可没有特殊要求。电源方面ESP32-C3 和 RP2040 都用 3.3V 供电。如果两个芯片由同一个 LDO 供电注意 LDO 的电流能力要足够RP2040 在满负荷运行时电流可以到 100mA 左右ESP32-C3 在 Wi-Fi 工作时峰值电流也有 300mA 左右所以 LDO 至少选 500mA 以上的。3.2 ESP32-C3 端固件框架搭建ESP32-C3 端的固件基于 ESP-IDF 开发整体框架分成四个模块网络通信模块、SWD 驱动模块、SPI 驱动模块和任务调度模块。网络通信模块负责接收来自控制端的指令和固件数据。我用的方案是 ESP32-C3 建立一个 TCP 服务器控制端通过 TCP 连接发送指令。指令格式很简单一个字节的命令码加上可变长度的数据负载。命令码包括固件下载、启动 RP2040、停止 RP2040、读取日志、擦除 Flash 等。SWD 驱动模块是整个固件的核心难点。它需要实现 SWD 协议的底层时序包括线复位、JTAG-to-SWD 切换、读写 DPDebug Port和 APAccess Port寄存器等操作。这部分代码我参考了 ARM 的 ADIArm Debug Interface规范用 GPIO 手动翻转的方式实现。SPI 驱动模块相对简单用 ESP-IDF 的 SPI 主机驱动配置好参数即可。关键是要处理好 CS 信号的控制和 DMA 传输的缓冲区管理。任务调度模块用 FreeRTOS 的任务和队列来实现。网络任务负责收发数据SWD 任务负责烧录操作SPI 任务负责日志采集。三个任务之间通过队列传递消息避免直接共享全局变量。// SWD 写操作的简化示例 void swd_write(uint8_t apndp, uint8_t addr, uint32_t data) { uint8_t parity 0; uint8_t packet 0x81; // 起始位 APnDP 写 地址 // 发送包头 for (int i 0; i 8; i) { swd_clock_out((packet i) 1); } // Trn 阶段 swd_set_io_input(); swd_clock_out(0); // 发送数据 swd_set_io_output(); for (int i 0; i 32; i) { swd_clock_out((data i) 1); parity ^ (data i) 1; } swd_clock_out(parity); // 空闲周期 swd_clock_out(0); swd_clock_out(0); }这段代码只是示意实际实现中还需要处理 Trn 阶段的精确时序、错误重试、以及 RP2040 的响应解析。3.3 RP2040 端固件与日志输出RP2040 端的固件需要做两件事一是正常运行业务逻辑二是把日志写入 SPI 从机的发送缓冲区。日志缓冲区的设计我用了一个 4KB 的环形缓冲区RP2040 的日志输出函数把格式化后的字符串写入缓冲区ESP32-C3 通过 SPI 读取缓冲区头部的数据。缓冲区满时旧的日志会被覆盖这样可以保证最新的日志总是可用的。SPI 从机的实现用 RP2040 的硬件 SPI 外设配置为从机模式模式 0数据位 8 位。当 ESP32-C3 发起传输时RP2040 的 SPI 中断会被触发中断处理函数从环形缓冲区中取出数据填入 SPI 发送寄存器。// RP2040 SPI 从机中断处理示例 void spi_slave_irq_handler(void) { if (spi_get_hw(SPI_PORT)-ris SPI_SSPSR_RFF_MASK) { while (spi_is_readable(SPI_PORT)) { uint8_t data spi_get_hw(SPI_PORT)-dr; // 将数据放入接收缓冲区 rx_buffer[rx_head] data; rx_head % RX_BUFFER_SIZE; } } if (spi_get_hw(SPI_PORT)-ris SPI_SSPSR_TFE_MASK) { if (tx_tail ! tx_head) { spi_get_hw(SPI_PORT)-dr tx_buffer[tx_tail]; tx_tail % TX_BUFFER_SIZE; } else { spi_get_hw(SPI_PORT)-dr 0x00; // 发送空数据 } } }实操心得RP2040 的 SPI 从机在 CS 拉高后需要一段时间来复位内部状态如果 ESP32-C3 连续发起传输且间隔太短RP2040 可能会丢失第一个字节。我的解决办法是在两次传输之间至少间隔 10 微秒或者在协议层加一个握手字节。3.4 固件下载流程的完整实现固件下载的完整流程分成以下几个步骤ESP32-C3 接收固件数据控制端通过 TCP 把固件二进制文件发送给 ESP32-C3ESP32-C3 把数据暂存在外部 Flash 或者内存中。如果固件比较大超过 1MB建议用外部 Flash 暂存。ESP32-C3 控制 RP2040 进入调试模式拉低 RUN 引脚再拉高复位 RP2040。然后通过 SWD 接口发送线复位序列切换到 SWD 模式。擦除 RP2040 的 Flash通过 SWD 接口访问 RP2040 的 Flash 控制器执行擦除操作。RP2040 的 Flash 是外部 QSPI Flash擦除需要按照扇区进行通常每个扇区 4KB。写入固件数据把固件数据分成小块通过 SWD 接口写入 RP2040 的 SRAM然后调用 RP2040 的 Flash 编程函数把数据写入 Flash。这个过程比较慢因为 SWD 的速率有限1MB 的固件大概需要几十秒。校验固件写入完成后通过 SWD 接口读回 Flash 中的数据与原始固件进行比对确保写入正确。复位并启动 RP2040拉低 RUN 引脚再拉高RP2040 从 Flash 启动新固件。注意RP2040 的 Flash 编程函数需要先在 SRAM 中运行一段引导代码这段代码负责初始化 QSPI 控制器并执行编程操作。这段引导代码需要提前通过 SWD 写入 SRAM然后再跳转执行。4. 常见问题与排查技巧实录4.1 SWD 连接失败的问题排查SWD 连接失败是最常见的问题表现是 ESP32-C3 发送线复位序列后读不到 RP2040 的 IDCODE或者读到的值不对。排查思路按以下顺序进行检查硬件连接用万用表量一下 SWCLK 和 SWDIO 的通断确认没有虚焊或者断线。SWDIO 的上拉电阻是否焊接阻值是否合适。检查电平用示波器看 SWCLK 和 SWDIO 的波形确认电平幅度是 3.3V没有明显的过冲或者振铃。降低时钟频率SWD 的时钟频率如果太高RP2040 可能来不及响应。先把频率降到 100kHz 试试如果通了再逐步提高。检查 RP2040 的供电RP2040 的 IO 电压是 3.3V但如果它的核心电压1.1V没有正常产生调试接口也不会工作。量一下 RP2040 的 VREG 输出是否正常。检查复位状态RP2040 的 RUN 引脚如果被意外拉低芯片一直处于复位状态SWD 自然连不上。确认 RUN 引脚的电平是高电平。我遇到过一次比较诡异的情况SWD 连接时好时坏后来发现是 SWCLK 和 SWDIO 的走线太长而且平行走线产生了串扰。把线缩短并且分开走之后问题就消失了。4.2 SPI 日志数据错位的解决方法SPI 日志采集时偶尔会出现数据错位读出来的日志字符串是乱码或者偏移了几个字节。这个问题的根源通常是CS 信号的时序问题。SPI 从机在 CS 拉高后需要一定的时间来复位内部移位寄存器如果 CS 拉高的时间太短从机可能还没有完成复位就被下一次传输激活了。解决方法有两个一是增加 CS 拉高后的延时至少保证 1 微秒以上二是在协议层加一个同步头每次传输的第一个字节固定为 0xAA接收端检测到这个字节后才开始正式解析数据。还有一个可能的原因是SPI 模式不匹配。ESP32-C3 和 RP2040 的 SPI 模式必须一致如果一边是模式 0 另一边是模式 1数据就会在错误的时钟沿被采样导致错位。检查两边的 CPOL 和 CPHA 配置是否相同。4.3 固件烧录后 RP2040 不启动的原因固件烧录完成校验也通过了但 RP2040 复位后就是不启动或者启动后行为异常。可能的原因有以下几个Flash 的引导扇区被破坏RP2040 的 Flash 前 256 字节是引导扇区包含了 Flash 的配置信息和校验和。如果烧录时覆盖了这部分内容RP2040 无法正确初始化 QSPI Flash自然启动不了。解决方法是烧录时跳过前 256 字节或者确保固件中包含了正确的引导扇区。向量表地址不对RP2040 启动后会从 Flash 的 0x10000000 地址读取向量表如果固件的链接地址不是这个启动就会失败。检查编译时的链接脚本。时钟配置错误如果固件中把系统时钟配置到了一个 RP2040 不支持频率芯片可能无法正常运行。先用默认时钟配置测试。看门狗未喂狗如果固件中启用了看门狗但没有及时喂狗RP2040 会不断复位。检查看门狗的配置。避坑技巧烧录固件之前先用picotool或者openocd读取 RP2040 的 Flash 内容备份原始固件。这样即使烧录出问题也可以快速恢复。4.4 常见问题速查表问题现象可能原因排查方法解决方案SWD 读不到 IDCODE接线错误、电平异常、时钟太快量通断、看波形、降频检查接线、加得上拉、降频到 100kHzSPI 数据错位CS 时序不对、模式不匹配看 CS 波形、检查 CPOL/CPHA增加 CS 延时、统一 SPI 模式烧录后不启动引导扇区损坏、向量表错误读回 Flash 对比、检查链接脚本保留引导扇区、修正链接地址日志丢失缓冲区溢出、SPI 速率太低检查缓冲区大小、提高 SPI 时钟增大缓冲区、优化 SPI 传输网络连接不稳定Wi-Fi 信号弱、TCP 缓冲区小看 RSSI、调整缓冲区增加天线、增大 TCP 窗口5. 性能优化与扩展思路5.1 提升固件下载速度的几种手段SWD 的速率是固件下载的瓶颈。标准的 SWD 时钟频率在 1MHz 到 10MHz 之间实际有效数据速率大概在几百 KB/s。1MB 的固件需要几十秒才能烧完这个速度对于频繁更新的场景来说有点慢。提升速度的手段有几种。一是提高 SWD 时钟频率在信号质量允许的前提下尽量往上调。我实测在短排线连接下ESP32-C3 可以跑到 5MHz 左右再高就不稳定了。二是优化 SWD 的传输协议把多个写操作合并成一个批量传输减少 Trn 阶段的切换开销。三是用 SPI 代替 SWD 进行数据传输SWD 只负责控制数据走 SPI 通道。这个方案需要 RP2040 端配合实现一个 SPI 引导程序复杂度较高但速度提升明显。还有一个思路是压缩固件。在 ESP32-C3 端对固件进行压缩传输到 RP2040 后再解压写入 Flash。压缩率通常在 50% 左右相当于把传输时间减半。常用的压缩算法有 heatshrink、miniz 等资源占用小适合嵌入式环境。5.2 日志采集的实时性优化日志采集的实时性取决于 SPI 的轮询频率和缓冲区的大小。如果轮询间隔太长日志会积压在 RP2040 的缓冲区里如果缓冲区太小日志会溢出丢失。我的做法是让 ESP32-C3 以 10ms 的间隔轮询 SPI每次读取 256 字节。这个频率下只要 RP2040 的日志输出速率不超过 25KB/s就不会丢失。对于大多数调试场景来说这个速率是够用的。如果需要更高的实时性可以用中断方式代替轮询。RP2040 在写入日志后通过一个 GPIO 通知 ESP32-C3ESP32-C3 收到中断后立即发起 SPI 传输。这样可以把延迟降到 1ms 以内。实操心得SPI 的 DMA 传输可以显著降低 CPU 占用率。ESP32-C3 的 SPI 外设支持 DMA配置好之后 CPU 只需要在传输完成中断里处理数据即可不用一直忙等。5.3 后续可以扩展的方向这个项目的基础框架搭好之后可以扩展的方向很多。比如增加 OTA 更新功能让 ESP32-C3 可以从网络下载 RP2040 的固件并自动烧录实现完全无线的固件更新流程。再比如增加日志的远程转发功能把采集到的日志通过 MQTT 或者 HTTP 推送到远程服务器方便集中管理。还可以支持多块 RP2040 的管理。ESP32-C3 的 GPIO 数量有限但可以通过 SPI 的片选信号扩展用多个 CS 引脚分别控制不同的 RP2040。SWD 接口也可以加模拟开关来切换不过这样会增加硬件复杂度。另一个有意思的方向是用 ESP32-C3 的蓝牙功能做近场调试。手机通过蓝牙连接 ESP32-C3直接在手机上查看 RP2040 的日志和发送控制指令不需要 Wi-Fi 网络。这个方案适合现场调试场景比连 Wi-Fi 更方便。我在实际使用中发现这套方案最实用的场景是设备出厂前的批量烧录和测试。把 ESP32-C3 和 RP2040 做成一个测试夹具工人只需要把待测板放上去测试夹具自动完成固件烧录、功能测试和日志采集效率比手动插 USB 线高很多。踩过几次坑之后我把 SWD 的时序参数和 SPI 的配置参数都做成了可配置的不同批次的板子可以根据实际情况微调适应性好了不少。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

IDM、Fabless、Foundry:芯片三种商业模式的核心分野与选型逻辑 2026/9/25 1:45:20

IDM、Fabless、Foundry:芯片三种商业模式的核心分野与选型逻辑

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

阅读更多 →
按键精灵2023入门教程:从录制到找图找色,手把手写第一个自动化脚本 2026/9/25 1:45:20

按键精灵2023入门教程:从录制到找图找色,手把手写第一个自动化脚本

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

阅读更多 →
RDRAND/RDSEED 真的不生成 0?硬件随机数指令的误解与验证 2026/9/25 1:45:20

RDRAND/RDSEED 真的不生成 0?硬件随机数指令的误解与验证

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

阅读更多 →
STM32软解433MHz OOK信号实现EV1527协议解析 2026/9/25 1:45:20

STM32软解433MHz OOK信号实现EV1527协议解析

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

阅读更多 →
Windows下RabbitMQ安装失败的五大根源与实操解法 2026/9/25 1:45:20

Windows下RabbitMQ安装失败的五大根源与实操解法

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

阅读更多 →
宇树G1人形机器人SSH远程调试与MobaXterm配置实战指南 2026/9/25 1:44:55

宇树G1人形机器人SSH远程调试与MobaXterm配置实战指南

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

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞