完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
//###########################################################################
// // FILE: Example_posspeed.c // // tiTLE: Pos/speed measurement using EQEP peripheral // // DESCRIPTION: // // This file includes the EQEP initialization and position and speed calcuation // functions called by Example_2833xEqep_posspeed.c. The position and // speed calculation steps performed by POSSPEED_Calc() at SYSCLKOUT = 150 MHz // and 100 MHz are described in detail below: // // For 150 MHz Operation: // ---------------------- // // 1. This program calculates: **theta_mech** // // theta_mech = QPOSCNT/mech_Scaler = QPOSCNT/4000, where 4000 is the number of // counts in 1 revolution.(4000/4 = 1000 line/rev. quadrature encoder) // // 2. This program calculates: **theta_elec** // // theta_elec = (# pole pairs) * theta_mech = 2*QPOSCNT/4000 for this example // // 3. This program calculates: **SpeedRpm_fr** // // SpeedRpm_fr = [(x2-x1)/4000]/T - Equation 1 // Note (x2-x1) = difference in number of QPOSCNT counts. Dividing (x2-x1) by // 4000 gives position relative to Index in one revolution. // 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 // // // If both sides of Equation 2 are divided by 6000 rpm, then: // 1 = [(x2-x1)/4000] rev./[(1/6000) min * 6000rpm] // Because (x2-x1) must be <4000 (max) for QPOSCNT increment, // (x2-x1)/4000 < 1 for CW rotation // And because (x2-x1) must be >-4000 for QPOSCNT decrement, // (x2-x1)/4000>-1 for CCW rotation // speed_fr = [(x2-x1)/4000]/[(1/6000) min * 6000rpm] // = (x2-x1)/4000 - Equation 3 // // To convert speed_fr to RPM, multiply Equation 3 by 6000 rpm // SpeedRpm_fr = 6000rpm *(x2-x1)/4000 - Final Equation // // // 2. **min rpm ** = selected at 10 rpm based on CCPS prescaler options available (128 is greatest) // // 3. **SpeedRpm_pr** // SpeedRpm_pr = X/(t2-t1) - Equation 4 // where X = QCAPCTL [UPPS]/4000 rev. (position relative to Index in 1 revolution) // If max/base speed = 6000 rpm: 6000 = (32/4000)/[(t2-t1)/(150MHz/128)] // where 32 = QCAPCTL [UPPS] (Unit timeout - once every 32 edges) // 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 // // // 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 $ //########################################################################### #include "DSP28x_Project.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) [ long tmp; unsigned int pos16bval,temp1; _iq Tmp1,newp,oldp; //**** Position calculation - mechanical and electrical motor angle ****// p->DirectionQep = EQep1Regs.QEPSTS.bit.QDF; // Motor direction: 0=CCW/reverse, 1=CW/forward pos16bval=(unsigned int)EQep1Regs.QPOSCNT; // capture position once per QA/QB period 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; // 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 Calcultation 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 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 ] ] 关于Example_posspeed.c的理解 在高速下每10ms进入if(EQep1Regs.QFLG.bit.UTO==1)这个case计算转速。 此时由于转速很高,故QCLK 32分频之后的时间远小于10ms,所以UPEVNT即Unit positon event的发生几率 很高,会频繁进入if(EQep1Regs.QEPSTS.bit.UPEVNT==1)这个case即低速模式计算,转速越高进入次数越多。 虽然频繁进入,但是只有当Unit time out即10ms单位时间到了以后才会更新QCPRDLAT的值。 利用更新后的QCPRDLAT同样会计算转速,将高速模式计算出的值覆盖。 所以高速模式下的工作过程是会同时在高速模式和低速模式下计算转速,会多次进入低速模式,但是实际起 作用的还是高速模式,低速模式计算出的值覆盖高速模式的数值,高速模式主导; 在低速下,32分频后的QCLK时间很长,所以会频繁进入高速模式计算,因为Unit time out 是10ms,在UTO的触发下, 会频繁更新QCPRDLAT的值,实现在低速时的转速计算,即频繁进入高速模式触发QCPRDLAT的更新,此时高速模式处于辅助 地位,低速模式主导。 疑问 开头的注释中有以下内容 “ 2. **min rpm ** = selected at 10 rpm based on CCPS prescaler options available (128 is greatest) ” 觉得最小转速不是10 rpm 由以下式子计算 1 X 32 ———————————— 128 Speed(rpm) == ———————————— X QCPRDLAT —————— X 4000 150000000 60 当QCPRDLAT取最大值0xFFFF时,可以计算出Speed = 8.58rpm,约为9rpm,不知道我的这个计算对不对。 再有就是因为UTO = 10ms , ccps设置为32分频,所以高速模式和低速模式应该有个切换点 计算如下: 32 X P = 10ms,其中P是正交编码脉冲A序列或B序列的四分之一周期, 因此可以计算出A或B序列的频率是800Hz,对应的转速为48rpm,这个是否正确请大家帮我看下,谢谢! |
|
相关推荐
14 个讨论
|
|
JASONbzyhzlq 发表于 2018-9-27 14:36 我按照这个配置但是还是测不出速度,您能帮我看一下程序吗?是我的程序配置的不对吗? //###########################################################################/*-----------------------------------------------------------------------------Default initializer for the POSSPEED Object.!! mech_scaler = 16384 (Q26格式) 1024线程-----------------------------------------------------------------------------*/ #define POSSPEED_DEFAULTS [0x0, 0x0,0x0,0x0,0x0,16384,2,0,0x0, 220,0,3000,0, 0,0,0, (void (*)(long))POSSPEED_Init, (void (*)(long))POSSPEED_Calc ]void POSSPEED_Init(void)[ EQep1Regs.QUPRD=1800000; // Unit Timer for 50Hz at 90 MHz SYSCLKOUT 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=6; // 1/64 for CAP clock EQep1Regs.QCAPCTL.bit.CEN=1; // QEP Capture Enable// EQep1Regs.QDECCTL.all = QDECCTL_INIT_STATE;// EQep1Regs.QEPCTL.all = QEPCTL_INIT_STATE;// EQep1Regs.QPOSCTL.all = QPOSCTL_INIT_STATE;// EQep1Regs.QUPRD = 900000; /* Unit Timer for 100Hz = sysclock/900000*/// EQep1Regs.QCAPCTL.all = QCAPCTL_INIT_STATE;// EQep1Regs.QPOSMAX = 4096; //4*LineEncoder 1024线程// EALLOW; /* Enable EALLOW*/// GpioCtrlRegs.GPAMUX2.bit.GPIO20 = 1; /* GPIO20 is EQEP1A */// GpioCtrlRegs.GPAMUX2.bit.GPIO21 = 1; /* GPIO21 is EQEP1B */// GpioCtrlRegs.GPAMUX2.bit.GPIO23 = 1; /* GPIO23 is EQEP1I */// EDIS; /* Disable EALLOW*/]void POSSPEED_Calc(POSSPEED *p)[ long tmp; unsigned int pos16bval,temp1;// unsigned int pos16bval; _iq Tmp1,newp,oldp;//**** Position calculation - mechanical and electrical motor angle ****// p->DirectionQep = EQep1Regs.QEPSTS.bit.QDF; // Motor direction: 0=CCW/reverse, 1=CW/forward pos16bval=(unsigned int)EQep1Regs.QPOSCNT; // capture position once per QA/QB period 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;// 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 Calcultation 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 |
|
|
|
|
|
只有小组成员才能发言,加入小组>>
NA555DR VCC最低电压需要在5V供电,为什么用3.3V供电搭了个单稳态触发器也使用正常?
669 浏览 3 评论
MSP430F249TPMR出现高温存储后失效了的情况,怎么解决?
597 浏览 1 评论
对于多级放大电路板,在PCB布局中,电源摆放的位置应该注意什么?
1048 浏览 1 评论
731 浏览 0 评论
普中科技F28335开发板每次上电复位后数码管都会显示,如何熄灭它?
520 浏览 1 评论
请问下tpa3220实际测试引脚功能和官方资料不符,哪位大佬可以帮忙解答下
158浏览 20评论
请教下关于TAS5825PEVM评估模块原理图中不太明白的地方,寻求答疑
120浏览 14评论
在使用3254进行录音的时候出现一个奇怪的现象,右声道有吱吱声,请教一下,是否是什么寄存器设置存在问题?
123浏览 13评论
TLV320芯片内部自带数字滤波功能,请问linein进来的模拟信号是否是先经过ADC的超采样?
122浏览 12评论
TPA6304-Q1: TPA6304 两片公用一组I2C的话,其中一片配置不成功怎么办
163浏览 10评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-22 11:42 , Processed in 1.144917 second(s), Total 80, Slave 70 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号