news 2026/10/27 18:06:51

PWM从原理到STM32实战:LED调光与电机调速全解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
PWM从原理到STM32实战:LED调光与电机调速全解析

1. 从一个LED灯说起:PWM到底在干什么

很多人第一次接触PWM,都是在点亮一颗LED的时候。代码里写一句“设置占空比50%”,烧录进去,灯就变成了半亮。再改成20%,灯暗下去;改成80%,灯又亮起来。整个过程没有改电压,没有换电阻,只是让一个GPIO引脚以极快的速度在高低电平之间来回切换,LED的亮度就跟着变了。

这件事第一次看会觉得有点反直觉。电压没变,电流峰值也没变,凭什么亮度会变?答案藏在两个东西里:一是人眼的视觉暂留,二是LED本身的响应速度。人眼对光强的感知有一个积分效应,大概几十毫秒以内的闪烁,眼睛分辨不出来,只会感知到一个平均亮度。如果引脚以1kHz的频率翻转,高电平占一半时间、低电平占一半时间,LED实际导通的时间就是总时间的一半,平均功率也就是满功率的一半,看起来就是半亮。

同样的逻辑放到直流电机上,效果更直观。给电机加一个恒定的5V,它全速转;加2.5V,它慢速转。但很多单片机的GPIO只能输出高或低,没法输出2.5V这种中间电压。PWM就绕开了这个限制:让引脚快速地在5V和0V之间切换,电机因为自身的机械惯性和电感惯性,感受到的是一个平均电压。占空比50%,平均电压就是2.5V,转速就降下来了。

所以PWM的本质,是用时间上的“开关比例”去等效一个模拟量。它不需要DAC,不需要可调电源,只需要一个能快速翻转的GPIO和一个定时器。这也是为什么从LED调光、电机调速、舵机控制、开关电源,到背光调节、加热控制,PWM几乎无处不在。

这篇文章我会把PWM从原理到落地完整走一遍。先讲清楚它为什么能调速、为什么能调光,再拆解频率和占空比这两个核心参数怎么选,然后落到STM32上用定时器输出PWM的实际配置,最后把LED和直流电机两个场景的实操过程、常见坑和排查方法都摊开讲。不管你是刚点亮第一颗LED的新手,还是已经在调电机但总遇到抖动、啸叫、发热的老手,应该都能从里面找到能直接抄的东西。

2. PWM能调速调光的底层逻辑

2.1 平均电压与占空比的关系

PWM波形其实很简单,就是一个方波。一个周期T内,高电平持续的时间记作Ton,低电平持续的时间记作Toff,那么占空比D就是:

D = Ton / T

如果高电平电压是Vcc,低电平是0V,那么一个周期内的平均电压就是:

Vavg = Vcc × D

这个公式是PWM所有应用的根。占空比50%,平均电压就是Vcc的一半;占空比10%,平均电压就是Vcc的十分之一。对于LED,平均电压近似对应平均电流,平均电流对应平均功率,平均功率对应亮度。对于直流电机,平均电压对应电枢两端的等效电压,等效电压决定转速(在负载不变的前提下)。

这里有一个容易被忽略的点:平均电压成立的前提是负载对PWM频率“不敏感”。也就是说,负载的响应速度要慢于PWM频率。LED的响应在微秒级,所以PWM频率要到几百Hz以上,人眼才看不到闪烁;电机的机械时间常数通常在几十毫秒到几百毫秒,所以PWM频率只要几百Hz到几kHz,电机就感受不到逐个脉冲的冲击,只会感受到平均转矩。

反过来说,如果PWM频率太低,比如给LED用10Hz,人眼就会看到明显的闪烁;给电机用10Hz,电机会一顿一顿地转,还会发出明显的噪音。这就是频率选择的第一个约束。

2.2 为什么不是直接调电压

有人会问,既然要调平均电压,为什么不直接用DAC输出一个模拟电压,或者用可调电阻分压?

DAC的问题在于成本和效率。很多单片机没有DAC,或者DAC通道很少。而且DAC输出的是小信号电压,要驱动LED或电机,后面还得加功率放大级,电路复杂、效率低。用可调电阻分压更不现实,电阻上会消耗大量功率,发热严重,效率极低,而且只能手动调,没法用程序控制。

PWM的优势在于:它直接用数字引脚控制功率开关(MOSFET或三极管),开关要么完全导通、要么完全截止,导通时压降很小,截止时电流为零,所以开关本身的损耗非常低,效率可以做到90%以上。这也是为什么开关电源、电机驱动、LED驱动几乎都用PWM而不是线性调节。

2.3 频率和占空比各自决定什么

PWM有两个核心参数:频率和占空比。很多人会把它们混在一起,其实它们管的是完全不同的两件事。

占空比决定“平均量”的大小。占空比越大,平均电压越高,LED越亮,电机越快。这是调速调光的直接手段。

频率决定“开关的快慢”。频率太低,负载会表现出脉冲响应,LED闪、电机抖、有噪音;频率太高,开关损耗增加,驱动电路可能跟不上,EMI也会变差。所以频率的选择要匹配负载特性和驱动能力。

应用场景典型PWM频率原因
LED调光1kHz ~ 20kHz高于人眼闪烁感知,低于驱动电路带宽极限
直流电机调速1kHz ~ 20kHz高于听觉范围可减少啸叫,低于电机驱动响应极限
舵机控制50Hz舵机标准协议要求
开关电源几十kHz ~ 几百kHz提高效率、减小电感体积
加热控制0.1Hz ~ 10Hz热惯性大,不需要高频

这张表不是随便定的,背后是负载的时间常数和系统的损耗权衡。比如电机用1kHz以下,人耳能听到明显的啸叫;用20kHz以上,MOSFET开关损耗和驱动芯片的发热会明显上升。所以10kHz到16kHz是一个常见的折中区间。

3. 频率与占空比怎么选:参数背后的取舍

3.1 频率选择的三个约束

选PWM频率,本质上是在三个约束之间找平衡。

第一个约束是负载响应速度。负载能不能“跟上”PWM的开关。LED响应快,频率可以很高;电机机械惯性大,频率不能太低;热系统惯性更大,频率可以很低。如果频率低于负载的响应带宽,负载就会表现出脉冲行为,而不是平均行为。

第二个约束是人耳和人眼的感知范围。人眼对闪烁的感知大概在几十Hz到几百Hz,所以LED调光频率要高于这个范围,通常1kHz以上就很稳。人耳听觉范围是20Hz到20kHz,电机如果在这个范围内开关,绕组和机械结构会发出啸叫,所以要么低于20Hz(但电机会抖),要么高于20kHz(但损耗增加)。实际工程里常用10kHz到16kHz,刚好在听觉上限附近,既能减少啸叫,又不至于损耗太大。

第三个约束是驱动电路的开关能力。MOSFET有栅极电容,驱动芯片有上升下降时间,光耦有响应延迟。如果PWM频率太高,驱动波形还没建立起来就被切断了,实际占空比会失真,开关损耗也会急剧上升。所以频率不能超过驱动电路的能力上限。

3.2 占空比分辨率的计算

占空比不是无限可调的。它由定时器的计数位数决定。如果定时器是16位,ARR(自动重装载寄存器)最大值是65535,那么占空比的分辨率就是1/65536,约0.0015%。如果ARR设成999,那分辨率就是1/1000,即0.1%。

分辨率决定了你能把亮度或转速调得多细。对于LED调光,人眼对低亮度区的变化更敏感,所以低占空比区需要更高的分辨率。如果分辨率不够,低亮度区会出现明显的跳变,比如从0%直接跳到5%,中间没有过渡。

计算分辨率很简单:

分辨率 = 1 / (ARR + 1)

比如STM32定时器时钟72MHz,预分频PSC=71,那么计数时钟是1MHz。要得到1kHz的PWM频率,ARR = 1MHz / 1kHz - 1 = 999。分辨率就是1/1000,即0.1%。这个分辨率对LED调光够用,对电机调速也够用。

如果要更高分辨率,可以降低PWM频率或者提高定时器时钟。比如同样1MHz计数时钟,PWM频率降到100Hz,ARR = 9999,分辨率就是0.01%。但100Hz对LED来说可能偏低,会有闪烁风险。

3.3 死区与互补输出的场景

在一些电机驱动和开关电源场景里,会用到互补PWM输出,也就是两个通道输出相反的波形,用来驱动H桥的上管和下管。这时候必须插入死区时间,防止上下管同时导通造成直通短路。

死区时间的选择取决于MOSFET的开关速度和驱动电路的延迟。太短了起不到保护作用,太长了会损失有效占空比、增加谐波。一般从几百纳秒到几微秒不等,需要根据具体器件手册和实测波形来调。

STM32的高级定时器(如TIM1、TIM8)支持硬件死区插入,配置BDTR寄存器即可。通用定时器一般不支持互补输出和死区,所以驱动H桥时通常选高级定时器。

4. STM32上输出PWM的完整实操

4.1 定时器与GPIO的对应关系

STM32的PWM输出依赖定时器的比较输出功能。每个定时器有四个独立通道,每个通道可以映射到特定的GPIO引脚。以常见的STM32F103C8T6为例,TIM1的CH1可以映射到PA8或PA9(重映射),TIM2的CH1可以映射到PA0,TIM3的CH1可以映射到PA6。

这里有一个关键点:不是随便一个GPIO都能输出PWM。只有定时器通道对应的引脚才行。所以选引脚的时候要先查数据手册的“引脚复用表”,确认这个引脚有没有定时器通道的复用功能。

以PA8输出PWM为例,PA8对应TIM1_CH1。配置步骤大致是:使能TIM1时钟和GPIOA时钟,把PA8配置为复用推挽输出,配置TIM1的时基和输出比较通道,最后使能定时器。

4.2 时基配置:PSC和ARR怎么算

时基配置决定PWM的频率。公式是:

PWM频率 = 定时器时钟 / ((PSC + 1) × (ARR + 1))

假设STM32F103的系统时钟是72MHz,TIM1挂载在APB2上,时钟也是72MHz。要得到1kHz的PWM频率,可以这样算:

先定PSC。如果PSC=71,那么计数时钟 = 72MHz / 72 = 1MHz。然后ARR = 1MHz / 1kHz - 1 = 999。

所以PSC=71,ARR=999,得到的PWM频率就是1kHz,占空比分辨率是1/1000。

如果要10kHz,可以保持PSC=71,ARR改成99,分辨率变成1/100。也可以PSC=7,计数时钟9MHz,ARR=899,分辨率1/900。两种方案频率一样,但分辨率不同。这就是参数选择时的取舍:频率越高,同样计数时钟下分辨率越低。

4.3 输出比较模式:PWM模式1和模式2的区别

STM32的定时器输出比较有PWM模式1和PWM模式2两种。它们的区别在于有效电平的定义。

PWM模式1:计数器小于CCR时输出有效电平,大于等于CCR时输出无效电平。 PWM模式2:计数器小于CCR时输出无效电平,大于等于CCR时输出有效电平。

如果有效电平设为高,那么PWM模式1下,CCR越大,高电平时间越长,占空比越大。PWM模式2则相反。

实际用的时候,通常选PWM模式1,有效电平设高,这样CCR值直接对应高电平时间,占空比 = CCR / (ARR + 1),直观好算。如果驱动的是低电平有效的电路(比如某些LED驱动芯片的使能脚),可以把有效电平设成低,或者用PWM模式2,效果一样。

4.4 代码实现:从寄存器到HAL库

用寄存器配置TIM1_CH1输出PWM,核心代码大概是这样:

// 使能时钟 RCC->APB2ENR |= RCC_APB2ENR_TIM1EN; RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; // 配置PA8为复用推挽输出 GPIOA->CRH &= ~(0xF << 0); GPIOA->CRH |= (0xB << 0); // 复用推挽,50MHz // 时基配置 TIM1->PSC = 71; TIM1->ARR = 999; TIM1->CCR1 = 500; // 50%占空比 // 输出比较配置 TIM1->CCMR1 &= ~TIM_CCMR1_OC1M; TIM1->CCMR1 |= (0x6 << 4); // PWM模式1 TIM1->CCMR1 |= TIM_CCMR1_OC1PE; // 预装载使能 TIM1->CCER |= TIM_CCER_CC1E; // 使能通道1输出 TIM1->BDTR |= TIM_BDTR_MOE; // 高级定时器需要使能主输出 TIM1->CR1 |= TIM_CR1_ARPE; // ARR预装载 TIM1->CR1 |= TIM_CR1_CEN; // 启动定时器

如果用HAL库,配置会更简洁:

TIM_HandleTypeDef htim1; TIM_OC_InitTypeDef sConfigOC; htim1.Instance = TIM1; htim1.Init.Prescaler = 71; htim1.Init.CounterMode = TIM_COUNTERMODE_UP; htim1.Init.Period = 999; htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim1.Init.RepetitionCounter = 0; HAL_TIM_PWM_Init(&htim1); sConfigOC.OCMode = TIM_OCMODE_PWM1; sConfigOC.Pulse = 500; sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1); HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);

改占空比的时候,直接改CCR1寄存器或者调用__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, value)。value的范围是0到ARR,对应0%到100%。

注意:高级定时器(TIM1、TIM8)必须使能MOE(主输出使能),否则通道不会有输出。这个坑很多人踩过,配置都对了但引脚就是没波形,最后发现是BDTR的MOE位没置1。

5. LED调光实操:从闪烁到平滑亮度

5.1 硬件连接与限流电阻计算

LED调光是最简单的PWM应用。硬件上,LED正极接限流电阻再到电源,负极接单片机引脚(低电平点亮),或者正极接引脚、负极接地(高电平点亮)。两种接法各有优劣。

低电平点亮的好处是单片机引脚的灌电流能力通常比拉电流强,能驱动更大的电流。比如STM32的GPIO灌电流最大25mA,拉电流最大20mA,所以低电平点亮能多带一点。但低电平点亮的逻辑是反的,占空比越大反而越暗,写代码时要注意。

限流电阻的计算:假设电源3.3V,LED正向压降2.0V,目标电流10mA,那么电阻 = (3.3 - 2.0) / 0.01 = 130Ω。取标准值130Ω或150Ω。如果目标电流20mA,电阻 = 1.3 / 0.02 = 65Ω,取68Ω。

这里要注意,PWM调光时LED是断续导通的,平均电流是峰值电流乘以占空比。所以如果按峰值电流算限流电阻,实际平均亮度会比预期低。通常按峰值电流略高于目标平均电流来选,或者直接用示波器测实际波形再调。

5.2 频率选择:为什么1kHz是甜点

LED调光的PWM频率,1kHz是一个很常用的甜点值。原因有几个:

第一,1kHz远高于人眼闪烁感知频率(约100Hz),所以不会看到闪烁。第二,1kHz远低于大多数LED和驱动电路的带宽极限,波形失真小。第三,1kHz下用1MHz计数时钟,ARR=999,分辨率0.1%,足够平滑。第四,1kHz的开关损耗对LED来说可以忽略。

如果频率太低,比如100Hz,虽然人眼可能勉强看不出闪烁,但在快速移动或者用手机摄像头拍的时候,会出现明显的条纹。如果频率太高,比如100kHz,驱动电路的上升下降时间占比变大,实际占空比会偏离设定值,而且EMI会变差。

所以1kHz到5kHz是LED调光的常见区间。如果用的是专用LED驱动芯片,频率还要看芯片的PWM调光脚支持范围,有些芯片支持几十kHz甚至上百kHz。

5.3 占空比渐变实现呼吸灯

呼吸灯的本质是让占空比随时间做周期性变化。最简单的做法是在主循环里写一个for循环,让CCR值从0加到ARR,再从ARR减到0,中间加一个延时。

while (1) { for (int i = 0; i <= 1000; i++) { __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, i); HAL_Delay(1); } for (int i = 1000; i >= 0; i--) { __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, i); HAL_Delay(1); } }

这样呼吸周期大约是2秒。但用HAL_Delay会阻塞CPU,实际项目里更推荐用定时器中断或者RTOS任务来更新CCR值。

呼吸灯的平滑度取决于两个因素:一是占空比分辨率,二是更新频率。分辨率不够,低亮度区会跳变;更新频率太低,亮度变化会卡顿。一般每1ms到10ms更新一次CCR,配合0.1%以上的分辨率,效果就很顺滑。

实操心得:人眼对亮度的感知是非线性的,近似对数关系。所以线性增加占空比,人眼看到的亮度变化是先快后慢。如果想让呼吸灯看起来更均匀,可以对占空比做伽马校正,或者用查表法输出预校正的亮度曲线。这个技巧在高端LED调光里很常用。

6. 直流电机调速实操:从转起来到稳下来

6.1 电机驱动电路的基本结构

单片机GPIO的电流能力通常只有几十毫安,驱动不了直流电机。电机启动电流可能是额定电流的几倍甚至十几倍,所以必须加驱动电路。常见的方案有:

  • 三极管驱动:适合小功率电机,一个NPN三极管加一个续流二极管就行。
  • MOSFET驱动:适合中大功率电机,导通电阻小,效率高。
  • H桥驱动:适合需要正反转的场景,比如L298N、DRV8833、DRV8323等驱动芯片。

不管哪种方案,续流二极管都是必须的。电机是感性负载,断电瞬间会产生反向电动势,没有续流回路的话,这个高压会击穿驱动管。所以二极管要反并联在电机两端,方向是截止方向。

6.2 PWM频率对电机噪音和发热的影响

电机调速的PWM频率选择,比LED要讲究一些。频率太低,电机会有可听啸叫,而且转矩脉动大,低速时可能转不起来。频率太高,MOSFET开关损耗增加,驱动芯片发热,而且电机绕组的集肤效应和涡流损耗也会上升。

实际经验是:1kHz到5kHz区间,电机会有明显的啸叫;10kHz到16kHz区间,啸叫基本听不到,但驱动芯片会温热;20kHz以上,啸叫完全没有,但驱动芯片发热明显,效率下降。

所以常见的折中是10kHz到16kHz。如果对噪音要求极高,可以用20kHz以上,但要选低栅极电荷的MOSFET和强驱动能力的驱动芯片。如果对发热要求极高,可以用1kHz以下,但要接受啸叫和转矩脉动。

PWM频率噪音发热低速性能适用场景
1kHz以下明显啸叫低一般对噪音不敏感、大功率
1k~5kHz有啸叫较低较好普通调速
10k~16kHz轻微中等好常用折中
20kHz以上无较高好静音要求高

6.3 占空比与转速的非线性关系

理论上占空比和平均电压是线性的,但转速和平均电压不是严格线性的。原因有几个:

第一,电机有启动死区。占空比太低时,平均电压不足以克服静摩擦和负载转矩,电机不转。这个死区通常在5%到20%之间,取决于电机和负载。

第二,电机有反电动势。转速越高,反电动势越大,实际电流越小,转矩越小。所以占空比增加到一定程度后,转速上升变缓。

第三,负载特性。如果负载是风扇,转矩随转速平方增加,那么占空比和转速的关系会更陡。

所以实际调电机的时候,不能简单地认为占空比50%就是半速。要用编码器或者测速发电机做闭环,或者至少在实际负载下测一条占空比-转速曲线,用查表法来设定。

实操心得:调电机的时候,先在空载下测一条曲线,再在额定负载下测一条,两条曲线对比就能看出负载对转速的影响。如果应用对转速精度要求高,建议直接上闭环控制,用PID调占空比,而不是开环给固定占空比。

6.4 电机启动与制动中的PWM策略

电机启动时,如果直接给一个较大的占空比,启动电流会很大,可能触发驱动芯片的过流保护。所以常见的做法是软启动:占空比从0慢慢加到目标值,比如用100ms到500ms的斜坡。

制动的时候,如果直接切断PWM,电机会因为惯性继续转,产生反电动势。如果驱动电路支持,可以用短接制动或者反向PWM制动。短接制动是把电机两端短接,反电动势产生的电流形成制动转矩。反向PWM制动是给一个反向的占空比,产生反向转矩,制动更快但电流更大。

这些策略在电机驱动芯片的手册里通常有推荐,实际用的时候要根据电机参数和保护要求来选。

7. 常见问题与排查技巧实录

7.1 PWM没有输出:从时钟到引脚的排查顺序

PWM配置完了但引脚没波形,是最常见的问题。排查顺序建议从时钟开始,一路查到引脚。

第一步,确认定时器时钟使能了。STM32的定时器挂在不同总线上,TIM1在APB2,TIM2~TIM4在APB1。用HAL库的话,HAL_TIM_PWM_Init里会调用__HAL_RCC_TIMx_CLK_ENABLE,但如果是寄存器配置,要手动使能。

第二步,确认GPIO时钟使能了,而且引脚配置成了复用推挽输出。如果配成了普通推挽输出,定时器的波形出不来。

第三步,确认高级定时器的MOE位使能了。TIM1和TIM8需要TIM_BDTR_MOE置1,否则通道输出被强制关闭。

第四步,确认CCR值不是0或者ARR。CCR=0时占空比0%,CCR=ARR时占空比接近100%但可能有一个计数周期的低电平。如果CCR设成了0,引脚一直是无效电平,看起来就像没输出。

第五步,用示波器或者逻辑分析仪看波形。万用表测PWM只能测平均电压,看不到频率和占空比,排查时不够用。

7.2 电机抖动、啸叫、发热的归因

电机抖动通常和PWM频率太低有关。频率低于电机的机械响应带宽时,每个脉冲都会让电机加速减速一次,表现出来就是抖动。提高频率到10kHz以上通常能解决。

啸叫也是频率问题,但更多是听觉范围内的开关频率引起的。1kHz到5kHz最容易听到。提高到16kHz以上,或者降到20Hz以下(但会抖),可以避开。

发热要分情况。如果是驱动芯片发热,可能是PWM频率太高导致开关损耗大,或者驱动电流不够导致MOSFET工作在放大区。如果是电机发热,可能是占空比太高、电流过大,或者频率太低导致电流纹波大、铜损增加。

现象可能原因排查方法解决方向
电机抖动PWM频率太低示波器看频率提高到10kHz以上
电机啸叫频率在听觉范围改变频率试听提到16kHz以上
驱动芯片发热开关损耗大测驱动波形上升下降时间降频或换低Qg MOSFET
电机发热电流纹波大测电流波形提高频率或加电感
低速不转启动死区逐步增加占空比软启动或闭环

7.3 占空比与实际亮度/转速不符的排查

有时候设了50%占空比,但LED亮度明显不是半亮,或者电机转速明显不是半速。原因可能有几个:

一是有效电平搞反了。如果电路是低电平点亮,而PWM配置的是高电平有效,那么占空比50%实际输出的是50%低电平,亮度关系就反了。

二是驱动电路的延迟。如果驱动芯片的上升下降时间占PWM周期的比例较大,实际占空比会偏离设定值。比如周期100us,上升时间10us,那么实际高电平时间会比设定值少10us,占空比偏低。

三是负载的非线性。LED的亮度和电流不是严格线性,电机转速和电压也不是严格线性。这个前面讲过,需要用查表或者闭环来校正。

四是测量方法的问题。万用表测PWM平均电压,如果万用表的带宽不够,读数会偏低。示波器测的时候,探头衰减和耦合方式也会影响读数。

7.4 PWM背光干扰显示的典型场景

用PWM调LCD背光的时候,有时候会出现屏幕上有横纹、闪烁或者颜色偏。这通常是PWM频率和LCD刷新率产生了拍频,或者PWM的开关噪声耦合到了显示信号线上。

解决办法有几个:一是把PWM频率提高到20kHz以上,远离LCD刷新率和人眼感知范围。二是把背光PWM的走线和显示信号线分开,减少耦合。三是在背光驱动电路上加LC滤波,把PWM波形平滑成近似直流。四是如果背光驱动芯片支持,用模拟调光代替PWM调光,彻底避开开关噪声。

这个坑在嵌入式显示项目里很常见,尤其是用ILI9341这类并口屏的时候,背光PWM和SPI或者并口信号线挨得近,很容易互相干扰。

8. 从能用到好用:几个进阶方向

8.1 用DMA自动更新占空比

如果要做复杂的PWM波形,比如呼吸灯的多段曲线、电机的S形加减速,手动在中断里改CCR会比较占CPU。STM32的定时器支持DMA请求,可以在每次更新事件时自动从内存搬一个CCR值到寄存器,实现无CPU干预的波形输出。

配置方法是把CCR的地址设为DMA目标,内存里放一个波形数组,DMA循环模式打开,定时器的更新事件触发DMA传输。这样CPU只需要准备波形数据,剩下的交给DMA和定时器硬件。

这个技巧在LED灯效、电机驱动、音频输出里都很有用,能大幅降低CPU占用。

8.2 互补PWM与死区在电机驱动中的应用

驱动H桥的时候,上下管不能同时导通。用高级定时器的互补输出功能,可以硬件生成一对互补波形,并自动插入死区。这样CPU只需要给一个占空比,硬件负责生成带死区的互补信号,安全又省事。

死区时间要按MOSFET的关断时间和驱动电路的延迟来算。一般取关断时间加一点余量,比如MOSFET关断时间100ns,死区取200ns到500ns。太短了保护不够,太长了损失有效占空比。

8.3 闭环调速:编码器加PID

开环PWM调速的精度受负载、温度、电压影响很大。要稳,就得加编码器做闭环。编码器测转速,和设定值比较,误差经过PID运算,输出PWM占空比。这样负载变化时,PID会自动调整占空比,保持转速稳定。

PID参数整定是个经验活。先调P,让系统有响应但不振荡;再加I,消除稳态误差;最后加D,抑制超调。如果系统惯量大,P和I要小一点;如果要求响应快,P和D可以大一点。实际调的时候用示波器看转速波形,边调边看。

这个方向展开能写很多,但核心就是:PWM提供执行手段,编码器提供反馈,PID提供决策。三者配合,才能从“能转”做到“转得稳”。

8.4 PWM故障保护与监控

在一些安全相关的应用里,PWM输出需要故障保护。比如电机堵转时,电流会急剧上升,如果不及时关断PWM,驱动管和电机都可能烧掉。STM32的高级定时器支持刹车输入(BKIN),检测到故障信号时硬件自动关闭PWM输出,不需要CPU干预。

配置方法是把BKIN引脚接到过流检测电路的输出,使能刹车功能,设置刹车后的输出状态(高阻、低电平或高电平)。这样一旦过流,硬件在几百纳秒内就能关断PWM,比软件中断快得多。

这个功能在电机驱动、开关电源里很关键,属于“平时用不到,用到时救命”的设计。

9. 我个人在实际操作中的几点体会

PWM这个东西,原理简单,但真正用好,细节都在参数选择和场景适配上。我刚开始调电机的时候,觉得占空比50%就是半速,结果实测发现低速区根本不转,高速区又非线性,后来老老实实测了曲线才搞明白。调LED的时候,觉得频率随便设,结果用手机一拍全是条纹,才知道频率和摄像头采样率还有关系。

踩过几次坑之后,我的习惯是:第一,任何PWM应用,先用示波器看波形,确认频率、占空比、上升下降时间都符合预期,再往下调。第二,电机和LED的参数不要凭感觉,实测一条曲线比什么都靠谱。第三,遇到抖动、啸叫、发热,先查频率,再查驱动,最后查负载,这个顺序能解决大部分问题。

还有一个小技巧:如果手头没有示波器,可以用单片机自己的定时器输入捕获功能来测PWM频率和占空比,虽然精度不如示波器,但排查基本问题够用了。这个方法在只有一块开发板的时候特别实用。

PWM的扩展方向很多,从简单的调光调速,到复杂的闭环控制、故障保护、DMA波形生成,每一个方向都有足够的深度可以挖。但不管走多远,核心始终是那个公式:平均量等于峰值乘以占空比。把这个想透了,剩下的都是工程实现的问题。

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

中国RoHS目录扩容至35种:新增23类产品合规指南与供应链排查实操

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

作者头像 李华
网站建设 2026/10/27 18:06:05

车规芯片黄金赛道:OBC与DCDC国产化突破与实战验证

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

作者头像 李华
网站建设 2026/10/27 18:04:52

STC8H BLDC带HALL换相与调速源码解析:从原理到避坑

简介&#xff1a;这份资源面向参加电子设计竞赛或从事电机控制开发的工程师与学生&#xff0c;提供基于STC8H1K28单片机的三相直流无刷电机&#xff08;BLDC&#xff09;驱动完整源码方案&#xff0c;采用带HALL传感器的换相方式&#xff0c;并支持电位器调速与捕捉中断换相&am…

作者头像 李华
网站建设 2026/10/27 18:04:51

AI安全危机:人脸识别错判与RAG知识库投毒的防御之道

今天聊一个让人后背发凉的话题&#xff1a;人脸识别把无辜路人错判成嫌疑人直接送进去&#xff0c;RAG知识库被投毒之后一本正经地输出错误信息。这两件事放在同一天爆出来&#xff0c;我第一反应不是“AI又出 bug 了”&#xff0c;而是“AI 安全危机全面爆发”不是危言耸听。这…

作者头像 李华
网站建设 2026/10/27 18:04:19

2026年Windows系统C盘清理全攻略与优化技巧

1. 为什么2026年的C盘清理需要特别关注&#xff1f;这个问题背后隐藏着三个关键变化&#xff1a;首先&#xff0c;Windows 11 24H2及后续版本采用了新的文件索引机制&#xff0c;传统的磁盘清理工具可能无法识别新型缓存文件&#xff1b;其次&#xff0c;微软从2025年开始强制启…

作者头像 李华
网站建设 2026/10/27 18:04:14

基于Rust与MCP构建AI Agent专用终端:多会话隔离与并发调度实践

1. 从一条命令说起&#xff1a;为什么要给 AI Agent 造一个终端 最早用 Claude Code 的时候&#xff0c;我的工作流其实很原始&#xff1a;开一个终端窗口跑 Claude Code&#xff0c;再开一个窗口手动敲命令&#xff0c;两边来回切。它说"你执行一下 npm run build"&…

作者头像 李华