BLDC六步换相_学习笔记(C语言)

一、有感方波控制

        根据HALL信号来进行,换相操作。HALL安装位置一般以120°或60°为主。两种方式所获去的HALL值会有所区别。下面以120°为例:

#include <stdio.h>
#define  CW    0
#define  CCW   1

unsigned char Motor_CommutateStep;                  //换相步序 
unsigned char HALL_currentvalue;                    //HALL当前值 
unsigned char HALL_nextvalue;                       //HALL下一个值 

//定义换相步序
unsigned char HallToMotorCwTable[8] = { 6, 2, 0, 1, 4, 3, 5, 6 };
unsigned char HallToMotorCCwTable[8] = { 6, 5, 3, 4, 1, 0, 2, 6 };

/*获取当前Hall值*/ 
unsigned char GetHallValue(){
	static unsigned char Hall_currentvalue = 0;
	//get value from register
	// user code:
	return Hall_currentvalue;
}

/*
    value        phase
      3  ------->  UV
	  1  ------->  UW
	  5  ------->  VW
	  4  ------->  VU
	  6  ------->  WU
	  2  ------->  WV 
*/ 
void MotorCommutatePhase(unsigned char dirct, unsigned char hallValue){
	if(dirct == CW){
		Motor_CommutateStep = HallToMotorCwTable[hallValue];            //根据hallvalue 生成一种映射关系。 
	}else{
		Motor_CommutateStep = HallToMotorCCwTable[hallValue];
	}
	Motor_CommutateStep +=5;
	Motor_CommutateStep %=6;
	switch(Motor_CommutateStep){
		case 0:          //U相上管开,V相下管开,其余关闭
			//user code:
			break;
		case 1:          //U相上管开,W相下管开,其余关闭
		 	//user code:
			break;
		case 2:          //V相上管开,W相下管开,其余关闭
		 	//user code:
			break;
		case 3:          //V相上管开,U相下管开,其余关闭
		 	//user code:
			break;	
		case 4:          //W相上管开,U相下管开,其余关闭
		 	//user code:
			break;
		case 5:          //W相上管开,V相下管开,其余关闭
		 	//user code:
			break;
		default:
			//disable pwm output
			break;
	}
} 

        应为是有感所以比较简单。代码中霍尔值与换相步序做了下映射,使得代码看起来美观一些。看不明白用笔画画。

        下面是对下次相序的预测,一般来说用于判断换相是否正确。

        

//预测下一次的HALL值,用于判断换相是否正确 
unsigned char PredictNextHallValue(unsigned char direct, unsigned char currenthallvalue){
	unsigned char NextHallValue
	if(direct == CW){                      //正向 
		swtich(currenthallvalue){
			case 3:
				NextHallValue = 1;
				break;
			case 1:
				NextHallValue = 5;
				break;
			case 5:
				NextHallValue = 4;
				break;
			case 4:
				NextHallValue = 6;
				break;
			case 5:
				NextHallValue = 2;
				break;
			case 2:
				NextHallValue = 3;
				break;
			default:
				break;	
		}
	}else{                                        //反向 
				swtich(currenthallvalue){
			case 3:
				NextHallValue = 2;
				break;
			case 2:
				NextHallValue = 6;
				break;
			case 6:
				NextHallValue = 4;
				break;
			case 4:
				NextHallValue = 5;
				break;
			case 5:
				NextHallValue = 1;
				break;
			case 1:
				NextHallValue = 3;
				break;
			default:
				break;	
		}
	}	
}

二、无感方波控制

        1、不使用比较器

               采用ADC中断的方式,实时计算三相的反电动势,来判断是否过零点。

#include <stdio.h>
#define  CW    0
#define  CCW   1

unsigned int  motorSectionTime;                     //两次过零点的时间,一般用一个定时器来纪录 
unsigned char motorWaitChangePhaseFlag;             // 等待换相标志 
typedef struct{
	int phase_A_EMF_AD;
	int phase_B_EMF_AD;
	int phase_C_EMF_AD;
}ADC_VALUE; 
ADC_VALUE gADC_value;     //三相反电动势 

typedef enum{	
    POS_UNKNOW = 0,
	POS_AB = 1,
	POS_AC = 2,
	POS_BC = 3,
	POS_BA = 4,
	POS_CA = 5,
	POS_CB = 6,   
} enu_motorpos_t;
enu_motorpos_t motorfluxposition;

//ADC中断 
unsigned char motorFindZerocrossFlag; 
void ADC_IRQHandler(void){
	static uint16_t motorbemfpositive = 0;
    static int16_t motorbemf = 0;
    static uint16_t motorbemfmid = 0;
    swtich(motorfluxposition){
    	case POS_AB: {
    		motorbemfmid = (gADC_value.phase_A_EMF_AD + gADC_value.phase_B_EMF_AD)>>1;
    		motorbemfpositive = gADC_value.phase_C_EMF_AD;
    		
			break;
		}
		
		case POS_CB:{
    		motorbemfmid = (gADC_value.phase_C_EMF_AD + gADC_value.phase_B_EMF_AD)>>1;
    		motorbemfpositive = gADC_value.phase_A_EMF_AD;			
			break;
		}
		
		case POS_CA:{
    		motorbemfmid = (gADC_value.phase_C_EMF_AD + gADC_value.phase_A_EMF_AD)>>1;
    		motorbemfpositive = gADC_value.phase_B_EMF_AD;			
			break;
		}
		
		case POS_BA:{
    		motorbemfmid = (gADC_value.phase_B_EMF_AD + gADC_value.phase_A_EMF_AD)>>1;
    		motorbemfpositive = gADC_value.phase_C_EMF_AD;			
			break;
		}
		
		case POS_BC:{
    		motorbemfmid = (gADC_value.phase_C_EMF_AD + gADC_value.phase_B_EMF_AD)>>1;
    		motorbemfpositive = gADC_value.phase_A_EMF_AD;			
			break;
		}
		
		case POS_AC:{
    		motorbemfmid = (gADC_value.phase_C_EMF_AD + gADC_value.phase_A_EMF_AD)>>1;
    		motorbemfpositive = gADC_value.phase_C_EMF_AD;			
			break;
		}
    	
		default:
			break;	
	} 

	if(motorFindZerocrossFlag ==0 &&motorWaitChangePhaseFlag ==0){        //等待换相完毕,未找到过零点 
		
		if(dirct == CW){
			//反电动势上升 
			if(motorfluxposition == POS_AB || motorfluxposition == POS_BC || motorfluxposition == POS_CA){
				if(motorbemfpositive >= (motorbemfmid + 30)){
					motorFindZerocrossFlag = 1;                       //上升找到过零点 
				}
			}else{      //反电动势下降
				if(motorbemfpositive <= (motorbemfmid - 30)){
					motorFindZerocrossFlag = 1;                       //下降找到过零点 
				}
				
			} 
				
		}else{
			
			if(motorfluxposition == POS_AB || motorfluxposition == POS_BC || motorfluxposition == POS_CA){
				if(motorbemfpositive <= (motorbemfmid - 30)){
					motorFindZerocrossFlag = 1;                       
				}
			}else{     
				if(motorbemfpositive >= (motorbemfmid + 30)){
					motorFindZerocrossFlag = 1;                       
				}
				
			} 
					
		}
	}
	
	if(motorFindZerocrossFlag == 1){
//		motorSectionTime = GetTimerCnt();                      //获取两次换相时间
		motorWaitChangePhaseFlag = 1;
//		OpenWaitChangePhaseTimer(motorSectionTime >> 2);       //motorSectionTime的时间刚好是物理上的60° 
															   //可用作换相提前角	 这个时间为了触发 Timer_IRQHandler
															   //来进行换相 
		motorFindZerocrossFlag  = 0; 
	} 		
} 

        有必要说明的是,反电动势过零点是存在上升沿河下降沿的,要区分一下。

        当找到过零点时,需要记录上一次与当前的间隔时间,用于实现换相提前角的操作。

        motorSectionTimes是用于触发比较器的溢出中断。这样既可以实现所谓换相提前与滞后。

//比较器溢出中断。 
void Timer_IRQHandler(void){
	if(motorWaitChangePhaseFlag){
		if(dirct == CW){
			motorfluxposition+=1;
			if(motorfluxposition == 7){
				motorfluxposition = POS_AB;
			}
		}else{
			motorfluxposition-=1;
			if(motorfluxposition == POS_UNKNOW){
				motorfluxposition = POS_CB;
			}
		}
		motorWaitChangePhaseFlag = 0;
	} 
}

        注意体会motorWaitChangePhaseFlag和motorFindZerocrossFlag这两个标志所起到的作用。

void MotorCommutatePhase(enu_motorpos_t motorfluxposition){
	switch(motorfluxposition){
		case POS_AB:{
			//A相上管开,B相下管开,其余关闭
			break;
		}
		
		case POS_CB:{
			//C相上管开,B相下管开,其余关闭
			break;
		}
		
		case POS_CA:{
			//C相上管开,A相下管开,其余关闭
			break;
		}
		
		case POS_BA:{
			//B相上管开,A相下管开,其余关闭
			break;
		}
		
		case POS_BC:{
			//B相上管开,C相下管开,其余关闭
			break;
		}
		
		case POS_AC:{
			//A相上管开,C相下管开,其余关闭
			break;
		}
		
		default:
			break;
	}
}

        这种控制方式就相对而言比较麻烦一点,需要ADC,一个定时器和一个比较器。

        2、使用比较器(2024.3.11)

                大体思路为:

                通过比较器来确定悬空相是否过零点,每一次触发中断都去采集一下过零点的时间,

                用作换相延时(定时器的溢出中断)。在定时器的溢出中断中实现换相操作。

                上面的方式比较容易一些。

//无感方波,使用比较器
//比较器(CMP):用于过零点检测。 
//定时器1    :用于检测2次过零点的时间。 
//定时器2    :用于进行换相操作。 

//用于确定悬空相作为输入比较 
unsigned char SetCMPTable[6] = {
	CMP_WC_TRGS,      //ab--C
	CMP_WB_TRGS,      //ac--B
	CMP_WA_TRGS,      //bc--A
	CMP_WC_TRGS,      //ba--C
	CMP_WB_TRGS,      //ca--B
	CMP_WA_TRGS,      //cb--A
}; 


code uint8_t driveCCwTable[8] =
{
  DRIVE_A_B,    //  0   
  DRIVE_A_C,    //  1   
  DRIVE_B_C,    //  2   
  DRIVE_B_A,    //  3   
  DRIVE_C_A,    //  4   
  DRIVE_C_B,    //  5  
  DRIVE_OFF,          
  DRIVE_OFF
};
code uint8_t driveCwTable[8] =
{
  DRIVE_B_A,    //  3
  DRIVE_C_A,    //  4
  DRIVE_C_B,    //  5
  DRIVE_A_B,    //  0
  DRIVE_A_C,    //  1
  DRIVE_B_C,    //  2
  DRIVE_OFF,
  DRIVE_OFF
};
//放置于比较中断函数中 
void CompareProgramTask(void){
	//获取过零点的时间
	//getzerocrossingtime();
	//....................
	//获得过零点时间可设置换相延时时间。 
	
} 

void  isrT2(void){
	if(dirct == CW){
		motorfluxposition +=1;
		motorfluxposition %=6;
	}else{
		motorfluxposition +=5;
		motorfluxposition %=6;
	}
	
	//change_phase(driveCwTable[motorfluxposition]);     //每过一次零点换一次相 
	if(dirct == CW) {
		//CMP2CON = SetCMPTable[motorfluxposition];      //根据当前相序 设置悬空相的输入用作比较 
		if(motorfluxposition & 0x01 == 0x01){
			//	CMPINT2 = CMP2INT_FALL;                  //寄存器操作下降沿 
 		}else{
 			//CMPINT2 = CMP2INT_RISE;	                 //寄存器操作上升沿 
		} 
	}else{
		//CMP2CON = SetCMPTable[motorfluxposition];      //根据当前相序 设置悬空相的输入用作比较 
		if(motorfluxposition & 0x01 == 0x00){
			//	CMPINT2 = CMP2INT_FALL;                  //寄存器操作下降沿 
 		}else{
 			//CMPINT2 = CMP2INT_RISE;	                 //寄存器操作上升沿 
		} 
	} 
	
}

  • 11
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
BLDC (Brushless DC)电机是一种无刷直流电机,它通过六步换相来实现转子的运动控制。六步换相是一种常用的控制方法,用于控制BLDC电机的转子位置和速度。 在六步换相中,电机的三个相依次通电,形成一个磁场,在磁场的作用下,转子受到力的作用而旋转。通过对相序的控制,可以实现转子的定向运动。 以下是实现BLDC六步换相的基本步骤: 1. 确定初始状态:首先,需要确定电机的初始状态,即确定转子的位置。可以使用霍尔传感器、编码器或反电动势等方式来检测转子位置。 2. 确定相序:根据转子的位置,确定下一步要通电的相序,即确定哪些相应该通电,以及它们的通电顺序。 3. 通电控制:根据确定的相序,通过控制功率驱动器或MOSFET等开关元件,将电流引入对应的相中。 4. 切换相序:在一个步进周期内,电流持续流过一个相后,需要切到下一个相。这可以通过相序表进行控制。 5. 控制频率:通过控制相序的切频率,可以调整电机的转速。通常,频率越高,转速越快。 6. 循环控制:通过循环执行上述步骤,可以实现电机的连续运转。 需要注意的是,BLDC电机的控制涉及到硬件和软件两方面。硬件方面需要有电机驱动器、传感器等组件,而软件方面需要编写相应的控制算法。在实际应用中,还需要考虑到电机的负载情况、电源电压等因素。 以上是关于BLDC六步换相的基本介绍,希望对你有所帮助。如果有任何进一步的问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值