本期的学习内容主要是:结合原理,对比PMSM有霍尔传感器和无霍尔传感器在程序上的区别,就有/无霍尔传感器程序中速度/位置检测的相关代码进行学习。
在PMSM中有霍尔传感器的程序中,主函数中定义了HALL_SENSORS,则执行HALL_HallTimerInit()函数,代码如下:
#elif defined HALL_SENSORS
HALL_HallTimerInit();
#endif
HALL_HallTimerInit()函数的功能是初始化处理霍尔传感器反馈的计时器,从而捕获霍尔传感器的位置,主要程序如下所示:
void HALL_HallTimerInit(void)
{
TIM_TimeBaseInitTypeDef
TIM_HALLTimeBaseInitStructure;
TIM_ICInitTypeDef TIM_HALLICInitStructure;
NVIC_InitTypeDef NVIC_InitHALLStructure;
GPIO_InitTypeDef GPIO_InitStructure;
#if defined(TIMER2_HANDLES_HALL)
/* TIM2 clock source enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
/* Enable GPIOA, clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_StructInit(&GPIO_InitStructure);
/* Configure PA.00,01 ,02 as Hall sensors input */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;// GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
#elif defined(TIMER3_HANDLES_HALL)
GPIO_PinRemapConfig(GPIO_FullRemap_TIM3, ENABLE);
/* TIM3 clock source enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
/* Enable GPIOA, clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC|RCC_APB2Periph_AFIO,
ENABLE);
/* Enable GPIOB, clock */
//RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
GPIO_StructInit(&GPIO_InitStructure);
/* Configure PA.06,07 PB.00 as Hall sensors input */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7| GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOC, &GPIO_InitStructure);
//GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
//GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
//GPIO_Init(GPIOB,&GPIO_InitStructure);
#else // TIMER4_HANDLES_HALL
/* TIM4 clock source enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);
/* Enable GPIOB, clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
/* Configure PB.06,07,08 as Hall sensors input */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6,GPIO_Pin_7, GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOB, &GPIO_InitStructure);
#endif
// Timer configuration in Clear on capture mode
TIM_DeInit(HALL_TIMER);
TIM_TimeBaseStructInit(&TIM_HALLTimeBaseInitStructure);
// Set full 16-bit working range
TIM_HALLTimeBaseInitStructure.TIM_Period = U16_MAX;
TIM_HALLTimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInit(HALL_TIMER,&TIM_HALLTimeBaseInitStructure);
TIM_ICStructInit(&TIM_HALLICInitStructure);
TIM_HALLICInitStructure.TIM_Channel = TIM_Channel_1;
TIM_HALLICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling;
TIM_HALLICInitStructure.TIM_ICFilter = ICx_FILTER;
TIM_ICInit(HALL_TIMER,&TIM_HALLICInitStructure);
// Force the HALL_TIMER prescaler with immediate access (no need of an update event)
TIM_PrescalerConfig(HALL_TIMER,(u16)HALL_MAX_RATIO,TIM_PSCReloadMode_Immediate);
TIM_InternalClockConfig(HALL_TIMER);
//Enables the XOR of channel 1, channel2 and channel3
TIM_SelectHallSensor(HALL_TIMER, ENABLE);
TIM_SelectInputTrigger(HALL_TIMER,TIM_TS_TI1FP1);
TIM_SelectSlaveMode(HALL_TIMER,TIM_SlaveMode_Reset);
// Source of Update event is only counter overflow/underflow
TIM_UpdateRequestConfig(HALL_TIMER,TIM_UpdateSource_Regular);
/* Enable the HALL_TIMER IRQChannel*/
#if defined(TIMER2_HANDLES_HALL)
NVIC_InitHALLStructure.NVIC_IRQChannel = TIM2_IRQChannel;
#elif defined(TIMER3_HANDLES_HALL)
NVIC_InitHALLStructure.NVIC_IRQChannel = TIM3_IRQChannel;
#else //TIMER4_HANDLES_HALL
NVIC_InitHALLStructure.NVIC_IRQChannel = TIM4_IRQChannel;
#endif
NVIC_InitHALLStructure.NVIC_IRQChannelPreemptionPriority = TIMx_PRE_EMPTION_PRIORITY;
NVIC_InitHALLStructure.NVIC_IRQChannelSubPriority = TIMx_SUB_PRIORITY;
NVIC_InitHALLStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitHALLStructure);
// Clear the TIMx's pending flags
TIM_ClearFlag(HALL_TIMER, TIM_FLAG_Update + TIM_FLAG_CC1 + TIM_FLAG_CC2 + \TIM_FLAG_CC3 + TIM_FLAG_CC4 + TIM_FLAG_Trigger +TIM_FLAG_CC1OF + \TIM_FLAG_CC2OF + TIM_FLAG_CC3OF + TIM_FLAG_CC4OF);
// Selected input capture and Update (overflow) events generate interrupt
TIM_ITConfig(HALL_TIMER, TIM_IT_CC1,ENABLE);
TIM_ITConfig(HALL_TIMER, TIM_IT_Update,ENABLE);
TIM_SetCounter(HALL_TIMER,HALL_COUNTER_RESET);
TIM_Cmd(HALL_TIMER, ENABLE);
}
其中,在整个程序中定时器2和定时器4没有定义,而定时器3则被用来作为霍尔传感器反馈定时器,通过定义TIMER3_HANDLES_HALL,与霍尔传感器相连。
在PMSM中有霍尔传感器的程序中,转子速度测量的方式为滚动识别的方式,通过比较当前状态和前一个状态推断出转子的转动方向,具体代码如下:
void TIM3_IRQHandler(void)
{
static u8 bHallState;
u8 bPrevHallState;
// Check for the source of TIMx int - Capture or Update Event -
if (TIM_GetFlagStatus(HALL_TIMER, TIM_FLAG_Update) == RESET )
{
bPrevHallState = bHallState;
bHallState = ReadHallState();
#if (HALL_SENSORS_PLACEMENT == DEGREES_120)
switch(bHallState)
{
case STATE_5:
if(bPrevHallState == STATE_5)
{
if(bSpeed<0)
{
bSpeed = POSITIVE_SWAP;
}
else
{
bSpeed = NEGATIVE_SWAP;
}
}
else if (bPrevHallState == STATE_6)
{
bSpeed = POSITIVE;
}
else if (bPrevHallState == STATE_3)
{
bSpeed = NEGATIVE;
}
//Update angle
if(bSpeed<0)
{
hElectrical_Angle = (s16)(S16_PHASE_SHIFT+S16_60_PHASE_SHIFT);
}
else if(bSpeed!= ERROR)
{
hElectrical_Angle = S16_PHASE_SHIFT;
}
break;
case STATE_3:
if(bPrevHallState == STATE_3)
{
//a speed reversal occured
if(bSpeed<0)
{
bSpeed = POSITIVE_SWAP;
}
else
{
bSpeed = NEGATIVE_SWAP;
}
}
else if (bPrevHallState == STATE_5)
{
bSpeed = POSITIVE;
}
else if (bPrevHallState == STATE_6)
{
bSpeed = NEGATIVE;
}
//Update of the electrical angle
if(bSpeed<0)
{
hElectrical_Angle =(s16)(S16_PHASE_SHIFT+S16_120_PHASE_SHIFT+S16_60_PHASE_SHIFT);
}
else if(bSpeed!= ERROR)
{
hElectrical_Angle =(s16)(S16_PHASE_SHIFT + S16_120_PHASE_SHIFT);
}
break;
case STATE_6:
if(bPrevHallState == STATE_6)
{
if(bSpeed<0)
{
bSpeed = POSITIVE_SWAP;
}
else
{
bSpeed = NEGATIVE_SWAP;
}
}
if(bPrevHallState == STATE_3)
{
bSpeed = POSITIVE;
}
else if(bPrevHallState == STATE_5)
{
bSpeed = NEGATIVE;
}
if(bSpeed<0)
{
hElectrical_Angle =(s16)(S16_PHASE_SHIFT - S16_60_PHASE_SHIFT);
}
else if(bSpeed!= ERROR)
{
hElectrical_Angle =(s16)(S16_PHASE_SHIFT - S16_120_PHASE_SHIFT);
}
break;
default: bSpeed = ERROR;
break;
}
本段程序中,霍尔传感器的状态是通过函数ReadHallState()获得,同时由于霍尔传感器的绝对性,使得,当得知霍尔传感器的输出状态,便可以重建转子位置。程序中也是每次霍尔传感器发生变化,产生中断,就会更新转子的电角度,根据电机的转向和霍尔传感器的状态,通过初始化软件变量,便可以计算出当前电角度,用于Park变化。从而可以得知,转子的机械频率,即转子的转速,具体代码如下:
s16 HALL_GetSpeed ( void )
{
s32 wAux;
if( hRotorFreq_dpp == HALL_MAX_PSEUDO_SPEED)
{
return (HALL_MAX_SPEED);
}
else
{
wAux = ((hRotorFreq_dpp* SAMPLING_FREQ * 10)/(65536*POLE_PAIR_NUM));
return (s16)wAux;
}
}
其中转子电频率hRotorFreq_dpp通过函数HALL_GetRotorFreq()获得。
在PMSM中无霍尔传感器的程序中,主函数中定义了NO_SPEED_SENSORS,则执行STO_StateObserverInterface_Init()函数,代码如下:
#elif defined NO_SPEED_SENSORS
STO_StateObserverInterface_Init();
#endif
其中,STO_StateObserverInterface_Init()的作用为提供观察转子位置的条件,当函数STO_Start_Up()启动时,各个相关参数进行初始化,另外,通过STO_Calc_Rotor_Angle()函数,运用离散状态检测方程,从而实现电机反电动式的计算。并且通过一个数字锁相环的方法,根据反电动势计算转子速度和角度,具体代码如下:
void STO_Calc_Rotor_Angle(Volt_Components Stat_Volt_alfa_beta,Curr_ComponentsStat_Curr_alfa_beta, s16 hBusVoltage)
{
s32 wIalfa_est_Next,wIbeta_est_Next;
s32 wBemf_alfa_est_Next,wBemf_beta_est_Next;
s16 hValfa,hVbeta;
s16 hIalfa_err, hIbeta_err;
s16 hRotor_Speed;
s32 bDirection;
if (wBemf_alfa_est > (s32)(S16_MAX*hF2))
{
wBemf_alfa_est = S16_MAX*hF2;
}
else if (wBemf_alfa_est <= (s32)(S16_MIN*hF2))
{
wBemf_alfa_est = -S16_MAX*hF2;
}
if (wBemf_beta_est > (s32)(S16_MAX*hF2))
{
wBemf_beta_est = S16_MAX*hF2;
}
else if (wBemf_beta_est <= (s32)(S16_MIN*hF2))
{
wBemf_beta_est = -S16_MAX*hF2;
}
if (wIalfa_est > (s32)(S16_MAX*hF1))
{
wIalfa_est = S16_MAX*hF1;
}
else if (wIalfa_est <= (s32)(S16_MIN*hF1))
{
wIalfa_est = -S16_MAX*hF1;
}
if (wIbeta_est > S16_MAX*hF1)
{
wIbeta_est = S16_MAX*hF1;
}
else if (wIbeta_est <= S16_MIN*hF1)
{
wIbeta_est = -S16_MAX*hF1;
}
hIalfa_err = (s16)((wIalfa_est/hF1)-Stat_Curr_alfa_beta.qI_Component1);
hIbeta_err = (s16)((wIbeta_est/hF1)-Stat_Curr_alfa_beta.qI_Component2);
hValfa = (s16)((Stat_Volt_alfa_beta.qV_Component1*hBusVoltage)/32768);
hVbeta = (s16)((Stat_Volt_alfa_beta.qV_Component2*hBusVoltage)/32768);
/*alfa axes observer*/
wIalfa_est_Next = (s32)(wIalfa_est-(s32)(hC1*(s16)(wIalfa_est/hF1))+ (s32)(hC2*hIalfa_err)+ (s32)(hC5*hValfa)- (s32)(hC3*(s16)(wBemf_alfa_est/hF2)));
//I(n+1)=I(n)-rs*T/Ls*I(n)+K1*(I(n)-i(n))+T/Ls*V-T/Ls*emf
wBemf_alfa_est_Next = (s32)(wBemf_alfa_est+(s32)(hC4*hIalfa_err)+
(s32)(hC6*hRotor_Speed_dpp*(wBemf_beta_est/(hF2*hF3))));
//emf(n+1)=emf(n)+K2*(I(n)-i(n))+p*w*emfb*T
/*beta axes observer*/
wIbeta_est_Next = (s32)(wIbeta_est-(s32)(hC1*(s16)(wIbeta_est/hF1))+ (s32)(hC2*hIbeta_err)+ (s32)(hC5*hVbeta)- (s32)(hC3*(s16)(wBemf_beta_est/hF2)));
wBemf_beta_est_Next = (s32)(wBemf_beta_est+(s32)(hC4*hIbeta_err)- (s32)(hC6*hRotor_Speed_dpp*(wBemf_alfa_est/(hF2*hF3))));
/* Extrapolation of present rotation direction, necessary for PLL */
if (hRotor_Speed_dpp >=0)
{
bDirection = 1;
}
else
{
bDirection = -1;
}
/*Calls the PLL blockset*/
hBemf_alfa_est = wBemf_alfa_est/hF2;
hBemf_beta_est = wBemf_beta_est/hF2;
hRotor_Speed = Calc_Rotor_Speed((s16)(hBemf_alfa_est*bDirection),(s16)(-hBemf_beta_est*bDirection));
Store_Rotor_Speed(hRotor_Speed);
hRotor_El_Angle = (s16)(hRotor_El_Angle +hRotor_Speed);
/*storing previous values of currents and bemfs*/
wIalfa_est = wIalfa_est_Next;
wBemf_alfa_est = wBemf_alfa_est_Next;
wIbeta_est = wIbeta_est_Next;
wBemf_beta_est = wBemf_beta_est_Next;
}
其中,函数的输入分别为:定子电流(Stat_Curr_alfa_beta),施加的电压命令(Stat_Volt_alfa_beta)和测量的直流母线电压(hBusVoltage)。
另外,函数STO_Get_Electrical_Angle()返回转子电角度,函数STO_Get_Mechanical_Angle()返回转子机械角度,他们的关系为:
s16 STO_Get_Mechanical_Angle(void)
{
return ((s16)(STO_Get_Electrical_Angle()/POLE_PAIR_NUM));
}
函数STO_Get_Speed()返回转子电速度,STO_Get_Speed_Hz()返回转子机械速度,他们之间的关系为:
s16 STO_Get_Speed_Hz(void)
{
return (s16)((STO_Get_Speed()* SAMPLING_FREQ * 10)/(65536*POLE_PAIR_NUM));
}
通过本期的学习,结合PMSM中有/无传感器的转子位置及转速检测算法的原理,对其相应的程序有了一定的认识,包括对各个参数的理解、信号反馈的处理过程等内容。接下来,将通过在实习中的动手实践,把所学的理论知识同实际进行一个初步的结合,从中提高自己。