该程序不需要连接电机以及电流传感器,只需要用杜邦线将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; // 采样ADCA0AdcRegs.ADCCHSELSEQ1.bit.CONV01 = 0x1; // 采样ADCA1AdcRegs.ADCCHSELSEQ1.bit.CONV02 = 0x2; // 采样ADCA2AdcRegs.ADCCHSELSEQ1.bit.CONV03 = 0x3; // 采样ADCA3AdcRegs.ADCCHSELSEQ2.bit.CONV04 = 0x4; // 采样ADCA4AdcRegs.ADCCHSELSEQ2.bit.CONV05 = 0x5; // 采样ADCA5AdcRegs.ADCCHSELSEQ2.bit.CONV06 = 0x6; // 采样ADCA6AdcRegs.ADCCHSELSEQ2.bit.CONV07 = 0x7; // 采样ADCA7AdcRegs.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 signalGpioDataRegs.GPACLEAR.bit.GPIO4 = 1; // Normally lowEDIS;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; //分频系数xEPwm1Regs.TBCTL.bit.CLKDIV=0; //分频系数yEPwm1Regs.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 registersPieVectTable.EPWM1_INT= &prdTick;EDIS;IER |= M_INT3;PieCtrlRegs.PIEIER3.bit.INTx1 = 1;EINT; // Enable Global interrupt INTMERTM; // Enable Global realtime interrupt DBGM
}void EQEP1_Init()
{EALLOW; // This is needed to write to EALLOW protected registersSysCtrlRegs.PCLKCR1.bit.EQEP1ENCLK = 1; // eQEP1EDIS;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 measurementqep_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 contolInterrupt_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 countEDIS;}// Acknowledge this interrupt to receive more interrupts from group 1PieCtrlRegs.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 filevoid 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 modeEQep1Regs.QEPCTL.bit.FREE_SOFT=2;EQep1Regs.QEPCTL.bit.PCRM=00; // PCRM=00 mode - QPOSCNT reset on index eventEQep1Regs.QEPCTL.bit.UTE=1; // Unit Timeout Enable EQep1Regs.QEPCTL.bit.QCLM=1; // Latch on unit time outEQep1Regs.QPOSMAX=0xffffffff;EQep1Regs.QEPCTL.bit.QPEN=1; // QEP enableEQep1Regs.QCAPCTL.bit.UPPS=5; // 1/32 for unit positionEQep1Regs.QCAPCTL.bit.CCPS=7; // 1/128 for CAP clockEQep1Regs.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/revolutiontmp = (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 occurrenceif (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 ****//
// 检查单位超时事件以进行速度计算:
// 单位计时器在初始化函数中配置为100Hzif(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 negativeelseTmp1 = 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); elsep->Speed_fr = Tmp1;// Update the electrical anglep->oldpos = newp;// Change motor speed from pu value to rpm value (Q15 -> Q0)// Q0 = Q0*GLOBAL_Q => _IQXmpy(), X = GLOBAL_Qp->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 overflowtemp1=(unsigned long)EQep1Regs.QCPRDLAT; // temp1 = t2-t1 else // Capture overflow, saturate the resulttemp1=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); elsep->Speed_pr = Tmp1;// Convert p->Speed_pr to RPMif (p->DirectionQep==0) // Reverse direction = negativep->SpeedRpm_pr = -_IQmpy(p->BaseRpm,p->Speed_pr); // Q0 = Q0*GLOBAL_Q => _IQXmpy(), X = GLOBAL_Qelse // Forward direction = positivep->SpeedRpm_pr = _IQmpy(p->BaseRpm,p->Speed_pr); // Q0 = Q0*GLOBAL_Q => _IQXmpy(), X = GLOBAL_QEQep1Regs.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-AEDIS;/*初始化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) - 独立于全局 Qint32 SpeedRpm_pr; // 速度 (rpm) (Q0) - 独立于全局 Q_iq oldpos; // Input: 电角度 (pu)_iq Speed_fr; // 每单位速度int32 SpeedRpm_fr; // Output : 速度 (rpm) (Q0) - 独立于全局 Qvoid (*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 头文件内容较少在此省略