该程序不需要连接电机以及电流传感器,只需要用杜邦线将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 头文件内容较少在此省略