简介面向手机与嵌入式开发初学者、电子类专业学生及刚入行的工程师这份资料围绕联发科MT6225、6223、6226、6235、6253系列多媒体手机平台提供一套从入门到实践的开发参考。内容涵盖平台参考电路设计、器件规格说明、软件系统与调试方法、MMI人机界面设计、设备驱动、手机校准与工厂测试、工具使用手册等模块并涉及PC端仿真开发环境、源码编译工具链、UI制作工具与射频测试等环节可帮助读者理解功能机时代手机软硬件的整体架构与开发流程。压缩包内为1个doc文档约35KB实为光盘配套使用手册集中说明光盘包含的SDK构成、硬件特性与器材清单、软件特性及开发文档目录便于在动手前建立清晰的学习路径。目前已有844人浏览学习适合作为MTK平台入门阶段的知识索引与资料导航。1. 功能机基带平台为什么一台上古手机里藏着一整套操作系统一台只能打电话、发短信、放 MP3 的功能机源代码规模可能比很多人想象的大得多。更反直觉的是它的 MMI、文件系统、协议栈、设备驱动、射频校准和烧写工具往往被塞进同一套手机开发平台里。6225/6226/6223/6235/6253 这一代基带平台就是典型样本硬件资源紧软件分层却一点不少。搞懂这套源代码不是为了背 API而是看清一个资源受限的实时系统怎样把“能启动、能显示、能保存、能量产”四件事同时成立。2. 启动链从按下电源键到 MMI 第一帧代码到底跑在哪很多人拿到一套平台源代码第一反应是找main()。真到板子上跑第一行日志都不一定出得来。功能机基带平台的启动不是“复位后直接进 C 语言主函数”而是一层层接力芯片内固化的 Boot ROM 先判断从哪里启动再把二级引导读进片内 SRAM二级引导完成时钟、存储和内存映射最后才把控制权交给操作系统和 MMI。这个顺序一旦错了后面所有调试都像在黑匣子里猜。2.1 Boot ROM、二级引导与分散加载Boot ROM 是芯片出厂就固定的改不了。它通常只做几件事采样启动引脚选择 UART/USB 下载模式或外部存储启动从存储的固定偏移读引导头校验长度和 CRC把二级引导搬到片内 SRAM跳转到入口。真正的平台初始化在二级引导里链接脚本会把代码分成加载区域和执行区域有的镜像还要先解压再搬到 RAM。常见的实现思路是启动头里放魔数、加载地址、入口地址、长度和校验值任何一项不对就退回下载模式避免半包镜像直接跑飞。typedef struct { uint32_t magic; // 防止空片或错镜像被当成有效引导 uint32_t load_addr; // 二级引导被搬到哪 uint32_t entry; // 跳转入口不是 main uint32_t length; // 参与校验的镜像长度 uint32_t crc; // 长度和载荷的校验值 } boot_header_t; void boot_stage2(void) { boot_header_t *h (boot_header_t *)BOOT_HEADER_ADDR; if (h-magic ! BOOT_MAGIC) { enter_download_mode(); // 空片或引导头损坏别再往下跑 return; } if (crc32((void *)h-load_addr, h-length) ! h-crc) { enter_download_mode(); // 半包镜像比不下载更危险 return; } clock_init(); // 先稳时钟串口分频才有意义 uart_init(115200); // 早期日志只走最小串口 mem_remap(); // 让链接脚本里的执行地址变成真实映射 ((void (*)(void))h-entry)(); }这段代码里最容易被忽略的是clock_init()和mem_remap()的顺序。串口波特率来自总线时钟PLL 没锁定时初始化串口日志一定是乱码分散加载把代码搬到 RAM 后不做重映射中断向量还指在旧地址第一颗按键中断就能把系统打死。entry也不是随便填的main它通常是平台启动汇编之后的 C 入口负责清 BSS、建栈、初始化堆再进任务调度。2.2 中断向量、时钟与外设初始化顺序启动阶段的外设初始化有一条硬顺序供电域、时钟树、引脚复用、控制器、中断使能。很多“按键没反应”“触摸漂移”“串口能发不能收”的问题不是驱动写得不对而是顺序反了。比如引脚复用还停在调试口模式按键 GPIO 的中断当然进不来控制器中断标志没清就开全局中断系统会卡在中断入口反复进不去。顺序动作做反后的典型症状1打开供电域确认电压稳定外设时好时坏像玄学2配置 PLL 和总线分频串口乱码、存储超时3设置引脚复用和上下拉按键无反应、触摸坐标漂移4初始化控制器并清中断标志一开中断就死循环5最后使能全局中断早期中断丢失日志缺段中断向量表的位置也要在启动阶段定好。有的平台把向量表放片内 RAM为的是缩短响应时间有的平台放 Flash靠硬件重映射。无论哪种向量表里的 IRQ 入口只做最少的现场保存然后把事件投递给上层。把耗时操作放在中断里功能机这种单核、小内存平台很快就会出现音频卡顿、屏幕撕裂甚至协议栈超时。2.3 从启动完成到任务调度谁先谁后二级引导跑完后平台一般会创建一个很小的实时调度环境再按依赖关系拉起任务。常见的顺序是驱动初始化、文件系统挂载、协议栈启动、音频和显示、MMI。文件系统要早于 MMI因为界面资源、字库、铃声都可能在文件系统里协议栈要早于 MMI 的网络相关界面但 MMI 可以先显示“正在初始化”等协议栈回调再刷新状态。PC 仿真开发环境在这个阶段很有价值但要知道它替代了什么。仿真环境通常把 Flash、LCD、按键、射频前端抽象成桩函数能让 MMI 和文件系统逻辑在 PC 上跑起来方便断点和单步。它不是周期精确的也不代表真实射频时序所以“仿真能跑”不等于“样机能跑”。我一般会把它当成逻辑验证工具真正涉及启动、功耗、射频和音频时钟的改动还是要在真实板子上看 Trace。3. MMI 框架事件循环如何把按键、触摸和界面解耦功能机的 MMI 看起来只是几个菜单和输入框背后却是一个典型的事件驱动系统。按键、触摸、定时器、来电、短信、低电、耳机插拔都会被压缩成事件投进队列再由当前活动窗口消费。MMI 不能直接在中断里画屏也不能在按键回调里等协议栈返回否则用户看到的就是“按一下卡三秒”。这套解耦做得好不好直接决定这台机器像不像一台正常的手机。3.1 事件队列与窗口栈事件队列通常是一个环形缓冲区生产者可能是中断、协议栈任务或定时器任务消费者是 MMI 任务。队列满时不能阻塞中断常见做法是返回失败由驱动置一个 pending 标志下一次扫描时补发。窗口栈则解决“谁来处理事件”的问题按键只发给栈顶窗口触摸先做命中测试再发给对应控件窗口切换时保存焦点和重绘区域返回时恢复。typedef enum { EV_KEY, EV_TOUCH, EV_TIMER, EV_SIGNAL } ev_type_t; typedef struct { ev_type_t type; uint16_t code; // 键值、触摸动作或信号 ID int16_t x, y; // 触摸坐标按键事件可忽略 uint32_t tick; // 事件产生时间用于去抖和超时 } mmi_event_t; static mmi_event_t g_evq[32]; static volatile uint8_t g_head, g_tail; bool mmi_post(const mmi_event_t *ev) { uint8_t next (g_head 1) 31; if (next g_tail) { return false; // 队列满宁可丢事件也不能让中断阻塞 } g_evq[g_head] *ev; g_head next; return true; } void mmi_task(void) { for (;;) { while (g_tail ! g_head) { mmi_event_t ev g_evq[g_tail]; g_tail (g_tail 1) 31; if (g_active_win g_active_win-handler) { g_active_win-handler(g_active_win, ev); // 只分发给栈顶窗口 } } mmi_idle(); // 低功耗、重绘或等待下一个事件 } }g_evq的大小不是随便定的。太小会丢按键太大会吃紧 RAMhead和tail用一个字节做掩码是为了在单核上避免复杂的原子操作。真正产品里还会给按键事件做时间窗去抖给触摸事件做坐标校准给EV_SIGNAL做优先级排序。mmi_idle()也不是空转它可能进入低功耗等待或者在 dirty region 非空时触发一次局部重绘。3.2 MMI 与协议栈的边界消息 ID 和回调MMI 和协议栈之间最忌讳直接函数调用。协议栈可能在处理网络信令MMI 可能在等一个菜单刷新直接调用会把两个任务的时序绑死。常见的实现思路是定义一组应用消息 ID由协议栈把“来电、短信到达、信号强度变化、通话结束”封装成消息投递给 MMI 的消息队列MMI 处理完再通过明确的 API 回给协议栈。这样协议栈不需要知道当前是哪个窗口MMI 也不需要知道网络层怎么解码。边界清晰之后调试也容易。Trace 里能看到消息 ID 的进出能判断是“协议栈没上报”还是“MMI 没处理”。如果所有逻辑都揉在一个回调里出问题时只能靠猜血泪经验往往就是这么攒出来的。3.3 UI 资源与 MCT 工具链控件树怎么落到屏幕功能机的界面资源通常不是运行时解析 XML而是由 PC 端 UI 制作工具生成资源包字符串表、图片、字体、窗口和控件树被打包成二进制烧进只读分区。运行时按 ID 取资源按控件树创建窗口再把脏矩形交给显示驱动。这样做的好处是省 RAM、启动快代价是改界面必须重新生成资源包不能像上层应用那样热更新。资源类型运行时形态常见问题字符串索引表加编码数据编码不匹配显示乱码图片压缩位图或调色板位图解压缓冲区不够花屏字体点阵字库或裁剪字库缺字显示方框窗口控件树加回调表焦点丢失按键无响应显示驱动一般只重绘 dirty region不会整屏刷新。整屏刷新在功能机上很贵既吃总线带宽又吃电。调试界面问题时先看脏矩形有没有被正确标记再看图层顺序最后才怀疑 LCD 初始化。很多“界面不刷新”不是 MMI 没收到事件而是重绘区域被上层窗口盖住了。4. 文件系统与 NV为什么换电池不能丢配置刷机却能清空功能机时代最容易被低估的是存储分层。用户看到的“手机内存”只是 FAT 文件系统的一部分下面还有引导区、代码区、资源区、NV 区和校准区。换电池不能丢音量、时间、语言是因为这些配置写进了 NV刷机能把机器清回出厂状态是因为烧写工具按分区擦除有的还会重写校准参数。理解这套分区才能理解“为什么同一个 Flash有的数据怕掉电有的数据怕全擦”。4.1 NOR/NAND 上的 FAT 与只读资源分区NOR 适合直接执行代码读速度快擦除块大NAND 容量大、成本低但需要坏块管理和 ECC。很多功能机平台把引导、代码、资源放在 raw 分区把用户数据放在 FAT 分区。FAT 的好处是 PC 能直接识别坏处是没有日志掉电时容易出现簇链断裂或目录项写一半。资源分区通常是只读的里面放图片、字库、铃声和 UI 布局升级时整块替换。分区典型介质内容是否频繁改写引导区NOR raw二级引导、启动头否代码区NOR/NAND raw平台代码、协议栈否资源区NOR/NAND raw图片、字库、UI 资源否用户区FAT音乐、照片、录音是NV 区raw 加双备份校准、配置、设备参数是FAT 分区在挂载时一般会做一次轻量检查发现异常目录项就隔离或重建。真正麻烦的是写到一半掉电目录项已经指向新簇簇内容却没落盘文件就变成“有名字、打不开”。常见的补救是写临时文件再原子改名或者关键配置根本不走 FAT直接进 NV 双备份区。4.2 NV 项、校准参数与掉电保护NV 区保存的是“丢了会影响功能”的数据射频校准值、音量曲线、语言选择、触摸校准、电池参数。它不能像普通文件那样随便覆盖写因为擦除期间掉电会把整块数据抹掉。常见实现是双 bank 交替写每条记录带递增序号和 CRC读的时候选序号最大且校验通过的那份。这样即使写到一半掉电另一份仍然可用。typedef struct { uint32_t seq; // 递增序号判断哪一份更新 uint16_t id; // NV 项 ID uint16_t len; // 有效载荷长度 uint8_t data[NV_MAX]; uint32_t crc; // 覆盖头部和载荷 } nv_record_t; int nv_write(uint16_t id, const void *buf, uint16_t len) { nv_record_t rec; rec.seq nv_next_seq(id); // 单调递增掉电后也能比较新旧 rec.id id; rec.len len; memcpy(rec.data, buf, len); rec.crc crc32(rec, offsetof(nv_record_t, crc)); // 双 bank 交替写写坏一份另一份还能回滚 return flash_write_nv(rec.seq 1, rec, sizeof(rec)); }seq不能只存在 RAM 里否则重启后归零双 bank 的新旧判断就失效。crc要覆盖头部和载荷不能只校验数据段否则 ID 或长度被写坏也会被当成有效记录。写 NV 之后最好做一次回读校验别等用户换电池才发现音量配置没落盘。校准数据还要和硬件版本、射频通道绑定拿错校准文件比不校准更麻烦。4.3 下载、擦除与校验烧写工具到底做了什么烧写工具不是“把文件拷进去”这么简单。它要先让目标进入下载模式握手、读芯片 ID、解保护、按分区擦除、分包写入、逐段校验最后跳转重启。全擦会连 NV 和校准区一起清掉保留 NV 的升级则只动代码和资源区。很多人刷完机发现信号差、触摸不准不是代码坏了而是校准数据被擦掉后没有重新校准。阶段主机动作目标动作失败表现握手发同步包进下载模式超时连不上擦除下发地址和长度解保护、擦块地址错擦到引导区写入分包传数据写 Flash、回 ACK校验错卡在某一包校验读回比对返回 CRC镜像不完整重启发跳转命令复位并启动白屏、反复重启调试下载问题先看握手再看擦除范围最后看校验。不要一上来就换线、换板很多问题是分区表偏移和镜像头里的加载地址对不上。烧写工具显示“成功”也不代表机器能启动它只证明写入和回读一致不证明入口地址、时钟和存储映射正确。5. 避坑与排查源码能编过不等于样机能跑起来这套平台资料最值钱的地方不是给出一个“能编译”的工程而是把启动、下载、校准和测试工具都摆在了一起。可也正因为链路长坑特别多。下面几条是功能机平台调试里很典型的翻车现场每条都按“现象、原因、解决”拆开。5.1 编译、链接与启动阶段的坑现象一编译零错误下载后串口只吐一个字符就停。原因多半在链接脚本加载地址和执行地址不一致二级引导搬完镜像没有重映射向量表或者入口指到了 C 库启动文件而不是平台启动入口。解决时先看 map 文件的 load region再看反汇编的第一个跳转最后用最小串口日志确认 PC 落在哪个地址。别急着怀疑芯片坏了启动链的问题九成能在地图文件里找到影子。现象二串口日志全是乱码。先别改代码查三件事PLL 有没有锁定、串口分频是不是按总线时钟算的、引脚复用有没有切到 UART。功能机平台经常把调试串口和耳机检测、充电检测复用在一起引脚配置错一位日志就变成天书。解决顺序是时钟、分频、引脚最后才看收发 fifo 和中断。现象三按键中断进不去但轮询能读到键值。原因可能是向量表偏移没设置或者中断使能顺序反了控制器标志没清就开了全局中断。还有一种是按键 GPIO 被上层电源管理切到了低功耗模式中断边沿配置丢失。解决时先看中断控制器挂起位再看 GPIO 复用和上下拉最后确认低功耗唤醒源有没有包含这颗按键。这类问题很像玄学其实每一步都有寄存器可查。5.2 下载、校准与运行阶段的坑现象四换电池后时间、音量、语言设置丢失。原因不是“电池没电”而是 NV 写没有落盘或者双 bank 的序号判断错了。有的实现只在关机时写 NV用户直接拔电池就丢了有的 CRC 覆盖范围不对读的时候把有效记录判成坏记录。解决时先回读 NV确认 seq 和 crc再检查关机流程有没有调用 flush。关键配置不要只存 RAM也不要等掉电中断那个中断往往来不及。现象五重新校准后射频指标反而漂移。常见原因是校准文件与硬件版本、通道表不匹配或者校准数据写进了错误的 NV 项。功能机的射频校准通常分频段、分信道、分温度补偿拿错一份表仪器上看着能过实际通话就断。解决时先确认校准工具读到的芯片 ID 和板型再逐项比对 NV 回读值最后在屏蔽箱里做一次全信道抽检。不要用“能注册上网”代替校准验证。排查顺序我一般固定为电源和复位、时钟和引脚、启动介质和校验、串口和 Trace、文件系统和 NV、最后才是射频和音频。这个顺序能把“黑匣子”缩小到一小段代码。Trace 工具再不好用也比在几千行 MMI 里瞎猜强。6. 设计取舍为什么功能机平台把“可移植”和“可量产”放在同一张光盘里这套平台资料最值得琢磨的地方是它没有把“教学”和“量产”切成两个世界。PC 仿真环境让 MMI、文件系统、NV 逻辑能在没有射频硬件的机器上跑起来降低了入门成本真实样机和校准工具又保留了量产必须的 Trace、烧写、测试链路。代价是整套东西看起来很重启动链长、分区多、工具杂初学者容易被一堆配置吓退。可正是这些“重”的部分构成了功能机时代的工程方法。取舍点偏教学的做法偏量产的做法代价运行环境PC 仿真断点方便真实样机时序真实仿真查不出射频和功耗问题代码组织裁剪模块便于阅读全量源码依赖复杂初学容易被编译宏淹没存储方案单一分区逻辑简单多分区加双备份烧写和升级更容易出错调试手段串口打印Trace 加校准工具工具链学习成本高我后来再看这类平台会先接受它的“不优雅”启动头、分散加载、双 bank NV、FAT 加 raw 分区都不是为了好看而是为了在低 RAM、慢 Flash、会掉电的硬件上把可靠性堆出来。真要学东西别只盯着 MMI 怎么写菜单先把启动日志、文件系统挂载和 NV 回读跑通。从那以后我每次拿到一套平台源码都强制先走一遍这三步再谈改功能。希望帮到你。本文还有配套的精品资源点击获取
企业数字化 ERP 产品动态
相关推荐
MTK 2G功能机源码剖析:从启动链路到MMI的嵌入式设计取舍 简介:面向手机与嵌入式开发初学者及电子专业学生,这份文档围绕MTK6225、6226、6223、6235、6253系列手机开发平台展开,重点说明配套资料光盘的组成、适用人群与学习路径,帮助读者在进入多媒体手机开发前建立对平台架构、开发环境和… · 2026/11/3 13:48:08
Paperclip协议详解:OpenClaw生态中的AI能力接入标准 1. Paperclip 不是回形针:它是个被严重误读的 AI 工程化枢纽“Paperclip”这个词在中文技术圈里,最近半年像被按了快进键一样高频闪现——但绝大多数人点进去,看到的不是回形针实物图,而是一堆 Node.js 版本号、React 组件树截图、… · 2026/11/3 13:48:08
LLM推理性能调优:GPU硬件驱动的四层协同优化方法论 1. 项目概述:Model-Optimizer 不是工具名,而是一类工程实践的统称 “Model-Optimizer”这个标题乍看像某个开源项目或商业软件的代号,但结合NVIDIA、TensorRT-LLM、vLLM、PT转TensorRT等高频热词,它实际指向的是 大语言模型&… · 2026/11/3 13:48:08
Rust 构建 Nostr relay:从 git 克隆到 WebSocket 事件处理 1. 从 "buzz" 这个项目名说起:它到底想解决什么问题 第一次看到 "buzz" 这个标题,加上 Nostr、relay、Rust、git 这几个关键词,我脑子里第一反应是:这大概率是一个用 Rust 写的 Nostr 中继(relay&… · 2026/11/3 15:22:53
回形针虽小,藏着工程学:从弹性原理到办公选型全解析 如果你问我办公室里最不起眼但最离不开的小东西是什么,我的答案不是订书机,也不是便利贴,而是那盒躺在抽屉角落里、看起来毫无技术含量的回形针(paperclip)。这东西单价低到可以忽略不计,形状也就那么几道弯… · 2026/11/3 15:22:53
一枚回形针的无限可能:从夹持原理到手工搭塔指南 paperclip,就是回形针。我估计你工位抽屉里至少有一盒,但很少正眼看它。我最近把它当成一个正经项目研究了一遍,从结构原理、日常用法到手工搭塔,前后折腾了两三周,收获比我预想的多。这篇东西不打算讲教科书式的大道理… · 2026/11/3 15:22:53
深入理解JavaScript中的$subscribe机制与应用 1. $subscribe 的基本概念与用途在JavaScript编程中,$subscribe通常出现在响应式编程框架或状态管理库中,特别是像RxJS这样的库。它主要用于订阅一个可观察对象(Observable),当这个对象发出新值时,订阅者就能接收到更新。举个例子… · 2026/11/3 15:22:53
Mentor DxDesigner原理图设计参数设置与DRC避坑指南 简介:本资源是一份面向电子设计工程师、EDA初学者及高校相关专业学生的Mentor原理图与PCB协同设计入门教程,聚焦DxDesigner原理图创建、参数配置、页面管理、DRC验证及原理图转Layout打包全流程,解决从零搭建规范项目到工程交付的关键实操问题… · 2026/11/3 15:22:53
智能运维核心技术解析与制造业实践指南 1. 智能运维如何成为企业数字化转型的核心引擎 第一次接触智能运维这个概念是在三年前的一次数据中心故障排查中。当时我们团队花了整整36小时才定位到一个由内存泄漏引发的连锁故障,而事后分析日志发现系统早在故障发生前12小时就出现了异常指标。这件事让我深刻意… · 2026/11/3 15:21:52
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 13:10:28
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 6:04:24
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 5:52:46
STM32F411RE与MAX14431实现SPI隔离:工业现场抗共模干扰实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59
ESP32+大模型AI硬件开发:从Demo到产品的8个工程问题 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59
基于MAX14431BAEE+与PIC18F85J10的SPI隔离方案设计与实践 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 13:10:28
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 6:04:24
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 5:52:46