4. PWM常见故障1:无波形输出——时钟使能、GPIO复用功能、定时器未启动排查
各位做嵌入式开发的同行,PWM无波形输出这个故障,我敢说十个新手有八个都遇到过。我自己刚用STM32那会儿,也在这个坑里爬了好一阵子。今天咱们就把这个问题的三个核心排查点掰开揉碎了讲清楚。
4.1 故障现象与排查思路
你配置好了定时器,写好了PWM初始化代码,信心满满地接上示波器——结果呢?引脚上啥也没有,一条直线。这时候别慌,先理清思路。
无波形输出,说白了就三个层面的问题:
- 时钟没给到——定时器根本没工作
- 引脚没配置对——GPIO没切换到复用功能
- 定时器没启动——寄存器配置了但没让定时器跑起来
我一般按这个顺序排查,效率最高。下面咱们一个一个来看。
核心排查顺序:时钟使能 → GPIO复用配置 → 定时器启动
这个顺序不是随便排的。时钟是基础,时钟没开后面全白搭;GPIO配置错了波形出不来;定时器没启动,前面配置得再好也没用。
4.2 时钟使能——最容易忽略的第一步
很多人上来就配置定时器的ARR、CCR,结果忘了开时钟。你想想看,定时器本身也是外设,没时钟它怎么工作?
STM32的定时器挂在不同总线上:
| 定时器类型 | 挂载总线 | 时钟使能函数 |
|---|---|---|
| TIM1、TIM8 | APB2 | RCC_APB2PeriphClockCmd() |
| TIM2~TIM7 | APB1 | RCC_APB1PeriphClockCmd() |
| TIM9~TIM14 | APB2 | RCC_APB2PeriphClockCmd() |
我见过最典型的错误:用TIM3输出PWM,结果写的是RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM3, ENABLE)。TIM3挂在APB1上,你用APB2的使能函数,时钟根本开不了。
避坑指南:我曾经在一个项目里排查了半小时,最后发现是时钟使能写错了总线。记住:TIM1/TIM8在APB2,其他基本定时器在APB1。拿不准的时候,去参考手册的时钟树那一章看一眼。
正确的写法应该是:
// 以TIM3为例,挂在APB1上
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
// 如果是TIM1,挂在APB2上
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
4.3 GPIO复用功能配置——波形出不去的关键
时钟开了,定时器配置了,但波形还是出不来?大概率是GPIO没配好。
STM32的GPIO引脚默认是普通IO模式。你要输出PWM,必须把引脚切换到复用功能(AF)模式。而且不同定时器的通道对应不同的引脚,这个得查数据手册。
举个例子,TIM3的通道1(CH1)输出PWM,对应的引脚是PA6:
GPIO_InitTypeDef GPIO_InitStructure;
// 使能GPIOA时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
// 配置PA6为复用推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 注意:部分STM32型号还需要配置AFIO或GPIOx_AFRL/AFRH寄存器
// 例如STM32F4系列需要设置GPIO_PinAFConfig()
个人经验:我习惯在配置GPIO时,先确认三件事:①引脚号对不对 ②模式是不是复用推挽(AF_PP) ③有没有遗漏AFIO时钟使能。F1系列有些引脚需要开启AFIO时钟,这个很容易忘。
常见GPIO配置错误汇总:
- 模式选错:用了
GPIO_Mode_Out_PP(普通推挽)而不是GPIO_Mode_AF_PP(复用推挽) - 引脚号不对:比如TIM3_CH1是PA6,你配成了PA7
- AFIO时钟遗漏:STM32F1系列重映射引脚时需要开启AFIO时钟
- 复用功能未映射:F4/F7/H7系列需要调用
GPIO_PinAFConfig()指定复用功能编号
4.4 定时器未启动——配置了不等于运行了
时钟开了,GPIO配好了,波形还是没有?嗯,这里要注意:你配置了定时器的ARR、PSC、CCR,但定时器还没开始计数呢。
很多人写完初始化代码就以为完事了,其实还差最后一步——让定时器跑起来。
// 使能定时器,开始计数
TIM_Cmd(TIM3, ENABLE);
// 如果需要,还可以使能主输出(高级定时器TIM1/TIM8需要)
TIM_CtrlPWMOutputs(TIM1, ENABLE);
这里有个坑:TIM1和TIM8是高级定时器,除了调用TIM_Cmd()之外,还得调用TIM_CtrlPWMOutputs()使能主输出。我刚开始用TIM1的时候,就因为这个函数没调,折腾了一下午。
定时器启动检查清单:
- 调用了
TIM_Cmd()使能计数器 - 高级定时器(TIM1/TIM8)额外调用了
TIM_CtrlPWMOutputs() - 检查了TIM_SR寄存器中的UIF位,确认定时器确实在跑
- 用示波器或逻辑分析仪测量引脚,别光靠眼睛看LED亮度
4.5 完整排查流程总结
说了这么多,咱们把整个排查流程串起来。下次遇到PWM无波形输出,按这个步骤来:
| 步骤 | 检查项 | 常见错误 | 验证方法 |
|---|---|---|---|
| 1 | 定时器时钟使能 | 总线选错、遗漏使能 | 读RCC寄存器,或加断点看时钟状态 |
| 2 | GPIO复用配置 | 模式选错、引脚不对、AFIO遗漏 | 检查GPIOx_CRL/CRH或MODER寄存器 |
| 3 | 定时器参数配置 | ARR/PSC/CCR值异常 | 读TIMx_ARR、TIMx_PSC、TIMx_CCR寄存器 |
| 4 | 定时器启动 | 遗漏TIM_Cmd、高级定时器缺主输出使能 | 读TIMx_CR1的CEN位 |
| 5 | 硬件连接 | 示波器探头没接好、引脚虚焊 | 用万用表测引脚电平,或用逻辑分析仪抓 |
最后提醒一句:别一上来就怀疑硬件。我见过太多人,波形出不来第一反应是“芯片坏了”,结果查了半天发现是软件里少写了一行TIM_Cmd()。先软件后硬件,按顺序排查,90%的问题都能自己搞定。