学习无霍尔传感器的BLDC方波调速

基本原理

反电动势法

无位置传感器的无刷直流电机的位置估计方法可以从多个方面论述,本文重点讲述反电势转子位置检测技术。

无刷直流电机中,受定子绕组产生的合成磁场的作用,转子沿着一定的方向连续转动。电机定子上放有电枢绕组。因此,转子一旦旋转,就会在空间形成导体切割磁力线的情况。根据电磁感应定律可知,导体切割磁力线会在导体中产生感应电势。所以,在转子旋转的时候就会在定子绕组中产生感应电势,即运动电势,一般称为反电动势或反电势。

当BLDCM的某相绕组反电势过零时,转子直轴与该相绕组轴线恰好重合。因此只要检测到各相绕组反电势的过零点,就可获知转子的若干个关键位置。再根据这些关键的转子位置信号,做相应的处理后控制BLDCM换相,实现BLDCM连续运转,这就是“反电势法”BLDCM控制。

无刷直流电机绕组反电势的过零点严格地反映了转子磁极位置。因此,只要能够准确的检测到绕组反电势的过零点信号,就可以判断出转子的关键位置。经过30°电角度延时处理后,就可以作为绕组的换相时刻。再根据功率管的导通顺序触发相应的功率管,就能够实现无刷直流电机的换相操作,保证电机按固定的方向连续旋转。这样可以保证电机换相满足“最佳换相逻辑”,减小转矩脉动。

无感BLDC的转子位置检测

为获得转子当前位置,需要采用某种转子位置检测环节。在有霍尔传感器的系统中,位置传感器的存在,增加了无刷直流电机的重量和结构尺寸,且不易安装和维护。同时,传感器的安装精度和灵敏度直接影响电机的运行性能。另外,霍尔传感器存在一定的磁不敏感区;其次,过多的传输线使系统易受干扰且可靠性降低;再次,在某些恶劣的工作环境中,常规的位置传感器根本就无法使用。因此,使用无感无刷直流电机控制,具有其一定的优势。

对于无位置传感器的直流无刷电机,必须通过一定的方法检测转子位置信息才能准确换相。反电动势法是其中最成熟和应用最广泛的位置检测方法。在六步换相控制中,每一个换相周期,将有一相绕组处于不导通状态。因此通过检测第三相反电动势信号、可检测到转子磁极在该绕组经过的时刻。

无感BLDC换相

以120°霍尔式位置传感器为例,三相无刷直流电机反电势和传感器输出信号间相位关系如图。
BLDC反电势和传感器信号当转子在0°电角度位置时,A相反电动势过零点。再延后30°时,HALL A传感器检测到边沿信号,此时需要换相。即30°电角度时,AB绕组通电,开始检测C相绕组反电动势。当转子位置在60°时,C相反电动势过零点。再延后30°时,HALL C传感器检测到边沿信号,此时需要换相。即90°电角度时,AC绕组通电,开始检测B相绕组反电动势。以此类推。反电动势的检测总在第三相未通电的绕组上进行。在检测到过零点时,需要再延时30°电角度进行换相。
因此,使用无感无刷直流电机控制反电动势过零点的检测是关键。

在功率开关管关断状态时采样

全数字反电势法根据A/D采样时刻的不同可分为三种:在功率开关管导通时刻采样、在功率开关管关断时刻采样和所有状态时刻采样。
PWM OFF时刻反电动势采样图中显示了六步换相方式中单相的反电动势波形。在PWM OFF时,进行检测反电动,以得到与0值相等时为过零时刻。在T1-T2区间,该相反电动为增大过程,由负值增加到正值的过程中检测到过零点;而在T4-T5区间,该相反电动势由正值减到负值过程中检测到过零点。通过PWM OFF采集方法,可很方便地得到反电动势过零点。

无感BLDC的“三段式”启动

