关键词不能为空

当前您在: 主页 > 英语 >

svpwm完整程序

作者:高考题库网
来源:https://www.bjmy2z.cn/gaokao
2021-02-09 08:40
tags:

-

2021年2月9日发(作者:6310)




头文件





UserParms.h




C


文件





ACIM.c



Encoder.c



InitCurModel.c




UserParms.h




//#define TORQUE_MODE



#define DIAGNOSTICS





//****************


振荡器



************************************



#define dFoscExt 7372800 //


外部晶振或时钟频率



(Hz)



#define dPLL 8 // PLL


比率




#define dLoopTimeInSec 0.00005 // PWM


周期



- 100 uS, 10Khz PWM



#define dDeadTimeSec 0.000002 //


以秒为单位的死区时间




// Derived



#define dFosc (dFoscExt*dPLL) //


时钟频率



( Hz)



#define dFcy (dFosc/4) //


指令频率



( Hz)



#define dTcy (1.0/dFcy) //


指令周期



(s)



#define dDeadTime (int)(dDeadTimeSec*dFcy) //




dTcys


为单位的死区时间




#define dLoopInTcy (dLoopTimeInSec/dTcy) //




Tcy


为单位的基本循环周期




#define dDispLoopTime 0.100 //


显示和按钮状态查询循环






//****************


电机参数



********************************



#define diPoles 1 //


极对数




#define diCntsPerRev 2000 //


每转的编码器线数




#define diNomRPM 3600 //


