DSP28335的EQEP模块的使用与电机测速

目录

一、QEP概述

一、采用增量型光电编码器来判别电机转速方向的基本原理

二、DSP28335的EQEP模块

三、测速方法

(1)M法

 (2)T法

 (3)M/T法

(4)二阶Lagrange插值多项式估值法。

(5)具体参数计算

四、相关测速部分代码

1、头文件

2、主文件

附录:


一、QEP概述

一、采用增量型光电编码器来判别电机转速方向的基本原理

增量式编码器是将设备运动时的位移信息变成连续的脉冲信号,脉冲个数表示位移量的大小。只有当设备运动的时候增量式编码器才会输出信号。编码器一般会把这些信号分为通道A和通道B 两组输出,并且这两组信号间有90° 的相位差。同时采集这两组信号就可以知道设备的运动和方向。除了通道A、通道B 以外,很多增量式编码器还会设置一个额外的通道Z 输出信号,用来表示编码器特定的参考位置,传感器转一圈Z 轴信号才会输出一个脉冲。增量式编码器只输出设备的位置变化和运动方向,不会输出设备的绝对位置。

增量式编码器都有A、B 两通道信号输出,这是因为增量式编码器的码盘上有两圈线槽,两圈线槽的之间会错开一定的角度,这个角度会使得光电检测装置输出的两相信号相差1/4 周期(90°)。码盘的具体工作方式如下图所示。图中黑色代表透光,白色代表遮光。当码盘转动时,内圈和外圈的线槽会依次透过光线,光电检测装置检测到光线通断的变化,就会相应的输出脉冲信号,因为内外圈遮光和透光时候存在时间差,所以也就有了A、B 两通道信号的相位差。

增量型编码器一般安装在电机或其他旋转机构的轴上,在码盘旋转过程中,输出两个信号称为QEPA 与QEPB,两路信号相差90°,这就是所谓的正交信号,当电机正转时,脉冲信号A 的相位超前脉冲信号 B 的相位 90°,此时逻辑电路处理后可形成高电平的方向信号 Dir。当电机反转时,脉冲信号 A 的相位滞后脉冲信号 B 的相位 90°,此时逻辑电路处理后的方向信号 Dir 为低电平。因此根据超前与滞后的关系可以确定电机的转向。其转速辩相的原理如图所示。

二、DSP28335的EQEP模块

TMS28335芯片将常用的转速测量电路集成于芯片内部,组成了增强型正交编码模块eQEP。当工作在正交计数模式下,正交解码单元可对正交信号进行4倍频处理,为位置计数器寄存器的计数提供时钟频率。

正交-计数模式: 在正交-计数模式下,正交解码器产生方向信号和时钟信号送给位置计数器。

方向解码---通过确定QEPA和QEPB两个脉冲信号,哪一个超前,来解码出旋转方向逻辑,并且将此方向逻辑更新到QEPSTS的QDF位。表10.1给出了方向解码逻辑的真值表。图10.7给出了方向解码的状态机。

时钟解码---QEP中的解码模块,会对QEPA和QEPB脉冲的上升沿及下降沿进行计数,所以最后解码的时钟频率将会是实际输入QEPA或者QEPB的4倍。

三、测速方法

(1)M法

M法又称之为测频法,其原理是先设定一定的时间,然后在这段时间TC内,对光电码盘输出的信号的个数进行计数。在测量过程中,计取的脉冲数M1不一定正好是整数,M1可能存在±1的误差。计取的M1的值越大,所得的误差越小,因此M法适用于高速转速的测量。

 (2)T法

T法又称之为测周法,此测量原理是在一个脉冲周期内对高频脉冲数进行计数。为了减小误差,计得的高频脉冲M2应尽量大,因此T法测量适用于低速测量。

                                        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        

 (3)M/T法

M/T法是将M法和T法两种方法结合起来,即在一定的时间范围TC内,计取光电码盘输出的脉冲数M1的同时,也对高频脉冲M2进行计数。TC时间到来后,再计取­T时间内的高频脉冲数m,­T是时间TC结束后到码盘信号下一个脉冲上升沿的时间间隔。

