ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

BLDC开发笔记2.六步PWM输出

2020-10-18 04:31:44  阅读:276  来源: 互联网

标签:六步 BLDC TIMx TIM Disable GPIO PWM Channel


6步PWM互补输出

6步PWM输出是对 F103 的 TIM1 进行配置成PWM输出模式,带刹车和死区功能。按照模块化进行初始化配置。勾选keil中的C99标准(支持任意地方定义变量)。

GPIO初始化

打开相应功能模块时钟,将TIM1 的TIx引脚配置为复用推挽输出模式,BKIN(刹车)引脚配置为浮空输入模式。

通过在头文件进行宏定义配置,在硬件改变的时候方便修改

#define BLDC_TIMx                       TIM1
#define BLDC_TIM_APBxClock_FUN          RCC_APB2PeriphClockCmd
#define BLDC_TIM_CLK                    RCC_APB2Periph_TIM1

#define BLDC_TIM_GPIO_APBxClock_FUN     RCC_APB2PeriphClockCmd
#define BLDC_TIM_GPIO_CLK               (RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB)
#define BLDC_TIM_CH1_PORT               GPIOA
#define BLDC_TIM_CH1_PIN                GPIO_Pin_8   //通道1
#define BLDC_TIM_CH2_PORT               GPIOA      
#define BLDC_TIM_CH2_PIN                GPIO_Pin_9   //通道2
#define BLDC_TIM_CH3_PORT               GPIOA
#define BLDC_TIM_CH3_PIN                GPIO_Pin_10  //通道3

#define BLDC_TIM_CH1N_PORT              GPIOB
#define BLDC_TIM_CH1N_PIN               GPIO_Pin_13  //互补通道1
#define BLDC_TIM_CH2N_PORT              GPIOB
#define BLDC_TIM_CH2N_PIN               GPIO_Pin_14  //互补通道2
#define BLDC_TIM_CH3N_PORT              GPIOB
#define BLDC_TIM_CH3N_PIN               GPIO_Pin_15  //互补通道3

#define BLDC_TIM_BKIN_PORT              GPIOB
#define BLDC_TIM_BKIN_PIN               GPIO_Pin_12  //刹车输入

GPIO初始化函数

static void BLDC_TIMx_GPIO_Config(void) 
{
        //GPIO初始化结构体
        GPIO_InitTypeDef GPIO_InitStruct;
    
        //打开GPIOA和GPIOB的时钟和复用功能时钟
        BLDC_TIM_GPIO_APBxClock_FUN(BLDC_TIM_GPIO_CLK|RCC_APB2Periph_AFIO, ENABLE); 

	//通道1引脚配置
        GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
	GPIO_InitStruct.GPIO_Pin=BLDC_TIM_CH1_PIN;
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;	
	GPIO_Init(BLDC_TIM_CH1_PORT,&GPIO_InitStruct);
	
	//通道2引脚配置
	GPIO_InitStruct.GPIO_Pin=BLDC_TIM_CH2_PIN;
	GPIO_Init(BLDC_TIM_CH2_PORT,&GPIO_InitStruct);
	
        //通道3引脚配置
	GPIO_InitStruct.GPIO_Pin=BLDC_TIM_CH3_PIN;
	GPIO_Init(BLDC_TIM_CH3_PORT,&GPIO_InitStruct);
	
	//互补通道1引脚配置
	GPIO_InitStruct.GPIO_Pin=BLDC_TIM_CH1N_PIN;
	GPIO_Init(BLDC_TIM_CH1N_PORT,&GPIO_InitStruct);
	
        //互补通道2引脚配置
	GPIO_InitStruct.GPIO_Pin=BLDC_TIM_CH2N_PIN;
	GPIO_Init(BLDC_TIM_CH2N_PORT ,&GPIO_InitStruct);
	
	//互补通道3引脚配置
	GPIO_InitStruct.GPIO_Pin=BLDC_TIM_CH3N_PIN;;
	GPIO_Init(BLDC_TIM_CH3N_PORT,&GPIO_InitStruct);
	
        //BKIN pin 引脚配置
	GPIO_InitStruct.GPIO_Pin=BLDC_TIM_BKIN_PIN;
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN_FLOATING;
	GPIO_Init(BLDC_TIM_BKIN_PORT ,&GPIO_InitStruct);
}

时基初始化

时基配置

APB2时钟为72Mhz,预分频系数PSC为0,(PSC决定记一次的时间),方便计算

将PWM频率为 f=20khz,故定时器计数周期ARR=72M/(PSC+1)/ f,因为我们预分频系数为0,故 ARR=72M/(0+1)/20k=3600。

通过在h文件宏定义配置这些参数:

//PWM频率
#define BLDC_TIM_PWM_FREQ   20000 
// 定时器预分频系数
#define BLDC_TIM_PRESCALER  0
//定时器计数周期
#define BLDC_TIM_PERIOD    (uint16_t)(SystemCoreClock/(BLDC_TIM_PRESCALER+1)/BLDC_TIM_PWM_FREQ) 
//定时器重复寄存器数值
#define BLDC_TIM_REPETITIONCOUNTER   0

时基初始化函数

这里需要说明的是 TIM_TimeBaseInitStruct.TIM_ClockDivision ,时钟分割系数,她实际上配置的是定时器控制寄存器1的 CKD [1:0]。

她的作用主要在两个方面:

  1. 死区时间配置,死区时间发生器需要一个死区时钟来计数,她通过内部时钟 CK_INT 分频得来,后面详细讲计算。这里我将CKD配置为00,即不分频,还是72Mhz。
  2. 当使用外部时钟模式(ETR/TIx)/输入捕获功能时(TIx),如果频率太高需要降频,或者滤波时,需要一个时钟对这些信号进行采样,采样时钟 \(F_{DTS}=CK_{INT}/CKD/N\),N是数字滤波器滤波长度
  3. 当CKD[1:0]=00,不对CK_INT分频,当CKD[1:0]=01,对CK_INT进行2分频,当CKD[1:0]=10,对CK_INT进行4分频。
static void BLDC_TIMx_TimeBaseInit(void)
{  	
	//打开TIM1时钟
	BLDC_TIM_APBxClock_FUN(BLDC_TIM_CLK,ENABLE); 
    
        TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;  //时基初始化结构体
  
        /*时基初始化*/
	TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;  //时钟分割为1
	TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;  //向上计数
	TIM_TimeBaseInitStruct.TIM_Period=BLDC_TIM_PERIOD;  //计数周期
	TIM_TimeBaseInitStruct.TIM_Prescaler=BLDC_TIM_PRESCALER;  //预分频
	TIM_TimeBaseInitStruct.TIM_RepetitionCounter=BLDC_TIM_REPETITIONCOUNTER;  //重复计数器值为0,不重复
	TIM_TimeBaseInit(BLDC_TIMx,&TIM_TimeBaseInitStruct);
    
        //定时器使能预装载功能
        TIM_ARRPreloadConfig(BLDC_TIMx,ENABLE);  //ARR预装载
}

输出比较模式初始化

输出比较模块的功能框图:

  1. 将定时器配置为输出比较模式——PWM1模式。将定时器配置为向上计数模式,当计数器数值小于输出比较寄存器的值时,即TIMx_CNT<TIMx_CCR1,输出有效电平。有效电平的选择通过TIM_OCInitStruct.TIM_OCPolarity这个成员配置,我将其配置为高电平有效。

  2. 需要注意的是,TIM_OCInitStruct.TIM_OCIdleStateTIM_OCInitStruct.TIM_OCNIdleState这两个成员是配置引脚空闲状态的,就是关闭定时器时的输出电平,所以在刹车功能有效时(关闭定时器输出),我们不能将同一桥的两个输入都配置为高电平,否则就烧mos了。这里我将两个空闲状态都配置为低电平。

  3. 占空比=CCR/ARR

static void BLDC_TIMx_OCInit(void)
{
  TIM_OCInitTypeDef TIM_OCInitStruct;  //输出比较初始化结构体

  //输出比较通道1模式配置
  TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_PWM1;  //TIMx_CNT<TIMx_CCR1,输出有效电平
  TIM_OCInitStruct.TIM_OCIdleState=TIM_OCIdleState_Reset;  //关闭定时器时空闲状态为高电平
  TIM_OCInitStruct.TIM_OCNIdleState=TIM_OCIdleState_Reset;
  TIM_OCInitStruct.TIM_OCPolarity=TIM_OCPolarity_High;   //输出有效电平为高电平
  TIM_OCInitStruct.TIM_OCNPolarity=TIM_OCNPolarity_High;
  TIM_OCInitStruct.TIM_OutputState=TIM_OutputState_Enable;     //输出使能
  TIM_OCInitStruct.TIM_OutputNState=TIM_OutputNState_Enable;   //互补通道输出使能
  TIM_OCInitStruct.TIM_Pulse=0;  //设置占空比,即CCR值,这里不使用,后面用库函数配置
  TIM_OC1Init(BLDC_TIMx ,&TIM_OCInitStruct);

  //输出比较通道2模式配置
  TIM_OCInitStruct.TIM_Pulse=0;
  TIM_OC2Init(BLDC_TIMx, &TIM_OCInitStruct);

  //输出比较通道3模式配置
  TIM_OCInitStruct.TIM_Pulse=0;
  TIM_OC3Init(BLDC_TIMx, &TIM_OCInitStruct);

  //输出比较使能预装载功能
  TIM_OC1PreloadConfig(BLDC_TIMx,TIM_OCPreload_Enable);  //CCR1预装载
  TIM_OC2PreloadConfig(BLDC_TIMx,TIM_OCPreload_Enable);  //CCR2预装载
  TIM_OC3PreloadConfig(BLDC_TIMx,TIM_OCPreload_Enable);  //CCR3预装载
}

死区和刹车功能初始化

static void BLDC_TIMx_BDTRInit(void)
{
  TIM_BDTRInitTypeDef TIM_BDTRInitStructure;  //刹车与死区初始化结构体
  
  //刹车功能初始化,配置断路时通道输出状态,以及死区时间
  /* Automatic Output enable, Break, dead time and lock configuration*/
   
  TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable;//运行模式下“关闭状态”选择
  TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable;//空闲模式下“关闭状态”选择
  TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_1; //锁定设置,防止软件出错,提供写保护
  TIM_BDTRInitStructure.TIM_DeadTime = 10;  //死区时间
  TIM_BDTRInitStructure.TIM_Break = TIM_Break_Enable;  //使能刹车功能
  TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High;  //刹车输入极性,高电平有效
  TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Disable;
  TIM_BDTRConfig(BLDC_TIMx, &TIM_BDTRInitStructure);
}

死区时间的计算

关于死区时间的计算,她是在刹车和死区寄存器(TIMx_BDTR)中的UTG[7:0]: 死区发生器设置 (Dead-time generator setup)中进行配置。

举例说明,假设将成员配置为TIM_BDTRInitStructure.TIM_DeadTime = 10;这个成员实际上配置的就是UTG[7:0]的值。

  1. 十进制10的二进制表示为00001010,可得DTG[7:5]=000,故死区持续时间DT=DTG[7:0]*Tdtg=10*Tdtg=10*Tdts

  2. Tdts由控制寄存器CR1中的CKD决定,前面我们已经分析过,我们将CKD[1:0]=00(即不分频),故Tdts=1/72M

  3. 综上,我们可以算出,死区持续时间DT=10/72M≈138.9ns

PWM输出总初始化

static void BLDC_TIMx_PWM_Init(void)
{
  //GPIO初始化  
  BLDC_TIMx_GPIO_Config();  
  //时基初始化
  BLDC_TIMx_TimeBaseInit(); 
  //输出比较模式初始化
  BLDC_TIMx_OCInit();  
  //死区和刹车功能初始化
  BLDC_TIMx_BDTRInit();  

  //定时器使能
  TIM_Cmd(BLDC_TIMx, ENABLE);

  //PWM输出使能,配置的是BDTR寄存器的MOE位,高级定时器独有。
  TIM_CtrlPWMOutputs(BLDC_TIMx, ENABLE);

  //关闭定时器输出比较
  TIM_CCxCmd(BLDC_TIMx,TIM_Channel_1,TIM_CCx_Disable);
  TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_1,TIM_CCxN_Disable);
  TIM_CCxCmd(BLDC_TIMx,TIM_Channel_2,TIM_CCx_Disable);
  TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_2,TIM_CCxN_Disable);
  TIM_CCxCmd(BLDC_TIMx,TIM_Channel_3,TIM_CCx_Disable);
  TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_3,TIM_CCxN_Disable);
		
}

这样就初始化完毕了。

换相函数

换相函数是要根据霍尔换相时序表编写,按照顺序对给定MOS管PWM信号,这里采用的是H-PWM-L-ON驱动方式。

在头文件中定义占空比

//PWM占空比
#define speed_duty 15  //占空比为15/100,注意这里没有除以100,只是定义数值

函数TIM_SetCompareX(TIM_TypeDef* TIMx, uint16_t Compare1),配置的就是CCR的值,我们知道占空比=CCR/ARR,所以CCR=ARR*(speed_duty/100)

void BLDC_PHASE_CHANGE(uint8_t uwstep)
{
  switch(uwstep)
	{
	  case 6: //B+ C-
			
	        //输出比较通道1配置
    	        TIM_CCxCmd(BLDC_TIMx,TIM_Channel_1,TIM_CCx_Disable);
	        TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_1,TIM_CCxN_Disable);
		
		//输出比较通道2配置
		TIM_SetCompare2(BLDC_TIMx,BLDC_TIM_PERIOD*speed_duty/100);
    		TIM_CCxCmd(BLDC_TIMx,TIM_Channel_2,TIM_CCx_Enable);
		
	        //输出比较通道3配置
                TIM_SetCompare3(BLDC_TIMx,BLDC_TIM_PERIOD);
	        TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_3,TIM_CCxN_Enable);
							
	  break;
		
	 case 2: //B+ A-
			
		//输出比较通道3配置
                TIM_CCxCmd(BLDC_TIMx,TIM_Channel_3,TIM_CCx_Disable);
	        TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_3,TIM_CCxN_Disable);
		
	        //输出比较通道1配置
		TIM_SetCompare1(BLDC_TIMx,BLDC_TIM_PERIOD);
	        TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_1,TIM_CCxN_Enable);
		
		//输出比较通道2配置
	        TIM_SetCompare2(BLDC_TIMx,BLDC_TIM_PERIOD*speed_duty/100);
    		TIM_CCxCmd(BLDC_TIMx,TIM_Channel_2,TIM_CCx_Enable);
		
	  break;
		
	 case 3: //C+ A-
			
		//输出比较通道2配置
                TIM_CCxCmd(BLDC_TIMx,TIM_Channel_2,TIM_CCx_Disable);
	        TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_2,TIM_CCxN_Disable);	
		
	        //输出比较通道1配置
		TIM_SetCompare1(BLDC_TIMx,BLDC_TIM_PERIOD);
	        TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_1,TIM_CCxN_Enable);
		
	        //输出比较通道3配置
                TIM_SetCompare3(BLDC_TIMx,BLDC_TIM_PERIOD*speed_duty/100);
	        TIM_CCxCmd(BLDC_TIMx,TIM_Channel_3,TIM_CCx_Enable);
		
	  break;
		
	 case 1: //C+ B-
			
		//输出比较通道1配置
    		TIM_CCxCmd(BLDC_TIMx,TIM_Channel_1,TIM_CCx_Disable);
	        TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_1,TIM_CCxN_Disable);
		
	        //输出比较通道2配置
		TIM_SetCompare2(BLDC_TIMx,BLDC_TIM_PERIOD);
	        TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_2,TIM_CCxN_Enable);
		
	        //输出比较通道3配置
                TIM_SetCompare3(BLDC_TIMx,BLDC_TIM_PERIOD*speed_duty/100);
	        TIM_CCxCmd(BLDC_TIMx,TIM_Channel_3,TIM_CCx_Enable);

	  break;
		
	 case 5: //A+ B-
					
		//输出比较通道3配置
                TIM_CCxCmd(BLDC_TIMx,TIM_Channel_3,TIM_CCx_Disable);
	        TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_3,TIM_CCxN_Disable);
						
		//输出比较通道1配置
		TIM_SetCompare1(BLDC_TIMx,BLDC_TIM_PERIOD*speed_duty/100);
    		TIM_CCxCmd(BLDC_TIMx,TIM_Channel_1,TIM_CCx_Enable);
		
	        //输出比较通道2配置
                TIM_SetCompare2(BLDC_TIMx,BLDC_TIM_PERIOD);
	        TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_2,TIM_CCxN_Enable);
    
           break;
		
	 case 4: //A+ C-
				
		//输出比较通道2配置
                TIM_CCxCmd(BLDC_TIMx,TIM_Channel_2,TIM_CCx_Disable);
	        TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_2,TIM_CCxN_Disable);
		
		//输出比较通道1配置
		TIM_SetCompare1(BLDC_TIMx,BLDC_TIM_PERIOD*speed_duty/100);
    		TIM_CCxCmd(BLDC_TIMx,TIM_Channel_1,TIM_CCx_Enable);

		//输出比较通道3配置
                TIM_SetCompare3(BLDC_TIMx,BLDC_TIM_PERIOD);
	        TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_3,TIM_CCxN_Enable);
		
	break;		
		
     default:  //关闭输出
			
		TIM_CCxCmd(BLDC_TIMx,TIM_Channel_1,TIM_CCx_Disable);
		TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_1,TIM_CCxN_Disable);
		TIM_CCxCmd(BLDC_TIMx,TIM_Channel_2,TIM_CCx_Disable);
		TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_2,TIM_CCxN_Disable);
		TIM_CCxCmd(BLDC_TIMx,TIM_Channel_3,TIM_CCx_Disable);
		TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_3,TIM_CCxN_Disable);
		
        break;		
	}
}

下一篇将完成霍尔接口初始化,通过判断霍尔组合值进行开环速度控制。

标签:六步,BLDC,TIMx,TIM,Disable,GPIO,PWM,Channel
来源: https://www.cnblogs.com/ckk-blog/p/13833363.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有