1. 程式人生 > >STM32F103做主控自制無刷電機(BLDC)控制器 有感/無感

STM32F103做主控自制無刷電機(BLDC)控制器 有感/無感

STM32F103做主控自制無刷電機(BLDC)控制器 支援 有感/無感 兩種模式

2018年9月21日 星期五 snail_dongbin 在這裡插入圖片描述 很早之前就想做一款無刷電機控制器,忙於工作一直沒有弄。最近有點時間畫板,打樣,焊接,除錯,總算順利的轉起來。期間也遇到很多問題,上網查資料,自己量波形前前後後搞了差不多近一個月,(中間又出差一週)總算搞的差不多了,特意寫個總結。

先來秀個板子外觀,100*60mm 中等大小。DC 12V輸入,設計最大電流10A. (實際沒試過那麼大的電機,手頭的電機也就5 6A的樣子) 硬體上可以切換有感(HALL)和無感(EMF)兩種模式,外部滑動變阻器調速 預留有 PWM輸入、剎車、正反轉、USB和uart等介面。

在這裡插入圖片描述 因為少了電滑環的摩擦所以壽命 靜音方面有了很大的提升,轉速也更高。

當然難點就在如何獲取當前轉子的位置好換相,所以又分為兩種 有感和無感。

有感就是在電機端蓋的部位加裝霍爾感測器分別相隔30度或60度。 無感就是靠檢測懸浮相的感應電動勢過零點(後面在細講)。 當然各有各的優缺點,有感在低速方面好,可以頻繁啟停換相。無感的結構簡單成本低,航模上應用居多。

先說有感,電源首先被分成了3個繞組 U V W這個交流電還是有區別的。 它只是3個h橋按一定的順序導通模擬出來的,本質還是直流電。 電機靠hall位置按一定順序換相,轉速與電壓電流有關。這一點切記,不是換的越快轉的越快。(位置決定換相時刻,電壓決定轉速)一般調速就是調電壓,6步pwm方式是目前常用的。當然後續還有foc等更好演算法。

硬體部分網上基本都是成熟的方案。三相H橋,H橋一般有上臂mos和下臂mos組成,如果只是簡單的做演示上臂選pmos下臂選nmos控制電路簡單直接用微控制器的io就可以驅動。但是pmos低內阻的價格高。功率上面很難做大。 這也就是為什麼基本所有的商業控制器全是nmos的原因。 但是上臂用nmos存在一個問題vgs控制電壓大與vcc 4v以上才能完全導通。為了簡化電路採用了ir公司出的驅動ic,它內部有自舉升壓電路。外部僅需一個續流的二極體及儲能電容即可。 在這裡插入圖片描述

有感模式控制相對簡單,3個霍爾感測器輸出一般都是數字訊號,分壓後直接接微控制器io.

在這裡插入圖片描述 當然控制方式上也就簡單很多,三個霍爾接中斷輸入,在中斷處理程式中根據組合狀態換相,程式上也沒什麼複雜的。主程式 一直檢測ad值,改變pwm佔空比,及電流保護等。 如下一個典型的換相程式碼。 Stm32 有兩個高階定時器tim1 tim8 可以輸出4組互補型pwm,還可以設定死區時間等,使用上非常方便。

switch(step) { case 4: //B+ C- /* Next step: Step 2 Configuration -------------------------------------- */ TIM_CCxCmd(BLDC_TIMx,TIM_Channel_1,TIM_CCx_Disable); TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_1,TIM_CCxN_Disable);

  /*  Channel1 configuration */
  /*  Channel2 configuration */    
  TIM_SetCompare2(BLDC_TIMx,BLDC_TIM_PERIOD);
  TIM_CCxCmd(BLDC_TIMx,TIM_Channel_2,TIM_CCx_Enable);
  /*  Channel3 configuration */
  TIM_SetCompare3(BLDC_TIMx,BLDC_TIM_PERIOD*speed_duty/1000);
  TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_3,TIM_CCxN_Enable);
  break;
case 5: //B+ A-
  /* Next step: Step 3 Configuration -------------------------------------- */      
  TIM_CCxCmd(BLDC_TIMx,TIM_Channel_3,TIM_CCx_Disable);
  TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_3,TIM_CCxN_Disable);
  
  /*  Channel1 configuration */
  TIM_SetCompare1(BLDC_TIMx,BLDC_TIM_PERIOD*speed_duty/1000);
  TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_1,TIM_CCxN_Enable);

  /*  Channel2 configuration */
  TIM_SetCompare2(BLDC_TIMx,BLDC_TIM_PERIOD);
  TIM_CCxCmd(BLDC_TIMx,TIM_Channel_2,TIM_CCx_Enable);
  /*  Channel3 configuration */
  break;
case 1: //C+ A-
  /* Next step: Step 4 Configuration -------------------------------------- */
  TIM_CCxCmd(BLDC_TIMx,TIM_Channel_2,TIM_CCx_Disable);
  TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_2,TIM_CCxN_Disable);

  /*  Channel1 configuration */
  TIM_SetCompare1(BLDC_TIMx,BLDC_TIM_PERIOD*speed_duty/1000);
  TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_1,TIM_CCxN_Enable);
  
  /*  Channel2 configuration */ 
  /*  Channel3 configuration */
  TIM_SetCompare3(BLDC_TIMx,BLDC_TIM_PERIOD);
  TIM_CCxCmd(BLDC_TIMx,TIM_Channel_3,TIM_CCx_Enable);
  break;
case 3: //C+ B-
  /* Next step: Step 5 Configuration -------------------------------------- */
  TIM_CCxCmd(BLDC_TIMx,TIM_Channel_1,TIM_CCx_Disable);
  TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_1,TIM_CCxN_Disable);    

  /*  Channel1 configuration */      
  /*  Channel2 configuration */   
  TIM_SetCompare2(BLDC_TIMx,BLDC_TIM_PERIOD*speed_duty/1000);
  TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_2,TIM_CCxN_Enable);

  /*  Channel3 configuration */      
  TIM_SetCompare3(BLDC_TIMx,BLDC_TIM_PERIOD);
  TIM_CCxCmd(BLDC_TIMx,TIM_Channel_3,TIM_CCx_Enable);
  break;
case 2: //A+ B-
  /* Next step: Step 6 Configuration -------------------------------------- */
  TIM_CCxCmd(BLDC_TIMx,TIM_Channel_3,TIM_CCx_Disable);
  TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_3,TIM_CCxN_Disable);
  
  /*  Channel1 configuration */
  TIM_SetCompare1(BLDC_TIMx,BLDC_TIM_PERIOD);
  TIM_CCxCmd(BLDC_TIMx,TIM_Channel_1,TIM_CCx_Enable);
  /*  Channel2 configuration */
  TIM_SetCompare2(BLDC_TIMx,BLDC_TIM_PERIOD*speed_duty/1000);
  TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_2,TIM_CCxN_Enable);
  /*  Channel3 configuration */
  break;
case 6: //A+ C-
  /* Next step: Step 1 Configuration -------------------------------------- */
  TIM_CCxCmd(BLDC_TIMx,TIM_Channel_2,TIM_CCx_Disable);
  TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_2,TIM_CCxN_Disable);
  
  /*  Channel1 configuration */
  TIM_SetCompare1(BLDC_TIMx,BLDC_TIM_PERIOD);
  TIM_CCxCmd(BLDC_TIMx,TIM_Channel_1,TIM_CCx_Enable);
  /*  Channel2 configuration */      
  /*  Channel3 configuration */
  TIM_SetCompare3(BLDC_TIMx,BLDC_TIM_PERIOD*speed_duty/1000);
  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;

}

下圖為uvw三相的霍爾檢測到的電平及w相的波形。

在這裡插入圖片描述 下圖為 uvw三相波形及w相霍爾電平 在這裡插入圖片描述

下圖為 w相電平, w相上臂on 下臂pwm ,w相霍爾訊號。 在這裡插入圖片描述 下圖為w相ir2304晶片輸出,上臂電壓可明顯看到已高於vcc,下臂為pwm訊號

在這裡插入圖片描述 在說說無感模式,由於沒有了霍爾,電機無法知道轉子當前的位置所以就無法換相,而感應電動勢也只有在轉起來之後才有,所以無感模式的啟動是個難點。 一般方法都是分三段法 ,1 預定位 2 啟動 3進入閉環反饋

正如網友說的江湖一層紙,戳破不值半文錢。 1 預定為就是強制給某一相通電一段時間,讓電機定位到這個位置。 佔空比30-50%不要太大,可能會發熱。 2 啟動,就是逐步的強制換相,當然要有個加速的過程,使電機轉起來。 這個過程太慢會抖動反轉,太快會丟步。引數需要一點點試,有點像控制步進電機。要能使電機轉的能產生電動勢,我也是參照的德國MK 電調的演算法 每次延時時間比上一次少1/25,形成一個加速的過程,直到電機完全轉起來產生足夠的電動勢。 3 閉環反饋控制換相跟有感差不多一樣。

speed_duty=30; //30% start
BLDC_PHASE_CHANGE(Step[Phase]); //固定一相
Delay_MS(200);

speed_duty=pwm; 
timer = 300;
while(1)
{
	for(i=0;i<timer; i++) 
	{
		Delay_US(120);  	//等待
	} 
	timer-= timer/25+1;
	if(timer < 25) 
	{ 		
		if(TEST_MANUELL)
		{
			timer = 25;   //開環強制換向
		}
		else
		{	
			bldc_dev.motor_state=RUN;
			break; 
		}				
	}	
	Phase++;
	Phase %= 6;	
	BLDC_PHASE_CHANGE(Step[Phase]); //
}