(4)二阶Lagrange插值多项式估值法。

其关于时间t的导数如下:

式中:t 0,t1,t 2,f (t0),f (t1),f (t2)分别为离当前时刻t最近的3个位置事件对应的时间和位置。假定在t0,t1,t2这3个时间点对应的位置增量相等,即

其中N为一个位置事件所对应的编码器脉冲数。令△t1 = t1 - t0,△t2 = t2 - t1,△t3 = t - t2,则可利用式(17)来估计当前时刻t的瞬时转速(rad/s):

(5)具体参数计算

采用双路QEP,512线光电编码器的直流减速电机 额定转速6000rpm 额定电压12V

M法:

T法、二阶Lagrange插值多项式估值法:

​​​​​​​

说明:TI的官方例程只有M、T法的相关代码,没有M、T法的,由于只是拿来用用(而且相关代码不是对照着修改的、这里就不给出了)

四、相关测速部分代码

1、头文件


#ifndef EQEP_POS_SPEED_GET_H
#define EQEP_POS_SPEED_GET_H

#include "IQmathLib.h"         // Include header for IQmath library

//-----------------------------------------------------------------------------
//  Define the structure of the POSSPEED Object 
//-----------------------------------------------------------------------------

typedef struct {float ElecTheta;    //OutPut: Motor Electrical Angle
                float MechTheta;    //Output: Motor Mechanical Angle
				float MechTheta_Beyond;  //存储超过一圈后的位置信息的变量
                  int DirectionQep; //output: Motor rotation direction
                  
				  int PolePairs;     //Parameter: 同步电机极对数
				  int LineEncoder;   //Parameter: 码盘一周脉冲数(增量式)
				  int Encoder_N;	 //Parameter: 码盘一周脉冲数的4倍(根据倍频的倍数而定,这里用4倍频)
				  int CalibrateAngle;//Parameter:电机A相绕组和码盘Index信号之间的夹角,与安装精度有关
				float Mech_Scaler;   //Parameter:1/Encoder_N
				float RawTheta;      //Variable: 初始定位后,电机转子d轴和定子A相绕组之间所相差的码盘计数值
				  int Index_sync_flag;//Output: Index sync status

				float BaseRpm;        //Parameter:额定转速

				float Speed_Mr_Rpm_Scaler;//Parameter:60000/(Encoder_N * T),其中T为M法测速时的时间间隔,单位ms//60/512线/(4倍频*0.001s)
				float Speed_Mr_Rpm;   //Output: speed int r.p.m
				float Speed_Mr;       //Output: speed in per-uint				
				float Position_k_1;   //Input: Current position 
                float Position_k;     //Input: Last position
                
                float Speed_Tr_Rpm_Scaler;//Parameter: (UPPS * 150e6 * 60)/(Encoder_N * CCPS)//150e6*60/512
				float Speed_Tr_Rpm;   //Output: spedd int r.p.m
				float Speed_Tr;       //Output: speed int per-uint

				float t1;
				float t2;
				float t3;

				float Ts; // 采样时间
                float K2; //滤波系数  
                
                float Speed_Temp;
                float Speed;             // Output :  speed in per-unit
				Uint32 K;
				
				  int cnt_old; //eQEP位置计数器寄存器中上一个时刻的计数值
				  int cycles; // 电机转过的圈数
				  float position;
				
				void (*init)();     	// Pointer to the init funcion          
                void (*calc)();
                } EQEP_POS_SPEED_GET;

//-----------------------------------------------------------------------------
// Define a POSSPEED_handle
//-----------------------------------------------------------------------------
typedef EQEP_POS_SPEED_GET  *EQEP_POS_SPEED_GET_handle;

