news 2026/11/3 18:12:09

51单片机步进电机调速系统:从定时器中断到Proteus仿真实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
51单片机步进电机调速系统:从定时器中断到Proteus仿真实战

步进电机这东西,说起来简单,真要把它的调速系统从头搭一遍,坑比想象中多得多。我见过太多人拿着现成的开发板,代码一烧、电机一转,就以为搞定了,结果一到自己要改速度曲线、要换细分、要接不同规格的电机,立马抓瞎。这篇东西就是写给那些不满足于"跑通就行"的人——从51单片机最小系统到驱动电路,从定时器中断调速到Proteus仿真验证,再到原理图设计和报告撰写,我会把整个链条上每个环节的取舍逻辑和实操细节都摊开讲。不管你是刚接触单片机的大二学生,还是工作几年想回头补硬件基础的嵌入式从业者,这套东西都能给你一个能落地、能复现、能讲清楚"为什么"的完整参考。

1. 为什么这个题目值得认真做一遍

1.1 步进电机调速的本质是什么

很多人把"调速"理解成"改一下延时函数的参数",这其实只看到了皮毛。步进电机的转速公式是 n = 60f / (N × m),其中 f 是脉冲频率,N 是转子齿数,m 是拍数。换句话说,调速的本质就是控制脉冲输出的频率。你用延时函数改速度,本质上是在改脉冲周期,但这种方式有个致命问题:CPU在延时期间什么都干不了,一旦系统需要同时处理按键、显示、限位检测,延时法立刻崩溃。

所以真正靠谱的做法是用定时器中断来产生脉冲。定时器每隔固定时间中断一次,在中断里翻转IO口电平,脉冲频率就由定时器的重装值决定。这样CPU的主循环就空出来了,可以去做别的事。这个思路的转变,是从"玩具级"走向"可用级"的分水岭。

1.2 51单片机做这件事的天然优势

有人会问,现在STM32这么便宜,为什么还要用51?我的看法是:51单片机的寄存器少、结构简单,特别适合把底层逻辑吃透。你用STM32的HAL库调一个定时器PWM,可能五分钟就出波形了,但你对定时器怎么计数、怎么重装、中断怎么响应这些事,其实是模糊的。而51不一样,TMOD、TH0、TL0、EA、ET0这几个寄存器摆在那里,你必须搞清楚每一个bit的含义,代码才能跑起来。

另外,51的生态极其成熟。STC89C52RC这颗芯片,资料铺天盖地,Keil C51的编译器稳定得不像话,Proteus里的仿真模型也足够准确。对于学习"脉冲控制"这个核心概念来说,51是最没有干扰项的平台。

1.3 这个项目到底包含哪些交付物

标题里写得很清楚:仿真、程序、原理图、设计报告。这四样东西不是孤立的,它们之间有严格的依赖关系。原理图决定了IO口分配和驱动方案,程序必须按照原理图的引脚定义来写,仿真则是对程序和电路联合验证的手段,设计报告是把整个思考过程沉淀成文档。很多人做项目是"先写代码再补图",最后引脚对不上,返工重来。正确的顺序应该是:需求分析 → 方案选型 → 原理图设计 → 程序编写 → 仿真验证 → 报告整理。

2. 驱动方案选型:从ULN2003到专用驱动芯片

2.1 五线四相步进电机的接线逻辑

市面上最常见的入门级步进电机是28BYJ-48,五线四相,减速比1:64。五根线里有一根是公共端(通常是红线),接正电源,另外四根是相线,分别对应A、B、C、D四个绕组。驱动方式就是按顺序给四个绕组通电,让转子一步步转起来。

这里有个容易搞混的地方:五线四相的"四相"指的是四组绕组,不是四个步距角。28BYJ-48的内部是单极性绕组,公共端接正,四相依次拉低就能导通。如果你拿到的是两相四线的双极性电机(比如42步进电机),接线逻辑完全不同,需要H桥驱动。这个区别在选驱动芯片的时候必须搞清楚,否则芯片选错了,电路怎么调都不转。

2.2 ULN2003驱动芯片的工作边界