說到感應電動勢很多人不明白,先來說說電流,電機線圈的內阻通常很小比如0.2歐,電機的電壓比如10v,按理來說電流100a為何電機不燒哪?? 其實電機線圈在通電的一瞬間並不是完全導通的,因為有反向電動感應勢的存在,可能有-9.8v。10v-9.8v = 0.2v /0.2 = 1A.這樣算起來電流還合理。 在說說那個初中學習的法拉第 ,當線圈切割磁場時會產生感應電動勢,根據右手定則。。。。。。。。。不懂的自行上網搜。 在這裡插入圖片描述 如下圖當ac相在通電12v的情況下,靜止狀態下正中間中性點理論為6v,但是轉起來就不一定了,因為b相實際是在切割磁場,是會產生電動勢的。而電動勢的大小正負取決與當前在磁場ns極的位置。當切割ns時為-1,切割sn時為1,平行時為0.

在這裡插入圖片描述

利用這一特性不就剛好可以獲得轉子的位置嗎? 在這裡插入圖片描述 首先檢測電路網上已經一大很成熟了。 如下圖,當然很多時候需要在4.7k對地的電阻上並一個100nf的電容,做一個低通濾波。也可以在軟體中做濾波處理。

我們所要做的就是檢測這個懸浮相的電動勢過零點。 網上常用的兩種方法 1 微控制器ad採集。2 比較器比較。 我選擇了比較器lm339價格已經很便宜了。在高速上比ad有明顯優勢。 只要比較cin bin ain 與n點的壓差即可獲得零點。

在這裡插入圖片描述

理想很完美,現實很殘酷,實際中根本得不到這麼完美的波形。 如下圖,這個已經是比較好的了,還是有很多毛刺。這個給微控制器中斷,肯定一大堆問題,嚴重的換錯相燒mos管。

在這裡插入圖片描述

在這裡插入圖片描述 為什麼會有這些毛刺哪,有些還挺有規律。 參考了網上的介紹,這中間還有一個叫消磁的東西。

在這裡插入圖片描述 原理不深究了,反正時間很短,軟體上做一個濾波消掉就可以了。

進入中斷函式後做如下處理 ,定時器的中斷我暫時用的20us。

const unsigned int FilterNums = 0xff; static unsigned int nums =0; static unsigned int Queue_UStatus =0; static unsigned int Queue_VStatus =0; static unsigned int Queue_WStatus =0; static unsigned char EMF_SVal =0; unsigned char Filter_U_Status=0; unsigned char Filter_V_Status=0; unsigned char Filter_W_Status=0; unsigned char EMF_Val=0; unsigned int status_h; unsigned int status_l; unsigned int Delay30deg =0;

/* 清除中斷標誌位 */ if ( TIM_GetITStatus(TIM3 , TIM_IT_Update) != RESET ) { TIM_ClearITPendingBit(TIM3 , TIM_FLAG_Update);

	nums++;
//快取io狀態
	Queue_UStatus= Queue_UStatus <<1;//左移
	Queue_VStatus= Queue_VStatus <<1;
	Queue_WStatus= Queue_WStatus <<1;
	
	Queue_UStatus |= EMF_U_STATUS; //賦值
	Queue_VStatus |= EMF_V_STATUS;
	Queue_WStatus |= EMF_W_STATUS;
	
	//連續檢測消除雜波
	status_h = Queue_UStatus &FilterNums;
	if(status_h == FilterNums) Filter_U_Status = 1;
	else if(status_h == 0x0) Filter_U_Status = 0;
	else return;

	status_h = Queue_VStatus &FilterNums;
	if(status_h == FilterNums) Filter_V_Status = 1;
	else if(status_h == 0x0) Filter_V_Status = 0;
	else return;
	
	status_h = Queue_WStatus & FilterNums;
	if(status_h == FilterNums) Filter_W_Status = 1;
	else if(status_h == 0x0) Filter_W_Status = 0;
	else return;
	
	//邊沿檢測
	status_l = UEMF_Edge(Filter_U_Status); //U 檢測邊沿
	if(status_l == 1) nums =0;		  //上升沿
	else if(status_l == 0)  		  //下降沿
	{
		Delay30deg = nums/4;  
	}
	if(VEMF_Edge(Filter_V_Status))//V 檢測邊沿
	{ nums =0; }
	
	if(WEMF_Edge(Filter_W_Status))//W 檢測邊沿
	{ nums =0; }
	//30度延時換相						
	if(nums == Delay30deg) 
	{	
		EMF_Val = (Filter_U_Status<<2 )| (Filter_V_Status<<1) |Filter_W_Status;

		if(EMF_SVal == EMF_Val) return;
		EMF_SVal = EMF_Val; //更新值
		
		EMF_EXTI_Callback(EMF_Val);
	}

}

至於網上說檢測到過零點後,延時30度換相,對電源效率有影響。我試了下,好像沒什麼明顯的差異。也有人說在大功率的電機下不延時反而更平滑等等。真實怎樣有待各位實際實驗了。

最後秀幾張轉起來的照片

在這裡插入圖片描述

硬碟電機 無感模式

硬碟電機 無感模式 在這裡插入圖片描述 電動工具電機 有感模式 在這裡插入圖片描述 加裝散熱片的樣子。