⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 spwm.c

📁 这是一个控制交流电机的程序
💻 C
📖 第 1 页 / 共 2 页
字号:
#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 + -