📄 spwm.c
字号:
#include "DSP28_Device.h"
#include "IQmathLib.h"
#define PI 3.1415926536
long GlobalQ = GLOBAL_Q;
#define write_RAM GpioDataRegs.GPFDAT.bit.GPIOF13 = 0
#define read_RAM GpioDataRegs.GPFDAT.bit.GPIOF13 = 1
#define Motor_state_stop GpioDataRegs.GPBDAT.bit.GPIOB1 = 0 //电机停止
#define Motor_state_back GpioDataRegs.GPBDAT.bit.GPIOB0 = 0 //电机反转
#define Motor_state_forward GpioDataRegs.GPFDAT.bit.GPIOF0 = 0 //电机正转
#define Control_power GpioDataRegs.GPFDAT.bit.GPIOF2 = 0 //控制板电源
#define frequence_key GpioDataRegs.GPFDAT.bit.GPIOF8 = 0 //键盘给定
#define Analog_key GpioDataRegs.GPFDAT.bit.GPIOF9 = 0 //模拟给定
#define Error GpioDataRegs.GPFDAT.bit.GPIOF12 = 0 //故障
#define motor_forward 1 //电机正转
#define motor_backward 2 //电机反转
#define motor_stop 0 //电机停止
#define fc_max 3000 //最大载波(三角波)频率
//定义外部RAM中数据的存放地址
#define motor_control * (unsigned int *) 0x002002 //电机运行状态命令:正传、反转
#define frequence_enactment * (unsigned int *) 0x002003 //键盘设定频率值
#define motor_run * (unsigned int *) 0x002004 //电机运行标志motor_run=0x55
#define motor_state_display * (unsigned int *) 0x002005 //电机运行状态:正传、反转、停止
#define motor_frequence_display * (unsigned int *) 0x002006 //电机实时运行频率
#define motor_speed_hundred * (unsigned int *) 0x002007 //电机转速的千位和百位
#define motor_speed_single * (unsigned int *) 0x002008 //电机转速的十位和个位
#define current_A * (unsigned int *) 0x002009 //A相电流
#define current_B * (unsigned int *) 0x00200a //B相电流
#define BUS_voltage * (unsigned int *) 0x00200b //母线电压
#define BUS_current * (unsigned int *) 0x00200c //母线电流
#define maximal_frequence * (unsigned int *) 0x002010 //最大频率
#define upper_limit_frequence * (unsigned int *) 0x002011 //上限频率
#define lower_limit_frequence * (unsigned int *) 0x002012 //下限频率
#define modulation * (unsigned int *) 0x002020 //调制方式选择
#define f_select * (unsigned int *) 0x002021 //调制方式选择
#define torque_lifting * (unsigned int *) 0x002022 //转矩曲线选择
#define speedup_time * (unsigned int *) 0x002023 //加速时间设置
#define speeddown_time * (unsigned int *) 0x002024 //减速时间设置
//=================================================================================
#define rxd_NUM 4
#define txd_NUM 4
unsigned int f=1; //调制波(正弦波)频率,将f初始化为1,避免后面N=fc/f产生错误
unsigned int fc = 3000; //载波(三角波)频率
unsigned int N; //载波比 N=fc/f
unsigned int fr=1; //期望调制波(正弦波)频率
unsigned int k=0; //第K个采样点
unsigned int Tpwm; //载波(三角波)周期 T=1/fc,程序中换算成了定时器周期寄存器的值
unsigned char motor_state = 0; //当前电机的运行状态,1 正转、 2 反转、0 停止
unsigned char motor_flag = 0; //当有电机正反转命令时置位,命令执行完毕后复位,作用是防止电机运行时突然改变方向
unsigned char modulation_select = 0;//记录当前的调制方式
unsigned char frequence_select = 0; //记录频率的给定方式
unsigned char error_flag = 0; //IPM错误标志
unsigned char speed_up = 0; //控制电机加速时间
unsigned char speed_down = 0; //控制电机减速时间
unsigned char speedup_times = 0; //控制电机加速时间
unsigned char speeddown_times = 0; //控制电机减速时间
unsigned char AD_times = 0; //控制AD转换的时间
float M; //调制度:正弦波峰值与三角波峰值之比,M的取值范围是0-1
float ADCINA0_value = 0; //存放通道A0的AD转换值
float ADCINA1_value = 0; //存放通道A1的AD转换值
float ADCINB0_value = 0; //存放通道B0的AD转换值
float ADCINB4_value = 0; //存放通道B4的AD转换值
float *m_sel; //指向不同转矩曲线的指针
//unsigned char rxd_counter = 0;
//unsigned char rxd_buffer[rxd_NUM] = {0x00,0x00,0x00,0x00};
//unsigned char txd_buffer[txd_NUM] = {0x00,0x00,0x00,0x00};
//unsigned char power_on_flag = 0; //主回路上电时间控制
//unsigned char resistance_off_flag = 0; //电阻切换时间控制
/***U/F曲线***/
float m1[50]={
0.0196,0.0392,0.0588,0.0784,0.098,0.118,0.137,0.157,0.176,0.196,
0.216,0.235,0.255,0.274,0.294,0.314,0.333,0.353,0.372,0.392,
0.412,0.431,0.451,0.47,0.49,0.51,0.529,0.549,0.568,0.588,
0.608,0.627,0.647,0.666,0.686,0.706,0.725,0.745,0.764,0.784,
0.804,0.823,0.843,0.862,0.882,0.902,0.921,0.941,0.96,0.98
};
float m2[50]={
0.0196,0.0552,0.0908,0.1264,0.162,0.1976,0.2332,0.2688,0.3044,0.34,
0.356,0.372,0.388,0.404,0.42,0.436,0.452,0.468,0.484,0.5,
0.516,0.532,0.548,0.564,0.58,0.596,0.612,0.628,0.644,0.66,
0.676,0.692,0.708,0.724,0.74,0.756,0.772,0.788,0.804,0.82,
0.836,0.852,0.868,0.884,0.9,0.916,0.932,0.948,0.964,0.98,
};
float m3[50]={
0.196,0.212,0.228,0.244,0.26,0.276,0.292,0.308,0.324,0.34,
0.356,0.372,0.388,0.404,0.42,0.436,0.452,0.468,0.484,0.5,
0.516,0.532,0.548,0.564,0.58,0.596,0.612,0.628,0.644,0.66,
0.676,0.692,0.708,0.724,0.74,0.756,0.772,0.788,0.804,0.82,
0.836,0.852,0.868,0.884,0.9,0.916,0.932,0.948,0.964,0.98,
};
interrupt void svpwm(void);
interrupt void spwm(void);
interrupt void scia(void);
interrupt void Timer0(void);
interrupt void AD_convert(void);
void carrier_wave_ratio(void);
void rxd_operate(void);
void parameter_select(void);
void Motor_operate(void);
void Data_display(void);
void Delay(unsigned int);
void main(void)
{
InitSysCtrl();
//禁止和清除所有CPU中断
DINT;
IER=0x0000;
IFR=0x0000;
InitPieCtrl(); //初始化PIE控制寄存器
InitPieVectTable(); //初始化PIE中断向量表
InitGpio();
InitXintf(); //初始化外部接口
InitSci(); //初始化串口
InitEv(); //初始化事件管理器EVA
InitAdc(); //初始化AD转换器
InitCpuTimers(); //初始化CPU定时器0
//重新分配中断服务的中断向量,使T1UFINT、RXAINT、TINT0指向各自的服务程序
EALLOW;
PieVectTable.T1UFINT = &spwm;
PieVectTable.RXAINT = &scia;
PieVectTable.TINT0 = &Timer0;
PieVectTable.ADCINT = &AD_convert;
EDIS;
//使能PIE级定时器0的中断
PieCtrl.PIEIER1.bit.INTx7 = 1;
PieCtrl.PIEIER1.bit.INTx6 = 1; //允许AD转换中断
//使能CPU级INT1、INT2、INT9
IER=0x0103;
EINT;
ERTM;
EvaRegs.EVAIFRA.all = 0xffff; //中断标志位复位
EvaRegs.ACTR.all = 0x0fff;
//启动定时器0,每0.02s中断一次
ConfigCpuTimer(&CpuTimer0,150,20000);
Control_power; //控制板电源指示灯点亮
f=1;
fr=1;
//设置电机初始状态
motor_state = motor_stop;
//点亮目前电机状态指示灯,停止
GpioDataRegs.GPBDAT.bit.GPIOB1 = 0; //电机停止
GpioDataRegs.GPBDAT.bit.GPIOB0 = 1; //电机反转
GpioDataRegs.GPFDAT.bit.GPIOF0 = 1; //电机正转
//清除双口RAM中电机启动命令
write_RAM;
Delay(100);
motor_run = 0;
while(1)
{
// rxd_operate(); //处理串口数据
KickDog(); //喂狗
Data_display(); //向双口RAM中写入电机运行参数
parameter_select(); //设定电机运行参数
Motor_operate(); //读取电机控制命令
if(error_flag != 0x55)
{
if(f<=1)
{
M=0; //根据U/F曲线确定M值
EvaRegs.ACTR.all = 0x0fff; //将PWM输出强制为高
}
else
{
M=m_sel[f-1];
//PWM1低有效、PWM2高有效、PWM3低有效、PWM4高有效、PWM5低有效、PWM6高有效
EvaRegs.ACTR.all = 0x0999;
}
}
else
{
EvaRegs.ACTR.all = 0x0fff; //将PWM输出强制为高
Error; //故障
}
carrier_wave_ratio(); //计算载波比N
}
}
/*********************************************************************************
**函数名称:spwm
**功能描述:定时器下溢中断服务程序,计算下一个载波周期时三个比较器的比较值,
并比较正负脉冲宽度是否小于3us,如果小于12us,转换为寄存器脉冲数是450,
则认为是窄脉冲,删除该脉冲
**输入参数:
**输出参数:
**全局变量:
**调用模块:
**说明:
**注意:
*********************************************************************************/
interrupt void spwm(void)
{
unsigned int t1,t2,t3;
_iq ton1,ton2,ton3,theta;
float camp1,camp2,camp3;
k++;
if(k > N){ k = 0; }
theta = _IQ( 2 * PI * k / N );
ton1 = _IQ( 0.5 ) + _IQmpy( _IQ( M / 2 ),_IQsin( theta + _IQ( PI / N ) ) );
camp1 = _IQtoF( ton1 * Tpwm );
t1 = (unsigned int)( Tpwm - camp1);
ton2 = _IQ( 0.5 ) + _IQmpy( _IQ( M / 2 ),_IQsin( theta + _IQ( 2 * PI / 3 ) + _IQ( PI / N ) ) );
camp2 = _IQtoF( ton2 * Tpwm );
t2 = (unsigned int)( Tpwm - camp2 );
ton3 = _IQ( 0.5 ) + _IQmpy( _IQ( M / 2 ),_IQsin( theta + _IQ( PI / N) - _IQ( 2 * PI / 3 ) ) );
camp3 = _IQtoF( ton3 * Tpwm );
t3 = (unsigned int)( Tpwm - camp3 );
if(motor_state == motor_forward)//正转
{
EvaRegs.CMPR1 = t3 / 2;
EvaRegs.CMPR2 = t2 / 2;
EvaRegs.CMPR3 = t1 / 2;
}
if(motor_state == motor_backward)//反转
{
EvaRegs.CMPR1 = t1 / 2;
EvaRegs.CMPR2 = t2 / 2;
EvaRegs.CMPR3 = t3 / 2;
}
EvaRegs.EVAIFRA.all = 0x0200; //写1清除下溢中断的标志
EvaRegs.EVAIMRA.all = 0x0200;
PieCtrl.PIEACK.all |= PIEACK_GROUP2; //写1清除中断响应标志位
}
/*********************************************************************************
**函数名称:svpwm(电压空间矢量)
**功能描述:定时器下溢中断服务程序,计算下一个载波周期时三个比较器的比较值,并送入
到比较寄存器中
**输入参数:
**输出参数:
**全局变量:K(采样序列)
**调用模块:
**说明: 电压空间矢量svpwm公式请见《电动机的DSP控制》120页
**注意:
*********************************************************************************/
interrupt void svpwm(void)
{
_iq B0,B1,B2,mid1,mid2;
_iq theta;
unsigned char p = 0,sector = 0; //用来确定扇区
long t1,t2;
k++;
if(k>N) k = 0;
if(motor_state == motor_forward)theta = _IQ(2*PI*f*k/3000); //计算电压空间矢量的电角度
if(motor_state == motor_backward)theta = _IQ(2*PI)-_IQ(2*PI*f*k/3000); //计算电压空间矢量的电角度
//计算扇区
B0 = _IQsin(theta);
B1 = _IQmpy(_IQ(0.866),_IQcos(theta))-_IQmpy(_IQ(0.5),_IQsin(theta));
B2 = -_IQmpy(_IQ(0.866),_IQcos(theta))-_IQmpy(_IQ(0.5),_IQsin(theta));
if(B0>0) p = p+1;
if(B1>0) p = p+2;
if(B2>0) p = p+4;
switch(p)
{
case 1: sector = 1; break;
case 2: sector = 5; break;
case 3: sector = 0; break;
case 4: sector = 3; break;
case 5: sector = 2; break;
case 6: sector = 4; break;
default:break;
}
switch(sector)
{
case 0:
mid1 = _IQmpy(_IQ(M),_IQsin(_IQ(PI/3)-theta));
mid2 = _IQmpy(_IQ(M),_IQsin(theta));
t1 = (Tpwm*mid1) >> 15;
t2 = (Tpwm*mid2) >> 15;
EvaRegs.CMPR1 = (Tpwm-t1-t2)/4;
EvaRegs.CMPR2 = (Tpwm+t1-t2)/4;
EvaRegs.CMPR3 = (Tpwm+t1+t2)/4;
break;
case 1:
mid1=_IQmpy(_IQ(M),_IQsin(theta-_IQ(PI/3)));
mid2=_IQmpy(_IQ(M),_IQsin(_IQ(2*PI/3)-theta));
t1=(Tpwm*mid1)>>15;
t2=(Tpwm*mid2)>>15;
EvaRegs.CMPR1=(Tpwm+t1-t2)/4;
EvaRegs.CMPR2=(Tpwm-t1-t2)/4;
EvaRegs.CMPR3=(Tpwm+t1+t2)/4;
break;
case 2:
mid1=_IQmpy(_IQ(M),_IQsin(_IQ(PI)-theta));
mid2=_IQmpy(_IQ(M),_IQsin(theta-_IQ(2*PI/3)));
t1=(Tpwm*mid1)>>15;
t2=(Tpwm*mid2)>>15;
EvaRegs.CMPR1=(Tpwm+t1+t2)/4;
EvaRegs.CMPR2=(Tpwm-t1-t2)/4;
EvaRegs.CMPR3=(Tpwm+t1-t2)/4;
break;
case 3:
mid1=_IQmpy(_IQ(M),_IQsin(theta-_IQ(PI)));
mid2=_IQmpy(_IQ(M),_IQsin(_IQ(4*PI/3)-theta));
t1=(Tpwm*mid1)>>15;
t2=(Tpwm*mid2)>>15;
EvaRegs.CMPR1=(Tpwm+t1+t2)/4;
EvaRegs.CMPR2=(Tpwm+t1-t2)/4;
EvaRegs.CMPR3=(Tpwm-t1-t2)/4;
break;
case 4:
mid1=_IQmpy(_IQ(M),_IQsin(_IQ(5*PI/3)-theta));
mid2=_IQmpy(_IQ(M),_IQsin(theta-_IQ(4*PI/3)));
t1=(Tpwm*mid1)>>15;
t2=(Tpwm*mid2)>>15;
EvaRegs.CMPR1=(Tpwm+t1-t2)/4;
EvaRegs.CMPR2=(Tpwm+t1+t2)/4;
EvaRegs.CMPR3=(Tpwm-t1-t2)/4;
break;
case 5:
mid1=_IQmpy(_IQ(M),_IQsin(theta-_IQ(5*PI/3)));
mid2=_IQmpy(_IQ(M),_IQsin(_IQ(2*PI)-theta));
t1=(Tpwm*mid1)>>15;
t2=(Tpwm*mid2)>>15;
EvaRegs.CMPR1=(Tpwm-t1-t2)/4;
EvaRegs.CMPR2=(Tpwm+t1+t2)/4;
EvaRegs.CMPR3=(Tpwm+t1-t2)/4;
break;
default:break;
}
EvaRegs.EVAIMRA.all = 0x0200;
EvaRegs.EVAIFRA.all = 0x0200;
PieCtrl.PIEACK.all |= PIEACK_GROUP2;
}
interrupt void scia(void)
{
/* unsigned char rxd;
rxd=SciaRegs.SCIRXBUF.all;
if(rxd==0xeb&&rxd_counter==0)
{
rxd_buffer[rxd_counter]=rxd;
rxd_counter=1;
return;
}
if(rxd_counter)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -