☰
STM32 TIM1输出PWM全攻略:标准库配置、避坑指南与死区刹车实战
2026/10/5 9:53:09 网站建设 项目流程

最近被问得最多的一个问题:STM32的TIM1明明照着别的定时器例程抄了一遍,引脚上就是测不到PWM波形,是不是芯片坏了?每次遇到这种问题,我基本都能猜到原因——不是芯片坏了,是把TIM1当成普通定时器用了。TIM1和TIM8是高级控制定时器,多出来一堆普通定时器没有的控制逻辑,少配置一步,输出就是静悄悄的。

这篇文章我会用标准库把TIM1输出PWM的完整流程拆开讲,从时钟树、GPIO复用模式到时基配置,再到那个最容易漏掉的主输出使能(TIM_CtrlPWMOutputs),每一步都解释清楚为什么要这么写,最后把我在项目里踩过、以及帮别人排查过的各种坑整理成一篇避坑清单。代码是完整的,直接复制就能跑,适合刚入门的小白,也适合从HAL库转回标准库做电机控制的工程师。

1. 为什么要认真对待TIM1和标准库

1.1 TIM1不是普通的定时器

很多教程讲STM32的PWM输出,会拿TIM2、TIM3举例。这些通用定时器也能输出PWM,配置起来也确实简单。但如果你只会在通用定时器上输出PWM,碰到电机驱动、数字电源这类项目时会很吃力,因为这些应用真正需要的不是“一个方波”,而是一整套波形安全控制机制,那正是TIM1这种高级控制定时器的看家本领。

TIM1和TIM8在STM32里单独归为一类,叫高级控制定时器(Advanced-control timer)。它们比普通定时器多出三样核心硬件能力:

  • 互补输出:同一个PWM信号可以同时输出到两个引脚,一路正相、一路反相,专门用来驱动H桥或者三相桥的上下桥臂。
  • 死区插入:正反两路信号切换的间隙里,自动插入一段两路都为低电平的时间,防止上下桥臂瞬间直通烧管子。
  • 刹车功能:外部故障信号一来,硬件立刻封锁PWM输出,不需要软件干预,响应速度是微秒级的。

普通定时器根本没有这些机制。你想用TIM3模拟互补PWM和死区,靠GPIO翻转加延时是做不出来的,中断延时的抖动足以让功率器件冒烟。所以只要涉及电机功率驱动,基本绕不开TIM1/TIM8。

1.2 这个场景为什么选标准库而不是HAL库

这些年HAL库越来越流行,CubeMX点点点就能生成工程,确实方便。但在TIM1这种高级定时器的配置场景下,我个人还是推荐标准库,原因很直接:

标准库的API基本和寄存器一一对应,每个函数配置哪个位、操作哪个寄存器,看代码一眼就能明白。比如TIM_CtrlPWMOutputs这个函数,操作的就是BDTR寄存器里的MOE(主输出使能)位。而HAL库里这层逻辑被封装得更靠上,很多人出了问题根本不知道往哪查。尤其当你需要精确操作死区时间、刹车极性、锁定级别这些寄存器细节时,标准库写起来更痛快——数据手册里说设置DTG位段,标准库代码就对应TIM_BDTRInitStructure.TIM_DeadTime,一行对一行,不容易绕晕。

另外一个现实原因是存量代码。手头大部分电机控制项目、竞赛代码、老工程师的参考例程,都是标准库写的。现在项目维护、代码移植,还是绕不开标准库。用HAL库重新写一遍,费时费力不说,还容易在移植过程中把时序细节改出错。

1.3 TIM1最常见的三大实际应用场景

TIM1的PWM输出在日常项目里主要分三类用法:

  • 电机调速类:直流电机用单路PWM配合H桥驱动,舵机用50Hz周期PWM控制角度,无刷电机用三组互补PWM做六步换相或者FOC。这类应用占TIM1使用场景的大多数。
  • 信号调制类:驱动无源蜂鸣器发声、LED调光、加热器功率控制。这类场景对占空比精度有一定要求,但对死区和刹车不敏感,属于TIM1的基础用法。
  • 电源变换类:同步Buck、Boost、推挽、半桥/全桥等拓扑,需要两个互补PWM带死区,配合刹车保护,TIM1简直就是为这个设计的。

把这三种场景归纳一下,你会发现它们有一个共同点:不只是要“有波形”,还要波形可靠、可控制、可保护。这也正是TIM1比普通定时器值钱的地方。

2. 标准库配置TIM1 PWM输出,一步一步来

2.1 时钟树:TIM1的72MHz是怎么来的

