在STM32中,除了TIM6 和TIM7这两个定时器,其他的定时器都可以用来产生 PWM 输出。其中高级定时器 TIM1 和 TIM8 可以同时产生多达 7 路的 PWM 输出。
我们先来看高级定时的主要功能
● 16位向上、向下、向上/下自动装载计数器
● 16位可编程(可以实时修改)预分频器,计数器时钟频率的分频系数为1~65535之间的任意
数值
● 多达4个独立通道:
─ 输入捕获
─ 输出比较
─ PWM生成(边缘或中间对齐模式)
─ 单脉冲模式输出
● 死区时间可编程的互补输出
● 使用外部信号控制定时器和定时器互联的同步电路
● 允许在指定数目的计数器周期之后更新定时器寄存器的重复计数器
● 刹车输入信号可以将定时器输出信号置于复位状态或者一个已知状态
● 如下事件发生时产生中断/DMA: ─ 更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发)
─ 触发事件(计数器启动、停止、初始化或者由内部/外部触发计数)
─ 输入捕获
─ 输出比较
─ 刹车信号输入
● 支持针对定位的增量(正交)编码器和霍尔传感器电路
● 触发输入作为外部时钟或者按周期的电流管理
其中就有死区时间可编程的互补输出这个功能,也就是说高级定时器可以很容易的实现互补PWM的输出,实际上也正是如此。
在复用功能的I/O口的表中,我们也可以发现,高级定时器比通用定时器多了几个引脚。这多了的几个引脚就是高级定时器用于输出互补PWM的I/O口了,所以很多参数都不需要我们自己再去设置,都是和高级定时器的另一I/O口共用。所以大体上和生成一个单纯的PWM类似。
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式2
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
TIM_OCInitStructure.TIM_OutputNState= TIM_OutputNState_Enable;
TIM_OCInitStructure.TIM_Pulse =crr; //设置待装入捕获比较寄存器的脉冲值 //初始占空比为1/10
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;
这里就可以看见,和普通的PWM 类似,只是加了个TIM_OCInitStructure. TIM_OCNPolarity 和 TIM_OCInitStructure.TIM_OCNIdleState ,这两个分别是设置互补通道的极性和空闲时输出的极性。另外和普通的PWM不同的,应该就是死区的设置了。
TIM_BDTRInitStruct.TIM_OSSRState = TIM_OSSRState_Enable;
TIM_BDTRInitStruct.TIM_OSSIState = TIM_OSSIState_Enable;
TIM_BDTRInitStruct.TIM_LOCKLevel = TIM_LOCKLevel_1;
//输出比较信号死区时间配置,具体如何设置可参考 BDTR:UTG[7:0]的描述
//这里配置的死区时间为152ns
TIM_BDTRInitStruct.TIM_DeadTime = 11;
TIM_BDTRInitStruct.TIM_Break = TIM_Break_Enable;
//当BKIN引脚检测到高电平的时候,输出比较信号被禁止,就好像刹车一样
TIM_BDTRInitStruct.TIM_BreakPolarity = TIM_BreakPolarity_High;
TIM_BDTRInitStruct.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable;
TIM_BDTRConfig(TIM1, &TIM_BDTRInitStruct);
大体上就是这么个流程,很简单,那么又是否只能通过高级定时器来生成互补的PWM呢,答案肯定是不是的,利用通用定时器当然也可以生成互补的PWM,只不过需要通用定时器两个通道,并且两个通道需要分别设置,在设置时,把两个通道的输出极性和空闲时的极性改成相反,便和高级定时器差不多了,可以输出互补PWM。
进行简单的总结下:
- 首先通用定时器需要用到两个通道,而高级定时器只需要一个通道(另一路是自带的互补通道);
- 其次,对于通用定时器而言,需要将两个通道的输出极性设置相反(或者将PWM的调制模式设置为不同),并而高级定时器不需要。然后,对于通用定时器而言,没有刹车刹车和死区寄存器(TIMx_BDTR),故对于死区的设置是通过设置一个变量DT来设置的,并通过公式来计算设置完成。
- 最后,是对于CCR比较寄存器而言,高级定时器互补共用同一个CCR寄存器,而通用定时器两个通道各需要一个CCR寄存器来设置,此时,可以按照网上教程所述,两个通道的CCR也互补(即相加为ARR),这样,两路输出互补的PWM有着近似相等的占空比,同时当CCR不等于ARR的一半时,在状态转变时,一侧会有一定的延时时间,一定的程度上减少了对于死区变量的依赖性,同时若设置计数模式为中心对齐模式,则依赖性更减少了;而若设置为相同的CCR时,则完全依赖于DT这个死区变量来设置状态转换时的延时,从而防止电路出现短路等情况。而对于占空比的动态调整,通用定时器和高级定时器就没什么区别,可以通过在主函数中,设置CCR变量,通过改变寄存器,从而实现占空比的循环改变;或者另外设置一个变量,再通过TIM_SetCompare()这样的库函数来改变CCR的值,从而把实现改变比较寄存器CCR的值,实现占空比的动态调整。
参考链接
初学者,有错误,欢迎大家指正。