高级定时器没有输出PWM有以下几个方面:
- 如果采用更新中断翻转电平输出PWM,那么需要检查是否进入更新中断、中断配置是否配置正确和外设时钟是否正常打开;
- 如果使用PWM模式,一般出现在IO复用功能和重映射上。如果没有使用IO的复用功能,那么它是不可能被定时器外设所驱动的。而如果你的IO不是该定时器默认的输出IO,那么就需要进行重映射。F1和F4的重映射机制如下:
STM32F1
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); // 开启复用时钟
GPIO_PinRemapConfig(GPIO_FullRemap_TIM2, ENABLE); // 开启TIM2全部重映射
STM32F4
GPIO_PinAFConfig(GPIOD, GPIO_PinSource12, GPIO_AF_TIIM4);
对比了F1和F4的重映射,可以看出F4的重映射直接与GPIO绑定,并且不需要开启外设时钟。但是F1重映射分为部分映射,全映射,还可能部分映射2
如何确定这些映射对应哪些引脚?
这时,我们应该打开相应的参考手册,找到GPIO这个章节,AFIO小节,找到定时器部分,可以查看所有定时器的IO映射关系。
从图中可以看出:
1)如果不开启重映射(没有重映射),定时器2默认输出 IO为:PA0、PA1、PA2、PA3。
2)部分重映射1 :PA15、PB3、PA2、PA3。
3)部分重映射2:PA0、PA1、PB10、PB11。
4)完全重映射:PA15、PB3、PB10、PB11。
从中我们也可以看到另一坑,那就是可能端口换了,而你的时钟并打开,导致初始化失败。
- 高级定时器的坑
1. 如果想要高级定时器输出脉冲,在配置高级定时器时增加一条语句
TIM_CtrlPWMOutputs(TIM8, ENABLE);
如果没有此函数,高级定时器的PWM功能是无法正常输出的。接下来测试做一下测试,使用相同的初始化函数,参数传递一样的情况下,定时器8可以正常输出,而定时器1却无法输出,这是怎么回事?在认真的。经过多方检查,一步一步的排查,最后发现是:把串口初始化函数屏蔽了。试了之后,发现定时器真的有输出了。
2. 为什么串口还能干扰到定时器的输出?
1. 这个时候就要说一说我们的栈了,关于栈的话题,基本上都是栈溢出,但是事实上,还有一个容易忽视的话题,栈值不确定。
2. 调用一个函数时会进行压栈操作(用于保存寄存器的值),同时如果函数有局部变量,也可能会从栈中自动分配内存。
因为局部变量用完就销毁,不会占用RAM资源,所以很多时候我们会选择局部变量。
在使用局部变量时,如果使用不规范就会导致问题的发生。
3. 现在解释一下,为什么串口会影响高级定时器的输出,而其他普通定时器并没有受影响?
当串口函数执行时,使用的栈空间比较大,而在定时器函数执行时,刚好使用了这部分已被修改的栈空间,并且使用时没有初始化它,导致出现了问题。
那为什么屏蔽了串口就没有问题?
那是单片机开始运行时,__main函数会将栈空间全部清0,如果不运行串口函数,那么栈中的脏数据就不会很多,那么定时器函数的局部变量即使不初始化,也可认为是0,而正是定时器需要的默认值。
那普通定时器什么不会被影响?拿TIM_TimeBaseInitTypeDef 结构体来举例。
基本定时器一般会初始化这几个变量,但是你查看该结构体的定义时你会发现:
该结构体还有一个变量是专为高级定时器准备的,你并没有对它进行初始化,此时它可能是任何值,并会直接赋值给高级定时器的寄存器中。
所以为了解决这个问题,有两个方法。
1. 使用库函数提前初始化局部变量:
2. 直接在初始化时,将结构体成员变量都初始化一遍,确定没有任何一个遗漏:
推荐使用第二种办法,这样高级定时器和普通定时器的代码可以统一,也能更直观的看出函数提供的功能。