电机铭牌上的转速(



RPM





#define dfRotorTmConst 0.078 //


以秒为单位的转子时间常数,来自电机制造商






//****************


测量



*************************************



#define diIrpPerCalc 30 //


每次速度计算的



PWM


循环次数






//************** PI


系数



************************************



#define dDqKp 0x2000 // 4.0 (NKo = 4)



#define dDqKi 0x0100; // 0.125



#define dDqKc 0x0100; // 0.125



#define dDqOutMax 0x5A82; // 0.707


设定该值以避免饱和






#define dQqKp 0x2000; // 4.0 (NKo = 4)



#define dQqKi 0x0100; // 0.125



#define dQqKc 0x0100; // 0.125



#define dQqOutMax 0x5A82; // 0.707


设定该值以避免饱和






#define dQrefqKp 0x4000 // 8.0 (NKo = 4)



#define dQrefqKi 0x0800 // 1.0



#define dQrefqKc 0x0800 // 1.0



#define dQrefqOutMax 0x3FFF // 0.4999


设定该值以避免饱和






//************** ADC


换算



************************************



//


标定常数



:


由校准或硬件设计确定。




#define dqK 0x3FFF; //


等于



0.4999



#define dqKa 0x3FFF; //


等于



0.4999



#define dqKb 0x3FFF; //


等于



0.4999





//**************


弱磁



************** **************************



//


在恒转矩范围内的磁通给定值。




//


根据经验确定、给出额定压



/


频比




#define dqK1 3750; //







ACIM.c



< br>/********************************************** ************************



**





*


作者



: John Theys/Dave Ross *



**



*


文件名



: ACIM.c *



*


日期



: 10/31/03 *



*


文件版本



: 3.00 *



**



*


使用工具



: MPLAB -> 6.43 *



*


编译器



-> 1.20.00 *



**



*


链接文件



: *



**



**



************* ************************************************** ********



*10/31/03 2.00


发布电机运行正常,但仍有些遗留的小问题




*



*12/19/03 2.01


完成结构,为所有用户定义变量创建



UserParms.h





*



*0 2/12/043.00-


从项目中去除了不需要的文件。




* -




iRPM


改为



int


以纠正浮点计算问题。




* -CalcVel()


和转速控制环仅在



iIrpPerC alc


指定的数个循环周期后执行




*



*-


增加了



iDispLoopCount


变量以安排显示和按钮子程序的执行时间




* -trig.s


文件改为使用程序空间来存储正弦数据。




*-


增加了



DiagnosticsOutput()


函数,该函数使用输 出比较通道来输出控




*


制变量信息。




*-


增加了



TORQUE_MODE


定义以忽略转速控制环。




*-


关闭



curmodel.s


文件中的



SATDW


位。自动饱和功能阻止转差角计算正确

< br>



*


翻转返回。




************************************************* ***********************



*


代码说明




*



*


该文件给出了使用



dsPIC30F


实现的三相交流感应电机矢量控制实例。



*


采用空间矢量调制作为控制策略。




*************************** ********************************************/



/***************************


全局定义



***********************/




#define INITIALIZE



#include



#include



#include



#include



#include



#include



#include



#include



#include



#include



#include



#include



#include



#include



#include





/***********************


全局定义结束



********************/




unsigned short uWork;



short iCntsPerRev;



short iDeltaPos;






union {





struct



{



unsigned DoLoop:1;



unsigned OpenLoop:1;



unsigned RunMotor:1;



unsigned Btn1Pressed:1;



unsigned Btn2Pressed:1;



unsigned Btn3Pressed:1;



unsigned Btn4Pressed:1;



unsigned ChangeMode:1;



unsigned ChangeSpeed:1;



unsigned :7;



}bit;





WORD Word;



} uGF; //


通用标志






tPIParm PIParmQ;



tPIParm PIParmQref;



tPIParm PIParmD;





tReadADCParm ReadADCParm;





int iRPM;



WORD iMaxLoopCnt;



WORD iLoopCnt;



WORD iDispLoopCnt;





/************** ************************************************** ******/



void __attribute__((__interrupt__)) _ADCInterrupt(void);



void SetupBoard( void );



bool SetupParm(void);



void DoControl( void );



void Dis_RPM( BYTE bChrPosC, BYTE bChrPosR );



void DiagnosticsOutput(void);





/********************


主函数开头



*************************/




int main ( void )





{



SetupPorts();



InitLCD();





while(1)



{



= 0; //


清除标志






//


初始化模式




op = 1; //


以开环模式起动






//


初始化



LED



pinLED1 = 0;



pinLED2 = !op;



pinLED3 = 0;



pinLED4 = 0;





//


初始化控制板




SetupBoard();





//


对用户指定参数进行初始化并在出错时停止





if( SetupParm() )



{



//


错误




or=0;



return;






}



//


清零



i





= 0;



= 0;



= 0;



iMaxLoopCnt = 0;



Wrt_S_LCD(



Wrt_S_LCD(



//


使能



ADC


中断并开始主循环定时




= 0;



= 1;



if(!or)



{



//


初始化电流偏移量补偿




while(!pinButton1) //


在此处等待直至按钮



1


按下




{



ClrWdt();



//


开始偏移量累加



//


并在等待时对电流偏移量进行累加




MeasCompCurr();



}



while(pinButton1); //


当按钮



1


释放时




or = 1; //


随后起动电机




}



//


电机运行




Mode = 1;



//


使能电机控制



PCB


上的驱动器



IC



pinPWMOutputEnable_ = 0;



Wrt_S_LCD(



Wrt_S_LCD(



//


电机运行循环




while(1)



{



ClrWdt();



//


如果使用



OC7




OC8


显示矢量控制变量,




//


调用更新代码。




#ifdefDIAGNOSTICS



DiagnosticsOutput();



#endif




//


每隔



50


毫秒执行更新



LCD


显示和查询按钮状态的代码。




//




if(iDispLoopCnt >= dDispLoopCnt)



{



//Display RPM



Dis_RPM(5,0);





//


按钮



1


控制电机的起停





if(pinButton1)



{



if( !1Pressed )





1Pressed = 1;



}



else







{





if( 1Pressed )



{



//


按钮刚被释放




1Pressed = 0;



//


开始停止过程




or = 0;



pinPWMOutputEnable_ = 1;



break;



}





}





//


在运行时按钮



2


将控制开



/


闭环模式之间的切换





if(pinButton2)



{



if( !2Pressed )





2Pressed = 1;



}





else



{



if( 2Pressed )





{



//


按钮刚释放




2Pressed = 0;



Mode = 1;



op = ! op;



pinLED2 = !op;



}





}





//


在运行时按钮



3


将加倍



/


减半速度或转矩给定





if(pinButton3)



{



if( !3Pressed )





3Pressed = 1;



0 = 0;



}





else



{



if( 3Pressed )





{



//


按钮刚释放




3Pressed = 0;



Speed = !Speed;



pinLED3 = Speed;



0 = 1;



}





}





//


按钮



4


不具备任何功能





if(pinButton4)



{



if( !4Pressed )





4Pressed = 1;



}





else



{



if( 4Pressed )





{



//


按钮刚被释放




4Pressed = 0;



//***


此处加入按钮



4


功能的代码




}





}






} //


显示和按钮查询代码结束





} //


电机运行循环结束





} //


主循环结束





//


不应执行到此处




while(1){}



}




//------------- -------------------------------------------------- -----//





Id


控制环、



Iq


控制环和速度控制环中的每个控制环执行一次



PI


迭代




void DoControl( void )



{



short i;




//


假定



ADC


通道



0


具有来自速度电位器(



AN7


)的有符号小数格式原始



A/D






ReadSignedADC0( &ReadADCParm );





//


设定给定速度




if(Speed)



f = ue/8;



else



f = ue/16;





if( op )



{



//


开环:强制旋转角、



Vd




Vq





if( Mode )



{



//


改变为开环模式




Mode = 0;



//


同步角度




ux = ux;




//


未使用



VqRef




VdRef



= 0;



= 0;



}





ch = f;





//




CorrectPhase


所需的给定值和符号




//


计算



1.15


格式的转子磁通旋转角。




ch = ch;



CurModel();





= 0;





if( ch >= 0 )



i = ch;



else



i = -ch;





uWork = i <<2;





if( uWork > 0x5a82 )



uWork = 0x5a82;





if( uWork < 0x1000 )



uWork = 0x1000;







= uWork;





OpenLoop();



= ux;





}





else



//


闭环矢量控制




{




if( Mode )



{



//


改变为闭环模式




Mode = 0;





//


同步角度以及准备



qdImag



ux = ux;



=



}





//


根据电流模型计算角度




ch = ch;





CurModel();





= ux;





//


计算弱磁控制模式的



qVdRef



FdWeakening();





//


设定给定速度





//


如果应用运行在转矩模式,转速控制环将被忽略。




//


从电位器读取的转速给定值将直接用作转矩给定



VqRef





#ifdefTORQUE_MODE



= f;





#else



//


通过对比每一次转速计算中的 中断数和速度计数采样数来确定是否可以获得新的转速信


息。




//



//


如果可以获得新的转速信息,则计算新的转速值并执行




//


转速控制环。




if(tDwn == rCalc)




{





//


根据编码器累计计数值来计算转速




CalcVel();



//


执行转速控制环




s = ch;



= f;



CalcPI(&PIParmQref);



=



}



#endif





// Q




PI


控制




s =



=



CalcPI(&PIParmQ);



=





// D




PI


控制






s =



=



CalcPI(&PIParmD);



=





}



}





//- -------------------------------------------------- -----------------//



ADC


中断服务程序执行速度计算以及电压矢量更新循环。




// ADC


采样和转换由



PWM


周期触发。




//


速度计算假定计算之间的间隔时间是固定的。




//------------------------- -------------------------------------------




void __attribute__((__interrupt__)) _ADCInterrupt(void)





{



= 0;



//


递增控制显示和按钮功能执行的计数变量。




//



iDispLoopCnt++;




//


累计自上一次中断后的编码器计数




CalcVelIrp();





if( or )



{





//


置位用于诊断的



LED1



pinLED1 = 1;





//


使用



TMR1


来测量用于诊断的中断时间




TMR1 = 0;



iLoopCnt = TMR1;





MeasCompCurr();





//


根据



qSin




qCos




qIa




qIb


计算



qId




qIq


ClarkePark();




//


计算控制值




DoControl();





//


根据



qAngle


计算



qSin




qCos



SinCos();





//


根据



qSin




qCos




qVd




qVq


计算



qV


alpha



InvPark() ;





//


根据



qValpha




qVbeta


计算



Vr1




Vr2




Vr3



CalcRefVec();




qVbeta








//


根据



Vr1




Vr2




Vr3


计算和设定



PWM


占空比




CalcSVGen();





//


测量循环时间




iLoopCnt = TMR1 - iLoopCnt;



if( iLoopCnt > iMaxLoopCnt )





iMaxLoopCnt = iLoopCnt;





//


清零用于诊断的



LED1



pinLED1 = 0;



}





}







//------------- -------------------------------------------------- -----//



SetupBoard



//



//


初始化控制板




//------------------------- -------------------------------------------




void SetupBoard( void )



{



BYTE b;





//


禁止



ADC


中断




= 0;





//


复位电机控制功率模块上的所有故障。




pinFaultReset = 1;



for(b=0;b<10;b++)





Nop();



pinFaultReset = 0;





//


确保



PFC


开关是关闭的。




pinPFCFire = 0;



//


确保制动开关是关闭的。




pinBrakeFire = 0;





}





//- -------------------------------------------------- -----------------//



Dis_RPM



//



//


显示



RPM



//---------- -------------------------------------------------- --------




void Dis_RPM( BYTE bChrPosC, BYTE bChrPosR )



{





if (Cnt < 0)



Wrt_S_LCD(



else



Wrt_S_LCD(





iRPM = Cnt*60/



(eriod*rCalc*erRev);





Wrt_Signed_Int_LCD( iRPM, bChrPosC+1, bChrPosR);



}



//--------------------------------------- -----------------------------bool



SetupParm(void)



{





//


开启抗饱和功能以确保能够平滑处理溢出。




= 0;





//


设置所需参数





//


选取定标值为



8


倍速度和电流标称值





//


在定标时使用



8


倍电机标称机械转速(单位为



RPM





MechRPM = diNomRPM*8;





//


极对数




= diPoles





//




ds PIC


正交编码配置检测的每转编码器计数值。




//



erRev = diCntsPerRev;










//


以秒为单位的转子时间常数




TmConst = dfRotorTmConst;





//


基 本循环周期(单位为秒)





PWM


中断周期)




eriod = dLoopInTcy * dTcy; //


循环周期(以周期为单位)



*




/


周期






//


编码器转速中断周期(单位为秒)





pPeriod = eriod;





//


每次转速计算的



vel


中断数。




rCalc = diIrpPerCalc; //


以循环为单位






//


电机的定标机械速度(单位为转



/


秒)




MechRPS = MechRPM/60.0;





//


定标后的电机磁通转速(单位为转



/


秒)



< /p>


//


通过该值定标后的所有无量纲磁通转速。



FluxRPS = *MechRPS;





//


磁通矢量每转一周的最小周期时间(单位为秒)




FluxPeriod = 1.0/FluxRPS;





//


在最大磁通转速时的每个



LoopTime


的转数系数




FracRevPerLoop = eriod * FluxRPS;





//


定标后的电机磁通转速(单位为弧度



/


秒)




//


通过该值定标后的所有无量纲转速(单位为弧度



/


秒)





FluxSpeed = 6.283 * FluxRPS;





// iScaleMechRPM


时的编码器计数频率




CntRate = erRev * (MechRPM/60.0);





// =============


开环



======================




a = 32768.0 * 2 * * eriod *





MechRPS;



ch = dqOL_VelMech;



f = ch;





InitOpenLoop();





// =============


编码器



===============




if( InitEncoderScaling() )



//


出错




return True;





// ============= ADC -


测量电流和电位器



======================




//


定标常数:由校准或硬件设计决定。




= dqK;





= dqKa;



= dqKb;





//


初始偏移量




InitMeasCompCurr( 450, 730 );





// =============


电流模型



===============




if(InitCurModelScaling())



//


出错




return True;








// =============


弱磁



===============



//


恒转矩范围的弱磁常数




1 = dqK1; //


磁通给定值





// ============= PI D




===============



= dDqKp;



= dDqKi;



= dDqKc;



x = dDqOutMax;



n = -x;




InitPI(&PIParmD);





// ============= PI Q




===============



= dQqKp;



= dQqKi;



= dQqKc;



x = dQqOutMax;



n = -x;




InitPI(&PIParmQ);





// ============= PI Qref




===============



= dQrefqKp;



= dQrefqKi;



= dQrefqKc;



x = dQrefqOutMax;



n = -x;




InitPI(&PIParmQref);





// ============= SVGen ===============



//




PWM


周期设定为循环时间




riod = dLoopInTcy;




// ============= TIMER #1 ======================



PR1 = 0xFFFF;



= 1;



= 1; //


预分频比为



8




=>


一个单位为



1.08504 uS




// =============


电机



PWM ======================




PDC1 = 0;



PDC2 = 0;



PDC3 = 0;



PDC4 = 0;





//


中心对齐



PWM





//


注:


PWM

周期设定为



dLoopInTcy/2

< br>,但由于先采用递增计数随后为递减计数,




// =>


在计数到零时中断标志置



1 =>


因此实际中断周期为



dLoopInTcy



//



PTPER = dLoopInTcy/2; //




PWM


周期设定为循环时间,该参数在



parms.h


中定义





PWMCON1 = 0x0077; //


使能



PWM 1,2,3


对工作在互补模式




DTCON1 = dDeadTime; //


死区时间




DTCON2 = 0;



FLTACON = 0; //


未使用



PWM


故障引脚




FLTBCON = 0;



PTCON = 0x8002; //


使能



PWM


中心对齐






// SEVTCMP:


特殊事件比较计数寄存器




//


相对于



PWM


周期的



ADC


捕获设定相位:



0


偏移量和递增计数




SEVTCMP = 2; //


不能为



0


,否则关断触发器(文档中未列明)







R = 0;





// =============


编码器



===============




MAXCNT = erRev;



POSCNT = 0;



QEICON = 0;



= 7; //


通过



MAXCNT


脉冲复位



x4



= 0; //


不要让索引脉冲复位计数器




= 0; //


方向




DFLTCON = 0; //


数字滤波器设定为关闭






// ============= ADC -


测量电流和电位器给定值



======================



// ADC


设定为对以下通道同时进行采样:




// CH0=AN7, CH1=AN0, CH2=AN1, CH3=AN2



//


采样由



PWM


触发,且采样结果以有符号小数形式存放。






ADCON1 = 0;



//


有符号小数格式(



DOUT = sddd dddd dd00 0000





= 3;



//


电机控制



PWM


间隔终止采样并启动转换




= 3;



//


同时采样选择位(仅当



CHPS =01




1x


时应用)




//


同时采样



CH0




CH1




CH2




CH3


(当



CHPS = 1x


时)




//


同时采样



CH0




CH1


(当



CHPS=01


时)




= 1;


//


在上一次转换结束后立即开始采样。




// SAMP


位自动置位。




= 1;





ADCON2 = 0;



//


同时采样



CH0




CH1




CH2




CH3


(当



CHPS = 1x


时)




= 2;





ADCON3 = 0;



// A/D


转换时钟选择位



= 8 * Tcy



= 15;





/* ADCHS



ADC


输入通道选择寄存器



*/



ADCHS = 0;



// CH0




AN7



0SA = 7;



// CH1


正极性输入为



AN0




CH2


正极性输入为



AN1




CH3


正极性输入为



AN2



123SA = 0;





/* ADPCFG



ADC


端口配置寄存器



*/



//


将所有端口设置为数字端口




ADPCFG = 0xFFFF;



0 = 0; // AN0


模拟




1 = 0; // AN1


模拟




2 = 0; // AN2


模拟




7 = 0; // AN7


模拟






/* ADCSSL



ADC


输入扫描选择寄存器



*/



ADCSSL = 0;





//


开启



A/D


模块




= 1;





#ifdefDIAGNOSTICS



//


对用于诊断模式的输出比较通道



7




8


进行初始化。







// PWM


模式中使用比较




// Timer2


用作时基




PR2 = 0x1FFF;



OC7CON = 0x0006;



OC8CON = 0x0006;



= 1;



#endif





return False;



}





#ifdefDIAGNOSTICS



void DiagnosticsOutput(void)



{



int Data;





if(IFS0bits.T2IF)



{



IFS0bits.T2IF = 0;



Data = ( >> 4) + 0xfff;



if(Data > 0x1ff0) Data = 0x1ff0;



if(Data < 0x000f) Data = 0x000f;



OC7RS = Data;



Data = (ch) + 0x0fff;



if(Data > 0x1ff0) Data = 0x1ff0;



if(Data < 0x000f) Data = 0x000f;



OC8RS = Data;



}





}



#endif







Encoder.c




//


编码器子程序的定标





#include



#include



#include





/************************** ********************************



InitEncoderScaling




对编码器子程序的定标常量进行初始化。




函数参数:




CntsPerRev


:来自正交编 码器的每转编码器计数值




Scal ingSpeedInRPS


:用于基本转速定标的每秒转数




IrpPerCalc


:每次转速计 算的



CalcVelIrp


中断数




VelIrpPeriod



VelCalcIrp


中断间的周期(单位为秒)




对于




CalcAng




运行时方程:





qMechAng = qKang * (POSCNT*4) / 2^Nang




定标方程:





qKang = (2^15)*(2^Nang)/CntsPerRev.


对于



CalcV

elIrp




CalcVel




运行时方程:





qMechVel = qKvel * (2^15 * Delta / 2^Nvel)




定标方程:





fVelCalcPeriod = fVelIrpPeriod * iIrpPerCalc



MaxCntRate = CntsPerRev * ScaleMechRPS



MaxDeltaCnt = fVelCalcPeriod * MaxCntRate



qKvel = (2^15)*(2^Nvel)/MaxDeltaCnt





*** ************************************************** *****/





bool InitEncoderScaling( void )





{



float fVelCalcPeriod, fMaxCntRate;



long MaxDeltaCnt;



long K;





erRev = erRev;





K = 32768;



K *= 1 << Nang;



= K/erRev;





rCalc = rCalc;



fVelCalcPeriod = pPeriod * rCalc;



fMaxCntRate = erRev * MechRPS;



MaxDeltaCnt = fVelCalcPeriod * fMaxCntRate;





// qKvel = (2^15)*(2^Nvel)/MaxDeltaCnt



K = 32768;



K *= 1 << Nvel;



K /= MaxDeltaCnt;



if( K >= 32768 )





//


出错




return True;



= K;





//




C alcVelIrp


使用的局部变量进行初始化。




InitCalcVel();



return False;





}








InitCurModel.c




//


电流模型子程序定标





#include



#include



#include





/************************** ********************************



InitCurModelScaling




对电流模型子程序中的定标常数进行初始化。




物理常数:




fRotorTmConst


转子时间常数,单位为秒。




方程的物理形式:



励磁电流(安培)






Imag = Imag + (fLoopPeriod/fRotorTmConst)*(Id - Imag)




转差速度,单位为



RPS





VelSlipRPS = (1/fRotorTmConst) * Iq/Imag / (2*pi)




转子磁通速度,单位为



RPS





VelFluxRPS = iPoles * VelMechRPS + VelSlipRPS




转子磁通角(弧度)






AngFlux = AngFlux + fLoopPeriod * 2 * pi * VelFluxRPS




定标后的变量:




qImag


采用最大电流定标后的励磁电流。




qVelSlip


采用



fScaleMechRPS


定标后的机械转差速度,单位为



RPS





qAngFlux


采用



pi


定标后的磁通角。




定标后的方程:





qImag = qImag + qKcur * (qId - qImag)



qVelSlip = Kslip * qIq/qImag



qAngFlux = qAngFlux + Kdelta * (qVelMech + qVelSlip)




定标因子:





qKcur = (2^15) * (fLoopPeriod/fRotorTmConst)



qKdelta = (2^15) * 2 * iPoles * fLoopPeriod * fScaleMechRPS



qKslip = (2^15)/(2 * pi * fRotorTmConst * iPoles * fScaleMechRPS)





*************************** *******************************/





bool InitCurModelScaling( void )



{



= 32768.0 * eriod / TmConst;





a = 32768.0 * 2 * * eriod *



MechRPS;





= 32768.0/(6.2832 * *



MechRPS*TmConst);





//


允许的最大转差速度




ipVel = 32768.0/8;





//




Cu rrModel


使用的局部变量进行初始化。




InitCurModel();



return False;





}







MeasCurr.s




;****************************************** *************************



; MeasCompCurr



;



;


说明:




;




ADC


通道



1


和通道



2


,使用



qKa




qKb


将其换算为有符号小数值,




;


并将结果存放到



ParkParm




qIa




qIb


中。




; ADC- Ave


的滚动平均值被保持并在换算前从



ADC


值中减去。




;



;



;


具体来说,偏移量将作为



32


位有符号整数进行累计。




; iOffset += (ADC-Offset)



;


并采用以下公式通过偏移量来校正 原始的



ADC


读数




; CorrADC = ADCBUFn - iOffset/2^16



;


将给出一个偏移时间常数



~ MeasurementPeriod*2^16



;



;


在转换结束之前不要调用该子程序。




;



;


定标常数



qKa




qKb


必须在其他代码中设定,使




; qIa = 2 * qKa * CorrADC1



; qIb = 2 * qKb * CorrADC2



;


采用



2


作为因子以允许



qKa




qKb


保持



1.15


格式。




;



;


函数原型:




; void MeasCompCurr( void );



; void InitMeasCompCurr( short iOffset_a, short iOffset_b );



;



;


开始时:必须调用



InitMeasCompCurr





;


进入时:



MeasCurrParm


结构必须包含



qKa




qKb





; ADC


通道



1




2


必须包括有符号小数值。




;


退出时:



ParkParm


将包含



qIa




qIb





;



;


参数:





;


输入参数:




;





;


返回值:




; V


oid



;


所需的



SFR


设定:




; = 0




;


如果累加器可能溢出,必须设定:




; = 1



;



;


所需的支持子程序:




;





;


局部堆栈使用:




;





;


修改的寄存器:




; w0,w1,w4,w5



;


执行时间:




; 29


个周期




;************************************************ *******************





global _MeasCompCurr



global MeasCompCurr





_MeasCompCurr:



MeasCompCurr:





;; CorrADC1 = ADCBUF1 - iOffsetHa/2^16





;; qIa = 2 * qKa * CorrADC1



mov.w _MeasCurrParm+ADC_iOffsetHa,w0



sub.w _ADCBUF1,WREG w0 = ADC - Offset



clr.w w1



btsc w0,#15



setm w1







mov.w w0,w5



mov.w _MeasCurrParm+ADC_qKa,w4



mpy w4*w5,A



sac A,#-1,w4



mov.w w4,_ParkParm+Park_qIa





;; iOffset += (ADC-Offset)



add _MeasCurrParm+ADC_iOffsetLa



mov.w w1,w0



addc _MeasCurrParm+ADC_iOffsetHa





;; CorrADC2 = ADCBUF2 - iOffsetHb/2^16



;; qIb = 2 * qKb * CorrADC2



mov.w _MeasCurrParm+ADC_iOffsetHb,w0





sub.w _ADCBUF2,WREG w0 = ADC -Offset



clr.w w1



btsc w0,#15



setm w1



mov.w w0,w5



mov.w _MeasCurrParm+ADC_qKb,w4



mpy w4*w5,A



sac A,#-1,w4



mov.w w4,_ParkParm+Park_qIb




;; iOffset += (ADC-Offset)



add _MeasCurrParm+ADC_iOffsetLb



mov.w w1,w0



addc _MeasCurrParm+ADC_iOffsetHb





return





ClarkePark.s




;**************************************** ***************************



; ClarkePark



;



;


说明:




;


计算



Clarke




Park


变换。




;


假定



Cos




Sin


值在



qSin




qCos


中。




;



; Ialpha = Ia



; Ibeta = Ia*dOneBySq3 + 2*Ib*dOneBySq3;



;


其中



Ia+Ib+Ic = 0



;



; Id = Ialpha*cos(Angle) + Ibeta*sin(Angle)



; Iq = -Ialpha*sin(Angle) + Ibeta*cos(Angle)



;



;


该子程序同样适用于整数定标和



1.15


定标格式。


;



;


函数原型:




;



; void ClarkePark( void )



;



;


进入时:



ParkParm


结构必须包含



qSin




qCos



;


退出时:



ParkParm


将包含



qId




qIq





;



;


参数:




;


输入参数:




;


返回值:




; V


oid



;


所需的



SFR


设定:




; = 0



;


如果



(I a+2*Ib)/sqrt(3)


可能出现溢出,必须设定







; = 1



;



;


所需的支持子程序:




;





;


局部堆栈使用:




;





;


修改的寄存器:




; w3 -> w7



;


执行时间:





qIa




qIb







; 20


个周期




;************************************************ *******************



;




include



;


外部引用




include




;


寄存器使用




.equ ParmW, w3


指向



ParkParm


结构的指针




.equ Sq3W, w4 OneBySq3



.equ SinW, w4 ;


替代



Work0W



.equ CosW, w5



.equ IaW, w6 qIa


的拷贝




.equ IalphaW, w6


替代



Ia



.equ IbW, w7 qIb


的拷贝




.equ IbetaW, w7




Ibeta


替代



Ib



;


常量




equ OneBySq3, 0x49E7 1/sqrt(3)


,采用



1.15


格式





;===================


代码



=====================



section .text



global _ClarkePark



global ClarkePark




_ClarkePark:





ClarkePark:



;; Ibeta = Ia*OneBySq3 + 2*Ib*OneBySq3;





mov.w #OneBySq3,Sq3W 1/sqrt(3)


,采用



1.15


格式




mov.w _ParkParm+Park_qIa,IaW



mpy Sq3W*IaW,A



mov.w _ParkParm+Park_qIb,IbW



mac Sq3W*IbW,A



mac Sq3W*IbW,A



mov.w _ParkParm+Park_qIa,IalphaW



mov.w IalphaW,_ParkParm+Park_qIalpha



sac A,IbetaW



mov.w IbetaW,_ParkParm+Park_qIbeta




;;


已经计算



Ialpha




Ibeta


。现在进行旋转。





;;


得到



ParkParm


结构的



qSin




qCos





mov.w _ParkParm+Park_qSin,SinW



mov.w _ParkParm+Park_qCos,CosW




;; Id = Ialpha*cos(Angle) + Ibeta*sin(Angle)





mpy SinW*IbetaW,A Ibeta*qSin -> A



mac CosW*IalphaW,A




Ialpha*qCos


加到



A



mov.w #_ParkParm+Park_qId,ParmW



sac A,[ParmW++]


存放到



qId


,将指针递增



1


指向



qIq




;; Iq = -Ialpha*sin(Angle) + Ibeta*cos(Angle)



mpy CosW*IbetaW,A Ibeta*qCos -> A



msc SinW*IalphaW,A




A


减去



Ialpha*qSin



sac A,[ParmW]


存入



qIq



return



.end







CurModel.s




;****************************************** *************************





;


子程序:



CurModel




;******************************************** ***********************





;


为文件中所有子程序共有




.include



.include



.include




;******************************************** ***********************





; CurModel





;





;


说明:





;





;


物理常数:





; fRotorTmConst


转子时间常数,单位为秒





;





;


方程的物理形式:





;


励磁电 流(安培)






; Imag = Imag + (fLoopPeriod/fRotorTmConst)*(Id - Imag)





;





;


转差速度,单位为



RPS






; VelSlipRPS = (1/fRotorTmConst) * Iq/Imag / (2*pi)





;





;


转子磁通速度,单位为



RPS






; VelFluxRPS = iPoles * VelMechRPS + VelSlipRPS





;





;


转子磁通角(弧度)






; AngFlux = AngFlux + fLoopPeriod * 2 * pi * VelFluxRPS





;





;


定标后的变量:





; qdImag


采用最大电流定标的励磁电流(



1.31






; qVelSlip


采用



fScale MechRPS


定标后的机械转差速度(单位为



RPS






; qAngFlux


采用



pi


定标后的磁通角





;





;


定标后的方程:





; qdImag = qdImag + qKcur * (qId - qdImag)





; qVelSlip = qKslip * qIq/qdImag





; qAngFlux = qAngFlux + qKdelta * (qVelMech + qVelSlip)





;





;


定标因子:





; qKcur = (2^15) * (fLoopPeriod/fRotorTmConst)





; qKdelta = (2^15) * 2 * iPoles * fLoopPeriod * fScaleMechRPS





; qKslip = (2^15)/(2 * pi * fRotorTmConst * iPoles * fScaleMechRPS)





;





;


函数原型:





;





; void CurModel( void )





;





;


进入时:



CurModelParm


结构必须包含



qKcur




qKslip




iKpoles






; qKdelta




qVelMech




qMaxSlipVel




;


退出时:



CurModelParm


将包含



qAngFlux




qdImag




qVelSlip




;





;


参数:





;


输入参数:





;






;


返回值:





; V


oid





;


所需的



SFR


设定:





; = 0





; = 0





;





;


所需的支持子程序:





;






;


局部堆栈使用:





;0







;


修改的寄存器:




: w0-w7,AccA



;


执行时间:




; 72


个指令周期



< br>;********************************************** *********************



;



;===================


代码



=====================





.section .text





;


用于



CurModel


的寄存器




.equ SignW, w2


跟踪符号变化




.equ ShiftW, w3


执行除法之前的移位位数




.equ IqW, w4 Q


电流(



1.15





.equ KslipW, w5 Kslip


常数(



1.15





.equ ImagW, w7


励磁电流(



1.15






.global _CurModel





.global CurModel





_CurModel:



CurModel:





;; qdImag = qdImag + qKcur * (qId - qdImag) ;


励磁电流





mov.w _CurModelParm+CurMod_qdImag,w6





mov.w _CurModelParm+CurMod_qdImag+2,w7





lac w7,A





mov.w w6,ACCALL





mov.w _ParkParm+Park_qId,w4



sub.w w4,w7,w4 qId- qdImagH



mov.w _CurModelParm+CurMod_qKcur,w5





mac w4*w5,A




Kcur*(Id- Imag)


加到



Imag



sac A,w7



mov.w ACCALL,w6



mov.w w6,_CurModelParm+CurMod_qdImag



mov.w w7,_CurModelParm+CurMod_qdImag+2




;; qVelSlip = qKslip * qIq/qdImag





;;


首先将



qIqW




qdImagW


置为正数,并将符号位存放在



SignW





clr SignW


将标志符号设定为正





;; if( IqW < 0 ) =>


翻转



SignW


并设定



IqW = -IqW




mov.w _ParkParm+Park_qIq,IqW





cp0 IqW





bra Z,jCurModSkip





bra NN,jCurMod1





neg IqW,IqW





com SignW,SignW ;


翻转符号位




jCurMod1:



;; if( ImagW < 0 ) =>


翻转



SignW


并设定



ImagW = -ImagW




cp0 ImagW





bra NN,jCurMod2





neg ImagW,ImagW





com SignW,SignW


翻转符号位




jCurMod2:



;;




Acc A


中计算



Kslip*|IqW|


以保持



1.31


格式





mov.w _CurModelParm+CurMod_qKslip,KslipW





mpy IqW*KslipW,A





;;


确保



denominator > numerator


,否则跳过项




sac A,w0


暂时的




cp ImagW,w0 |qdImag| - |Kslip*qIq|



bra LEU,jCurModSkip


跳过项:



|qdImag| <= |Kslip*qIq|







;;




6010


(芯片本身的错误)以 后版本中将不再需要。




clr.w ShiftW





;;


计算不将最高有效位直接置



1


(保留符号位)的情况下,可将



ImagW


移位多少位。





;;



ff1l ImagW,ShiftW



sub.w ShiftW,#2,ShiftW


为将



1


放入



bit 14


,需要移位的位数






;;


移位:


ImagW = ImagW << ShiftW



sl ImagW,ShiftW,ImagW



;;




AccA


进行移位,需要将



(-ShiftW)


左移。




neg ShiftW,ShiftW



;; |Kslip*qIq| = |Kslip*qIq| << ShiftW



sftac A,ShiftW





;;


执行除法操作



|qKslip*qIq|/|ImagW|


。此时结果将为正且



< 1.0


,同时具有最高的精度。




;;



;;





sac A,w6



repeat #17



divf w6,ImagW w0 = KslipW*IqW/ImagW, w1 = remainder





;;


限制最大转差速度




mov.w _CurModelParm+CurMod_qMaxSlipVel,w1



cp w1,w0 qMaxSlipSpeed - | Kslip*qIq/qdImag |



bra NN,jCurMod4




;;


结果太大



:




qMaxSlipSpeed


代替




mov.w w1,w0



bra jCurMod4





jCurModSkip:



;;


整个项被跳过



-


将其置为



= 0



clr.w w0




jCurMod4:





;;


设定正确的符号




btsc SignW,#0



neg w0,w0





;;


用于测试




mov.w w0,_CurModelParm+CurMod_qV


elSlip





;;


加入机械转速




mov.w _CurModelParm+CurMod_qVelMech,w4



add.w w0,w4,w4



mov.w w4,_CurModelParm+CurMod_qV


elFlux





;;




AngFlux


载入



Acc A



mov.w _CurModelParm+CurMod_qAngFlux,w1



lac w1,A





mov.w _CurModelParm+CurMod_qKdelta,w5



mac w4*w5,A





sac A,w4



mov.w w4,_CurModelParm+CurMod_qAngFlux



return






InvPark.s



< p>
;******************************************* ************************



; InvPark



;



;


说明



:



;


计算



Park


反变换。假定



Cos




Sin


值位于



ParkParm


结构中。




;



; Valpha = Vd*cos(Angle) - Vq*sin(Angle)



; Vbeta = Vd*sin(Angle) + Vq*cos(Angle)



;


该子程序同样适用于整数定标和



1.15


定标格式。




;



;


函数原型:




; void InvPark( void )



;


进入时:



ParkParm


结构必须包含



qCos




qSin




qVd




qVq





;


退出时:



ParkParm


将包含


< p>
qV


alpha




qVbeta





;



;


参数:





;


输入参数:无




;


返回值



: Void



;


所需的



SFR


设定:



= 0



;


所需的支持子程序:无




;


局部堆栈使用



:





;


修改的寄存器:



w3 -> w7, A



;


执行时间:大约



14


个指令周期





;************** ************************************************** ***



;



include



;


外部引用




include




;


寄存器使用




.equ ParmW, w3


指向



ParkParm


结构的指针




.equ SinW, w4



.equ CosW, w5



.equ VdW, w6 qVd


的拷贝




.equ VqW, w7 qVq


的拷贝





;===================


代码



=====================




.section .text



.global _InvPark



.global InvPark





_InvPark:



InvPark:





;;




ParkParm


结构获得



qVd




qVq



mov.w _ParkParm+Park_qVd,VdW



mov.w _ParkParm+Park_qVq,VqW




;;




ParkParm


结构获得



qSin




qCos



mov.w _ParkParm+Park_qSin,SinW



mov.w _ParkParm+Park_qCos,CosW




;; Valpha = Vd*cos(Angle) - Vq*sin(Angle)



mpy CosW*VdW,A Vd*qCos -> A



msc SinW*VqW,A ;




A


减去



Vq*qSin




mov.w #_ParkParm+Park_qValpha,ParmW



sac A,[ParmW++]


存储到



qValpha


,指针递增



1


指向



qVbeta




;; Vbeta = Vd*sin(Angle) + Vq*cos(Angle)



mpy SinW*VdW,A Vd*qSin -> A



mac CosW*VqW,A




Vq*qCos


加到



A



sac A,[ParmW] ;


存储到



Vbeta




return








CalcRef.s




;************** ************************************************** ***





; CalcRefVec





;





;


说明:





;


根据



qValpha




qVbeta


计算定标后的参考矢量(



Vr1, Vr2, Vr3







;


该方法是一种改进后的



Clarke


反变换。与常规



Clarke


反变换相比,将



Valpha




Vbeta




;


进行了交换。





;





; Vr1 = Vbeta





; Vr2 = (-Vbeta/2 + sqrt(3)/2 * Valpha)





; Vr3 = (-Vbeta/2 - sqrt(3/2) * Valpha)





;





;


函数原型:





;





; void CalcRefVec( void )





;





;


进入时:



ParkParm


结构必须包含



qCos




qSin




qValpha




qVbeta






;


退出时:



SVGenParm


将包含



qVr1




;





;


参数:





;


输入参数:





;






;


返回值:





; V


oid





;


所需的



SFR


设定:





; = 0





;


所需的支持子程序:





;






;


局部堆栈使用:





;






;


修改的寄存器:





; w0, w4, w5, w6





;


执行时间:




qVr2




qVr3





;


大约



20


个指令周期





;************** ************************************************** ***





;



.include





;


外部引用




.include



.include




;


寄存器使用





.equ WorkW, w0 ;


工作寄存器




.equ ValphaW, w4 qValpha


(定标后)




.equ VbetaW, w5 qVbeta


(定标后)




.equ ScaleW, w6


定标




;


常量




.equ Sq3OV2,0x6ED9 sqrt(3)/2


,采用



1.15


格式





;===================


代码



=====================




.section .text



.global _CalcRefVec



.global CalcRefVec





_CalcRefVec:



CalcRefVec:





;;




ParkParm


结构获得



qValpha




qVbeta






mov.w ParkParm+Park_qValpha,ValphaW





mov.w _ParkParm+Park_qVbeta,VbetaW



;;


使



Vr1 = Vbeta



mov.w VbetaW,_SVGenParm+SVGen_qVr1



;;


装载



Sq(3)/2



mov.w #Sq3OV2,ScaleW







;; AccA = -Vbeta/2



neg.w VbetaW,VbetaW



lac VbetaW,#1,A





;; Vr2 = -Vbeta/2 + sqrt(3)2 * Valpha)



mac ValphaW*ScaleW,A




Valpha*sqrt(3)/ 2


加到



A



sac A,WorkW



mov.w WorkW,_SVGenParm+SVGen_qVr2




;; AccA = -Vbeta/2



lac VbetaW,#1,A





;; Vr3 = (-Vbeta/2 - sqrt(3)2 * Valpha)



msc ValphaW*ScaleW,A




A


减去



Valpha*sqrt(3)/2





sac A,WorkW



mov.w WorkW,_SVGenParm+SVGen_qVr3



return



.end






CalcVel.s




;************** ************************************************** ***



;


子程序:



InitCalcVel, CalcVel



;


< p>
;******************************************* ************************



;


为文件中所有子程序共有





.include





.include





;** ************************************************** ***************



; void InitCalcVel(void)



;


对局部转速变量进行初始化。




;


在进入时



iIrpPerCalc


必须被设定。




;************************** *****************************************





; InitCalcVel


的寄存器使用






.equ Work0W, w4


工作寄存器





.equ PosW, w5


当前位置:



POSCNT




;************** ************************************************** ***





.global _InitCalcVel





.global InitCalcVel





_InitCalcVel:





InitCalcVel:





;;


此后的



5


条指令禁止中断。




DISI #5





;;


装载



iPrevCnt




zero Delta



;;


编码器值。注意:要获得精确的转速,



qVelMech


必须计算两次。




;;





mov.w POSCNT,PosW


当前编码器值




mov.w PosW,_EncoderParm+Encod_iPrevCnt



clr.w _EncoderParm+Encod_iAccumCnt





;;


装载



iVelCntDwn



mov.w _EncoderParm+Encod_iIrpPerCalc,WREG



mov.w WREG,_EncoderParm+Encod_iVelCntDwn





return





;** ************************************************** ***************



; CalcVelIrp



;



;


以指定的间隔,被定时器中断调用。




;



;


中断间隔



VelPeriod


,必须小于最大转速时转过



1/2


转所需的最小时间。




;



;


该子程序将对



iIrpPerCal c


中断的编码器计数变化进行累加,




;


时间周期



= iIrpPerCalc * VelPeriod


,随后将累加值复制到




; iDeltaCnt


以供



CalcV el


子程序进行转速计算使用。




;


随后该累加值被置回零并开始一个新的累加操作。




;



;


函数原型:



void CalcVelIrp( void );



;



;


进入时:



EncoderParm


必须包含



iPrevCnt




iAccumCnt




iVelCntDwn



;



;


退出时:



EncoderParm


将包含



iPrevCnt




iAccumCnt




iDeltaCnt



;(


如果递减计数到达零)





;







;


参数:





;


输入参数无




;



;


返回:




; V


oid



;



;


所需的



SFR


设定:



:





;



;


所需的支持子程序:无




;



;


局部堆栈使用:



3



;



;


修改的寄存器:无




;



;


执行时间:大约



29


个指令周期(如果产生了新的


< /p>


iDeltaCnt






;


-


-


-


-


-


-


-


-



本文更新与2021-02-09 08:40,由作者提供,不代表本网站立场,转载请注明出处:https://www.bjmy2z.cn/gaokao/620086.html

svpwm完整程序的相关文章