//-----------------------------------------------------------------------------
// Default initializer for the POSSPEED Object.
//-----------------------------------------------------------------------------
#if (CPU_FRQ_150MHZ)
#define EQEP_POS_SPEED_GET_DEFAULTS {0,0,0,0,\
                                     2,500,2000,0,1.0/2000,0,0,\
                                     6000.0,\
                                     9.76,0,0,0,0,\
                                     17578125,0,0,\
									 0,0,0,0,0,0,0,0,0,0,0,\
									 (void (*)(long))eQEP_pos_speed_get_Init,\
									 (void (*)(long))eQEP_pos_speed_get_Calc}
                                     //注意9.76是0.003s为周期


//#define EQEP_POS_SPEED_GET_DEFAULTS {0,0,0,0,\
//                                     2,500,2000,0,1.0/2000,0,0,\
//                                     6000.0,\
//                                     29.29,0,0,0,0,\
//                                     17578125,0,0,\
//                                     0,0,0,0,0,0,0,0,0,0,0,\
//                                     (void (*)(long))eQEP_pos_speed_get_Init,\
//                                     (void (*)(long))eQEP_pos_speed_get_Calc}

#endif

#if (CPU_FRQ_100MHZ)
#define EQEP_POS_SPEED_GET_DEFAULTS {0,0,0,\
                                     2,500,2000,0,1.0/2000,0,0,\
                                     6000.0,\
                                     3.0,0,0,0,0,\
                                     1125000,0,0,\
									 0,0,0,0,0,0,0,0,\
									 (void (*)(long))eQEP_pos_speed_get_Init,\
									 (void (*)(long))eQEP_pos_speed_get_Calc}
#endif

//-----------------------------------------------------------------------------
//  Prototypes for the functions in posspeed.c                                 
//-----------------------------------------------------------------------------
void eQEP_pos_speed_get_Init(EQEP_POS_SPEED_GET_handle);
void eQEP_pos_speed_get_Calc(EQEP_POS_SPEED_GET_handle);

#endif
//==============================================================
//End of file.
//==============================================================

2、主文件

#include "DSP2833x_Device.h"     // DSP2833x Headerfile Include File
#include "DSP2833x_Examples.h"   // DSP2833x Examples Include File #include "Example_posspeed.h" 

#include "Example_posspeed.h" 
#include <math.h>

//======== Definations for functions ===========================

void eQEP_pos_speed_get_Init(EQEP_POS_SPEED_GET *p)
{


#if (CPU_FRQ_150MHZ)
//	EQep1Regs.QUPRD=1500000;			// Unit Timer for 100Hz at 150 MHz SYSCLKOUT
//案例给的程序错误的地方 这个是单位事件使能 也就是说M法
	EQep1Regs.QUPRD=150000*3;            // Unit Timer for 100Hz at 150 MHz SYSCLKOUT
#endif
#if (CPU_FRQ_100MHZ)
	EQep1Regs.QUPRD=1000000;			// Unit Timer for 100Hz at 100 MHz SYSCLKOUT
#endif


	p->Encoder_N=4*p->LineEncoder;
	p->Mech_Scaler=1.0/p->Encoder_N;

	EQep1Regs.QDECCTL.bit.QSRC=0x00;		// QEP quadrature count mode
	EQep1Regs.QEPCTL.bit.FREE_SOFT=2;
	EQep1Regs.QEPCTL.bit.PCRM=0x01;  		// PCRM=00 mode - QPOSCNT reset on index event
	EQep1Regs.QEPCTL.bit.UTE=1; 		// Unit Timeout Enable 
	EQep1Regs.QEPCTL.bit.QCLM=1; 		// Latch on unit time out
	EQep1Regs.QPOSMAX=p->Encoder_N;     // Encoder_N
	EQep1Regs.QEPCTL.bit.QPEN=1; 		// QEP enable

	EQep1Regs.QCAPCTL.bit.UPPS=1;   	// 1/2 for unit position
	EQep1Regs.QCAPCTL.bit.CCPS=3;		// 1/8 for CAP clock
	EQep1Regs.QCAPCTL.bit.CEN=1; 		// QEP Capture Enable
//	EQep1Regs.QPOSMAX=0xffffffff;

	p->cycles=0;
	p->Speed_Tr_Rpm_Scaler=60.0*150*1000000/4/p->Encoder_N;
	p->Speed_Tr_Rpm=0;

	//EQep1Regs.QEPCTL.bit.SWI=1;// software generate index pulse

}

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

void eQEP_pos_speed_get_Calc(EQEP_POS_SPEED_GET *p)
{

	int cnt_inc , cnt_cur;
	float tmp1;
	unsigned int t2_t1;
	unsigned long M1,M2,fclk;

	//Check the rotational direction
	p->DirectionQep = EQep1Regs.QEPSTS.bit.QDF;
	cnt_cur = EQep1Regs.QPOSCNT;

	//Check the position counter for EQep1
	p->RawTheta = cnt_cur + p->CalibrateAngle;
	if(p->RawTheta < 0)
	{
		p->RawTheta = p->RawTheta + EQep1Regs.QPOSMAX;
	}
	else if(p->RawTheta > EQep1Regs.QPOSMAX)
	{
		p->RawTheta = p->RawTheta - EQep1Regs.QPOSMAX;
	}

	//Compute the mechanical angle

	p->MechTheta = p->Mech_Scaler * p->RawTheta;

	/*****************超过一圈后的角度计算*************/
	// Check the counter for QEP 
	cnt_inc = cnt_cur - p->cnt_old;
	if (abs(cnt_inc) > 200)  	//6000 RPM, 1ms能读到的最大差值就是200,  除非转角超过1圈.
	{
		if (cnt_inc < 0)
			p->cycles +=1;
		else
			p->cycles -=1;
	}	

	p->cnt_old = cnt_cur;

	//Compute the mechanical angle
	tmp1=p->MechTheta_Beyond;   // old position
	p->MechTheta_Beyond = p->MechTheta+p->cycles;
	
	p->Speed = 60*(p->MechTheta_Beyond-tmp1)/p->Ts;   // speed in RPM values


	// Check an index occurrence
	if (EQep1Regs.QFLG.bit.IEL == 1)
	{
		p->Index_sync_flag = 0x00F0;
		EQep1Regs.QCLR.bit.IEL=1;					// Clear interrupt flag
	}


    //
    // High Speed Calculation using QEP Position counter
    // Check unit Time out-event for speed calculation:
    // Unit Timer is configured for 100Hz in INIT function
    //


     if(EQep1Regs.QFLG.bit.UTO==1)// If unit timeout (one 100Hz period)
         {
          p->Position_k =1.0 * EQep1Regs.QPOSLAT;
          if(p->DirectionQep==0) // POSCNT is counting down
            {
             if(p->Position_k > p->Position_k_1)
               { tmp1 = -(p->Encoder_N - (p->Position_k - p->Position_k_1)); }
             else
               { tmp1 = p->Position_k - p->Position_k_1;}// x2-x1 should be negative
            }
          else if(p->DirectionQep==1)    // POSCNT is counting up
            {
             if(p->Position_k < p->Position_k_1)
               { tmp1 = p->Encoder_N - (p->Position_k_1 - p->Position_k); }
             else
               { tmp1 = p->Position_k - p->Position_k_1;}// x2-x1 should be positive
            }

          if(tmp1 > p->Encoder_N)
            { p->Speed_Mr_Rpm = p->BaseRpm;  }
          else if(tmp1 < -p->Encoder_N)
            { p->Speed_Mr_Rpm = -p->BaseRpm; }
          else
            { p->Speed_Mr_Rpm = tmp1 * p->Speed_Mr_Rpm_Scaler; }

           p->Speed_Mr = p->Speed_Mr_Rpm / p->BaseRpm;

           p->Position_k_1 = p->Position_k;

           EQep1Regs.QCLR.bit.UTO=1; // Clear interrupt flag
         }

#ifndef  Larrange_qep
//	  // Low-speed computation using QEP capture counter //	T法
	if(EQep1Regs.QEPSTS.bit.UPEVNT==1)                          // Unit position event
	{
		if(EQep1Regs.QEPSTS.bit.COEF==0)                        // No Capture overflow
			t2_t1 =  EQep1Regs.QCPRD;
		else                                                    // Capture overflow, saturate the result
			t2_t1 = 0xFFFF;

        //
        // Convert p->Speed_pr to RPM
        //

		if(p->DirectionQep==0)
			p->Speed_Tr_Rpm = - p->Speed_Tr_Rpm_Scaler / t2_t1; //negative
		else
			p->Speed_Tr_Rpm =  p->Speed_Tr_Rpm_Scaler / t2_t1;



		//	     if(p->Speed_Tr_Rpm > p->BaseRpm)
		//		   p->Speed_Tr_Rpm = p->BaseRpm;
		//	     else if(p->Speed_Tr_Rpm < -p->BaseRpm)
		//		   p->Speed_Tr_Rpm = -p->BaseRpm;
		//
		EQep1Regs.QEPSTS.all=0x88;          // Clear Unit position event flag
		                                    // Clear overflow error flag
	}

#else
     //Lagrange
	if(EQep1Regs.QEPSTS.bit.UPEVNT==1)
	{
		p->t1=p->t2;
		p->t2=(unsigned int)EQep1Regs.QCPRD;
		EQep1Regs.QEPSTS.bit.UPEVNT=1;
	}
	p->t3=EQep1Regs.QCTMR;

	p->Speed_Tr_Rpm=(p->Speed_Tr_Rpm_Scaler)*((2*p->t3+2*p->t2+p->t1)*2/(p->t1+p->t2)/p->t2-(2*p->t3+p->t2+p->t1)/p->t2/p->t1);
	if(p->DirectionQep==0)
		p->Speed_Tr_Rpm=-p->Speed_Tr_Rpm;
#endif

}

