电流采集(ADC)、位置转速测量(EQEP)、数模转换(DAC)模块实验程序

该程序不需要连接电机以及电流传感器,只需要用杜邦线将DSP的GPIO对应的接口连接即可调试。

程序中采集的电流是通过生成正弦波的数字信号再通过TLV5620数模转换器将其转换为模拟信号,以此来模拟实际电流信号;

程序中通过EPWM模块生成正交的脉冲信号来模拟正交编码器的A、B输出,通过GPIO口生成正交编码器的I索引脉冲信号;

main.c

/利用EQEP1模块测量电机的转速以及位置
//采用EPWM1模块生成EQEPA、EQEPB正交信号
//GPIO4生成EQEPI索引信号
//分别用M法和T法测速得到电机的转速

#include "DSP2833x_Device.h"     // DSP2833x Headerfile Include File
#include "DSP2833x_Examples.h"   // DSP2833x Examples Include File
#include "eqep1.h"
#include "ADC.h"
#include "math.h"
#include "tlv5620.h"
#define PI 3.14159265358979323846
#define SINE_RESOLUTION 100
void main ()
{
    int index = 0;
    int i;
    Uint16 dacvalue;
    float sine_wave[SINE_RESOLUTION];
    InitSysCtrl();
    InitPieCtrl();
    IER = 0x0000;
    IFR = 0x0000;
    InitPieVectTable();
    ADC_Init();
    EQEP1_Init();
    EINT;
    ERTM;
    TLV5620_Init();
    for (i = 0; i < SINE_RESOLUTION; i++) {
        sine_wave[i] = (sin(2 * PI * i / SINE_RESOLUTION) + 1) * 127.5; // 将正弦波值映射到0-255范围
    }
    while(1)
    {
        dacvalue = (Uint16)sine_wave[index];
        DAC_SetChannelData(0,0,dacvalue);
        index++;
        if (index >= SINE_RESOLUTION)
        {
            index = 0;
        }
    DELAY_US(1*100);
    }
}

ADC.c 

/*
 * ADC.c
 *
 *  Created on: 2024年6月18日
 *      Author: ZnDream666
 */
#include"ADC.h"
//初始化ADC,设置ADC为EPW1的CTR=PRD事件到来开始转换
//完成8个通道的采样后进入ADC中断,中断程序内将采集到的电流值记录
#define ADC_usDELAY  5000L
int sampleTable[8];
float I[8];
int i;
int k=0;
float I7_buf[100];
void ADC_Init()
{
    extern void DSP28x_usDelay(Uint32 Count);
    EALLOW;
    SysCtrlRegs.PCLKCR0.bit.ADCENCLK = 1;
    EDIS;

    EALLOW;
    SysCtrlRegs.HISPCP.all = ADC_MODCLK;    // HSPCLK = SYSCLKOUT/(2*ADC_MODCLK)
    ADC_cal();
    EDIS;

    AdcRegs.ADCTRL3.all = 0x00E0;
    DELAY_US(ADC_usDELAY);
    AdcRegs.ADCTRL1.bit.CPS= 0;
    AdcRegs.ADCTRL1.bit.SEQ_CASC = 0;   //双序列发生器模式
    AdcRegs.ADCTRL3.bit.SMODE_SEL=0;    //顺序采样模式
    AdcRegs.ADCTRL1.bit.CONT_RUN = 0; //启动/停止模式
    AdcRegs.ADCMAXCONV.bit.MAX_CONV1 = 0x7;
    AdcRegs.ADCCHSELSEQ1.bit.CONV00 = 0x0; // 采样ADCA0
    AdcRegs.ADCCHSELSEQ1.bit.CONV01 = 0x1; // 采样ADCA1
    AdcRegs.ADCCHSELSEQ1.bit.CONV02 = 0x2; // 采样ADCA2
    AdcRegs.ADCCHSELSEQ1.bit.CONV03 = 0x3; // 采样ADCA3
    AdcRegs.ADCCHSELSEQ2.bit.CONV04 = 0x4; // 采样ADCA4
    AdcRegs.ADCCHSELSEQ2.bit.CONV05 = 0x5; // 采样ADCA5
    AdcRegs.ADCCHSELSEQ2.bit.CONV06 = 0x6; // 采样ADCA6
    AdcRegs.ADCCHSELSEQ2.bit.CONV07 = 0x7; // 采样ADCA7
    AdcRegs.ADCTRL2.bit.EPWM_SOCA_SEQ1 = 1;//EPWM_SOCA启动方式
//    AdcRegs.ADCTRL2.bit.EPWM_SOCB_SEQ2 = 1;
    EALLOW;
    PieVectTable.ADCINT = &adc_isr;    //配置adc中断服务函数地址
    EDIS;
    PieCtrlRegs.PIEIER1.bit.INTx6 = 1;    //开启INT1.6中断
    IER |= M_INT1;                     // 开启第一组中断
    EINT;
    ERTM;
    AdcRegs.ADCTRL2.bit.INT_ENA_SEQ1 = 1; //允许SEQ1发送中断申请
    AdcRegs.ADCTRL2.bit.INT_ENA_SEQ2 = 0; //禁止SEQ2发送中断申请
    AdcRegs.ADCTRL2.bit.INT_MOD_SEQ1 = 0; //每个SEQ1序列转换完成后发送一次中断申请
}
interrupt void adc_isr()
{
    sampleTable[0] = (AdcRegs.ADCRESULT0) >> 4;
    sampleTable[1] = (AdcRegs.ADCRESULT1) >> 4;
    sampleTable[2] = (AdcRegs.ADCRESULT2) >> 4;
    sampleTable[3] = (AdcRegs.ADCRESULT3) >> 4;
    sampleTable[4] = (AdcRegs.ADCRESULT4) >> 4;
    sampleTable[5] = (AdcRegs.ADCRESULT5) >> 4;
    sampleTable[6] = (AdcRegs.ADCRESULT6) >> 4;
    sampleTable[7] = (AdcRegs.ADCRESULT7) >> 4;
    AdcRegs.ADCTRL2.bit.RST_SEQ1 = 1; //初始化状态指针位置
//    AdcRegs.ADCTRL2.bit.RST_SEQ2 = 1;
    AdcRegs.ADCST.bit.INT_SEQ1_CLR = 1;
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
    for(i = 0; i < 8; i++)
    {
        I[i] = (float)sampleTable[i] * 3.0 / 4095.0;
    }
    I7_buf[k++] = I[7];
    if (k>=100)
        k = 0;
}

eqep1.c 

/*
 * eqep1.c
 *
 *  Created on: 2024年6月12日
 *      Author: ZnDream666
 */
#include "eqep1.h"
#include "Example_posspeed.h"
#define CPU_CLK   150e6
#define PWM_CLK   10e3              // 5kHz (150rpm) EPWM1 frequency. Freq. can be changed here
#define SP        CPU_CLK/(2*PWM_CLK)
//#define SP        0xFFFF
POSSPEED qep_posspeed=POSSPEED_DEFAULTS;
Uint16 Interrupt_Count = 0;
float P_A = 0;
float P_B = 0;
float P_C = 0;
float P_D = 0;
float P_E = 0;
float P_F = 0;
float P_G = 0;
float P_H = 0;
Uint16 j=0;
int PA_buf[100];
interrupt void prdTick(void);
void  EPwm1Setup()
{

    EALLOW;
    SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 0;
    SysCtrlRegs.PCLKCR1.bit.EPWM1ENCLK = 1;
    EDIS;

    InitEPwm1Gpio();

    EALLOW;
    GpioCtrlRegs.GPADIR.bit.GPIO4 = 1;    // GPIO4 as output simulates Index signal
    GpioDataRegs.GPACLEAR.bit.GPIO4 = 1;  // Normally low
    EDIS;

    EPwm1Regs.TBCTL.bit.SYNCOSEL = TB_SYNC_DISABLE;
    EPwm1Regs.TBSTS.all=0;
    EPwm1Regs.TBPHS.half.TBPHS =0;
    EPwm1Regs.TBCTR=0;

    EPwm1Regs.TBPRD = SP;
    EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN;
    EPwm1Regs.TBCTL.bit.HSPCLKDIV=0;     //分频系数x
    EPwm1Regs.TBCTL.bit.CLKDIV=0;         //分频系数y

    EPwm1Regs.CMPCTL.bit.SHDWAMODE = CC_IMMEDIATE;
    EPwm1Regs.CMPCTL.bit.SHDWBMODE = CC_IMMEDIATE;
    EPwm1Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO;
    EPwm1Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO;
    //当计数器达到零点时,阴影寄存器的值会被加载到实际的CMPA寄存器中。这种加载模式确保CMPA值的更新在计数器归零时进行,从而保持PWM信号的同步和一致性。

    EPwm1Regs.CMPA.half.CMPA = SP/2;
    EPwm1Regs.CMPB = 0;

    EPwm1Regs.AQCTLA.bit.CAD = AQ_CLEAR;
    EPwm1Regs.AQCTLA.bit.CAU = AQ_SET;
    EPwm1Regs.AQCTLB.bit.ZRO = AQ_CLEAR;
    EPwm1Regs.AQCTLB.bit.PRD = AQ_SET;

    EPwm1Regs.ETSEL.bit.INTSEL = ET_CTR_PRD;     // TBPCR=TBPRD时触发中断申请
    EPwm1Regs.ETSEL.bit.INTEN = 1;  // Enable INT    //使能EPWM6模块的中断功能
    EPwm1Regs.ETPS.bit.INTPRD = ET_1ST;

    EPwm1Regs.ETSEL.bit.SOCAEN = 1;  //使能EPwm1SOCA信号产生
    EPwm1Regs.ETSEL.bit.SOCBEN = 1;
    EPwm1Regs.ETSEL.bit.SOCASEL = 2;  //当TBCTR=TBPRD时产生SOCA信号
    EPwm1Regs.ETSEL.bit.SOCBSEL = 2;
    EPwm1Regs.ETPS.bit.SOCAPRD = 1;   //在第一个事件来到时产生SOCA信号
    EPwm1Regs.ETPS.bit.SOCBPRD = 1;

    EALLOW;
    SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 1;
    EDIS;

    EALLOW;  // This is needed to write to EALLOW protected registers
    PieVectTable.EPWM1_INT= &prdTick;
    EDIS;

    IER |= M_INT3;
    PieCtrlRegs.PIEIER3.bit.INTx1 = 1;
    EINT;   // Enable Global interrupt INTM
    ERTM;   // Enable Global realtime interrupt DBGM
}


void EQEP1_Init()
{
    EALLOW;  // This is needed to write to EALLOW protected registers
    SysCtrlRegs.PCLKCR1.bit.EQEP1ENCLK = 1;  // eQEP1
    EDIS;

    InitEQep1Gpio();

    EPwm1Setup();

    qep_posspeed.init(&qep_posspeed);
}

interrupt void prdTick(void)                  // EPWM1 Interrupts once every 4 QCLK counts (one period)
{
    Uint16 i;

    // Position and Speed measurement
    qep_posspeed.calc(&qep_posspeed);
    P_A=((qep_posspeed.theta_raw-390+444)%444)*20/444;
    P_B=((qep_posspeed.theta_raw-390-111+444)%444)*20/444;
    P_C=((qep_posspeed.theta_raw-390-222+444)%444)*20/444;
    P_D=((qep_posspeed.theta_raw-390-333+444)%444)*20/444;

    P_E=((qep_posspeed.theta_raw-335+444)%444)*20/444;
    P_F=((qep_posspeed.theta_raw-335-111+444)%444)*20/444;
    P_G=((qep_posspeed.theta_raw-335-222+444)%444)*20/444;
    P_H=((qep_posspeed.theta_raw-335-333+444)%444)*20/444;

    // Control loop code for position control & Speed contol
    Interrupt_Count++;
    if (Interrupt_Count==2000)                 // Every 1000 interrupts(4000 QCLK counts or 1 rev.)
    {
        EALLOW;
        GpioDataRegs.GPASET.bit.GPIO4 = 1;     // Pulse Index signal  (1 pulse/rev.)
        for (i=0; i<700; i++){
    }
    GpioDataRegs.GPACLEAR.bit.GPIO4 = 1;
    Interrupt_Count = 0;                   // Reset count
    EDIS;
    }

    // Acknowledge this interrupt to receive more interrupts from group 1
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP3;
    EPwm1Regs.ETCLR.bit.INT=1;
}

 Example_posspeed.c

//###########################################################################
//
// FILE:	Example_posspeed.c
//
//标题:使用 EQEP 外设进行位置/速度测量
//
// DESCRIPTION:
//
// 该文件包含由 Example_2833xEqep_posspeed.c 调用的 EQEP 初始化和位置及速度计算函数。
// POSSPEED_Calc() 函数在 SYSCLKOUT = 150 MHz 和
//100 MHz 时执行的位置和速度计算步骤如下详细描述:
//
// For 150 MHz Operation:
// ----------------------
//
// 1. 该程序计算: **theta_mech**
//    
//    theta_mech = QPOSCNT/mech_Scaler = QPOSCNT/4000,
//其中,4000 是一圈内的计数数。(4000/4 = 1000 线/圈的增量编码器)
//
// 2. 该程序计算: **theta_elec**
//
//    theta_elec = (# pole pairs) * theta_mech = 2*QPOSCNT/4000 for this example
//
// 3. 该程序计算: **SpeedRpm_fr** 高速测量
//
//    SpeedRpm_fr = [(x2-x1)/4000]/T                                             - Equation 1
//    其中 (x2-x1) 是 QPOSCNT 计数的差值。
//将 (x2-x1) 除以 4000 给出相对于索引的一圈内的位置。
// If base RPM  = 6000 rpm:
//                      6000 rpm = [(x2-x1)/4000]/10ms                     - Equation 2
//                                        = [(x2-x1)/4000]/(.01s*1 min/60 sec)
//                                        = [(x2-x1)/4000]/(1/6000) min
//                         max (x2-x1) = 4000 counts, or 1 revolution in 10 ms
//
//
// 将等式两边除以 6000 rpm:
//                            1 = [(x2-x1)/4000] rev./[(1/6000) min * 6000rpm] 
//							因为 (x2-x1) 对于 QPOSCNT 增量必须小于 4000(最大),
//						    (x2-x1)/4000 < 1 for CW rotation
//                          因为 (x2-x1) 对于 QPOSCNT 减量必须大于 -4000
//                          (x2-x1)/4000>-1  for CCW rotation
//						    speed_fr = [(x2-x1)/4000]/[(1/6000) min * 6000rpm]
//                                   = (x2-x1)/4000                              - Equation 3
//
// 将 speed_fr 转换为 RPM,乘以 6000 rpm:
//                           SpeedRpm_fr = 6000rpm *(x2-x1)/4000                 - Final Equation
//			SpeedRpm_fr = 2.5*	(x2-x1)
//
// 2. **min rpm ** = 根据可用的 CCPS 预分频选项选择为 10 rpm(最大为 128)
//
// 3. **SpeedRpm_pr**  低速测量
//    SpeedRpm_pr = X/(t2-t1)                                                    - Equation 4
//    其中 X = QCAPCTL [UPPS]/4000 圈(相对于索引的一圈内的位置)
// 如果最大/基础速度 = 6000 rpm:  6000 = (32/4000)/[(t2-t1)/(150MHz/128)]
//    其中 32 = QCAPCTL [UPPS](单位超时 - 每 32 个边缘一次)
//          32/4000 = position in 1 revolution (position as a fraction of 1 revolution)
//          t2-t1/(150MHz/128),  t2-t1= # of QCAPCLK cycles, and
//		                  1 QCAPCLK cycle = 1/(150MHz/128)
//										  = QCPRDLAT
//
//		        So: 6000 rpm = [32(150MHz/128)*60s/min]/[4000(t2-t1)]
//		             t2-t1 = [32(150MHz/128)*60 s/min]/(4000*6000rpm)           - Equation 5 
//		                   = 94 CAPCLK cycles = maximum (t2-t1) = SpeedScaler
//
// Divide both sides by (t2-t1), and:
//                   1 = 94/(t2-t1) = [32(150MHz/128)*60 s/min]/(4000*6000rpm)]/(t2-t1)
//				     Because (t2-t1) must be < 94 for QPOSCNT increment:
//				     94/(t2-t1) < 1 for CW rotation
//                   And because (t2-t1) must be >-94 for QPOSCNT decrement:
//				     94/(t2-t1)> -1 for CCW rotation
//
//					 speed_pr = 94/(t2-t1) 
//                      or [32(150MHz/128)*60 s/min]/(4000*6000rpm)]/(t2-t1)  - Equation 6
//
// To convert speed_pr to RPM:
// Multiply Equation 6 by 6000rpm:
//                  SpeedRpm_fr  = 6000rpm * [32(150MHz/128)*60 s/min]/[4000*6000rpm*(t2-t1)]
//							                = [32(150MHz/128)*60 s/min]/[4000*(t2-t1)]
//                                        or [(32/4000)rev * 60 s/min]/[(t2-t1)(QCPRDLAT)]- Final Equation
//SpeedRpm_fr = 562500 /(t2-t1)
//
// For 100 MHz Operation:
// ----------------------
//
// The same calculations as above are performed, but with 100 MHz
// instead of 150MHz when calculating SpeedRpm_pr.
// The value for freqScaler_pr becomes: [32*(100MHz/128)*60s/min]/(4000*6000rpm) = 63
// More detailed calculation results can be found in the Example_freqcal.xls
// spreadsheet included in the example folder.
//
//
//
// This file contains source for the posspeed module
//
//###########################################################################
// Original Author: SD
//
// $TI Release: 2833x/2823x Header Files and Peripheral Examples V133 $
// $Release Date: June 8, 2012 $
//###########################################################################
//使用固定点数运算而不是浮点数运算,以及在不同的 Q 格式之间进行转换,主要是为了提高性能、效率和确定性,节省资源,并利用硬件优化。这种方法虽然看起来复杂,
//但在嵌入式系统和实时控制应用中具有显著优势。
//即使有 FPU,定点数运算在某些情况下仍然比浮点数运算快。定点数运算使用整数运算,通常比浮点数运算消耗更少的时钟周期。
#include "DSP2833x_Device.h"     // DSP2833x Headerfile Include File
#include "DSP2833x_Examples.h"     // Device Headerfile and Examples Include File
#include "Example_posspeed.h"   // Example specific Include file

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;
	EQep1Regs.QEPCTL.bit.PCRM=00;		// 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=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
	

}