ULN2003是一颗达林顿管阵列,内部集成了7组达林顿管和续流二极管,单路最大灌电流500mA。用它驱动28BYJ-48是绰绰有余的,因为这颗电机每相的电流大概在100mA左右。但它的局限性也很明显:

  • 只能灌电流,不能拉电流。也就是说,电机公共端必须接正电源,ULN2003把相线拉低来导通。这个拓扑叫"低侧驱动"。
  • 没有细分功能。ULN2003只能做整步或半步驱动,想要细分必须换专用驱动芯片。
  • 发热明显。达林顿管的饱和压降在1V左右,电流100mA时每路功耗0.1W,四路同时导通就是0.4W,芯片会温热。

如果你只是做课程设计或者入门学习,ULN2003足够了。但如果你想做更平滑的低速运行、更小的振动,就得考虑专用驱动芯片。

2.3 专用驱动芯片的选型对比

芯片型号驱动方式最大电流细分支持供电范围适用场景
ULN2003单极性低侧500mA/路无5-12V28BYJ-48入门驱动
L298N双极性H桥2A/路无5-35V42步进电机整步/半步
A4988双极性H桥2A/路1/16细分8-35V3D打印机、CNC
DRV8825双极性H桥2.5A/路1/32细分8-45V高精度定位
TB6600双极性H桥4A/路1/32细分9-42V大扭矩场景

选型的原则很简单:先看电机类型,再看电流需求,最后看是否需要细分。28BYJ-48配ULN2003是最经济的组合;42步进电机配A4988或TB6600是主流方案。对于51单片机来说,控制信号就是脉冲(PUL)和方向(DIR),专用驱动芯片把这些信号转换成绕组电流,单片机不需要关心换相逻辑。

2.4 驱动电路中的续流与保护

步进电机的绕组是感性负载,断电瞬间会产生反向电动势。如果不加续流回路,这个高压脉冲会击穿驱动管。ULN2003内部已经集成了续流二极管,所以外围不需要额外加。但如果你用分立MOS管搭H桥,必须在每个MOS管旁边反并联一个快恢复二极管。

另外,电源端一定要加去耦电容。电机启停时电流突变很大,会在电源线上产生纹波,干扰单片机工作。我的习惯是在驱动芯片的电源引脚旁边放一个100μF的电解电容和一个0.1μF的陶瓷电容,前者吸收低频波动,后者滤高频噪声。这个细节在很多原理图里被省略,但实际调试时,少了这两个电容,单片机莫名其妙复位的情况会频繁出现。

3. 定时器中断调速的完整实现

3.1 为什么不用延时函数

先看一段典型的延时法代码:

void step_delay(unsigned int t) { while(t--) { _nop_(); _nop_(); } } void motor_run(void) { while(1) { // 正转 P1 = 0x01; step_delay(500); P1 = 0x02; step_delay(500); P1 = 0x04; step_delay(500); P1 = 0x08; step_delay(500); } }

这段代码能转,但问题很明显:step_delay执行期间,CPU被完全占用。如果你想在电机运行的同时扫描按键,按键响应会严重滞后;如果你想动态调整速度,只能改step_delay的参数,但改完之后电机会突然变速,没有平滑过渡。

更严重的是,延时法的速度精度极差。_nop_()的执行时间受编译器优化等级影响,不同优化等级下实际延时可能差好几倍。你算出来是1ms,实际可能是0.7ms或者1.5ms。对于需要精确速度控制的场景,这是不可接受的。

3.2 定时器0的工作模式配置

51单片机的定时器0有四种工作模式,我们用的是模式1(16位定时器)。TMOD寄存器的低四位控制定时器0,配置成模式1的代码是:

TMOD &= 0xF0; // 清除T0的控制位 TMOD |= 0x01; // T0工作在模式1,16位定时器

模式1的计数范围是0~65535,最大定时时间取决于晶振频率。假设晶振是12MHz,机器周期是1μs,那么最大定时时间是65536μs ≈ 65.5ms。对于步进电机的脉冲周期来说,这个范围完全够用。

定时初值的计算公式是:

初值 = 65536 - (定时时间 / 机器周期)

比如要定时1ms,机器周期1μs,初值 = 65536 - 1000 = 64536 = 0xFC18。所以TH0 = 0xFC,TL0 = 0x18。

3.3 中断服务函数里的换相逻辑

换相逻辑放在定时器中断里执行,每次中断切换一个拍。以单四拍为例,通电顺序是A→B→C→D→A:

unsigned char code phase_table[] = {0x01, 0x02, 0x04, 0x08}; unsigned char phase_index = 0; void timer0_isr(void) interrupt 1 { TH0 = 0xFC; // 重装初值 TL0 = 0x18; P1 = (P1 & 0xF0) | phase_table[phase_index]; phase_index++; if(phase_index >= 4) phase_index = 0; }

这段代码里有个细节:P1 = (P1 & 0xF0) | phase_table[phase_index]。为什么要先与0xF0?因为P1口的高四位可能被其他功能占用,直接赋值会破坏高四位的状态。这个操作叫"读-改-写",是51单片机IO口操作的常见手法。

3.4 速度调节的两种策略

速度调节本质上就是改定时器的重装值。有两种策略:

策略一:在中断里动态修改重装值。主循环根据按键输入计算新的定时初值,存到全局变量里,中断服务函数每次重装时从这个变量读取。这种方式的优点是响应快,缺点是如果主循环在修改全局变量时被中断打断,可能出现数据不一致。解决办法是在修改前关中断,修改后开中断。

策略二:改变中断次数分频。定时器保持固定频率中断,比如每500μs中断一次,然后用一个计数器累计中断次数,达到设定值才换相一次。这种方式的优点是速度调节不影响定时器配置,缺点是速度分辨率受限于定时器频率。

我一般用策略一,因为代码更直观。但要注意,定时初值不能太小。如果初值对应的定时时间小于中断服务函数的执行时间,中断会嵌套堆积,系统直接卡死。中断服务函数的执行时间大概在20~30μs左右,所以定时时间最好不要低于50μs。

3.5 加减速曲线的实现思路

直接改速度会导致电机失步,尤其是在加速阶段。正确的做法是加入加减速曲线,让速度逐渐变化。最简单的实现是线性加减速:

unsigned int speed = 30000; // 当前定时初值 unsigned int target_speed = 60000; // 目标定时初值 unsigned int accel_step = 100; // 每次调整的步长 void speed_update(void) { if(speed < target_speed) { speed += accel_step; if(speed > target_speed) speed = target_speed; } else if(speed > target_speed) { speed -= accel_step; if(speed < target_speed) speed = target_speed; } }

这个函数在主循环里每隔一段时间调用一次,速度就会平滑地过渡到目标值。accel_step的大小决定了加速的快慢,太小则响应慢,太大则可能失步。对于28BYJ-48这种小电机,accel_step取100~500比较合适。

4. Proteus仿真中的那些坑

4.1 仿真模型的选取与参数设置

Proteus里的步进电机模型叫"STEPPER MOTOR",有单极性和双极性两种。28BYJ-48对应的是单极性五线四相模型。在元件库中搜索"MOTOR"就能找到。

放置好电机后,双击进入属性设置,有几个参数必须改:

  • Step Angle:28BYJ-48的步距角是5.625°/64,但Proteus模型里通常直接填5.625,因为模型内部不模拟减速箱。
  • Rated Voltage:填5V。
  • Resistance:填50Ω左右,这是绕组的直流电阻。

如果这些参数不对,仿真时电机可能不转,或者转速和实际差很多。

4.2 仿真速度与真实速度的差异

Proteus的仿真速度受电脑性能影响很大。在"System"菜单下的"Set Animation Options"里,可以调整仿真速度。默认设置下,仿真速度可能比真实时间慢很多。如果你发现电机在仿真里转得特别慢,先检查这里。

另外,Proteus对中断的响应不是实时的。它按照事件驱动的方式模拟,定时器中断的触发时刻可能和真实硬件有偏差。所以仿真里跑通不代表硬件上一定没问题,反之亦然。仿真的价值在于验证逻辑正确性,而不是精确的时序。

4.3 驱动电路的仿真连接

ULN2003在Proteus里的模型是"ULN2003A"。连接时注意:

  • 输入端1B~4B接单片机的P1.0~P1.3。
  • 输出端1C~4C接电机的四相线。
  • COM端接电源正极(这是续流二极管的公共端)。
  • GND接电源负极。

电机的公共端(红线)接电源正极。这个连接方式叫"共阳接法",和实际硬件一致。

有个坑要注意:Proteus里的ULN2003模型没有内部续流二极管。如果你直接连感性负载,仿真时可能会出现电压尖峰导致异常。解决办法是在每个输出端和COM端之间手动加一个二极管,方向是输出端为阳极、COM端为阴极。

4.4 仿真中常见的报错与解决

报错信息原因解决办法
"No model specified for U1"元件没有仿真模型换用带仿真模型的元件
"Timestep too small"电路中有振荡或短路检查连线,加去耦电容
电机不转相序错误或驱动信号缺失用示波器查看P1口波形
电机抖动不连续定时初值太小增大定时时间
仿真卡死中断嵌套或死循环检查中断服务函数

Proteus里有个很实用的工具叫"Digital Oscilloscope",可以实时查看IO口的波形。把探头接到P1.0~P1.3上,就能看到四相脉冲的时序关系。如果波形不对,说明程序逻辑有问题,不用怀疑电路。

5. 原理图设计的关键细节

5.1 最小系统的必要外围

51单片机的最小系统包括:晶振电路、复位电路、电源电路。这三样缺一不可。

晶振电路:12MHz晶振加两个30pF瓷片电容,接在XTAL1和XTAL2之间。电容的作用是帮助晶振起振,容值太大会导致起振慢,太小则不稳定。30pF是经过验证的经典值。

复位电路:10μF电解电容加10kΩ电阻,构成上电复位。电容正极接VCC,负极接RST,电阻一端接RST,另一端接GND。上电瞬间电容充电,RST保持高电平约10ms,单片机完成复位。有些设计还会加一个手动复位按键,并联在电容两端。

电源电路:如果用USB供电,5V直接可用。如果用9V电池,需要加7805稳压。7805的输入输出端都要加电容,输入端100μF,输出端10μF。

5.2 IO口分配与引脚定义

这个项目的IO口分配如下:

功能引脚说明
电机A相P1.0接ULN2003的1B
电机B相P1.1接ULN2003的2B
电机C相P1.2接ULN2003的3B
电机D相P1.3接ULN2003的4B
加速按键P3.2外部中断0,按下加速
减速按键P3.3外部中断1,按下减速
正反转切换P3.4普通IO,按下切换方向
启停控制P3.5普通IO,按下启停

P3.2和P3.3用外部中断是为了保证按键响应的实时性。如果用电平扫描,主循环忙的时候可能漏掉按键。外部中断的响应是硬件级的,只要中断没被关闭,一定会响应。

5.3 按键消抖的硬件与软件配合

机械按键按下时会有5~10ms的抖动,如果不处理,一次按下可能被识别成多次。硬件消抖是在按键两端并联一个0.1μF电容,软件消抖是在检测到按键后延时10ms再确认。

我的习惯是硬件加电容,软件加延时,双保险。硬件电容滤掉高频抖动,软件延时确认稳定状态。在外部中断里,延时消抖要谨慎,因为中断服务函数里不宜做长时间延时。更好的做法是中断里只置一个标志位,主循环检测到标志位后再做消抖和逻辑处理。

5.4 PCB布局时的注意事项

如果要把这个设计做成PCB,有几个地方要特别注意:

  • 电机驱动部分和单片机部分要分开布局。电机电流大,走线粗,产生的电磁干扰会影响单片机。两者之间最好用地线隔开。
  • 晶振尽量靠近单片机。晶振走线太长会引入寄生电容,影响起振。
  • 电源走线要粗。电机启动电流可能是额定电流的2~3倍,细走线会导致压降过大。
  • ULN2003的散热焊盘要足够大。如果四路同时导通,芯片会发热,散热不好会触发过热保护。

6. 程序架构与代码组织

6.1 主循环与中断的分工

一个好的程序架构应该是:中断负责实时性要求高的任务,主循环负责逻辑处理和状态更新。在这个项目里:

  • 定时器0中断:负责换相,保证脉冲时序精确。
  • 外部中断0/1:负责按键捕获,保证按键不丢失。
  • 主循环:负责速度计算、加减速曲线更新、状态机切换。

这种分工的好处是,即使主循环里某个函数执行时间较长,也不会影响电机的脉冲输出。中断会按时打断主循环,执行换相逻辑。

6.2 状态机设计

电机的运行状态可以用一个简单的状态机来管理:

typedef enum { STATE_STOP, STATE_RUN, STATE_ACCEL, STATE_DECEL } MotorState; MotorState state = STATE_STOP;

按键触发状态切换,主循环根据当前状态执行相应的动作。比如在STATE_ACCEL状态下,每次循环增加速度值;在STATE_DECEL状态下,每次循环减小速度值。状态机的写法比一堆if-else清晰得多,也更容易扩展。

6.3 速度表的存储与查表

如果要做更精细的速度控制,可以预先算好一张速度表,存在code区(Flash)里,运行时直接查表。比如把速度分成64档,每档对应一个定时初值:

unsigned int code speed_table[64] = { 65000, 64500, 64000, /* ... */ 30000 };

查表法的优点是速度快,不需要实时计算。缺点是占用Flash空间,而且速度档位是离散的。对于51单片机来说,Flash通常有8KB,存一张64项的表完全没问题。

6.4 代码中的常见错误与排查

错误一:中断服务函数没有重装初值。模式1的定时器不是自动重装的,每次中断后必须手动重装TH0和TL0。忘了重装,定时器会从0开始计数,脉冲周期完全乱掉。

错误二:全局变量没有加volatile。中断里修改的全局变量,在主循环里读取时,编译器可能优化成寄存器缓存,导致读到的值不是最新的。加volatile关键字可以强制每次从内存读取。

错误三:中断服务函数执行时间过长。如果在中断里做浮点运算或者调用复杂函数,中断执行时间可能超过定时周期,导致中断嵌套。中断服务函数应该尽可能短,只做必要的操作。

错误四:IO口赋值时没有保护其他位。前面提到的P1 = (P1 & 0xF0) | phase_table[phase_index]就是正确的做法。如果直接P1 = phase_table[phase_index],高四位会被清零,如果高四位有别的功能,就会出问题。

7. 设计报告的撰写要点

7.1 报告的结构与逻辑

设计报告不是流水账,它应该体现你的设计思路和决策过程。一份合格的报告应该包含:

  • 需求分析:要做什么,达到什么指标。
  • 方案论证:为什么选这个方案,有哪些备选方案,各自的优缺点。
  • 硬件设计:原理图、PCB、元件选型。
  • 软件设计:程序流程图、关键代码说明。
  • 仿真验证:仿真结果、波形分析。
  • 问题与解决:遇到了什么问题,怎么解决的。
  • 总结与改进:还有什么不足,后续怎么优化。

其中方案论证是最能体现水平的部分。很多人只写"我选了ULN2003",但不写"为什么没选L298N"。把选型的思考过程写出来,报告的质量立刻上一个档次。

7.2 图表的使用规范

报告里的图表要规范:

  • 原理图要用标准符号,标注元件编号和参数。
  • 流程图要清晰,判断框、处理框、起止框要区分。
  • 波形图要标注时间和幅值刻度。
  • 表格要有表头和单位。

图表的编号要连续,正文中要有引用。比如"如图3-1所示"、"见表4-2"。这些细节看似琐碎,但评审老师一眼就能看出你有没有认真做。

7.3 数据记录与分析

仿真和实测的数据要记录下来,并且做分析。比如:

设定速度档位定时初值理论转速(rpm)实测转速(rpm)误差
1650002.32.24.3%
2600002.52.44.0%
3550002.72.63.7%

有了数据,才能说明你的系统是"可测量、可复现"的。误差分析也能体现你对系统精度的理解。

8. 从仿真到实物的过渡经验

8.1 仿真通过但实物不转的排查顺序

这是最让人抓狂的情况。我的排查顺序是:

  1. 先查电源。用万用表量单片机VCC和GND之间的电压,必须是5V±0.2V。电压不对,后面都不用查。
  2. 再查晶振。用示波器看XTAL2引脚,应该有正弦波,频率12MHz。如果没有波形,检查晶振和电容。
  3. 查复位。量RST引脚电压,正常工作时应该是0V。如果是高电平,单片机一直在复位。
  4. 查IO口输出。写一个最简单的程序,让P1.0每隔1秒翻转一次,用LED或者示波器确认IO口有输出。
  5. 查驱动电路。量ULN2003的输入端和输出端,输入有信号但输出没有,说明芯片坏了或者接反了。
  6. 查电机。用万用表量电机各相的通断,正常应该有几十欧姆的电阻。如果开路,电机坏了。

这个顺序是从简单到复杂,从电源到信号,能快速定位问题。

8.2 电机发热与失步的处理

电机发热通常是电流过大导致的。28BYJ-48的额定电流是100mA左右,如果实测超过150mA,说明驱动电压太高或者限流电阻太小。可以在公共端串一个电阻限流,阻值根据实测电流调整。

失步的表现是电机发出"咔咔"声但不转,或者转几圈后位置偏移。原因通常是加速太快或者负载太大。解决办法是减小accel_step,让加速更平缓;或者降低最高速度,留出扭矩余量。

8.3 提高系统稳定性的几个习惯

  • 电源入口加TVS管。防止浪涌电压损坏芯片。
  • 信号线加磁珠。抑制高频干扰。
  • 电机线双绞。减少电磁辐射。
  • 程序里加看门狗。防止程序跑飞。
  • 关键变量加备份。防止意外复位后状态丢失。

这些习惯在实验室里可能看不出差别,但在实际产品中,往往是稳定性的关键。

9. 这个设计还能怎么扩展

9.1 加入LCD显示当前速度

用1602或者12864液晶显示当前速度档位和转速,操作起来更直观。1602的驱动很简单,8位数据线接P0口,控制线接P2口,网上有大量现成的驱动代码。

9.2 用上位机通过串口控制

51单片机有一个UART,可以通过串口和电脑通信。用Python写一个简单的上位机,通过串口发送速度指令,单片机接收后调整速度。这个扩展能让你理解通信协议的设计和解析。

9.3 升级到闭环控制

开环步进电机最大的问题是不知道有没有失步。加一个编码器或者霍尔传感器,检测实际转速,和设定值比较,用PID算法调整输出,就构成了闭环控制。这是从"能转"到"精确控制"的关键一步。

9.4 换用STM32或ESP32平台

如果51的资源和性能不够用了,可以迁移到STM32或者ESP32。STM32的定时器更强大,支持PWM输出和编码器接口;ESP32自带WiFi和蓝牙,可以做远程控制。但底层原理是一样的,把51上的这套逻辑吃透了,换平台只是改寄存器的事。

我在实际带学生做这个项目的时候发现,那些愿意花时间把定时器中断、换相逻辑、驱动电路这三块彻底搞明白的人,后面学STM32、学电机控制都特别快。反而是那些直接抄代码、只求跑通的人,换个芯片就完全不知道从哪下手。这个项目最大的价值不在于最后那个转起来的电机,而在于你在这个过程中建立起来的对"脉冲控制"和"硬件驱动"的直觉。最后分享一个小技巧:调试步进电机的时候,先把速度降到最低,用眼睛能看清每一步的转动,确认相序正确之后,再逐步提速。这个笨办法能帮你省下大量怀疑人生的时间。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/11/3 18:11:46

PIC18F46K22+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 18:11:36

工业级隔离SPI设计实战:MAX14431与Kinetis KV4x选型布线调试

/* 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 18:11:13

STM32+MAX14431隔离SPI实战:从选型到PCB与驱动全解析

/* 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 18:10:11

飞行汽车电控解析:AURIX与SiC的完整技术版图

/* 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 18:09:23

TM4C123GH6PZ与MAX14431BAEE+的SPI隔离设计实战

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

作者头像 李华