(1)转子预定位:给任意两相通电,通电一段时间后,转子会转到与该通电状态对应的预知位置,完成转子的定位;
(2)外同步加速:根据预先设计好的优化加速曲线不断提升换相信号的频率及增大端电压实现电机的外同步加速;
(3)运行状态切换:当电机加速到一定转速后,就可以准确地检测到反电动势的过零点信号,并用此代替外同步信号,实现外同步运转到自同步运转的切换。

程序应用

相关函数初始化参数配置:系统时钟,中断,GPIO,ADC和定时器等

#define KEY_PORT 	 GPIOC
#define KEY1_Pin	 GPIO_Pin_15
#define KEY2_Pin 	 GPIO_Pin_5

#define T1CH1NON()     	PBSET = PBO_T1CH1N
#define T1CH1NOFF()    	PBRESET = PBO_T1CH1N

#define T1CH2NON()     	PBSET = PBO_T1CH2N
#define T1CH2NOFF()    	PBRESET = PBO_T1CH2N

#define T1CH3NON()     	PBSET = PBO_T1CH3N
#define T1CH3NOFF()    	PBRESET = PBO_T1CH3N

#define PBO_T1CH1N 				GPIO_Pin_13
#define PBO_T1CH2N 				GPIO_Pin_14
#define PBO_T1CH3N 				GPIO_Pin_15

按键读取

启动和停止后换向

    if(KEY_Read(KEY1))
	{	
			Delay1Us();
		if(KEY_Read(KEY1))
		{
			My_PWM=250;			
		 TIM_Configuration1();
		 TIM_Configuration2();      //Tim1定时器初始化
		}
	}
	if(KEY_Read(KEY2))
	{
			Delay1Us();
		if(KEY_Read(KEY2))
		{
		    BLDC_Stop();
			 if(ucT10S>=1) 
	    {
			My_PWM=250;
			if(ClockDir==1)ClockDir=0;
			else ClockDir=1;
	        ucT10S=0;
		}
		}
	}
    
uint8_t KEY_Read(uint8_t key)
{
	uint8_t data=0;
	switch(key)
	{
		case KEY1: 	data=GPIO_ReadInputDataBit( KEY_PORT, KEY1_Pin);
		break;
		case KEY2:  data=GPIO_ReadInputDataBit( KEY_PORT, KEY2_Pin);
		break;
		default: data=1;
	}
	if(data)
	{
	 	return 0;
	}
     	return 1;
}

六步换相驱动

void BLDC_SwitchStep(void)
{
	if (ClockDir==0)
	{
	MotorA.Step = (MotorA.Step + 1) % 6;
	}
	else
	{
	MotorA.Step = (MotorA.Step + 6-1) % 6;
	}
    MotorA.PWMTicksPre = MotorA.PWMTicks;
    MotorA.FlagBEMF = 0;
    MotorA.PWMTicks = 0;
    switch (MotorA.Step)
    {
    	case 0:                     //step1
			TIM1->CCR1=My_PWM;      //A+
		   	Delay1Us();
		  	T1CH1NON();
			T1CH2NOFF();            //B-
		   	Delay1Us();
  			TIM1->CCR2=0;
			T1CH3NON();		    	//C
  			TIM1->CCR3=0;
			break;
		case 1:                     //step2
			TIM1->CCR1=My_PWM;	    //A+
		   	Delay1Us();
		   	T1CH1NON();
			T1CH3NOFF();			//C-
		   	Delay1Us();
  			TIM1->CCR3=0;
			T1CH2NON();				//B
  			TIM1->CCR2=0;
			break;
		case 2:                     //step3
			TIM1->CCR2=My_PWM;      //B+
		   	Delay1Us();
		   	T1CH2NON();
		  	T1CH3NOFF();            //C-
		   	Delay1Us();	  
  			TIM1->CCR3= 0;						  
			T1CH1NON();		        //A
  			TIM1->CCR1=0;
			break;
		case 3:                     //step4
			TIM1->CCR2=My_PWM;      //B+
		  	Delay1Us();
		  	T1CH2NON();
		  	T1CH1NOFF();			//A-
		  	 Delay1Us();	   
  			TIM1->CCR1=0;
			T1CH3NON();		    	//C
  			TIM1->CCR3=0;
			break;
		case 4:                     //step5
			TIM1->CCR3=My_PWM;      //C+
		   Delay1Us();
		   T1CH3NON();
		   T1CH1NOFF();          	//A-
		   Delay1Us();
  			TIM1->CCR1 = 0;					 
		   T1CH2NON();		     	//B
		  Delay1Us();
  			TIM1->CCR2=0;
			break;
		case 5:                     //step6
			TIM1->CCR3=My_PWM;      //C+
		   	Delay1Us();
		   	T1CH3NON();
			T1CH2NOFF();			//B-
		   	Delay1Us();
 			TIM1->CCR2=0;
			T1CH1NON();				//A
  			TIM1->CCR1=0;
			break;
			default:
			break;
    }
}

