51单片机驱动16x16 LED点阵屏:从硬件设计到代码实现的完整指南 简介本资源是一套完整的基于51单片机的16×16 LED点阵显示控制系统设计资料适用于电子类课程设计、毕业设计及单片机实践入门学习者解决初学者在点阵驱动、字符动态显示与人机交互控制方面的典型工程实现难题。压缩包共53个文件涵盖Proteus仿真工程.dsn/.dbk、Keil源码工程.c/.h/.uvproj、原理图.schdoc、流程图.bmp、物料清单.xlsx、汉字字模提取工具PCtoLCD2002.exe及配套字库、功能演示视频.mp4及详细说明文档.pdf/.txt总大小30.52MB。已有200人下载学习资料结构清晰、模块分工明确——含74HC595驱动、DS18B20温度采集扩展接口、串口通信更新显示内容、独立按键切换闪烁/平移/静止等显示模式并提供完整可运行HEX文件与调试日志大幅降低复现门槛。1. 项目概述从零到一点亮你的16x16点阵最近在整理资料时翻出了一个大学时期的课程设计项目——基于51单片机的16x16点阵显示控制系统。这个项目要求实现学号和姓名的滚动或静态显示麻雀虽小五脏俱全涵盖了从硬件原理图设计、软件流程图绘制、Proteus仿真验证到最终物料清单整理和源代码编写的完整开发流程。对于很多刚接触单片机特别是从51单片机入门的朋友来说这是一个非常经典的练手项目。它能让你把C语言、数字电路、单片机原理这些分散的知识点通过一个看得见、摸得着的“发光”项目串联起来。今天我就把这个项目的完整实现过程结合我当年踩过的坑和后来积累的经验重新梳理一遍希望能给正在做类似课程设计或想深入理解单片机显示控制的朋友提供一个可以直接“抄作业”的详细指南。这个项目的核心目标很明确用最经典的STC89C52单片机驱动一块16x16的LED点阵屏稳定地显示出指定的字符信息比如你的学号“20241152”和名字。听起来简单但里面涉及了行扫描、列驱动、字模提取、动态刷新等多个关键技术点。很多人第一步就卡在硬件连接上点阵屏的行列引脚密密麻麻接错了要么不亮要么显示乱码第二步卡在字模软件的使用和代码移植上第三步则是Proteus仿真时模型参数没设对仿真结果和实物对不上。别担心接下来我会把这些环节一一拆解不仅告诉你“怎么做”更会讲清楚“为什么这么做”以及“怎么做更稳”。2. 硬件系统设计与核心原理剖析硬件是整个系统的基础设计不合理代码写得再漂亮也白搭。对于16x16点阵显示硬件设计的核心在于理解点阵屏的驱动原理和单片机的驱动能力限制。2.1 16x16 LED点阵屏的驱动原理市面上常见的16x16点阵屏内部结构其实就是256个LED按照矩阵排列。它有16个行引脚通常是阳极和16个列引脚通常是阴极或者反过来。每个LED位于某一行和某一列的交叉点上。如果我们想点亮左上角第一个LED就需要给第一行高电平假设行是阳极同时给第一列低电平假设列是阴极这样电流才能形成回路。这里的关键是单片机IO口的电流驱动能力是有限的。以STC89C52为例单个IO口的拉电流输出高电平时向外提供的电流和灌电流输出低电平时向内吸入的电流能力通常都在十几毫安左右。如果我们试图用IO口直接驱动一整行或一整列的LED最多可能同时点亮16个电流会远远超过IO口的承受能力导致端口烧毁或者电压被拉低显示暗淡甚至混乱。因此必须加入驱动电路。最经典、成本最低的方案是使用三极管进行电流放大。对于行驱动阳极通常使用PNP型三极管如8550因为我们需要单片机给出低电平时三极管导通为点阵屏的行提供高电平电压和较大电流。对于列驱动阴极则使用NPN型三极管如8050单片机给出高电平时三极管导通将点阵列拉到低电平。这样单片机IO口只负责提供微弱的控制信号大电流由三极管和电源承担完美解决了驱动能力问题。2.2 系统整体原理图设计要点基于以上原理我绘制了整个控制系统的原理图。核心控制器是STC89C52搭配一个12MHz的晶振和两个30pF的电容组成时钟电路一个10kΩ的上拉电阻和10μF的电容组成复位电路这是51单片机最小系统的标准配置。点阵屏的驱动部分是本设计的重点行驱动电路16个行引脚我使用了4片74HC595串行转并行芯片来驱动。为什么用74HC595因为它只需要单片机3个IO口数据、时钟、锁存就能通过串行方式输出多达8位一片甚至级联后更多位的并行数据极大地节省了单片机宝贵的IO资源。一片74HC595驱动8行两片级联正好驱动16行。74HC595的输出电流能力比单片机IO口强但为了驱动一行可能同时点亮的多个LED我仍然在74HC595的每个输出脚上接了一个限流电阻如220Ω后再去控制一个PNP三极管8550的基极由三极管来提供最终的行驱动电流。列驱动电路16个列引脚我直接使用了单片机的P0口和P2口的一部分共16个IO来控制。但同样不能直接连接点阵列。我在每个IO口和点阵列之间加入了一个NPN三极管8050和基极限流电阻。当IO输出高电平时三极管导通对应的列被拉低有效当IO输出低电平时三极管截止该列被上拉电阻置为高电平无效。P0口内部无上拉电阻所以必须外接10kΩ的上拉电阻排。电源与滤波点阵屏全亮时电流较大电源部分一定要做好。我在单片机电源入口和点阵屏驱动电路电源入口附近都放置了0.1μF和10μF的电容进行滤波以消除电流突变引起的电压波动确保系统稳定。注意原理图中每个三极管的基极限流电阻阻值需要计算。以8050为例假设驱动电流需要100mA三极管放大倍数β约为100那么基极电流Ib约为1mA。单片机IO口高电平电压约4.5V三极管BE结压降约0.7V则限流电阻R (4.5V - 0.7V) / 0.001A 3.8kΩ。为了确保饱和导通通常取更小的值比如1kΩ到2.2kΩ。我在项目中使用了2.2kΩ。2.3 物料清单BOM精讲一份清晰的物料清单是采购和焊接的基础。除了单片机、晶振、电容电阻这些常规元件这里重点提几个容易出错或需要注意的物料单片机STC89C52RCDIP-40封装。务必确认是“RC”版本内部有8K Flash足够本项目使用。也可以使用AT89C52但烧录器不同。点阵屏16x16 LED点阵屏共阳或共阴必须明确。我的原理图是按照行共阳、列共阴来设计的。如果你买到的点阵屏规格书相反那么行、列的驱动逻辑用PNP还是NPN需要全部对调。采购时一定要问清楚或自己用万用表测量确认。三极管PNP型如8550用于行驱动NPN型如8050用于列驱动数量各16个。注意三极管的封装TO-92别买成贴片的了。74HC595DIP-16封装需要4片。注意是74HC595不是74LS595HC系列工作电压更兼容5V系统速度也更快。电阻10kΩ排阻9脚用于P0口上拉1个。10kΩ电阻复位电路1个。2.2kΩ电阻三极管基极限流32个16行16列。220Ω电阻74HC595输出限流16个每个行信号一个。电容30pF瓷片电容晶振负载电容2个。10μF电解电容复位电容1个。0.1μF104和10μF电解电容电源滤波若干。其他12MHz晶振、轻触开关复位用、DIP-40 IC座、排针、万能板或PCB、导线等。3. 软件流程图与核心算法设计硬件是躯体软件是灵魂。控制点阵屏显示软件的核心任务是实现“动态扫描”。3.1 动态扫描算法与流程图所谓动态扫描就是利用人眼的视觉暂留效应在极短的时间内通常每行1-5ms逐行快速点亮点阵屏。在任一时刻实际上只有一行LED被点亮阳极有效但这一行上哪些LED亮则由列数据阴极决定。只要扫描速度足够快比如整个16行扫描一遍在20ms以内人眼就会看到一幅稳定的完整图像。主程序流程图可以这样设计初始化配置定时器、IO口模式将控制行列的IO口设为推挽输出模式效果更佳、初始化显示缓冲区。主循环检查是否需要更新显示内容如切换学号和姓名。调用显示扫描函数。显示扫描函数由定时器中断触发关闭所有行防止切换时的鬼影。从显示缓冲区中取出当前扫描行第i行对应的16位列数据。通过74HC595串行发送当前行选信号只有第i行为高。将列数据输出到P0和P2口。开启行驱动锁存74HC595数据。扫描行索引i加1如果等于16则归零。延时一小段时间1-2ms维持当前行显示。循环。这里的关键是“显示缓冲区”。我们可以在内存中开辟一个二维数组disp_buf[16][2]因为16列需要16个位用两个字节2*816表示。这个数组存储了当前需要显示的完整一帧图像的点阵数据。3.2 字模提取与数据处理我们想要显示“20241152”和名字比如“张三”首先需要把这些字符图形化转换成点阵数据这就是字模。可以使用PC软件如“PCtoLCD2002”来取模。设置参数至关重要点阵格式16x16。取模方式逐列式、从上到下、从左到右。这必须和你的扫描方式匹配我的扫描方式是逐行扫描那么对于每一行我需要知道这一行上所有列的点是亮还是灭。所以取模时软件应该按“逐列”方式生成数据。对于16x16每列有16个点对应2个字节。一个汉字会生成32个字节的数据16列 * 2字节/列。取模走向顺向高位在前低位在前也要统一通常高位代表上面的点。输出格式C语言格式十六进制数组。例如“张”字的点阵数据会得到一个32字节的数组。我们将这些数据按照显示位置填充到disp_buf这个显示缓冲区的对应位置。如果要实现滚动其实就是定期地更新disp_buf中数据的起始偏移量。实操心得取模软件参数设错是导致显示乱码最常见的原因。务必先用一个简单的图形比如一个“心”形测试你的取模方式和扫描代码是否匹配。一个快速验证方法是在代码里将disp_buf全部填充为0xFF如果扫描正确你应该能看到所有LED都微亮。如果全亮或全灭可能是行或列的驱动电平逻辑搞反了。4. Proteus仿真调试与问题排查在动手焊接实物前用Proteus仿真可以验证硬件设计和软件逻辑的正确性节省大量时间和物料成本。4.1 Proteus仿真模型搭建关键步骤元件选择单片机选择“AT89C52”因为Proteus自带的51模型是Atmel的与STC兼容。点阵屏在“Optoelectronics”类别里找到“MATRIX-8x8-RED”我们需要用4个8x8的红色点阵模块拼成一个16x16的。注意放置时将两个模块的行对齐列并排拼成8行16列再将两组这样的结构上下拼接最终形成16行16列。接线时会比较繁琐但这是最接近真实点阵屏内部结构的方法。三极管选择“NPN”和“PNP”通用模型如“2N2222”NPN和“2N2907”PNP。74HC595在“Microprocessor ICs” - “74HC series”中找到。电阻、电容、晶振等基础元件按原理图添加。连线技巧由于拼接点阵屏连线复杂务必使用“网络标号”来简化。比如将第一行的控制线命名为ROW1然后在所有需要连接的地方都放置标号为ROW1的连线它们就在电气上连接了。单片机的P0口需要接上拉电阻在Proteus中可以直接给P0口添加“PULLUP”属性或者放置一个电阻排模型。程序加载双击AT89C52在“Program File”一栏选择你Keil编译生成的.hex文件。将“Clock Frequency”设置为12MHz与你的代码和硬件设计一致。4.2 常见仿真问题与解决方案仿真不成功、显示不正常是常态关键在于排查思路问题一点阵屏完全不亮或部分模块不亮。排查首先检查电源和地是否连接到所有元件。然后重点检查74HC595的级联是否正确。第一片595的串行输出引脚Q7‘要接到第二片的数据输入DS。它们的移位时钟SHCP和锁存时钟STCP要并联。可以用Proteus的电压探针或逻辑分析仪工具测量这些关键引脚是否有信号变化。解决方案确保代码中74HC595的发送函数正确。一个常见的错误是字节发送顺序MSB first还是LSB first与硬件接线不匹配。问题二显示乱码但LED有闪烁。排查这几乎肯定是扫描逻辑和字模数据不匹配。首先简化测试让程序固定显示第一行为全亮。如果第一行亮了但位置不对说明行扫描顺序错了。如果第一行该亮的不亮说明列数据输出逻辑错了。解决方案回顾第3.2节核对取模方式。在代码中将字模数据数组直接打印出来Proteus不支持printf到串口但你可以将数据映射到某个IO口用逻辑分析仪看或者先在实物单片机上用串口打印调试与取模软件生成的对比看顺序是否一致。问题三显示闪烁感严重或有鬼影上一行的残影。排查动态扫描的时序问题。扫描每一行后维持点亮的时间延时太长会导致刷新率过低人眼感到闪烁。如果太短则亮度不足。“鬼影”是因为在切换行选信号时没有先关闭所有行消隐。解决方案调整定时器中断的周期。将每行的显示时间控制在1-2ms左右这样16行扫描一遍就是16-32ms刷新率在30-60Hz基本无闪烁。在更新行选信号和列数据之前先执行一个“消隐”操作即关闭所有行选输出无效电平等新的行列数据都准备好后再同时开启。踩坑记录我在仿真时曾遇到一个诡异问题显示总是错位一位。后来发现我在发送74HC595行数据时是循环16次每次发送1位代表一行。但我的点阵屏是4块8x8拼接的行控制用了4片595。我错误地将第9-16行的数据也发给了控制前8行的两片595导致数据覆盖。正确的做法是将16位行选信号作为一个整体分两次每次8位发送给第一片595通过级联它会自动分配到后级。这个坑让我意识到仿真时不仅要看逻辑更要理解数据在芯片间的流动路径。5. 源代码逐行解析与编程技巧有了正确的硬件和清晰的流程代码就是最后的组装。这里给出核心代码段并解析其背后的设计逻辑。#include reg52.h #include intrins.h // 定义74HC595控制引脚 sbit DS P1^0; // 串行数据输入 sbit SHCP P1^1; // 移位时钟 sbit STCP P1^2; // 锁存时钟 // 定义列数据输出端口P0和P2口低8位 #define COL_DATA_PORT P0 #define COL_DATA_PORT_EXT P2 // 显示缓冲区存放当前要显示的16行数据每行2个字节16列 unsigned char code disp_buf[16][2]; // 字模数据示例“张”的部分数据实际需完整 unsigned char code zm_zhang[] { 0x00,0x40,0x40,0x20,0x10,0x10,0x08,0x08, 0x04,0x04,0x02,0x02,0x01,0x01,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; unsigned char scan_line 0; // 当前扫描行索引 // 向74HC595发送一个字节 void SendByteTo595(unsigned char dat) { unsigned char i; for(i0; i8; i) { SHCP 0; // 时钟拉低 // 先发送最高位(MSB) DS (dat 0x80) ? 1 : 0; _nop_(); SHCP 1; // 时钟上升沿数据移入 dat 1; // 左移一位准备发送下一位 } } // 显示扫描函数由定时器中断调用 void DisplayScan(void) { // 1. 消隐关闭所有行假设行有效为高电平则发送全0 SendByteTo595(0x00); SendByteTo595(0x00); // 发送两个字节因为级联了2片595控制16行 STCP 0; _nop_(); STCP 1; // 锁存数据此时行输出全低 // 2. 准备当前行数据 // 计算行选信号只有当前扫描行为高其余为低 unsigned int row_sel 0x0001 scan_line; // 拆分为两个字节发送给595 SendByteTo595((unsigned char)(row_sel 8)); // 高8位控制第9-16行 SendByteTo595((unsigned char)(row_sel)); // 低8位控制第1-8行 // 3. 输出当前行的列数据 COL_DATA_PORT ~disp_buf[scan_line][0]; // P0口输出低8列数据取反因为列低电平有效 COL_DATA_PORT_EXT ~disp_buf[scan_line][1]; // P2口输出高8列数据 // 4. 开启当前行锁存行选信号 STCP 0; _nop_(); STCP 1; // 5. 维持一段时间控制亮度 DelayMs(1); // 一个简单的延时函数实际应用建议用定时器精确控制 // 6. 更新扫描行 scan_line; if(scan_line 16) scan_line 0; } // 定时器0中断服务函数用于定时刷新显示 void Timer0_ISR() interrupt 1 { TH0 (65536 - 2000) / 256; // 重装2ms定时初值假设12MHz晶振 TL0 (65536 - 2000) % 256; DisplayScan(); // 每2ms扫描一行 } // 主函数 void main() { Timer0_Init(); // 初始化定时器02ms中断一次 EA 1; // 开总中断 ET0 1; // 开定时器0中断 TR0 1; // 启动定时器0 // 初始化显示缓冲区例如显示“张” for(int i0; i16; i) { disp_buf[i][0] zm_zhang[i*2]; // 每行第1个字节左半部分列 disp_buf[i][1] zm_zhang[i*2 1]; // 每行第2个字节右半部分列 } while(1) { // 主循环可以处理按键切换显示内容等任务 // 显示刷新由定时器中断自动完成无需在此干预 } }代码关键点解析消隐的重要性在DisplayScan函数中第一步是发送全0关闭所有行。这是消除“鬼影”的关键。如果不做这一步在更新行选信号的瞬间旧的列数据可能还残留在IO口上导致错误的LED被短暂点亮。行选信号的生成row_sel 0x0001 scan_line;这行代码非常巧妙。它生成了一个16位的变量只有当前扫描行对应的位是1。例如当scan_line0row_sel就是0x0001当scan_line5row_sel就是0x0020二进制第6位为1。这比使用一个16元素的数组来查找要高效得多。列数据取反COL_DATA_PORT ~disp_buf[scan_line][0];这里用了取反操作“~”。因为在我的硬件设计中列引脚低电平时对应的LED点亮共阳点阵列阴极为低有效。而我们的字模数据通常用1表示亮点0表示暗点。所以需要取反将字模数据中的1要点亮转换成IO输出的0拉低阴极。定时器中断刷新将显示扫描放在定时器中断中是保证刷新率稳定的最佳实践。主循环 (while(1)) 可以腾出来处理其他任务如按键扫描、串口通信、更新显示内容等两者互不干扰。定时器初值的计算要准确确保中断间隔时间即每行显示时间合适。字模数据填充在初始化disp_buf时注意字模数组zm_zhang的排列顺序。我假设取模软件生成的32个字节前16个字节是左半部分8列的数据每列2字节中的高字节或低字节需根据取模设置确认后16个字节是右半部分。填充时需要正确对应到disp_buf的[行][左/右]。进阶技巧实现平滑滚动如果要实现文字从右向左平滑滚动不是简单地每隔一段时间移动整个缓冲区。那样会跳变。平滑滚动需要每帧移动一列。我们可以维护一个更大的“画布缓冲区”比如canvas_buf[16][32]里面存放了完整的待显示字符串的点阵数据。然后在定时中断里我们根据一个滚动偏移量offset从canvas_buf中截取16列数据复制到disp_buf。每次中断只将offset加1当offset超过字符串总宽度时归零。这样disp_buf中的内容就会连续变化实现平滑滚动效果。这比直接操作disp_buf进行块移动要更清晰、更节省CPU时间。6. 从仿真到实物的关键过渡与调试Proteus仿真成功只成功了80%。剩下的20%是实物制作中会遇到的各种“玄学”问题。焊接与布线电源线要粗点阵屏全亮时电流可能达到数百毫安电源线太细会导致压降屏幕亮度不均甚至单片机复位。建议使用AWG22或更粗的导线单独为驱动电路供电。地线要共地单片机的地、驱动电路的地、电源的地最终要接到一起形成一个“星型”或单点接地避免噪声干扰。三极管和595芯片方向焊接前再三确认特别是三极管的E、B、C极和595芯片的凹槽方向。焊反了通电可能烧毁元件。上电调试步骤第一步不插芯片测电源。通电用万用表测量所有IC插座和关键点的电压是否为稳定的5V。第二步只插单片机测最小系统。编写一个最简单的程序让一个LED闪烁测试单片机是否正常工作程序能否下载。第三步逐级增加。先只焊接和连接行驱动电路74HC595和三极管不接点阵屏。写程序让595循环输出一个走马灯信号用逻辑分析仪或示波器甚至可以用LED加电阻在595输出脚测量看信号是否正确。同理测试列驱动电路。第四步接上点阵屏低压测试。可以用一个可调电源先将电压调到3V左右接上点阵屏。运行一个最简单的全亮程序观察电流是否在预期范围内屏幕是否均匀发光。没问题再升至5V。常见实物故障排查整行/整列不亮检查对应行或列的控制线是否虚焊、断路。检查该路上的三极管或限流电阻是否损坏。显示重影/交叉通常是上下或左右两块8x8模块的行列线接反了。仔细检查拼接点阵屏时行线R1, R2...和列线C1, C2...的对应关系。单片机频繁复位电源功率不足或滤波不良。检查电源适配器额定电流是否足够建议1A以上。在单片机VCC和GND引脚最近处增加一个100μF的电解电容并联一个0.1μF的瓷片电容。亮度不足检查限流电阻是否过大。行驱动三极管是否工作在饱和区基极电流是否足够。可以尝试减小行限流电阻如从220Ω降到100Ω或增大三极管基极电阻确保饱和。最终优化亮度调节可以通过改变定时器中断的周期即每行点亮时间来调节整体亮度。时间越长越亮但刷新率会降低需要平衡。省电设计如果显示内容不变可以让单片机在空闲时进入空闲模式或掉电模式由定时器中断唤醒进行扫描可以大幅降低功耗。增加功能加入红外遥控如HS0038接收头或蓝牙模块如HC-05就可以远程切换显示内容让项目更具实用性。这个基于51单片机的16x16点阵显示项目虽然基础但贯穿了嵌入式开发从设计、仿真、编程到调试的全过程。它像一把钥匙帮你打开了单片机世界的一扇门。当你看到自己的学号和名字在亲手搭建的屏幕上稳定亮起时那种成就感是看一百遍教程也无法替代的。希望这份超详细的复盘能帮你避开我当年走过的弯路更顺畅地完成这个有趣的项目。记住硬件调试需要耐心软件逻辑需要严谨两者结合方能成功。本文还有配套的精品资源点击获取