void POSSPEED_Calc(POSSPEED *p)     //传入&qep_posspeed也就是结构体的地址,用于存储数据,类似于数组
{
     long tmp;
     unsigned int pos16bval,temp1;
   	 _iq Tmp1,newp,oldp;

//位置计算——机械和电角度//
     p->DirectionQep = EQep1Regs.QEPSTS.bit.QDF;    // 电机方向: 0=逆时针/反向, 1=顺时针/正向
//p是指向结构体的指针,里面存放了结构体的地址,->相当于先解引用指针p,再访问结构体里面的成员
	 pos16bval=(unsigned int)EQep1Regs.QPOSCNT;     // 捕获QA,QB的脉冲数
     p->theta_raw = pos16bval+ p->cal_angle;        // raw theta = current pos. + ang. offset from QA
	 
	 // 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;          //保留有效的15位数据,限制其值在合理的范围内,避免溢出

// Check an index occurrence
     if (EQep1Regs.QFLG.bit.IEL == 1)     //检测到索引脉冲,CNT值锁存入QPOSILAT
     {  
    	p->index_sync_flag = 0x00F0;        //同步索引标志使用这种特定的值(而不是简单的 1 或 0)可以帮助避免与其他标志或状态混淆。
    	EQep1Regs.QCLR.bit.IEL=1;					// Clear interrupt flag
     }
      


//**** High Speed Calcultation using QEP Position counter ****//
// 检查单位超时事件以进行速度计算:
//  单位计时器在初始化函数中配置为100Hz

	if(EQep1Regs.QFLG.bit.UTO==1)                    // 如果单位超时(一个100Hz周期)
	{ 
		/** 微分器 	**/
		// 计算位置变化量 = (x2-x1) / 4000(每转位置)
	 	pos16bval=(unsigned int)EQep1Regs.QPOSLAT;	              // 锁存的POSCNT值
     	tmp = (long)((long)pos16bval*(long)p->mech_scaler);  	  // Q0*Q26 = Q26 
     	tmp &= 0x03FFF000;
     	tmp = (int)(tmp>>11);         			                  // Q26 -> Q15 
     	tmp &= 0x7FFF;
		newp=_IQ15toIQ(tmp);            //将Q15格式转换为Q格式
		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 = _IQdiv(p->SpeedScaler,temp1);    // p->Speed_pr = 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
			p->SpeedRpm_pr = -_IQmpy(p->BaseRpm,p->Speed_pr); 	// Q0 = Q0*GLOBAL_Q => _IQXmpy(), X = GLOBAL_Q
		else                                                    // Forward direction = positive
			p->SpeedRpm_pr = _IQmpy(p->BaseRpm,p->Speed_pr); 	// Q0 = Q0*GLOBAL_Q => _IQXmpy(), X = GLOBAL_Q

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


}


 tlv5620.c

/*
 * tlv5620.c
 *
 *  Created on: 2018-3-1
 *      Author: Administrator
 */

#include "tlv5620.h"


void TLV5620_Init(void)
{
	EALLOW;
	SysCtrlRegs.PCLKCR0.bit.SPIAENCLK = 1;   // SPI-A
	EDIS;

	/*初始化GPIO;*/
	InitSpiaGpio();

	EALLOW;
	GpioCtrlRegs.GPAMUX2.bit.GPIO26 = 0; // 配置GPIO为GPIO口
	GpioCtrlRegs.GPADIR.bit.GPIO26 = 1;      // 定义GPIO输出引脚
	GpioCtrlRegs.GPAPUD.bit.GPIO26 = 0;      // 禁止上啦 GPIO引脚
	EDIS;

	SpiaRegs.SPICCR.all =0x0a;///进入初始状态,数据在上升沿输出,自测禁止,11位数据模式
	SpiaRegs.SPICTL.all =0x0006; // 使能主机模式,正常相位,使能主机发送,禁止接收
		                            //溢出中断,禁止SPI中断;
	SpiaRegs.SPIBRR =0x0031;	//SPI波特率=37.5M/50	=0.75MHZ;
	SpiaRegs.SPICCR.all =0x8a; //退出初始状态;
	SpiaRegs.SPIPRI.bit.FREE = 1;  // 自由运行

	SET_LOAD;
}


///大家要知道这里所定义的各个变量的含义,channel是4个通道的地址(00,01,10,11)
///                                     rng是输出范围的倍数,可以是0或1。
///                                     dat是0~256数据
void DAC_SetChannelData(unsigned char channel,unsigned char rng,unsigned char dat)
{
	Uint16 dacvalue=0;

	//注意这里的有效数据是11位,SPI初始化中也进行了定义
	dacvalue = ((channel<<14) | (rng<<13) | (dat<<5));

	while(SpiaRegs.SPISTS.bit.BUFFULL_FLAG ==1);//判断SPI的发送缓冲区是否是空的,等于0可写数据
	SpiaRegs.SPITXBUF = dacvalue;	//把发送的数据写入SPI发送缓冲区
	while( SpiaRegs.SPISTS.bit.BUFFULL_FLAG==1);		//当发送缓冲区出现满标志位时,开始琐存数据

	ClEAR_LOAD;
	DELAY_US(2);

	SET_LOAD;
	DELAY_US(10);

}

  Example_posspeed.h

//###########################################################################
// 文件: Example_posspeed.h
//
// 标题: 使用 EQEP 外设进行位置/速度测量
//
// 描述:
//
// 包含数据类型和对象定义以及初始化器的头文件。
//
//###########################################################################
// 原作者: SD
//
// $TI 发布: 2833x/2823x 头文件和外设示例 V133 $
// $发布日期: 2012 年 6 月 8 日 $
//###########################################################################

#ifndef __POSSPEED__
#define __POSSPEED__

#include "IQmathLib.h"         // Include header for IQmath library
/*-----------------------------------------------------------------------------
定义 POSSPEED 对象的结构
-----------------------------------------------------------------------------*/
typedef struct {int theta_elec;     	// Output: 电机电角度 (Q15)
                int theta_mech;     	// Output: 电机机械角度 (Q15)
                int DirectionQep;      	// Output: 电机旋转方向 (Q0)
                int QEP_cnt_idx; 	 	// Variable: 编码器计数器索引 (Q0)
                int theta_raw;     		// Variable: 来自 Timer 2 的原始角度 (Q0)
                int mech_scaler;    	// Parameter: 0.9999/总计数,总计数 = 4000 (Q26)
                int pole_pairs;     	// Parameter: 极对数 (Q0)
                int cal_angle;     		// Parameter:  编码器与相位 A 之间的原始角偏移 (Q0)
                int index_sync_flag; 	// Output: 索引同步状态 (Q0)

                Uint32 SpeedScaler;     // Parameter :  将 1/N 周期转换为 GLOBAL_Q 速度的缩放器 (Q0) - 独立于全局 Q
                _iq Speed_pr;           // Output :  每单位速度
                Uint32 BaseRpm;         // Parameter : 将 GLOBAL_Q 速度转换为 rpm 的缩放器 (Q0) - 独立于全局 Q
                int32 SpeedRpm_pr;      // 速度 (rpm) (Q0) - 独立于全局 Q

                _iq  oldpos;  			// Input: 电角度 (pu)
                _iq Speed_fr;           //  每单位速度
                int32 SpeedRpm_fr;     	// Output : 速度 (rpm) (Q0) - 独立于全局 Q
                void (*init)();     	// 指向初始化函数的指针
                void (*calc)();    		// 指向计算函数的指针
                }  POSSPEED;

/*-----------------------------------------------------------------------------
Define a POSSPEED_handle
-----------------------------------------------------------------------------*/
typedef POSSPEED *POSSPEED_handle;

/*-----------------------------------------------------------------------------
Default initializer for the POSSPEED Object.
-----------------------------------------------------------------------------*/

#if (CPU_FRQ_150MHZ)
  #define POSSPEED_DEFAULTS {0x0, 0x0,0x0,0x0,0x0,8388,2,0,0x0,\
        47,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,8388,2,0,0x0,\
        63,0,6000,0,\
        0,0,0,\
        (void (*)(long))POSSPEED_Init,\
        (void (*)(long))POSSPEED_Calc }
#endif


/*-----------------------------------------------------------------------------
Prototypes for the functions in posspeed.c                                 
-----------------------------------------------------------------------------*/
void POSSPEED_Init(void);                                              
void POSSPEED_Calc(POSSPEED_handle);
                
#endif /*  __POSSPEED__ */

ADC.h eqep1.h tlv5620.h 头文件内容较少在此省略

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ZnDream66

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值