反电势过零点检测

在PWM OFF时,检测单相反电势过零点,确定过零时刻

  unsigned long BEMF(void)
{
    unsigned long dir = 0;
	if (ucMotorStep!=MotorA.Step)
	{
		ucMotorStep=MotorA.Step;
		ucMotorAD=0;
	}
    switch (MotorA.Step)
    {
    case 0:
        VoltBEMF[ucMotorAD] = ADCConvertedValue_2[2];
        dir = 1;  //下降
        break;
    case 1:
        VoltBEMF[ucMotorAD] = ADCConvertedValue_2[1];
        break;
    case 2:
        VoltBEMF[ucMotorAD] = ADCConvertedValue_2[0];
        dir = 1;//下降
        break;
    case 3:
        VoltBEMF[ucMotorAD] = ADCConvertedValue_2[2];
        break;
    case 4:
        VoltBEMF[ucMotorAD] = ADCConvertedValue_2[1];
        dir = 1;//下降
        break;
    case 5:
        VoltBEMF[ucMotorAD] = ADCConvertedValue_2[0];
        break;
    default:
        break;
    }
	if(ucMotorAD<2) 
	{
		ucMotorAD++;
	}
	else
	{
		if (((dir == 1)&&(ClockDir==0))||((dir == 0)&&(ClockDir==1))) 
		//下降
		//PWM-OFF检测BEMF,过零点标志是BEMF电压为0
    	{
				if((VoltBEMF[0]>0)&&(VoltBEMF[1]==0))
				{
					usOZTimeS++;
					return 1;
				}		
    	}
    	else
    	{
				if ((VoltBEMF[0]==0)&&(VoltBEMF[1]>0))
				{
				usOZTimeS++;
				return 1;
			} 
    	}
		VoltBEMF[0]=VoltBEMF[1];//后一个值赋给前一个值
		VoltBEMF[1]=VoltBEMF[2];//新读取值赋给后一个值
		                        //达到持续进行比较检测
	}
    return 0;
}

“三段式”启动

PWM波形使用TIM1产生,1、2、3三个通道产生PWM驱动MOSFET,4通道用于触发ADC采样,ADC1扫描3个通道获取反电动势,使用PWM OFF采集方法检测反电势过零点,结果通过DMA传输,获取过零时刻,再经一定延时,进行相应的换相驱动

