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

📄 control.zip.c

📁 该代码是完整的BLDC正旋波驱动解决办法,电机可以正常运行
💻 C
📖 第 1 页 / 共 2 页
字号:
 //---------------------------------------------------------------------
//
//	单头绣花机主轴驱动软件
//
//---------------------------------------------------------------------
//
//---------------------------------------------------------------------
// 03 /17/07 -- 第一版 
//---------------------------------------------------------------------- 

//--------------------------器件配置------------------------
_FOSC(CSW_FSCM_OFF & XT_PLL16);
_FWDT(WDT_OFF);
_FBORPOR(PBOR_ON & BORV_20 & PWRT_64 & MCLR_EN);///器件配置
//----------------------------------------------------------------------

typedef signed int SFRAC16;

#define FCY  20000000	// 配置外部晶体5M,16倍频。	xtal = 5Mhz; PLLx16 -> 20 MIPS
#define FPWM 19531		// 设定PWM频率为19。5KHZ
#define _10MILLISEC		10
#define _50MILLISEC		50
#define _100MILLISEC	100
#define _500MILLISEC	500

#define HALLA	1	// RB3
#define HALLB	2	// RB4
#define HALLC	4	// RB5
#define CW	0		// 定义电机正转
#define CCW	1		// 定义电机反转
#define Switch_2	(!PORTCbits.RC14)
///周期计算变量定义//

#define MINPERIOD	313		// 以6000转计算最小周期
#define MAXPERIOD	31250	// 以6转计算最大周期
#define MINABSSPEED	327      //最小速度
#define MAXABSSPEED 32663    //最大速度
 
//当用沸点数初始化有符号16位小数变量时用这个宏
#define SFloat_To_SFrac16(Float_Value)	(((Float_Value) < 0.0) ? (SFRAC16)(32768 * (Float_Value) - 0.5) : (SFRAC16)(32767 * (Float_Value) + 0.5))

void SixStepComm(int _Current_Sector, int _Required_Voltage);	// 这个函数是用来转化转子位置的换向信号/
void InitADC10(void);	// ADC初始化程序用与速度给定
void InitMCPWM(void);	// 初始化PWM在20K,互补模式中心对成,500NS的死区时间 
void InitTMR1(void);	// 初始化T1,速度控制和停止保护
void InitTMR3(void);	// 初始化T3,两个输入扑捉通道的时基
void InitUserInt(void);	//初始化所有用到的口的方向
void Init_IC_and_CN(void);	//初始化扑捉输入和电平变化断口用与或而信号输入
void RunMotor(void);	// 初始化所有电机开始启动时用到的变量和中断
void StopMotor(void);	// 清除所有标志位,并关断任何关于电机控制和PWM势能
void ForceCommutation(void); // 当电机很慢产生霍儿中断时这个功能是强制换向
void ChargeBootstraps(void);// 在电机开始工作时,给电容充电以保证15V控制电压能够驱动上桥IGBT。
extern void SpeedControl(void);	//速度PID运算函数包括汇编和C。
extern void SpeedCalculation(void);

//////// 结构定义用到的标志位
struct 
{
	unsigned MotorRunning	:1;  
	unsigned MotorCommInAdv :1;
	unsigned MotorAdvEnabled:1;
	unsigned unused			:13;
} Flags;
 
unsigned int HallValue;	// 定义读到的霍儿值数据类型.
unsigned int Sector;	// 定义当前变量转子位置
unsigned int LastSector;	// 此变量定义上次转子位置,用来滤出回转率的问题 
unsigned int MotorStalledCounter = 0;	// 每增加1毫秒当发现新的霍尔值后并清除上次的值,用于强制换向和保持停机保护/
                                        

char SectorTable[] = {-1,4,2,3,0,5,1,-1};

/*************************************************************
    驱动低端表,高端是PWM,低端开关	
*************************************************************/

unsigned int StateLoTable[] = {	0x0204,  /* PWM2L -> 1, PWM1H -> PWM */
							 	0x0210,  /* PWM3L -> 1, PWM1H -> PWM */
                                                        0x0810,  /* PWM3L -> 1, PWM2H -> PWM */
								0x0801,  /* PWM1L -> 1, PWM2H -> PWM */
								0x2001,  /* PWM1L -> 1, PWM3H -> PWM */
								0x2004}; /* PWM2L -> 1, PWM3H -> PWM */



/////////////////////////////////////////////////////////
//////////* 定义速度控制变量数据类型
/////////////////////////////////////////////////////////

unsigned char Current_Direction;	// 当前电机旋转方向,通过霍尔中断获得。
unsigned char Required_Direction;	// 需要的方向,
                                    
unsigned int PastCapture, ActualCapture, Period;	// 半个电周期变量,通过一个HALL边缘中断获


//////////////////////////////////////////////////////////////////////
// 通过调节使用器绝对PID增益,位置来自数字PID的执行
SFRAC16 Kp = SFloat_To_SFrac16(0.10000);
SFRAC16 Ki = SFloat_To_SFrac16(0.01000);
SFRAC16 Kd = SFloat_To_SFrac16(0.00000);
SFRAC16 Speed, RefSpeed;	// 实际和给定速度的误差给PID调节器//
SFRAC16 SpeedAbsValue;		// 速度变量的绝对数值,通过相位超前函数//
SFRAC16 ControlOutput = 0;	// 调节器输出数值电压数值,用它的需要的方向


////////////////////////////////////////////////////////////////////////////////////////
//常数通过PID调节器,有一个MAC操作在FOO,注意和库函数有变化的,见SpeedControl() Comments。
//////////////////////////////////////////////////////////////////////////////////////// 
SFRAC16 ControlDifference[3] __attribute__((__space__(xmemory), __aligned__(4)));	
SFRAC16 PIDCoefficients[3] __attribute__((__space__(ymemory), __aligned__(4)));	

// Used as a temporal variable to perform a fractional divide operation in assembly
SFRAC16 _MINPERIOD = MINPERIOD - 1;	// Used by fractional divide operation


/**********************************************************************
   T1中断服务程序,通过PID速度计算产生新的PDC数值	
  **********************************************************************/

void __attribute__((__interrupt__)) _T1Interrupt (void)
{
	IFS0bits.T1IF = 0;
	Period = ActualCapture - PastCapture;	// This is an UNsigned sub straction

	if (Period < (unsigned int)MINPERIOD) 	// MINPERIOD corresponds to 6000 rpm
		Period = MINPERIOD;
	else if (Period > (unsigned int)MAXPERIOD) // MAXPERIOD corresponds to 60 rpm
		Period = MAXPERIOD;

	//调用这个汇编函数用来计算速度小数数值 。
	//	                              MINPERIOD
	// Speed = (Fractional divide) ---------------
	//                                 Period

	SpeedCalculation();
	SpeedAbsValue = Speed;

	// 依照转子的当前方向调整速度
	if (Current_Direction == CCW)
		Speed = -Speed;

	// Condition                RPM              SFRAC16       SINT         HEX
	// Max Speed CW  -> 6000 RPM  -> 0.996805  -> 32663  -> 0x7F97  //32663
	// Min Speed CW  --> 60 RPM   - -> 0.009984  -> 327    -> 0x0147  //327
	// Min Speed CCW -> -60 RPM   -> -0.009984 -> -327   -> 0xFEB9  //-32441
	// Max Speed CCW -> -6000 RPM -> -0.996805 -> -32663 -> 0x8069  //105

	// 速度PID调节器调用函数,它用实际速度,参考速度加上一定的常数来为SVM计算一个新的速度
	SpeedControl();

	// 设置最小调节器速度输出/10%/保持电机运转Set minimum ControlOutput to 10% to keep the motor running
	if (ControlOutput < 3276)   //为什么要在小于3276的时候赋值3276呢??????????????
		ControlOutput = 3276;

	MotorStalledCounter++;	    // 这个变量是在每个霍尔中断里面清除的。
    if ((MotorStalledCounter % _10MILLISEC) == 0)
	{
		ForceCommutation();	    // 根据指令方向决定PID的输出数值是正还是负,从而决定旋转方向。
                                //Force Commutation if no hall sensor changes have occured in specified timeout.
	}
	else if (MotorStalledCounter >= _100MILLISEC)
	{
		StopMotor(); // 锁定停止电机。
	}
	return;
}

/**********************************************************************
  霍尔中断程序,做电平变化CN5/RB3/HALLA的中断服务程序,目的是计算电机旋转的实际机械方向
  并依靠得到的霍尔值和查表来调整相位变量。
  注意:为了引起误中断,要进行回转率霍尔输入滤波。
**********************************************************************/

void __attribute__((__interrupt__)) _CNInterrupt (void)
{
	IFS0bits.CNIF = 0;	     // 清除所有电平变化中断标志。
	HallValue = (unsigned int)((PORTB >> 3) & 0x0007);	// 从PORTB积存器读取霍尔状态换向信息。
	Sector = SectorTable[HallValue];	// 查表获得相应的数据(1-5)。
	if (Sector != LastSector)	// This is a MUST for getting around the HW slow rate
	{
		// 因为检测到一个新数据,如果杜撰发生就清除变量并停止惦记
		MotorStalledCounter = 0;
		// 电机当前的方向是通过SECTOR值决定的。
		if ((Sector == 5) || (Sector == 2))	// 如条件发生方向为CCW。
                                            
			Current_Direction = CCW;
		else
			Current_Direction = CW;
	
		SixStepComm(Sector, ControlOutput); // 如果ControlOutput大于0将正转,否则反转。
		LastSector = Sector;	// 更新上次SECTOR的数值在有变化的时候。
	}
	return;
}

/**********************************************************************
	
         Hall B 中断服务程序

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

void __attribute__((__interrupt__)) _IC7Interrupt (void)
{
	IFS1bits.IC7IF = 0;	
	HallValue = (unsigned int)((PORTB >> 3) & 0x0007);	// Read halls
	Sector = SectorTable[HallValue];	// Get Sector from table
	if (Sector != LastSector)	// This is a MUST for getting around the HW slow rate
	{
		// 依照半个电周期计算霍尔周期
		PastCapture = ActualCapture;
		ActualCapture = IC7BUF;
		// 清除所有缓冲器?????
		IC7BUF;
		IC7BUF;
		IC7BUF;
		
		MotorStalledCounter = 0;
		// 电机当前的方向是基于SECTOR的数值计算的。
		if ((Sector == 3) || (Sector == 0))//???????
			Current_Direction = CCW;
		else
			Current_Direction = CW;

		SixStepComm(Sector, ControlOutput); // 如果调节器输出大于0将运行CW,否则运行CCW。

		LastSector = Sector;	// 更新上次SECTOR的数值在有变化的时候。
	}
	return;
}

//**********************************************************************
	
//     Hall C 中断服务程序

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

void __attribute__((__interrupt__)) _IC8Interrupt (void)
{	
	IFS1bits.IC8IF = 0;	// 清除IC8中断标志。
	HallValue = (unsigned int)((PORTB >> 3) & 0x0007);	// 读霍尔状态数值。
	Sector = SectorTable[HallValue];	// 查表获得数据(1-5)。
	if (Sector != LastSector)	// 如果等于上次就什么也不做
	{
		// 就认为检测到一个新的霍尔数值。
		MotorStalledCounter = 0;
		// 电机当前的方向是依据SECTOR计算的。
		if ((Sector == 1) || (Sector == 4))	// 如果状态是1或4就认为是CCW
			Current_Direction = CCW;
		else
			Current_Direction = CW;
		
		SixStepComm(Sector, ControlOutput); // 如果调节器输出大于0将运行CW,否则运行CCW。

		LastSector = Sector;	// 把本次的数值作为上一次的数值。
	}
	return;
}

//*********************************************************************
//	The ADC 中断服务程序

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

void __attribute__((__interrupt__)) _ADCInterrupt (void)
{
	IFS0bits.ADIF = 0;
	RefSpeed = (int)(((unsigned int)ADCBUF0) / 2);
	if (RefSpeed < 2000) 
		RefSpeed = 2000;
	return;
}

//*********************************************************************
//	主程序
//*********************************************************************/

int main(void)
{ 
	InitUserInt();	
	InitADC10();	
	InitTMR1();		// 1 ms周期定时中断初始化
	InitTMR3();		

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -