/*************************ad初始化子程序***************************/
#include"regs240x.h"
void ad_init()
{
ADCTRL1=0X0000; // 仿真停止时挂起;采样时间1分频;AD为启动/停止模式,排 // 序器为独立编组方式,且禁止特殊的两种工作模式
ADCTRL2=0X0400; // 编组器1复位不起作用(采用手动复位),
// 中断标志置1时立即申请中断,此时未启动AD转换
MAXCONV=0X0001; // 2个通道转换,ADCIN00,ADCIN08;
CHSELSEQ1=0X0080; // 转换通道顺序是0,8;结果存于寄存器RESULT0和RESULT1 CHSELSEQ2=0X0000;
CHSELSEQ3=0X0000;
CHSELSEQ4=0X0000;
}
/*********************************clarke变换*********************************/
#define Kcurrent -313 //Q20,-910,电流系数,由于实际的母线电压为30v,所以要将算得的值*30/310 extern ia,ib;
int ialfa,ibeta;
void clarke() //ab--->alfa,beta
{
int iapu12,ibpu12;
iapu12=(int)(((long)Kcurrent*ia)>>8); //iapu12 ,ibpu12 Q12格式
ibpu12=(int)(((long)Kcurrent*ib)>>8);
ialfa=(int)(((long)5018*iapu12)>>12); //sqrt(3/2)的Q12格式为5018,
ibeta=(int)(((long)2896*(iapu12+2*ibpu12))>>12); //sqrt(2)/2的Q12格式为2896
//ialfa_pu,ibeta_pu为Q12格式, 且为PU值 ,其Q0格式再乘以1.796A后和实际值相等 }
.ref _c_int0
.ref _ad_int1
.ref _pwm_int2
.ref _phantom
.sect ".vectors"
rset: B _c_int0 ;00h reset int1: B _ad_int1 ;02h INT1 int2: B _pwm_int2 ;04h INT2 int3: B _phantom ;06h INT3 int4: B _phantom ;08h INT4 int5: B _phantom ;0Ah INT5 int6: B _phantom ;0Ch INT6
//ev.c文件
//描述:基于ev寄存器的一些操作,
#include"regs240x.h"
#include"ev.h"
//描述:EV初始化
void ev_init(EV_Handle p)
{
//定时器
GPTCONA=GPTCONB=0;
T1CON=T2CON=T3CON=T4CON=0; T1PR=T2PR=T3PR=T4PR=0;
T1CNT=T2CNT=T3CNT=T4CNT=0;
T1CMPR=T2CMPR=T3CMPR=T4CMPR=0; //比较器
COMCONA=COMCONB=0;
ACTRA=ACTRB=0;
DBTCONA=DBTCONB=0;
CMPR1=CMPR2=CMPR3=CMPR4=CMPR5=CMPR6=0;
//中断管理
EVAIMRA=EVAIMRB=EVAIMRC=EVBIMRA=EVBIMRB=EVBIMRC=0; //屏蔽所有中断 EVAIFRA=EVAIFRB=EVAIFRC=EVBIFRA=EVBIFRB=EVBIFRC=0XFFFF; //清除所有中断标志
T1PR=TP; //周期寄存器值,设置PWM脉宽调制周期
T1CON=0X0840; //仿真挂起时立即停止,连续增减计数模式,允许定时器操作,时钟源为内部时钟,计数器值为0时重?
ACTRA=0X0999; //SVPWM逆时针,基本空间矢量000,2.4.6引脚高有效,1,3,5引脚低有效 DBTCONA=0X04F4; //死区 4*32/30M=4.3us
EVAIMRA=0X0200; //开定时器1下溢中断
CMPR1=0X02EE; //占空比为0,0X02EE=750
CMPR2=0X02EE;
CMPR3=0X02EE;
}
//描述:输出适量到ACTRA,
void ev_pwm(EV_Handle p)
{
CMPR1=p->tcm1;
CMPR2=p->tcm2;
CMPR3=p->tcm3;
}
//描述:pwm管脚有效
void ev_open(EV_Handle p)
{
COMCONA=0X8200;
}
//描述:pwm管脚高祖有效
void ev_close(EV_Handle p)
{
COMCONA=0X8000;
}
//init_reg.c
//描述:初始化2407A的寄存器
#include"regs240x.h"
void init_reg(void)
{
asm(" setc SXM "); //抑制符号位扩展
asm(" setc OVM "); //累加器中结果溢出方式:正相溢出发生,累加器中的值是最大正数(7FFF FFFFH), //负相溢出时,累加器中是最大负数(8000 0000H)
asm(" clrc CNF "); //B0被配置为数据存储空间
WSGR=0X0000; //禁止所有等待状态
IMR=0X0003; // 0011,开中断INT2(定时器1下溢中断),INT1(高优先级模式的ADC中断)
IFR=0X0FFFF; //清楚所有中断标志
SCSR1=0X02FC;//0000 0010 1111 1100,30MHZ(晶振15MHZ,2倍频)
XINT1CR=XINT2CR=0X8006; //1000 0000 0000 0110 屏蔽外部中断1和2
WDCR=0X0068; //0110 1000 关看门狗
WDKEY=0X0055;
WDKEY=0X00AA;
MCRA=0X0FFB; //配置捕获单元CAP1,2,3 QEP1,2和PWM1-6端口
// 位 1 0 值
// 0 SCITXD IOPA0 1
// 1 SCIRXD IOPA1 1
// 2 XINT1 IOPA2 0
// 3 CAP1/QEP1(A) IOPA3 1
// 4 CAP2/QEP2(B) IOPA4 1
// 5 CAP3(Z) IOPA5 1
// 6 PWM1 IOPA6 1
// 7 PWM2 IOPA7 1
// 8 PWM3 IOPB0 1
// 9 PWM4 IOPB1 1
// 10 PWM5 IOPB2 1
// 11 PWM6 IOPB3 1
// 12 T1PWM/T1CMP IOPB4(U) 0
// 13 T2PWM/T2CMP IOPB5(V) 0
// 14 TDIRA IOPB6 0
// 15 TCLKINA IOPB7 0
MCRB=0x0FE01; //配置读写端口、仿真控制端口
// 位 1 0 值 // 0 W/R IOPC0 1 // 1 BIO IOPC1 0 // 2 SPISIMO IOPC2 0 // 3 SPISOMI IOPC3 0 // 4 SPICLK IOPC4 0 // 5 SPISTE IOPC5 0 // 6 CANTX IOPC6 // 7 CANRX IOPC7 // 8 XINT2/ADCSOC IOPD0 // 9 EMU0 RESERVE // 10 EMU1 RESERVE // 11 TCK RESERVE // 12 TD1 RESERVE // 13 TD0 RESERVE // 14 TMS RESERVE // 15 TMS2 RESERVE
MCRC=0x0000;
// 位 1 0 // 0 CLKOUT IOPE0 // 1 PWM7 IOPE1 // 2 PWM8 IOPE2 // 3 PWM9 IOPE3 // 4 PWM10 IOPE4 // 5 PWM11 IOPE5 // 6 PWM12 IOPE6 // 7 CAP4/QEP3 IOPE7 // 8 CAP5/QEP4 IOPF0 // 9 CAP6 IOPF1 // 10 T3PWM/T3CMP IOPF2(W) // 11 T4PWM/T4CMP IOPF3 // 12 TDIRB IOPF4 // 13 TCLKINB IOPF5 // 14 RESERVE IOPF6 // 15 RESERVE RESERVE PADATDIR=0x0000;
PBDATDIR=0x0000; //0x0C000 1100 配置所有引脚均为输入 PCDATDIR=0x0000; //2020
PDDATDIR=0X0000;
PEDATDIR=0X0000;
PFDATDIR=0x0000; //0x0B00 0 0 0 1 1 1 1 1 1 1 值 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
}
/****************************电流调节***************************/
//Q轴电流调节器参数
extern iq_ref; //Q12 q轴电流调节器输入,即速度调节器的输出
unsigned Kp_iq=2457;//Q12 q轴电流比例系数
unsigned Ki_iq=122; //Q12 q轴电流积分系数
unsigned Kc_iq=204; //Q12 q轴电流几分修正系数
int min_iq=-11901; //电流pu值为4096,max=4096*3.69/1.27 q轴电流调节器输出的限幅值 int max_iq=11901;
//D轴电流调节器参数
#define ID_REF 0 //Q12 d轴电流输入的参考值
unsigned Kp_id=4096;//Q12 d轴电流比例系数
unsigned Ki_id=122; //Q12 d轴电流积分系数
unsigned Kc_id=122; //Q12 d轴电流几分修正系数
int min_id=-11901; //电流pu值为4096,max=4096*3.69/1.27,d轴电流调节器输出的限幅值 int max_id=11901;
extern iq_fdb; //Q12 q轴电流的反馈值
extern id_fdb; //Q12 d轴电流的反馈值
int uq_out; //Q12 q轴电流调节器的输出值
int ud_out; //Q12 d轴电流调节器的输出值
int xi_iq=0; //Q12 q轴电流调节器的积分累积量
int xi_id=0; //Q12 d轴电流调节器的积分累积量
void ipi()
{
int ek_iq; //Q12 偏差值
int un_iq; //Q12
int el_iq; //Q12
int ek_id; //Q12
int un_id; //Q12
int el_id; //Q12
extern Ni;
//Q轴电流调节
ek_iq=iq_ref-iq_fdb; //Q12 计算偏差值
un_iq=xi_iq+(int)(((long)Kp_iq*ek_iq)>>12); //Q12
if(un_iq>max_iq) uq_out=max_iq;
else if(un_iq<min_iq) uq_out=min_iq;
else uq_out=un_iq;
el_iq=uq_out-un_iq; //Q12
xi_iq=xi_iq+(int)(((long)Ki_iq*ek_iq)>>12)+(int)(((long)Kc_iq*el_iq)>>12);
//D轴电流调节
ek_id=ID_REF-id_fdb; //Q12 计算偏差值
un_id=xi_id+(int)(((long)Kp_id*ek_id)>>12); //Q12
if(un_id>max_id) ud_out=max_id;
else if(un_id<min_id) ud_out=min_id;
else ud_out=un_id;
el_id=ud_out-un_id; //Q12
xi_id=xi_id+(int)(((long)Ki_id*ek_id)>>12)+(int)(((long)Kc_id*el_id)>>12);
Ni=Ni-1; //计算电流调节次数
}
/*********************************park逆变换***********************************/
extern ud_out,uq_out; //Q12
extern sin_theta,cos_theta; //Q15
int ualfa,ubeta; //Q12
void nipark() //alfa,beta-->d,q
{
ualfa=(int)(((long)cos_theta*ud_out)>>15)+(int)(((long)-sin_theta*uq_out)>>15);
ubeta=(int)(((long)sin_theta*ud_out)>>15)+(int)(((long)cos_theta*uq_out)>>15);
}
/*********************************park变换***********************************/ #include"qmath.h"
extern ialfa,ibeta; //Q12
extern sin_theta,cos_theta; //Q15
int id_fdb,iq_fdb; //Q12
void park() //alfa,beta-->d,q
{
id_fdb=(int)(((long)cos_theta*ialfa)>>15)+(int)(((long)sin_theta*ibeta)>>15);
iq_fdb=(int)(((long)-sin_theta*ialfa)>>15)+(int)(((long)cos_theta*ibeta)>>15);
}
// phantom.c文件
void interrupt phantom(void)
{
return;
}
//描述:转子相位初始化文件,phase_init()
#include"regs240x.h"
int theta_m;
void phase_init()
{
int u,v,w;
u=PBDATDIR&0X0010; //读u相的状态值
if(u==0x0010) u=1;
else u=0;
v=PBDATDIR&0X0020; //读v相的状态值
if(v==0x0020) v=1;
else v=0;
w=PFDATDIR&0X0004; //读w相的状态值
if(w==0x0004) w=1;
else w=0;
if(u==1&v==0&w==1) theta_m=208; //电角度30度 else if(u==1&v==0&w==0) theta_m=625; //电角度90度 else if(u==1&v==1&w==0) theta_m=1042;//电角度150度 else if(u==0&v==1&w==0) theta_m=1458;//电角度210度 else if(u==0&v==1&w==1) theta_m=1875;//电角度270度 else if(u==0&v==0&w==1) theta_m=2292;//电角度330度 }
//pnl.c文件
//描述:输入变量的Q15格式转换和计算
#include"pnl.h"
void pnl_calc(PNL_Handle p)
{
//计算p->udc
if(p->rudc>=U_QMAX)
p->udc=0X7FFF;
else
p->udc=(unsigned)(((unsigned long)p->rudc<<15)/U_QMAX);
p->k=(unsigned)(((unsigned long)46334<<15)/p->udc); //sqrt(2)的Q15格式为46334
//k=sqrt(2)/udc
}
/***************************QEP初始化子程序***********************************/
#include"regs240x.h"
void qep_init()
{
T2CNT=0X0000; //计数器清零
T2PER=0X7530; //通用定时器周期寄存器的值为30000
T2CON=0X1870; //通用定时器2为定向增减计数模式,以正交编码脉冲电路作为时钟源,使用自身的使能位,禁止比较操作,计数值为0时重载,使用自己的周期寄存?
CAPCONA=0X0E000; //禁止捕获单元,使能QEP电路,
}
/***************************速度PI调节*********************************/ #define N_REF 1024 //Q12 750~~1024 输入速度给定
//速度调节器参数
unsigned Kp_spd=40960; //Q12 速度比例系数
unsigned Ki_spd=0; //Q12 速度积分系数
unsigned Kc_spd=0; //Q12 速度积分修正系数
int max_spd=5120; //Q12 速度调节器输出的限幅值
int min_spd=-5120; //Q12 Ibase=1.796A 的Q12格式4096*(1+20%)
extern n_fdb; //Q12 实际反馈转速
int spd_out; //Q12 速度调节器的输出
int xi_spd=0; //Q12
void spi()
{
int ek_spd; //Q12
int un_spd; //Q12
int el_spd; //Q12
ek_spd=N_REF-n_fdb; //Q12 计算偏差值
un_spd=xi_spd+(int)(((long)Kp_spd*ek_spd)>>12); //Q12
if(un_spd>max_spd) spd_out=max_spd;
else if(un_spd<min_spd) spd_out=min_spd;
else spd_out=un_spd;
el_spd=spd_out-un_spd; //Q12
xi_spd=xi_spd+(int)(((long)Ki_spd*ek_spd)>>12)+(int)(((long)Kc_spd*el_spd)>>12); }
//svpwm.c文件
//描述:三部分,计算角度、选择适量、计算有效适量作用时间
#include"svpwm.h"
#include"qmath.h"
extern ualfa,ubeta; //Q12
void svpwm_calc(SVPWM_Handle p)
{
int x,y,z; //Q12
unsigned int a,b,c; //Q0
unsigned int t1,tm;
unsigned int t1_q0,tm_q0; //q0
unsigned int taon,tbon,tcon;
x=ubeta; //Q12
y=(int)(((long)28377*ualfa)>>15)+(int)(((long)16384*ubeta)>>15);
//y=sqrt(3)/2*ualfa+1/2*ubeta
z=-(int)(((long)28377*ualfa)>>15)+(int)(((long)16384*ubeta)>>15);
//z=-sqrt(3)/2*ualfa+1/2*ubeta
//sqrt(3)/2的Q15格式为28377,1/2的Q15格式为16384
if(x>=0) a=1;
else a=0;
if(-z>=0) b=1;
else b=0;
if(-y>=0) c=1;
else c=0;
p->sector=4*c+2*b+a;
switch(p->sector)
{
case 1: t1=(unsigned)(((unsigned long)z*p->k)>>15),
tm=(unsigned)(((unsigned long)y*p->k)>>15); break; //t1,tm,为Q12格式 case 2: t1=(unsigned)(((unsigned long)y*p->k)>>15),
tm=(unsigned)(((unsigned long)-x*p->k)>>15);break; //k为Q15格式 case 3: t1=(unsigned)(((unsigned long)-z*p->k)>>15),
tm=(unsigned)(((unsigned long)x*p->k)>>15); break;
case 4: t1=(unsigned)(((unsigned long)-x*p->k)>>15),
tm=(unsigned)(((unsigned long)z*p->k)>>15); break;
case 5: t1=(unsigned)(((unsigned long)x*p->k)>>15),
tm=(unsigned)(((unsigned long)-y*p->k)>>15);break;
case 6: t1=(unsigned)(((unsigned long)-y*p->k)>>15),
tm=(unsigned)(((unsigned long)-z*p->k)>>15);break;
default:break;
}
t1_q0=(unsigned)(((unsigned long)t1*TP)>>12);
tm_q0=(unsigned)(((unsigned long)tm*TP)>>12);
if(t1_q0+tm_q0>TP)
{
t1_q0=(unsigned)(((unsigned long)t1_q0*TP)/(t1_q0+tm_q0)); tm_q0=(unsigned)(((unsigned long)tm_q0*TP)/(t1_q0+tm_q0)); }
taon=(unsigned)((TP-t1_q0-tm_q0)/2);
tbon=taon+t1_q0;
tcon=tbon+tm_q0;
switch(p->sector)
{
case 1: p->tcm1=tbon, p->tcm2=taon, p->tcm3=tcon; break; case 2: p->tcm1=taon, p->tcm2=tcon, p->tcm3=tbon; break; case 3: p->tcm1=taon, p->tcm2=tbon, p->tcm3=tcon; break; case 4: p->tcm1=tcon, p->tcm2=tbon, p->tcm3=taon; break; case 5: p->tcm1=tcon, p->tcm2=taon, p->tcm3=tbon; break; case 6: p->tcm1=tbon, p->tcm2=tcon, p->tcm3=taon; break; default:break;
}
}
/**********************读编码脉冲数,计算转角增量和转角绝对位置************************/ #include"qmath.h"
#define Ktheta 26844 //角度系数
extern pulse;
extern theta_m; //Q0 theta_m要进行初始定位,0~2500
unsigned int count0=0; //Q0
unsigned int theta_e; //Q0
int count; //每个电流采样周期内的脉冲增量,电机的正反转决定其正负值,正转编码器增计数,反转减计数
int sin_theta,cos_theta; //Q15
int s_count=0; //每个速度采样周期内的脉冲增量,电机的正反转决定其正负值,正转编码器增计数,反转减计数
void theta_calc()
{
unsigned int count1; //Q0
int theta_e_p; //Q0
int theta_e_pu15; //Q15
count1=pulse; //读编码脉冲数 以theta0点作为脉冲计数的零点
count=count1-count0; //计算每个电流采样周期内的编码器脉冲增量值
//处理编码器读数溢出的情况,即pulse的溢出,计数值会由65535变为0或者由0变为65535 //由于在电机正转转速为最大值3000r/min时count的值最大为50,将范围放宽一些,取值为100 //由于在电机反转转速为最大值-3000r/min时count的值最小为-50,将范围放宽一些,取值为100 if(count<-100) count=count+30000; //count溢出时的处理
else if(count>100) count=count-30000;
s_count=s_count+count; //累加速度采样周期内的脉冲增量
theta_m=count+theta_m; //机械角度,并将范围调整为(0,10000)
if(theta_m<0)
{
theta_m=theta_m+10000;
}
else if(theta_m>10000)
{
theta_m=theta_m-10000;
}
count0=count1; //更新初始计数值 Q0
//计算绝对电角度 在parke,clarke变换中用的是电角度
theta_e=4*theta_m; //电角度的范围是(0,40000)
while(theta_e>10000) //将其范围变到(0,10000)
{
theta_e=theta_e-10000;
}
theta_e_p=theta_e-5000; //范围-5000~5000
theta_e_pu15=(int)(((long)Ktheta*theta_e_p)>>12); //theta_e_pu15 为Q15格式
//计算电角度的sin,cos值,Q15格式
sin_theta=qsinlt(theta_e_pu15); //Q15
cos_theta=qcoslt(theta_e_pu15); //Q15
}
//************************* AD中断服务子程序************************************
#include"regs240x.h"
unsigned int ad_flag=0; //声明flag为外部变量
int ia,ib;
void interrupt ad_int1()
{
unsigned int ia0,ib0;
if(PIVR==0X0004) //判断是否为ad中断,
{
ia0=RESULT0;
ib0=RESULT1;
ia=(ia0>>6)-388; //-388是为了可以表示电流的正负值,6.25A对应-388,-6.25A对应388,所以Kcurrent为负值
ib=(ib0>>6)-388;
ad_flag=1; //置位转换结束标志位
}
else
return; //不是:返回
ADCTRL2=ADCTRL2|0X4200; // 是:复位SEQ1,且清除中断标志位INT FLAG SEQ1标志写"1"清0 asm(" clrc intm "); //开中断,因为一进入ad中断,就屏蔽了其他所有中断
}
// z_main.c文件
//描述:主程序。z_前缀是为了让其在CCS中显示在最后而已。
//定义和声明对象
#include"pnl.h"
PNL pnl=PNL_DEFAULTS;
#include"ev.h"
extern EV ev;
//函数声明
void init_reg(void);
void ad_init(void);
void qep_init(void);
void phase_init(void);
void main(void)
{
asm(" setc intm "); //关中断
init_reg(); //初始化2407A寄存器
ev.init(&ev); //初始化ev寄存器
ad_init();
qep_init();
phase_init(); //转子相位初始化
pnl.calc(&pnl); //给定参数转换成Q15格式
ev.open(&ev); //开pwm
asm(" clrc intm "); //开中断
for(;;) //循环运行,手动停止电机运行 {
}
}
// pwm_int2文件
//描述:中断函数,产生svpwm,并输出到ev
#include"regs240x.h"
#include"svpwm.h"
SVPWM svpwm=SVPWM_DEFAULTS;
#include"ev.h"
EV ev=EV_DEFAULTS;
#include"pnl.h"
extern PNL pnl;
#define Kspeed 2097 //速度系数,Q20格式,算法见说明
extern s_count; //计数速度调节周期内的脉冲增量值,正负值可以区分电机的正反转 extern spd_out; //速度调节器的输出
extern ad_flag; //A/D转换结束标志
unsigned int pulse; //编码器计数脉冲0~65536
unsigned int Ni=0; //计数电流调节次数,当Ni=0时,进行速度调节
int n_fdb=0; //Q12格式,电机的实际转速,可以有正有负
int iq_ref; //Q12
//函数声明
void theta_calc(void);
void clarke(void);
void park(void);
void ipi(void);
void nipark(void);
void spi(void);
//定时器1下溢中断服务程序
void interrupt pwm_int2(void)
{
if(PIVR==0X0029) //判断是否为t1下溢中断
EVAIFRA=(unsigned int)1<<9; //是TIMER1下溢中断:清除中断标志位 else //否则返回
return;
ADCTRL2=ADCTRL2|0X2000; //启动AD转换,软件启动编组器AD转换,向SOCSEQ1位写1
asm(" clrc intm "); //开中断,因为进入T1下溢中断后,会关闭其它中断 for(;;) //循环等待AD转换
{
if(ad_flag==1) break; //判断AD转换是否结束,结束后才能执行下面的程序 }
ad_flag=0; //A/D转换标志位清零
pulse=T2CNT; //读编码器的计数脉冲
theta_calc(); //计算转子机械位置角和电角度
if(Ni==0) //进行10次电流采样后进行速度采样
{
n_fdb=(int)(((long)Kspeed*s_count)>>8); //计算转速,Q12格式 spi(); //转速的PI调节
Ni=10;
s_count=0; //将速度采样周期内的脉冲增量清零
iq_ref=spd_out; //将速度调节器的输出赋值给q轴电流参考值
}
clarke(); //坐标变换
park();
ipi(); //电流的PI调节
nipark(); //逆变换
svpwm.k=pnl.k; //比例系数 k=sqrt(2)/udc
svpwm.calc(&svpwm);
//ev模块,有3个输入
ev.tcm1=svpwm.tcm1;
ev.tcm2=svpwm.tcm2;
ev.tcm3=svpwm.tcm3;
ev.pwm(&ev);
}
百度搜索“爱华网”,专业资料,生活学习,尽在爱华网