STM32控制BLDC-如何让电机转起来

无刷直流电机比较流行,很多电机内部加入霍尔元件,通过霍尔元件可以知道电机转子的位置,根据这个位置给电机相线供电,这样电机就转起来了。框图如下所示

霍尔元件输出与相线输入电压的关系可以让BLDC电机厂家提供,一般都提供这个对应关系表,如下图所示

有了上面这些足可以让我们设计电路编写程序让电机转起来!

 

有上面的框图可以看出,3相电机的驱动需要六个mos管,一般用的是NMOS,大功率的NMOS比较便宜。大功率MOS管有较大的结电容,控制电压也高些,无法用单片机直接驱动,所以需要驱动电路。驱动芯片组成的驱动电路比较简单,常见的有IR2110S,我这里用IR2110S设计了MOS驱动电路,如下图所示,其中C24和D5是自举电路,为了控制Q3抬高电压。

3片IR2110S驱动6个NMOS,如下图

霍尔元件供电是5V,他的输出一般也是5V,可以分压后给单片机用。

单片机用流行STM32,他有高级定时器T1,T8,可以输出3对互补的PWM波,还有刹车信号输入,这些特性对于电机的可控制非常合适。电路如下图所示

BLDC电机控制用到单片机定时器及IO中断,初始化部分如下