void TIM1_CC_IRQHandler(void)
{
    TIM_ClearITPendingBit(TIM1, TIM_IT_CC4);
    MotorA.PWMTicks++;
		if (DMA_GetFlagStatus(DMA1_FLAG_TC1)) //等待ADC转换,DMA传输完成
		{
			DMA_ClearFlag(DMA1_FLAG_TC1);	  //清除DMA传输完成标志位
			switch(MotorA.State)                  //State表示电机状态
        	{
      	case 0:                               //转子预定位
           	if(MotorA.PWMTicks >= 1000)
            {
               	MotorA.State++;
				TIM1->CCR1=0;                 //A+
		   		Delay1Us();
		  		T1CH1NOFF();
				T1CH2NOFF();                  //B-
		   		Delay1Us();
  				TIM1->CCR2=0;
				T1CH3NOFF();                  //C
  				TIM1->CCR3=0;
                BEMF_Cnt = 0;
				usPWMSpd=(Period-1-My_PWM);
            }
            break;
		case 1:
			if(MotorA.PWMTicks >= usPWMSpd)   //外同步加速
			{
				usPWMSpd-=(usPWMSpd/16+1);
				BLDC_SwitchStep(); 
				BEMF_Cnt ++;
			}
			if(BEMF_Cnt >= 36)
			{
				MotorA.State++;
				BEMF_Cnt=0;
			}
			break;
        case 2:                               //启动
            if (MotorA.PWMTicks >= 8)         //过滤电动势,消除消磁事件的影响
            {
                if (BEMF())                   //判断是否过零
                {
                    BLDC_SwitchStep();
                    BEMF_Cnt++;
                }
            }
            if (BEMF_ADC_Cnt < ADN)           //记录启动过程BEMF数据
            {
                ADC_Value[BEMF_ADC_Cnt][0] = ADCConvertedValue_2[0];
                ADC_Value[BEMF_ADC_Cnt][1] = ADCConvertedValue_2[1];
                ADC_Value[BEMF_ADC_Cnt][2] = ADCConvertedValue_2[2];
                BEMF_ADC_Cnt++;
            }
            if (BEMF_Cnt >= 50)               //50次换向之后,认为达到平衡状态,运行状态切换
            {
                MotorA.State++;
                BEMF_Cnt = 0;
            }
            break;
        case 3:
            if (MotorA.FlagBEMF == 0)         //未检测到过零事件
            {
                if (MotorA.PWMTicks >= 4)
				{		
                    if (BEMF())
                    {
                        MotorA.FlagSwitchStep = MotorA.PWMTicksPre >> 4;  
                        //延迟30电角度,此时应该是按照一个换相周期时间计算延迟
                        //如果改为>> 1,PWMTicksPre记录的就是上一步换相的时间
                        MotorA.FlagBEMF = 1;  //检测到过零事件之后,不再检测
                    }
                }
            }
            else
            {
                if (MotorA.FlagSwitchStep == 0)//延迟时刻到
                {
                    BLDC_SwitchStep();         //换相
                    BEMF_Cnt++;
                }
                else
                {
                    MotorA.FlagSwitchStep--;   //延迟时刻未到,自减
                }
            }
            if (BEMF_Cnt >= 50000)             //50000次换相之后,自动停机
            {
                MotorA.State++;                //若删除该语句,则手动停机
                BEMF_Cnt = 0;
            }
            break;
        case 4:
            BLDC_Stop();
            break;
        case 5:
            break;
        default:
            break;
            }
		}
		ADC_SoftwareStartConvCmd(ADC1, ENABLE);
	}

闭环自动调速

调节PWM的占空比:设定电机进入自同步运转后,自动加速和减速的范围

void Timeproc()
{
	if (fgT10Ms == 0)
	 {
		return;
	 }
	 fgT10Ms = 0;
	 ucT100ms++;
	 ucT1S++;
	 if(ucT100ms>=10)
	 {
		if((My_PWM<1000)&&(flag == 0))
		{
		My_PWM=My_PWM+10;
		}
		if(My_PWM>=1000) flag = 1;
		if(My_PWM>=200)
		{
		if(flag == 1)	My_PWM=My_PWM-10;
		}
		else
		{			
			flag = 0;	
		}
		MENON();
		ucT100ms=0;
	 }
	 if(ucT1S>=100)
	 {
	  	speed_1=My_PWM;
		ucT10S++;
		ucT1S=0;
	 }
	 if(ucT10S>=10)
	 {
	    ucT10S=0;
	 }
}