//==============================================================
//End of file.
//==============================================================


说明:该文件是从ti官方例程修改的(不是我改的),搬运ing......

附录:

Example_2833xEqep_pos_speed 工程内的两个文件(对比一下)

#ifndef __POSSPEED__
#define __POSSPEED__

//
// Included Files
//
#include "IQmathLib.h"         // Include header for IQmath library

//
// Typedef for the structure of the POSSPEED Object 
//
typedef struct 
{
    int theta_elec;     	// Output: Motor Electrical angle (Q15)  
    int theta_mech;     	// Output: Motor Mechanical Angle (Q15) 
    int DirectionQep;      	// Output: Motor rotation direction (Q0) 
    int QEP_cnt_idx; 	 	// Variable: Encoder counter index (Q0)
    int theta_raw;     		// Variable: Raw angle from Timer 2 (Q0)            
    
    //
    // Parameter: 0.9999/total count, total count = 4000 (Q26)
    //
    int mech_scaler;
    
    int pole_pairs;     	// Parameter: Number of pole pairs (Q0) 
    
    //
    // Parameter: Raw angular offset between encoder and phase a (Q0) 
    //
    int cal_angle;     		
    int index_sync_flag; 	// Output: Index sync status (Q0)                   

    //
    // Parameter :  Scaler converting 1/N cycles to a GLOBAL_Q speed (Q0)
    // independently with global Q
    //
    Uint32 SpeedScaler;     
    _iq Speed_pr;           // Output :  speed in per-unit
    
    //
    // Parameter : Scaler converting GLOBAL_Q speed to rpm (Q0) speed
    // independently with global Q
    //
    Uint32 BaseRpm;         
    
    //
    // Output : speed in r.p.m. (Q0) - independently with global Q 
    //
    int32 SpeedRpm_pr;

    _iq  oldpos;  			// Input: Electrical angle (pu) 
    _iq Speed_fr;           // Output :  speed in per-unit
    
    //
    // Output : Speed in rpm  (Q0) - independently with global Q
    //
    int32 SpeedRpm_fr;
    void (*init)();     	// Pointer to the init function          
    void (*calc)();    		// Pointer to the calc function        
} POSSPEED;

//
// Typedef for the POSSPEED_handle
//
typedef POSSPEED *POSSPEED_handle;

