写这篇文章是为了对最近学习无刷电机FOC的一些学习心得进行记录,本文基于STM32F407标准库函数编写。

TIM时钟频率

知道TIM的时钟频率是相当重要的,这关系到定时器计数周期和预分频器的值怎么给。这里使用高级定时器TIM1作为PWM输出,在STM32F407中TIM1是挂在APB2总线上,TIM1的时钟频率与APB2总线分频系数有关,若APB2总线分频系数为1,那么TIM1时钟频率为APB2的时钟频率,若APB2总线分频系数不为1,那么TIM1时钟频率为APB2的时钟频率的2倍。而挂在APB1总线上的TIM2也是同理。

如果使用的是默认设置,那么APB1总线时钟为4分频即42M,APB2总线时钟为2分频即84M,即TIM2时钟频率为84MHZ,TIM1时钟频率为168MHZ。

定时器初始化

STM32F407单片机定时器初始化与F103系列相比变化不大。其主要流程如下:
1.TIM时钟初始化
2.GPIO初始化
与f103系列不同,f4系列GPIO初始化时把GPIO口的复用、输入/出、上/下拉分开了,需要单独设置,且f4系列GPIO速度最大为100MHZ。
3.GPIO复用映射
在f103系列中,TIM1输出PWM的默认IO口为PA8、PA9、PA10、PA11,如果要使用PE9、PE11、PE13、PE14作为PWM的GPIO口输出,需要打开AFIO时钟,设置完全映射或部分映射。
但在f407系列中则取消了默认IO口,无论是使用PA口作为PWM输出,还是使用PE口,都需要使用GPIO_PinAFConfig(GPIOx,GPIO_PinSourcex,功能(比如定时器1GPIO_AF_TIM1,串口GPIO_AF_USART1))函数进行设置。
4.定时器初始化
5.定时器OC初始化
6.定时器PWM使能

代码

#include "stm32f4xx.h"                  // Device header

#define FOC_PWM_RCC 				RCC_APB2Periph_TIM1//TIM时钟
#define FOC_PWM_GPIO_RCC 			RCC_AHB1Periph_GPIOE//GPIOE时钟
#define FOC_PWM_GPIO 				GPIOE
#define FOC_PWM_GPIO_CH1 			GPIO_Pin_9
#define FOC_PWM_GPIO_CH2 			GPIO_Pin_11
#define FOC_PWM_GPIO_CH3 			GPIO_Pin_13
#define FOC_PWM_GPIO_CH1_PS   		GPIO_PinSource9
#define FOC_PWM_GPIO_CH2_PS   		GPIO_PinSource11
#define FOC_PWM_GPIO_CH3_PS   		GPIO_PinSource13
#define FOC_PWM_TIM 				TIM1
#define FOC_PWM_GPIO_AF				GPIO_AF_TIM1
#define FOC_PWM_TIM_Period			8400-1							//计数周期,即ARR值
#define FOC_PWM_TIM_Prescaler		1 - 1							//预分频器,即PSC的值
#define FOC_PWM_TIM_Mode			TIM_OCMode_PWM2
#define FOC_PWM_TIM_CounterMode 	TIM_CounterMode_CenterAligned1

void PWM_Init(){
	
	RCC_APB2PeriphClockCmd(FOC_PWM_RCC,ENABLE);

	RCC_AHB1PeriphClockCmd(FOC_PWM_GPIO_RCC,ENABLE);
	
	//将PE9、PE11、PE13设置为复用推挽输出,下拉模式
	//在硬件上一个PWM控制一个桥臂,即一个PWM输出口同时连接到栅极驱动芯片的HO和LO
	//PWM为高电平时上管打开下管关闭,PWM为低电平时上管关闭下管打开
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF;//复用
	GPIO_InitStruct.GPIO_OType=GPIO_OType_PP;//推挽输出
	GPIO_InitStruct.GPIO_Pin=FOC_PWM_GPIO_CH1|FOC_PWM_GPIO_CH2|FOC_PWM_GPIO_CH3;
	GPIO_InitStruct.GPIO_PuPd=GPIO_PuPd_DOWN;//下拉
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_100MHz;
	GPIO_Init(FOC_PWM_GPIO,&GPIO_InitStruct);
	
	TIM_InternalClockConfig(FOC_PWM_TIM);
	
	GPIO_PinAFConfig(FOC_PWM_GPIO, FOC_PWM_GPIO_CH1_PS, FOC_PWM_GPIO_AF); 
	GPIO_PinAFConfig(FOC_PWM_GPIO, FOC_PWM_GPIO_CH2_PS, FOC_PWM_GPIO_AF);
	GPIO_PinAFConfig(FOC_PWM_GPIO, FOC_PWM_GPIO_CH3_PS, FOC_PWM_GPIO_AF);
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;				//定义结构体变量
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;     //时钟分频,选择不分频
	TIM_TimeBaseInitStructure.TIM_CounterMode = FOC_PWM_TIM_CounterMode;
	TIM_TimeBaseInitStructure.TIM_Period = FOC_PWM_TIM_Period ;                 //计数周期,即ARR的值
	TIM_TimeBaseInitStructure.TIM_Prescaler = FOC_PWM_TIM_Prescaler;            //预分频器,即PSC的值
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;            //重复计数器
	TIM_TimeBaseInit(FOC_PWM_TIM, &TIM_TimeBaseInitStructure);      
	
	TIM_OCInitTypeDef TIM_OCInitStructure;							
	TIM_OCStructInit(&TIM_OCInitStructure);
	TIM_OCInitStructure.TIM_OCMode = FOC_PWM_TIM_Mode;              //输出比较模式,选择PWM模式1
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;       //输出极性
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;   //输出使能
	TIM_OCInitStructure.TIM_Pulse = 0;
	
	TIM_OC1Init(FOC_PWM_TIM, &TIM_OCInitStructure); 
	TIM_OC2Init(FOC_PWM_TIM, &TIM_OCInitStructure); 
	TIM_OC3Init(FOC_PWM_TIM, &TIM_OCInitStructure);

	TIM_CtrlPWMOutputs(FOC_PWM_TIM,ENABLE);
	
	TIM_Cmd(FOC_PWM_TIM, ENABLE);			//使能定时器
}
void PWM_Channel1(int Compare)
{
	TIM_SetCompare1(FOC_PWM_TIM, Compare);
}

void PWM_Channel2(int Compare)
{
	TIM_SetCompare2(FOC_PWM_TIM, Compare);
}

void PWM_Channel3(int Compare)
{
	TIM_SetCompare3(FOC_PWM_TIM, Compare);
}

PWM频率计算

在上述TIM初始化过程中,需要注意几个参数:TIM_Period (计数周期,即ARR的值)、TIM_Prescaler(预分频器,即PSC的值)、TIM_CounterMode (TIM计数模式)、TIM_OCMode(PWM输出比较模式)、TIM_OCPolarity(输出极性),CCR(通过TIM_SetComparex设置,比较值)
TIM_Period 、TIM_Prescaler和CCR决定了TIM输出PWM的频率,其计算公式如下:
PWM频率=168MHZ(ARR+1)(PSC+1) PWM频率= \frac{168MHZ}{(ARR+1)(PSC+1)} PWM频率=(ARR+1)(PSC+1)168MHZ
PWM占空比=CCR(ARR+1)(与PWM输出模式,计数模式有关) PWM占空比= \frac{CCR}{(ARR+1)} (与PWM输出模式,计数模式有关) PWM占空比=(ARR+1)CCR(与PWM输出模式,计数模式有关)

PWM的工作原理

TIM_CounterMode有三种模式:向上计数模式、向下计数模式、中央对齐模式123
以向上计数模式为例:
在这里插入图片描述
定时器从0开始计数,每记一次CNT(计数器当前值)加1,在计数过程中,STM32硬件会不断地将CNT的值与CCR的值进行比较,当CNT的值与CCR的值相等时GPIO口电平翻转,当CNT加到ARR值时CNT置为0重新开始计数。

TIM_OCMode有两种模式:PWM模式1和PWM模式2。
PWM模式1:无论向上计数还是向下计数,一旦CNT<CCR时通道为有效电平,否则为无效电平
PWM模式2:无论向上计数还是向下计数,一旦CNT<CCR时通道为无效电平,否则为有效电平;

TIM_OCPolarity有两种模式:TIM_OCPolarity_High和TIM_OCPolarity_Low,这决定了有效电平是高电平或者低电平。
TIM_OCPolarity_High:有效电平为高电平,无效电平为低电平。
TIM_OCPolarity_Low:有效电平为低电平,无效电平为高电平。

例如,将ARR设为84-1,PSC设为100-1,TIM_OCMode为PWM模式1,TIM_CounterMode为向上计数模式,TIM_OCPolarity为TIM_OCPolarity_High,CCR为60。

这样PWM频率=168MHZ84∗100=20000=20KHZ PWM频率= \frac{168MHZ}{84*100} =20000=20KHZ PWM频率=84100168MHZ=20000=20KHZ
由于PSC设为100-1,所以在CNT从0计数到100的过程中,CNT的值会与CCR(60)的值进行比较,当
CNT<CCR时,PWM为模式1,通道为有效电平,为高电平,当CNT>CCR时,通道为无效电平,为低电平。当CNT计数到100时,此时CNT会立刻清0,此时CNT<CCR,GPIO口重新由低电平翻转为高电平。在CNT计数到100的过程中,从0加到60都为高电平,因此PWM占空比为
PWM占空比=60(ARR+1)=60% PWM占空比= \frac{60}{(ARR+1)} =60\% PWM占空比=(ARR+1)60=60%

FOC定时器PWM设置

如果你是使用六部换向调制或者SPWM(正选波调制)来驱动无刷电机的话,那么只需要向上面例子那样将TIM_OCMode为PWM模式1,TIM_CounterMode为向上计数模式,TIM_OCPolarity为TIM_OCPolarity_High即可。但在FOC中,大多使用SVPWM调制方法,这需要产生一个中央对称的PWM波形,如图所示
在这里插入图片描述

每两个虚线为一个计数周期,SVPWM为了产生一个这样中心对齐的PWM,需要将TIM_CounterMode设为中央对齐模式1,这个模式下CNT会从0加计数到ARR,然后在减计数到0。(中央对齐模式2会从ARR的值先减到0在加)为了使中央为高电平,需要将PWM模式设为模式2,将TIM_OCPolarity设为TIM_OCPolarity_High,这样在CNT<CCR使为无效电平,为低电平,当CNT>CCR使为有效电平,为高电平。

这样设置会使PWM频率是用上述公式计算出的值的一半。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