相关新闻

最新新闻

晶体管检测仪示波器功能实战指南:从原理到故障诊断

晶体管检测仪示波器功能实战指南:从原理到故障诊断

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

2026/9/3 2:29:45
高质量古诗词数据集构建与应用:从数据清洗到大模型训练实战

高质量古诗词数据集构建与应用:从数据清洗到大模型训练实战

简介:本资源是一套面向大语言模型(LLM)训练与古诗文领域微调的高质量中文古诗词数据集,覆盖先秦至现代逾两千年的经典文本,专为AI研究人员、NLP工程师及古典文学数字化实践者设计,解决古诗数据噪声多、格式…

2026/9/3 2:29:45
用Python拆解无畏契约选手转会:从数据分析看AG复仇者联盟能否撼动EDG

用Python拆解无畏契约选手转会:从数据分析看AG复仇者联盟能否撼动EDG

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

2026/9/3 2:29:45
Maya 2026 官方正版安装与配置全指南:从系统准备到问题排查

Maya 2026 官方正版安装与配置全指南:从系统准备到问题排查

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

2026/9/3 2:29:45
51单片机Proteus+Keil联合仿真实战指南

51单片机Proteus+Keil联合仿真实战指南

简介:本资源是一套面向单片机初学者与嵌入式开发者的C51综合实践仿真学习包,涵盖300个基于Proteus平台的完整可运行设计案例,覆盖定时器、中断、I/O扩展、ADC/DAC、LCD/LED显示、串口通信、温度传感、PWM控制等核心知识点,适用于课…

2026/9/3 2:29:45
录制回放优化:解决JSON体积、卡顿与安全三座大山

录制回放优化:解决JSON体积、卡顿与安全三座大山

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

2026/9/3 2:24:45