//
// Defines for the default initializer for the POSSPEED Object.
//
#if (CPU_FRQ_150MHZ)
    #define POSSPEED_DEFAULTS {0x0, 0x0,0x0,0x0,0x0,16776,2,0,0x0,\
        94,0,6000,0,\
        0,0,0,\
        (void (*)(long))POSSPEED_Init,\
        (void (*)(long))POSSPEED_Calc }
#endif
#if (CPU_FRQ_100MHZ)
    #define POSSPEED_DEFAULTS {0x0, 0x0,0x0,0x0,0x0,16776,2,0,0x0,\
        63,0,6000,0,\
        0,0,0,\
        (void (*)(long))POSSPEED_Init,\
        (void (*)(long))POSSPEED_Calc }
#endif

//
// Function Prototypes
//
void POSSPEED_Init(void);                                              
void POSSPEED_Calc(POSSPEED_handle);
                
#endif /*  __POSSPEED__ */

//
// End of File
//


//
// Included Files
//
#include "DSP28x_Project.h"     // Device Headerfile and Examples Include File
#include "Example_posspeed.h"   // Example specific Include file

//
// POSSPEED_Init - 
//
void
POSSPEED_Init(void)
{
    #if (CPU_FRQ_150MHZ)
        EQep1Regs.QUPRD=1500000;  // Unit Timer for 100Hz at 150 MHz SYSCLKOUT
	#endif
    #if (CPU_FRQ_100MHZ)
        EQep1Regs.QUPRD=1000000;  // Unit Timer for 100Hz at 100 MHz SYSCLKOUT
	#endif

	EQep1Regs.QDECCTL.bit.QSRC=00;		// QEP quadrature count mode

	EQep1Regs.QEPCTL.bit.FREE_SOFT=2;
	
    //
    // PCRM=00 mode - QPOSCNT reset on index event
    //
    EQep1Regs.QEPCTL.bit.PCRM=00;
    
	EQep1Regs.QEPCTL.bit.UTE=1; 		// Unit Timeout Enable
	EQep1Regs.QEPCTL.bit.QCLM=1; 		// Latch on unit time out
	EQep1Regs.QPOSMAX=0xffffffff;
	EQep1Regs.QEPCTL.bit.QPEN=1; 		// QEP enable

	EQep1Regs.QCAPCTL.bit.UPPS=5;   	// 1/32 for unit position
	EQep1Regs.QCAPCTL.bit.CCPS=7;		// 1/128 for CAP clock
	EQep1Regs.QCAPCTL.bit.CEN=1; 		// QEP Capture Enable
}

//
// POSSPEED_Calc -
// 
void 
POSSPEED_Calc(POSSPEED *p)
{
    long tmp;
    unsigned int pos16bval,temp1;
    _iq Tmp1,newp,oldp;

    //
    // Position calculation - mechanical and electrical motor angle
    //
    
    //
    // Motor direction: 0=CCW/reverse, 1=CW/forward
    //
    p->DirectionQep = EQep1Regs.QEPSTS.bit.QDF;

    //
    // capture position once per QA/QB period
    //
    pos16bval=(unsigned int)EQep1Regs.QPOSCNT;
    
    //
    // raw theta = current pos. + ang. offset from QA
    //
    p->theta_raw = pos16bval+ p->cal_angle;

    //
    // The following lines calculate p->theta_mech ~= 
    // QPOSCNT/mech_scaler [current cnt/(total cnt in 1 rev.)]
    // where mech_scaler = 4000 cnts/revolution
    //
    tmp = (long)((long)p->theta_raw*(long)p->mech_scaler);  // Q0*Q26 = Q26
    tmp &= 0x03FFF000;
    p->theta_mech = (int)(tmp>>11);         		// Q26 -> Q15
    p->theta_mech &= 0x7FFF;

    //
    // The following lines calculate p->elec_mech
    //
    p->theta_elec = p->pole_pairs*p->theta_mech;    // Q0*Q15 = Q15
    p->theta_elec &= 0x7FFF;

    //
    // Check an index occurrence
    //
    if (EQep1Regs.QFLG.bit.IEL == 1)
    {
        p->index_sync_flag = 0x00F0;
        EQep1Regs.QCLR.bit.IEL=1;					// Clear interrupt flag
    }

    //
    // High Speed Calculation using QEP Position counter
    // Check unit Time out-event for speed calculation:
    // Unit Timer is configured for 100Hz in INIT function
    //
    if(EQep1Regs.QFLG.bit.UTO==1)      // If unit timeout (one 100Hz period)
    {
        //
        // Differentiator
        // The following lines calculate position = 
        // (x2-x1)/4000 (position in 1 revolution)
        //
        pos16bval=(unsigned int)EQep1Regs.QPOSLAT;	    // Latched POSCNT value
        tmp = (long)((long)pos16bval*(long)p->mech_scaler); // Q0*Q26 = Q26
        tmp &= 0x03FFF000;
        tmp = (int)(tmp>>11);           // Q26 -> Q15
        tmp &= 0x7FFF;
        newp=_IQ15toIQ(tmp);
        oldp=p->oldpos;

        if (p->DirectionQep==0)      	// POSCNT is counting down
        {
            if (newp>oldp)
            {
                Tmp1 = - (_IQ(1) - newp + oldp);    // x2-x1 should be negative
            }
            else
            {
                Tmp1 = newp -oldp;
            }
        }
        else if (p->DirectionQep==1)    // POSCNT is counting up
        {
            if (newp<oldp)
            {
                Tmp1 = _IQ(1) + newp - oldp;
            }
            else
            {
                Tmp1 = newp - oldp;     // x2-x1 should be positive
            }
        }

        if (Tmp1>_IQ(1))
        {
            p->Speed_fr = _IQ(1);
        }
        else if (Tmp1<_IQ(-1))
        {
            p->Speed_fr = _IQ(-1);
        }
        else
        {
            p->Speed_fr = Tmp1;
        }

        //
        // Update the electrical angle
        //
        p->oldpos = newp;

        //
        // Change motor speed from pu value to rpm value (Q15 -> Q0)
        // Q0 = Q0*GLOBAL_Q => _IQXmpy(), X = GLOBAL_Q
        //
        p->SpeedRpm_fr = _IQmpy(p->BaseRpm,p->Speed_fr);
        
        EQep1Regs.QCLR.bit.UTO=1;					// Clear interrupt flag
    }

    //
    // Low-speed computation using QEP capture counter
    //
    if(EQep1Regs.QEPSTS.bit.UPEVNT==1)     // Unit position event
    {
        if(EQep1Regs.QEPSTS.bit.COEF==0)   // No Capture overflow
        {
            temp1=(unsigned long)EQep1Regs.QCPRDLAT;   // temp1 = t2-t1
        }
        else   // Capture overflow, saturate the result
        {
            temp1=0xFFFF;
        }

        //
        // p->Speed_pr = p->SpeedScaler/temp1
        //
        p->Speed_pr = _IQdiv(p->SpeedScaler,temp1);
        Tmp1=p->Speed_pr;

        if (Tmp1>_IQ(1))
        {
            p->Speed_pr = _IQ(1);
        }
        else
        {
            p->Speed_pr = Tmp1;
        }
        
        //
        // Convert p->Speed_pr to RPM
        //
        if (p->DirectionQep==0)     // Reverse direction = negative
        {
            //
            // Q0 = Q0*GLOBAL_Q => _IQXmpy(), X = GLOBAL_Q
            //
            p->SpeedRpm_pr = -_IQmpy(p->BaseRpm,p->Speed_pr);
        }
        else                        // Forward direction = positive
        {
            //
            // Q0 = Q0*GLOBAL_Q => _IQXmpy(), X = GLOBAL_Q
            //
            p->SpeedRpm_pr = _IQmpy(p->BaseRpm,p->Speed_pr);
        }

        EQep1Regs.QEPSTS.all=0x88;	// Clear Unit position event flag
                                    // Clear overflow error flag
    }
}

  • 26
    点赞
  • 167
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值