配置PWM频率之前,先得搞清楚TIM1的输入时钟是多少。以最常见的STM32F103系列为例,系统时钟一般由外部8MHz晶振经过PLL倍频到72MHz。STM32内部有两条外设总线APB1和APB2,APB1最高36MHz,APB2最高72MHz。TIM1挂在APB2上。

这里有个非常容易理解错的地方:APB2预分频器对定时器时钟有自己的一套规则。当APB2分频系数为1(即不分频)时,TIM1的时钟就是APB2的时钟,也就是72MHz。当APB2分频系数大于1时,TIM1内部会自动把APB2时钟乘以2,所以即便APB2被分频到36MHz,TIM1最终拿到的时钟依然是72MHz。

简单记忆:在常见的72MHz主频配置下,不管APB2怎么分频,TIM1的输入时钟基本就是72MHz。F407略有不同,它的APB2最高84MHz,TIM1时钟在分频系数大于1时取APB2的两倍,也就是168MHz。写代码前先确认目标芯片的定时器时钟,后面所有PWM频率计算都基于这个数字。

2.2 GPIO:复用推挽不是推挽

定时器波形通过引脚输出时,必须把引脚配置成复用功能模式。对于F103来说,TIM1_CH1默认复用引脚是PA8,TIM1_CH1N是PB13,CH2是PA9,CH2N是PB14,CH3是PA10,CH3N是PB15,CH4是PA11。这些默认复用映射在绝大多数F103封装上都是固定的,不需要开启重映射。

GPIO的模式要选GPIO_Mode_AF_PP,也就是复用推挽输出,不是普通的GPIO_Mode_Out_PP。这两个模式在标准库里是两个完全不同的配置路径。普通推挽输出模式下,引脚状态由ODR寄存器控制,定时器外设根本接管不了引脚;而复用推挽模式下,引脚控制权才会交给片内外设。很多新手把定时器配置得毫无问题,但GPIO模式选错,引脚始终是死的,自然测不到波形。

另外别忘了打开GPIO的时钟。代码里用到的引脚如果涉及重映射,还要额外开启AFIO时钟。开时钟这件事放在所有配置的最前面,和TIM1时钟一起用RCC_APB2PeriphClockCmd打开。

典型GPIO配置代码段如下:

GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure);

2.3 时基和输出通道:频率、占空比的计算公式

TIM1要输出PWM,需要配置两个核心单元:时基单元(Time Base)和输出比较通道(OC Channel)。

时基单元决定了计数器的计数周期,配置项包括自动重装载值ARR、预分频系数PSC、计数模式和时钟分割。PWM频率的计算公式是:

PWM频率 = TIM时钟 / (PSC + 1) / (ARR + 1)

占空比 = 通道比较值CCR / (ARR + 1)

这里的PSC和ARR都是16位寄存器,取值范围0到65535。举个例子,如果TIM时钟是72MHz,想要输出1kHz的PWM,可以设置PSC=71、ARR=999。计算过程:72MHz除以72再除以1000,正好1000Hz。如果此时CCR=500,占空比就是500/1000,也就是50%。

这里有个细节值得留意:ARR=999时,计数器计数值从0到999,一共1000个计数周期。占空比的分子是CCR的值,不是CCR加一。用公式时注意别把ARR+1和CCR+1混在一起,不然算出来的占空比会差一个计数脉冲,频率高的场景下误差被放大,波形看着总是不对劲。

时基单元的初始化代码如下:

TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_TimeBaseStructure.TIM_Period = arr; // ARR, 自动重装载值 TIM_TimeBaseStructure.TIM_Prescaler = psc; // PSC, 预分频系数 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; // 时钟分割, 一般填0 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数 TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);

输出比较通道负责把计数器和CCR比较的结果映射成引脚电平。PWM模式1的定义是:计数器计数值小于CCR时输出有效电平,大于等于CCR时输出无效电平。如果选择PWM模式2,逻辑正好反过来。电机控制里绝大多数场景用PWM模式1,配合TIM_OCPolarity_High的极性设置,直观理解就是“CCR越大,高电平时间越长,占空比越大”。

2.4 主输出使能:高级定时器和普通定时器的分水岭

TIM1和普通定时器在配置流程上最大的区别就在这里。普通定时器初始化完时基和输出通道,调用TIM_Cmd使能定时器,引脚上就有PWM了。TIM1不行,它还有个叫主输出使能(MOE)的门控位,在BDTR寄存器里。MOE不置1,即使计数器在跑、CCR在变,四个通道的PWM也全都不会送到引脚上。

标准库把这一位封装成了TIM_CtrlPWMOutputs函数:

TIM_CtrlPWMOutputs(TIM1, ENABLE);

这一行是TIM1配置里绝对不能漏的。我排查过的那么多“TIM1没输出”问题里,大概有一半就是漏了这一句。剩下的才是GPIO配置、时钟分频等问题。

和主输出使能一起提的还有预装载功能。TIM_OC1PreloadConfig和TIM_ARRPreloadConfig分别控制CCR1寄存器和ARR寄存器有没有预装载。使能预装载后,修改CCR或ARR不会立刻生效,而是等下一个更新事件(计数器溢出)统一加载。如果不使能预装载,运行中修改CCR可能造成PWM波形中出现一个异常宽或异常窄的脉冲,在电机控制这种场景里是致命的。

2.5 完整可复制代码:初始化加动态调占空比

把上面这些串起来,写一个完整的初始化函数。这个函数传两个参数:arr和psc,分别对应自动重装载值和预分频系数,方便在main里灵活设置频率。

void TIM1_PWM_Init(u16 arr, u16 psc) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; // 1. 开启TIM1和GPIOA的时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1 | RCC_APB2Periph_GPIOA, ENABLE); // 2. 配置PA8为复用推挽输出, 用于TIM1_CH1 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); // 3. 配置时基单元 TIM_TimeBaseStructure.TIM_Period = arr; TIM_TimeBaseStructure.TIM_Prescaler = psc; TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); // 4. 配置输出比较通道为PWM模式1 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable; TIM_OCInitStructure.TIM_Pulse = 0; // 初始占空比为0% TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High; TIM_OC1Init(TIM1, &TIM_OCInitStructure); // 5. 使能预装载, 避免运行中改参数产生毛刺 TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable); TIM_ARRPreloadConfig(TIM1, ENABLE); // 6. 高级定时器特有: 使能主输出 TIM_CtrlPWMOutputs(TIM1, ENABLE); // 7. 启动定时器 TIM_Cmd(TIM1, ENABLE); }

main函数里可以这样动态调整占空比。下面这版是个呼吸灯的效果,占空比从0逐渐加到最大再降回来,实际跑的时候LED亮度会有明显的渐变过程,非常适合第一次验证PWM是否正常工作:

int main(void) { u16 duty = 0; s8 dir = 1; TIM1_PWM_Init(999, 71); // 初始化TIM1, PWM频率为1kHz while (1) { TIM_SetCompare1(TIM1, duty); duty += dir; if (duty >= 999) dir = -1; if (duty <= 0) dir = 1; Delay_ms(3); } }

这里有几个点要提醒一下。TIM_SetCompare1函数实际修改的是TIM1->CCR1寄存器,参数类型是u16,最大值不要超过ARR的值。如果设置的duty大于ARR,输出就会变成常高电平,波形直接失真,别问我怎么知道的。另外,占空比到达0时我把方向标志切回来,但没让PWM彻底关闭,这是因为占空比0和PWM关闭在行为上有一点区别——前者引脚固定低电平,后者引脚可能处于高阻态。在驱动电机时,这两种状态对电路的影响完全不同,实际项目里要根据场景明确区分。

3. 避坑实录:TIM1 PWM高频翻车现场

3.1 没输出,先查这四处

TIM1配置完成后引脚没波形,这是最常见的故障现象。我按排查优先级列一下原因:

  • MOE位没置1。这个前面强调过了,TIM_CtrlPWMOutputs(TIM1, ENABLE)漏掉的话,其他全对也没用。
  • GPIO模式选错。复用推挽AF_PP写成了普通推挽Out_PP,定时器信号没法输出到引脚。
  • 定时器没启动。TIM_Cmd(TIM1, ENABLE)漏掉,计数器根本不跑。
  • 输出通道没使能。TIM_OCInitStructure里的TIM_OutputState没置ENABLE,通道被关着。

这四个问题分别对应BDTR寄存器、GPIO配置、CR1寄存器、CCER寄存器。排查的时候不用凭感觉猜,打开调试器直接看这几个寄存器的值,一目了然。

3.2 频率差一倍或者差很多:时钟倍频规则

现象:明明按公式算好了PSC和ARR,示波器测出来的频率却是理论值的两倍,或者完全对不上。

频率是理论值两倍,大概率是APB2分频器规则没吃透。有的工程里SystemInit被改动过,或者移植代码时把系统时钟配置换了一套,APB2分频系数不是1,定时器时钟自动乘2,频率自然翻倍。这种问题隐蔽性很强,因为从RCC配置代码上看,系统时钟依然是72MHz,但APB2分频路径已经不同。

频率差得离谱,还要检查外部晶振频率。很多开发板用的12MHz晶振,如果SystemInit里的PLL配置是按8MHz写的,实际主频会变成108MHz而不是72MHz,全部外设的时钟基准都会偏。遇到这类问题,先停一下,用示波器测一下MCO引脚输出的系统时钟,确认基准频率没问题,再往下查定时器。

3.3 占空比调了没反应或者波形毛刺多

原因一般出在预装载上。没有使能TIM_OC1PreloadConfig时,修改CCR1会立即生效。如果修改的时机不凑巧,正好赶上计数器跳到CCR附近,PWM脉冲宽度就会出现一个突变的毛刺。在示波器上看,波形整体占空比好像是变了,但某些周期明显异常。

还有一种情况是CCR写错通道了。比如初始化用TIM_OC1Init配的CH1,main里却用了TIM_SetCompare2去改CH2的CCR。这时CH1的占空比当然不会有任何变化。检查这种问题最快的办法,就是在调试器里查看TIM1->CCR1的实际值,确认它跟着你的设置走。

3.4 CH1N互补通道没有波形

TIM1_CN通道表示互补输出通道。很多人想用CH1N输出反向PWM,但只配置了CH1相关的参数,结果PB13引脚上静悄悄。

要输出互补波形,必须明确配置三个点:TIM_OCInitStructure里把TIM_OutputNState置为Enable;PB13这个引脚要初始化成复用推挽输出;MOE位同样要置1。缺任何一个,CH1N都没波形。另外注意,即使只用CH1N不用CH1,CH1对应的输出状态也不一定要关掉,实际项目中一路正相一路反相的互补输出,才是CH1N存在的意义。

初始化代码里需要额外加上GPIOB的时钟和PB13的配置,再把TIM_OutputNState打开。这样CH1N才有正常的互补PWM输出。

3.5 上电瞬间波形乱跳

在一些电机控制项目里,MCU刚上电那几十毫秒,引脚上偶尔会冒出不规则的脉冲,直接把功率管打穿。这种现象多半是初始化顺序问题:先启动了定时器,才去配置输出通道,或者CCR的初值是个垃圾值,还没被重置就已经输出了一拍异常PWM。

标准库推荐的做法是先配置好GPIO、时基、输出通道,把输出状态设为Enable,同时把TIM_Pulse初始化为0,最后再统一使能主输出和定时器。这样从第一拍开始,波形就是可控的。如果涉及功率电路,更稳妥的办法是硬件上加RC延迟,让MCU先稳定运行几百毫秒再让功率级上电。

3.6 调试三板斧:快速定位PWM问题

排查PWM输出,我有三个固定套路,基本能覆盖90%的情况:

  • 先用示波器看引脚有没有波形。如果没有,把引脚临时配置成普通输入,读一下引脚电平是不是悬空或固定电平,能快速判断GPIO是否被正确复用。
  • 用调试器看寄存器。重点看TIM1->CR1的CEN位是不是1,TIM1->BDTR的MOE位是不是1,TIM1->CCMR1的OC1M字段是不是110(PWM模式1)。这三个位置对了,配置基本没问题。
  • 把参数调到最小。PSC设0,ARR设9,定时器时钟按72MHz算,输出就是7.2MHz的方波。这种频率示波器一抓一个准,能快速验证时基和通道链路通不通。等确认链路正常,再把ARR和PSC调到目标值。

4. 进阶玩法:互补输出、死区与刹车

4.1 死区时间是怎么算的

死区时间通过BDTR寄存器(Break and Dead-time register)的DTG位段配置。标准库里面对应的是TIM_BDTRInitStructure里的TIM_DeadTime字段。DTG一共8位,配置分成几种模式,最常用的是DTG[7:5]=000的情况,此时死区时间等于DTG[6:0]乘以tDTS。

tDTS等于定时器时钟周期的整数倍。以72MHz为例,tDTS大约是13.89ns。如果TIM_DeadTime填72,死区时间就是72乘以13.89ns,约等于1微秒。如果DTG的高三位不是000,那对应的是更长的死区范围,公式要查参考手册的表格,实际项目中基本用不到。

死区时间怎么选?太短会失效,太长会增加功耗。驱动IGBT时死区一般取1微秒到3微秒;驱动低压MOSFET的半桥驱动芯片,像IR2104这类,死区取0.5微秒到2微秒比较常见。具体数值还要看栅极电阻、开关速度、寄生电容等因素,不是拍脑袋定的。第一次调试时可以把死区设置得稍微保守一点,用示波器同时看上下桥的Vgs波形,确认没有直通后再逐步减小死区。

4.2 配置CH1和CH1N互补输出的完整步骤

要配置互补输出,需要在前面基础代码上扩展。GPIO方面,除了PA8,还需要初始化PB13为复用推挽输出。输出通道配置里,把TIM_OutputNState置为Enable。

补充的GPIO配置如下:

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure);

通道配置里增加互补输出使能:

TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; // 使能互补输出

然后在初始化过程中调用TIM_BDTRConfig配置死区参数:

TIM_BDTRInitTypeDef TIM_BDTRInitStructure; TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable; TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable; TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_OFF; TIM_BDTRInitStructure.TIM_DeadTime = 72; // 约1us死区(72MHz时钟) TIM_BDTRInitStructure.TIM_Break = TIM_Break_Disable; TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High; TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable; TIM_BDTRConfig(TIM1, &TIM_BDTRInitStructure);

配置顺序上有个讲究:BDTR相关的配置应该在主输出使能之前完成。如果把TIM_CtrlPWMOutputs放在TIM_BDTRConfig前面,某些寄存器位可能被后续配置覆盖,导致保护逻辑没有完全生效。

4.3 刹车保护:异常时自动封锁波形

电机控制里最担心的就是过流。软件上可以通过ADC采样电流,超过阈值就让PWM占空比归零,但软件路径有延迟,中断响应再快也得几十个微秒。TIM1的刹车功能是硬件级的,外部故障信号一到BKIN引脚,输出立刻被封锁,响应速度是纳秒级的,不需要软件参与。

标准库里配置刹车功能,同样在TIM_BDTRInitStructure里。把TIM_Break置为Enable,设置刹车信号的极性,再配置自动输出功能。刹车触发后,输出通道会进入一个由OSSI/OSSR位决定的安全状态,通常配置成输出低电平,让电机停转。

实际项目里,常用一个比较器电路检测母线电流,过流时比较器输出跳变信号接到TIM1_BKIN引脚。硬件上再配合DMA或中断记录故障状态,形成一个完整的保护链路。这就是TIM1区别于普通定时器最有价值的地方,没有刹车功能的话,功率电路的保护只能靠软件硬扛,风险大得多。

4.4 实际项目中的参数选择经验

带互补输出的TIM1 PWM配置,参数选择有一些通用经验可以参考。

频率选择上,直流有刷电机和BLDC的PWM频率一般取10kHz到20kHz,高于人耳可听范围又低于开关损耗爆炸区间。20kHz正好是人耳听觉阈值临界点,很多产品为了静音都选这个值,但这时开关损耗也会相应增加,需要平衡。舵机控制则固定在50Hz,周期20毫秒,脉宽0.5毫秒到2.5毫秒对应不同角度,这是舵机协议本身定义的。

占空比范围方面,驱动半桥芯片时一般不建议让占空比达到100%。很多自举式驱动芯片的自举电容需要靠下桥开通来充电,占空比长时间接近100%,下桥一直关断,自举电容电压会掉下去,上桥驱动就会失效。实际使用中会限制占空比上限在95%左右。这个是典型的实战经验,光看芯片手册不容易想到。

还有一个容易被忽略的参数是GPIO输出速度。PWM频率越高、边沿越陡,对GPIO速度的要求就越高。20kHz以下的PWM用GPIO_Speed_50MHz完全够用,但如果你在搞几百kHz的高频电源,GPIO速度等级设置不当会影响上升沿质量,甚至造成额外的开关损耗。

5. 写在最后的一点体会

用TIM1输出PWM这件事,原理本身并不复杂,难的是把每一个配置环节的因果关系理清楚。我刚开始接触高级定时器时也走了不少弯路,最头疼的就是“看起来都对了但就是没波形”。后来养成了一个习惯:每次配置完新外设,先用最简单的参数验证链路,再逐步叠加功能。比如先让PA8输出7.2MHz的裸PWM,确认没问题后再加死区、加刹车、加互补输出,每一步都验证过再往前走。

最后分享一个实用小技巧:调试PWM和电机控制时,可以把占空比、当前PWM频率、故障标志这些变量通过串口打印出来,配合上位机做实时曲线。尤其是做PID调参那会儿,光靠示波器看波形效率特别低,串口数据配合波形图才能快速看到控制环路的动态响应。这也是我后来在所有电机项目里都保留的一个调试接口。希望这篇东西能帮你少踩几个坑,早日跑出自己满意的PWM波形。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询