天天看點

學習無霍爾傳感器的BLDC方波調速基本原理程式應用

無霍爾傳感器的BLDC方波調速

  • 基本原理
    • 反電動勢法
    • 無感BLDC的轉子位置檢測
      • 無感BLDC換相
      • 在功率開關管關斷狀态時采樣
    • 無感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采樣時刻的不同可分為三種:在功率開關管導通時刻采樣、在功率開關管關斷時刻采樣和所有狀态時刻采樣。

學習無霍爾傳感器的BLDC方波調速基本原理程式應用

圖中顯示了六步換相方式中單相的反電動勢波形。在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;
	 }
}