stm32F407 实现有感BLDC 六步换相 cubemx配置及源代码(二)

接上节stm32F407 实现有感BLDC 六步换相 cubemx配置及源代码(一)-CSDN博客

基本配置设置完成之后,本文代码采用KEIL5软件进行编写及实现。

首先新建一个HALL.c文件与HALL.h文件,HALL.c文件包括霍尔状态真值判断、六步换相函数、以及霍尔传感器的初始化。

霍尔状态真值判断的目的是为了获取当前电机旋转到的位置,对UVW三相霍尔值进行读取最直接的方法就是通过读取stm32的IO电平来实现。

以下为对应的霍尔状态真值判断函数:

复制代码
uint8_t HALL_Value(void)
{
//HALL_Ustate --- PD12
//HALL_Vstate --- PD13
//HALL_Wstate --- PB8
	
    uint8_t State = 0;
	
    /* 读取霍尔位置传感器 U 的状态 */
    if(HAL_GPIO_ReadPin(GPIOD, GPIO_PIN_12) != GPIO_PIN_RESET)
    {
        State |= 0x01U << 2;
    }

    /* 读取霍尔位置传感器 V 的状态 */
    if(HAL_GPIO_ReadPin(GPIOD, GPIO_PIN_13) != GPIO_PIN_RESET)
    {
        State |= 0x01U << 1;
    }

    /* 读取霍尔位置传感器 W 的状态 */
    if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_8) != GPIO_PIN_RESET)
    {
        State |= 0x01U << 0;
    }

    return State;
}

这个时候,会想到一个问题,就是这个函数既然是获取电机位置,那么我具体在哪些场景下会调用这些函数呢?

其实我们在刚拿到BLDC电机的时候,就会用这个函数来调试查看电机正转与反转时霍尔真值的变化情况,当然了,要调试查看的话,可以采用串口来看。

另外一个场景就是六步换相时,需要获取霍尔真值。

下面则是六步换相程序和霍尔传感器初始化,我的BLDC电机在正转时,真值2对应A相桥臂的上桥臂导通,B相桥臂的下桥臂导通,C相桥臂悬空,不做动作。真值3对应A相桥臂的上桥臂导通,B相桥臂悬空,C相桥臂的下桥臂导通。其余真值也是根据我实际电机的霍尔状态与相序导通关系来做发波处理的。

复制代码
void SIX_STEP(uint8_t hallState) 
{
	
 
  switch(hallState) 
	{

    case 2: // A+ B-    
			__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, 200);      
			HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
      HAL_TIMEx_PWMN_Stop(&htim1, TIM_CHANNEL_1); 
		
		
			__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, 0); 
			HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_2);            //使得对应所用驱动板上的下管一直导通
      HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_2);  
			
			__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_3, 200);
			HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_3);
      HAL_TIMEx_PWMN_Stop(&htim1, TIM_CHANNEL_3);            
      break;
      
    case 3: // A+ C-
			
			__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, 200);      
			HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
      HAL_TIMEx_PWMN_Stop(&htim1, TIM_CHANNEL_1); 
		
			__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, 200); 
			HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_2);
      HAL_TIMEx_PWMN_Stop(&htim1, TIM_CHANNEL_2);  
			
			__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_3, 0);
			HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_3);
      HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_3);  
      break;
      
    case 1: // B+ C-
			
			__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, 200);      
			HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_1);
      HAL_TIMEx_PWMN_Stop(&htim1, TIM_CHANNEL_1); 
		
		
			__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, 200); 
			HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2);
      HAL_TIMEx_PWMN_Stop(&htim1, TIM_CHANNEL_2);  
			
			__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_3, 0);
			HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_3);
      HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_3);  
      break;
      
    case 5: // B+ A-
			
			__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, 0);      
			HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_1);
      HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_1); 
		
		
			__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, 200); 
			HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2);
      HAL_TIMEx_PWMN_Stop(&htim1, TIM_CHANNEL_2);  
			
		
			__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_3, 200);
			HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_3);
      HAL_TIMEx_PWMN_Stop(&htim1, TIM_CHANNEL_3);  
      break;
      
    case 4: // C+ A-
			
			__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, 0);      
			HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_1);
      HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_1); 
		
		
			__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, 200); 
			HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_2);
      HAL_TIMEx_PWMN_Stop(&htim1, TIM_CHANNEL_2);  
			
		
			__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_3, 200);
			HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_3);
      HAL_TIMEx_PWMN_Stop(&htim1, TIM_CHANNEL_3);  
      break;
      
    case 6: // C+ B-
			
			__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, 200);      
			HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_1);
      HAL_TIMEx_PWMN_Stop(&htim1, TIM_CHANNEL_1); 
		
		
			__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, 0); 
			HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_2);
      HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_2);  
			
		
			__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_3, 200);
			HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_3);
      HAL_TIMEx_PWMN_Stop(&htim1, TIM_CHANNEL_3);   
      break;
      
    default: // 错误处理
      break;
  }
}




/*霍尔传感器初始化*/
void HALL_Init(void)
{
	
	/* 启动霍尔传感器接口 */
  HAL_TIMEx_HallSensor_Start_IT(&htim4);	
	
}

200是PWM波的占空比,占空比改变能够改变电机的速度 。

下面是主程序和中断程序:

复制代码
int main(void)
{

  SystemClock_Config();

  MX_GPIO_Init();
  MX_USART1_UART_Init();
  MX_TIM1_Init();
  MX_TIM4_Init();         
  HALL_Init();            //霍尔传感器初始化


  HALL_State = HALL_Value();
  SIX_STEP(HALL_State);  
  while (1)
  {

 
  }

}

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
    if (htim->Instance == TIM4)
    {
		HALL_State = HALL_Value();
		SIX_STEP(HALL_State);
			
		HAL_GPIO_WritePin(GPIOH,GPIO_PIN_9,GPIO_PIN_SET);
			
		
		__HAL_TIM_CLEAR_FLAG(&htim4,TIM_FLAG_CC1);
			
    }
}

看到这里,肯定有人会疑问,为什么中断中放了六步换相和霍尔真值判断的程序,还要在主程序里面加两行一模一样的程序呢?

这是因为刚开始电机在没有六步换相转动之前,电机是处于静止的,因为霍尔信号没有变化,所以这个时候是触发不了霍尔中断的。因此先在主程序里面判断一下静止时候的霍尔值,然后根据这个霍尔值发波,来让电机转动一下,从而产生变化的一个霍尔信号,这个时候产生霍尔中断,然后执行六步换相程序,最后循环往复的触发中断,不断地进行换相。

根据以上程序,电机能够正常转动,采用六步换相的电机噪声较大是正常的。