void TIM_Config(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef	TIM_TimeBaseInitStruct;
	TIM_OCInitTypeDef  TIM_OCInitStructure;
	TIM_BDTRInitTypeDef TIM_BDTRInitStructure;
	EXTI_InitTypeDef EXTI_InitStructure;//
	NVIC_InitTypeDef NVIC_InitStructure;
	TIM_ICInitTypeDef TIM_ICInitStructure;
	// ¿ªÆô¶¨Ê±Æ÷ʱÖÓ,¼´ÄÚ²¿Ê±ÖÓCK_INT=72M
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_TIM1, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
	
   // Êä³ö±È½ÏͨµÀ1 GPIO ³õʼ»¯
	GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 ;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOB, &GPIO_InitStructure);
	//»ô¶ûÊäÈë
	GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_6 | GPIO_Pin_7 ;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
	GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_0 ;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
  GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource0);
	
	EXTI_InitStructure.EXTI_Line=EXTI_Line0; 
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTI_InitStructure);
	
	NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;  
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 
  NVIC_Init(&NVIC_InitStructure);
	
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource6);
	
	EXTI_InitStructure.EXTI_Line= EXTI_Line6; 
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTI_InitStructure);
	
	NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;  
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 
  NVIC_Init(&NVIC_InitStructure); 
	
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource7);
	
	EXTI_InitStructure.EXTI_Line= EXTI_Line7; 
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTI_InitStructure);
	
	NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;  
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x03;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 
  NVIC_Init(&NVIC_InitStructure); 
	
	TIM_DeInit(TIM1);        //½«ÍâÉèTIM1¼Ä´æÆ÷ÖØÉèΪȱʡֵ  
	TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1 ;    
	TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up ;  
	TIM_TimeBaseInitStruct.TIM_Period = 1000 ;       
	TIM_TimeBaseInitStruct.TIM_Prescaler = 3 ;     
	TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM1, &TIM_TimeBaseInitStruct ) ;       
	
	/* ¶¨Ê±Æ÷Êä³öͨµÀ1ģʽÅäÖà */
  
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;	 
  TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; 
  TIM_OCInitStructure.TIM_Pulse = 1000;
  
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
  TIM_OCInitStructure.TIM_OCNPolarity= TIM_OCNPolarity_High;
  TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
  TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Set;
  
  TIM_OC1Init(TIM1, &TIM_OCInitStructure);
  TIM_OC2Init(TIM1, &TIM_OCInitStructure);
  TIM_OC3Init(TIM1, &TIM_OCInitStructure);

  /* 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_OFF;
  TIM_BDTRInitStructure.TIM_DeadTime = 1;
  TIM_BDTRInitStructure.TIM_Break = TIM_Break_Disable;
  TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High;
  TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable;
  TIM_BDTRConfig(TIM1, &TIM_BDTRInitStructure);
  
  TIM_OC1PreloadConfig(TIM1,TIM_OCPreload_Enable);
  TIM_OC2PreloadConfig(TIM1,TIM_OCPreload_Enable);
  TIM_OC3PreloadConfig(TIM1,TIM_OCPreload_Enable);
	
  TIM_ARRPreloadConfig(TIM1, ENABLE);
  TIM_Cmd(TIM1, ENABLE);
  TIM_CtrlPWMOutputs(TIM1, ENABLE); 
  
  TIM_CCxCmd(TIM1,TIM_Channel_1,TIM_CCx_Enable);
  TIM_CCxNCmd(TIM1,TIM_Channel_1,TIM_CCxN_Enable);
  TIM_CCxCmd(TIM1,TIM_Channel_2,TIM_CCx_Enable);
  TIM_CCxNCmd(TIM1,TIM_Channel_2,TIM_CCxN_Enable);
  TIM_CCxCmd(TIM1,TIM_Channel_3,TIM_CCx_Enable);
  TIM_CCxNCmd(TIM1,TIM_Channel_3,TIM_CCxN_Enable);
}

让电机转起来需要知道电机转子的位置,根据霍尔相位对应表驱动电机相线,程序里用中断获取霍尔电平的变化。

void EXTI0_IRQHandler(void) 
{ 
	int i,j;
	if(EXTI_GetITStatus(EXTI_Line0)!=RESET)
	{
		EXTI_ClearITPendingBit(EXTI_Line0);


		step=((GPIOA->IDR & GPIO_Pin_6)>>6)+((GPIOA->IDR & GPIO_Pin_7)>>6)+((GPIOB->IDR & GPIO_Pin_0)<<2);
		if(start==1)
		{
			TIM1->CCER=PHASE_CHANGE[step];
			int_count1++;
		}
	}
}

void EXTI9_5_IRQHandler(void) 
{ 
	int i,j;
	if(EXTI_GetITStatus(EXTI_Line6)!=RESET)
	{
		EXTI_ClearITPendingBit(EXTI_Line6);

		step=((GPIOA->IDR & GPIO_Pin_6)>>6)+((GPIOA->IDR & GPIO_Pin_7)>>6)+((GPIOB->IDR & GPIO_Pin_0)<<2);
		if(start==1)
		{
			TIM1->CCER=PHASE_CHANGE[step];
			int_count2++;
		}

	}
	if(EXTI_GetITStatus(EXTI_Line7)!=RESET)
	{
		EXTI_ClearITPendingBit(EXTI_Line7);

		step=((GPIOA->IDR & GPIO_Pin_6)>>6)+((GPIOA->IDR & GPIO_Pin_7)>>6)+((GPIOB->IDR & GPIO_Pin_0)<<2);
		if(start==1)
		{
			TIM1->CCER=PHASE_CHANGE[step];
			int_count3++;
		}
	}
}

 

检测到变化后改变定时器输出,从而使电机相线得到驱动,我在程序里做好了数组,把得到了位置通过数组给定时器CCER寄存器,这样电机就转起来了

int PHASE_CHANGE[7]={0x0000,0x0104,0x0041,0x0140,0x0410,0x0014,0x0401};

这是霍尔输出与PWM输出波形的截图

这是定时器3对PWM的输出截图

这是电机和电路板

  • 23
    点赞
  • 164
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: STM32 控制 BLDC 电机的程序主要包括以下步骤: 1. 初始化:配置 STM32 的外设,如定时器、PWM、ADC 等。 2. 检测 BLDC 电机速:通过编写代码实现对电机速进行检测。 3. 计算电机控制信号:根据所需的速,计算出控制电机的 PWM 信号。 4. 控制电机:通过控制 PWM 信号来控制电机速。 5. 循环上述步骤,不断监测和调整电机速,以保证系统的稳定性和效率。 注意:以上是一般的步骤,具体的实现可能会因硬件平台和软件环境的不同而有所差异。 ### 回答2: STM32是一款广泛应用于嵌入式系统的微控制器系列,其强大的处理能力和丰富的外设使之成为控制BLDC电机的理想选择。BLDC电机是一种无刷直流电机,它与传统的有刷直流电机相比具有较高效率、较低噪音和较长使用寿命等优点。 在STM32控制BLDC电机的程序中,首先需要配置GPIO口和定时器用于生成PWM信号。GPIO口用于控制电机的相位,通过改变不同相位的电平来实现电机的启动和运。定时器用于产生一定频率和占空比的PWM信号,用于控制电机速。 接下来,需要编写定时器中断服务程序(ISR)用于控制电机速和方向。在ISR中,可以通过改变PWM信号的占空比来控制电机速,而改变电机相位的顺序可以实现电机的正反。 除了控制电机速和方向,还可以通过使用传感器(如霍尔传感器)或者开环控制的方法来实现电机位置的闭环控制。传感器可以用于检测电机子位置,并通过引脚来反馈给STM32,以便更准确地控制电机的运行状态。 此外,在控制BLDC电机的程序中,还需要考虑保护电路的设计。例如,过流保护、过压保护和过温保护等,以防止电机在异常情况下的损坏。 综上所述,STM32控制BLDC电机的程序需要通过配置GPIO口和定时器生成PWM信号,编写定时器中断服务程序来控制电机速和方向,并使用传感器或开环控制来实现电机位置的闭环控制。此外,还需要考虑保护电路的设计,以确保电机的安全运行。 ### 回答3: 控制BLDC电机STM32程序主要包括以下几个重要的步骤: 首先,需配置STM32的GPIO引脚作为PWM输出引脚,用于控制电机的三个相位。通过GPIO初始化的函数设置引脚的工作模式,并将其配置为PWM模式。 接着,需要选择合适的PWM定时器以及通道,用于产生PWM信号。通常情况下,定时器需要设置为频率足够高的模式,以满足电机控制的需求。同时,通道的设置需要匹配到对应的GPIO引脚上。 然后,需要编写一个函数来调节PWM占空比,控制电机速。这可以通过改变PWM定时器的计数值来实现。根据电机速度的反馈信号,通过计算得到一个合适的占空比,并将其应用到PWM定时器中。 此外,还需要配置一组外部中断来检测电机的位置信息。根据电机子位置,可以选择合适的相位驱动方式,以实现无刷电机子位置控制。 最后,为了保证电机的稳定运行,还需考虑加入PID控制算法。通过对电机速度和位置的反馈进行PID计算,对PWM占空比进行实时调整,使得电机能够按预期的速度和位置运行。 综上所述,控制BLDC电机STM32程序需要配置PWM输出引脚、设置PWM定时器和通道、调节PWM占空比、配置外部中断检测位置信息,并加入PID控制算法等关键步骤。通过合理的编写和调试,可以实现精确控制BLDC电机速和位置。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值