eQEP增强型正交编码脉冲
一、简介、原理及构成
1.正交编码器
编码器通常用于测量电机位置、转速等信息,可分为绝对式和增量式,绝对式每一个角度对应一个二进制数,而相对式通常产生两路相隔90度的脉冲(编码器通常两路脉冲检测相隔90度放置),以常见的光电编码器为例:

旋转时输出的两路信号QEPA、QEPB,两路信号相隔周期的1/4即90度,此外,每旋转一周会输出QEPI为索引信号,判断电机绝对位置。
3.eQEP简介
eQEP模块通常用于对电机编码器测量转速、转向和位置信息。28335有两个结构一样的eQEP模块,其基本构成如下图:
eQEP模块的输入有4个引脚:EQEPxA/XCLK、EQEPxB/XDIR(用于输出脉冲信号)、EQEPxI(用于输出索引信号复位eQEP计数器)和EQEPxS(用于锁存eQEP计数器值)

由上图,eQEP由以下几部分构成:
(1)正交解码单元(QDU) ,可以获得电机的转向信息;
(2)位置计数器及控制单元(PCCU) ,可以获得电机转子的位置信息;
(3)边沿捕获单元(QCAP) ,用于测量若干个脉冲之间的时间;
(4)定时器基准单元(UTIME) ,用于测量一定时间内的脉冲个数;
(5)看门狗电路(QWDOG)
下面进行详细介绍
二、工作原理
1.正交解码单元(QDU)
正交解码单元主要的功能是对输入的EQEPA、EQEPB、EQEPI和EQEPS进行预处理,提供给后续模块所需要的信号。比如将QEPA和QEPB进行解码,得到脉冲信号QCLK 和方向信号QDIR。
举例:

为了提高编码器的计数精度,EQEPA和EQEPB的每个上升沿和下降沿经过eQEP正交解码单元解码后,都会生成计数脉冲,因此eQEP逻辑产生的计数脉冲频率是每个输入脉冲频率的4倍
若编码器为1024线,即每个引脚输出1024个脉冲信号,则码盘每旋转一圈共输出1024*4=4096个脉冲,即编码器的精度为1/4096
当EQEPA信号超前EQEPB信号90°时,计数方向为增多,QDIR=1,此时电机转子正转,即顺时针旋转;当EQEPB信号超前EQEPA信号90°时,计数方向为减少,QDIR=0,此时电机转子反转,即逆时针旋转。
可以通过读取eQEP状态寄存器 QEPSTS[QDF] 来判断电机的转向。
2.位置计数器及控制单元(PCCU)
通过两个寄存器QEPCTL与QPOCTL来配置位置计数器的运行模式、初始化/锁存模式以及位置比较同步信号的产生。
(1)输入模式
输入模式分为:正交计数模式、方向计数模式、增计数模式、减计数模式
(A)正交计数模式:
最普遍的编码器输入模式
计数方向判断:当EQEPA超前EQEPB相位90°时,QDIR=1,位置计数器增计数;当EQEPB超前EQEPA相位90°时,QDIR=0,位置计数器减计数。
举例:
如果第一个脉冲检测到的是EQEPA的上升沿,第二个脉冲检测到的是EQEPB的上升沿,则QDIR=1,位置计数器增计数。如果第一个脉冲检测到的是EQEPA的上升沿,而第二个脉冲检测到的是EQEPB的下降沿,则QDIR=0。状态机过程如下图:
(B)方向计数模式
有的编码器可以直接提供方向信号和计数时钟
引脚EQEPA/XCLK直接为位置计数器提供计数脉冲,引脚EQEPB/XDIR为位置计数器提供计数方向。
当EQEPB/XDIR为高电平时,位置计数器在每个计数时钟的上升沿增计数;当EQEPB/XDIR为低电平时,位置计数器在每个计数时钟的上升沿减计数。
(C)增计数模式
位置计数器的方向直接被硬件设定为增计数模式,位置计数器用来测量EQEPA输入的信号频率。将QDECCTL[XCR]置位将使能EQEPA输入的两个边沿都产生计数脉冲,从而将检测精度提高一倍。
(D)减计数模式
位置计数器的方向直接被硬件设定为减计数模式,其余与增计数模式一致
(2)运行模式
该部分用于配置位置寄存器的复位功能,由(QEPCTL[PCRM]控制)4种运行模式能使得编码器的测量方式更加多元,在
位置计数器可配置成以下4种运行模式:
(1)位置计数器在索引脉冲到来时发生复位;
(2)位置计数器在计数到最大计数值时复位;
(3)位置计数器仅在第一个索引脉冲到来时复位;
(4)位置计数器在单位时间输出事件时复位(频率测量)。
不管哪种运行模式,计数器在增加到QPOSMAX时,如果下一个计数脉冲到来,将复位到0;计数器在减计数到0时,如果下个计数脉冲到来,将复位到QPOSMAX。
(A)位置计数器在索引脉冲到来时发生复位(QEPCTL[PCRM]=00)
正向运行时,如果出现索引脉冲信号,位置计数器在下一个eQEP时钟到来时被复位到0;反向运行时,如果出现索引脉冲信号,位置计数器在下一个eQEP时钟到来时被复位为QPOSMAX 寄存器中的值。
将第一个索引脉冲边沿到来后的正交信号的边沿定义为索引标志时刻,eQEP模块记录第一个索引标志的发生(QEPSTS[FIMF])以及第一个索引事件发生时的方向 (QEPSTS[FIDF]),还记录第一个索引标志对应的正交信号边沿 ,从而使用这个相同的正交边沿完成复位操作。
例如,如果第一次复位操作发生在正向运行过程中的EQEPB的下降沿,那么以后所有正向运行的复位操作都将发生在EQEPB的下降沿,而反向运行的复位操作发生在EQEPB的上升沿。
在每个索引事件发生时,位置计数器的值被锁存到QPOSILAT寄存器中,运行方向也被记录到**QEPSTS[QDLF]**位中。
(B)位置计数器在计数到最大值时复位(QEPCTL[PCRM]=01)
正向运行时,如果位置计数器的值到达QPOSMAX寄存器中的值,那么在下一个eQEP时钟信号到来时将位置计数器复位为0,并且将位置计数器上溢标志位置位。
反向运行时,如果位置计数器的值到达0,那么在下一个eQEP时钟信号到来时将位置计数器复位到QPOSMAX,并且将位置计数器下溢标志位置位。
(C)位置计数器仅在第一个索引脉冲到来时复位(QEPCTL[PCRM]=10)
正向运行时,如果出现索引脉冲信号,那么位置计数器在下一个eQEP时钟到来时被复位到0;反向运行时,如果出现索引脉冲信号,那么位置计数器在下一个eQEP时钟到来时被复位为QPOSMAX寄存器中值。
需要注意的是,以上复位操作只发生在第一次索引事件到来时,接下来的索引事件不能将位置计数器复位。位置计数器以后的复位操作与第2种情况描述的相同。
(D)位置计数器在单位时间输出事件时复位(频率测量)(QEPCTL[PCRM]=11)
在该模式下,当一次单位时间事件发生时,QPOSCNT的值被锁存到QPOSLAT寄存器中,并且QPOSCNT被复位到0或QPOSMAX(这由QDECCTL[QSRC]方向控制位决定)。该模式可用于频率的测量。
(3)锁存
用于储存某时刻计数器的值及运行方向
eQEP模块的索引输入EQEPI及提示输入EQEPS可以将位置计数器的值分别锁存到QPOSILAT 和 QPOSSLAT寄存器中,分以下两类:
(A)索引事件锁存
在许多应用中,却不需要在每个索引事件发生时将位置计数器的值复位,相反,要使位置计数器运行在32位模式下(QEPCTL[PCRM]=01或10)。在这种情况下,可在每个索引事件发生时将位置计数器的值以及方向进行锁存,具有如下3种选择:
(a)上升沿锁存(QEPCTL[IEL]=01)。位置计数器的当前值(QPOSCNT)在每次索引信号的上升沿被锁存到QPOSILAT寄存器中。
(b)下降沿锁存(QEPCTL[IEL]=10)。位置计数器的当前值(QPOSCNT)在每次索引信号的下降沿被锁存到QPOSILAT寄存器中。
( c)索引事件标志时刻锁存(QEPCTL[IEL]=11)。索引事件的标志时刻定义为索引脉冲第一个边沿后的正交信号的边沿,在这个边沿到来时将位置计数器的当前值
举例:
在两次索引事件中,分别将QPOSCNT的值锁存进QPOSILAT寄存器中

(B)提示事件锁存
当QEPCTL[SEL]=0时,位置计数器的值在提示信号的上升沿被锁存到QPOSSLAT寄存器中;当QEPCTL[SEL]=1时,正向运行时将在提示信号的上升沿锁存数据,反向运行时将在提示信号的下降沿锁存数据,锁存事件中断标志位QFLG[SEL]被置位
(4)初始化
(A)使用索引事件初始化(IEI)。
在索引脉冲的上升沿或下降沿可对位置计数器进行初始化:
a.如果QEPCTL[IEI]=2,那么索引脉冲的上升沿将QPOSINIT 寄存器中的值装载到位置计数器QPOSCNT 中;
b.如果 QEPCTL[IEI]=3,那么索引脉冲的下降沿将QPOSINIT寄存器中的值装载到位置计数器QPOSCNT中。
(B)使用提示事件初始化(SEI)。
如果QEPCTL[SEI]=2,那么在提示脉冲的上升沿将QPOSINIT寄存器中的值装载到位置计数器 QPOSCNT中;
如果 QEPCTL[SEI]=3,则正向运行时将在上升沿完成装载过程,反向运行时将在下降沿完成装载过程。
©软件初始化(SWI)。
通过向QEPCTL[SWI]中写1对位置计数器发起一次软件初始化过程。
QEPCTL[SWI]位并不会自动清零,但当再次向其写1时会发起另一次初始化过程
(5)位置比较单元
eQEP模块拥有一个位置比较单元。当位置比较寄存器QPOSCMP和位置寄存器QPOSCNT
匹配时,会产生同步输出信号和中断信号
其结构如下图:

位置比较寄存器QPOSCMP具有映射寄存器,可通过QPOSCTL[PSSHDW]位来控制是否使用映射功能。在映射模式下,可通过QPOSCTL[PCLOAD]位控制何时将映射寄存器中的内容装载到当前寄存器中,装载完成后会产生相应的中断(QFLG[PCR])。
位置比较寄存器可以在以下两个事件发生时完成装载:
· 当QPOSCNT=QPOSCMP时;
· 当QPOSCNT=0时。
当QPOSCNT=QPOSCMP时会产生一次比较匹配事件,将QFLG[PCM]置位,并输出脉冲宽度可调的同步脉冲以触发外部器件。
例如,如果QPOSCMP=2,那么增计数时匹配事件将发生在1到2的跳变过程中,减计数时匹配事件将发生在3到2的跳变过程中,如下图:

3.边沿捕获单元(QCAP)
其结构如下图:

(1)M法(测频法)
(A)原理
测量一段时间内的脉冲个数,适用于电机高速测量

其中,x(k)是当前读取的脉冲数,x(k-1)是先前一刻的脉冲数,x(k)-x(k-1)是时间T内测量到的脉冲个数。
上式中,假设固定时间窗为 T T T秒,编码器为 N N N线,即一圈最多检测脉冲数为 4 N 4N 4N,则每个脉冲用时: T / △ ( X ) T/\triangle(X) T/△(X),电机旋转一圈用时则为:
t = T △ ( X ) ∗ 4 N t=\frac{T}{\triangle(X)}*4N t=△(X)T∗4N
即电机的转速为(具体还要考虑传动比): v = 1 t = △ ( X ) T ∗ 4 N ( r a d / s ) = △ ( X ) ∗ 60 T ∗ 4 N ( r a d / m i n ) v=\frac{1}{t}=\frac{\triangle(X)}{T*4N}(rad/s)=\frac{\triangle(X)*60}{T*4N}(rad/min) v=t1=T∗4N△(X)(rad/s)=T∗4N△(X)∗60(rad/min)
上式中, △ ( X ) \triangle(X) △(X)为时间间隔 T T T内的脉冲个数, N N N为编码器线数
(B)实现
定时的实现:
eQEP中有一个定时器基准单元UTIME,它由一个32位的定时器 QUTMR和一个32位的周期寄存器 QUPRD组成。QUTMR的时钟是SYSCLKOUT,在这里就是150MHz,因此将QUPRD的值设置为1500000就可以,当QUTMR计数的值等于QUPRD时,就会产生定时器基准单元超时事件,位置计数器寄存器QPOSCNT的值就会被锁存到位置计数器锁存寄存器QPOSLAT中,此时eQEP中断标志寄存器QFLAG的UTO位被置位。
△ ( X ) \triangle(X) △(X)计数的实现:
假设电机正转,则可能存在的情况如图

左图是在读取位置锁存寄存器的时候,索引脉冲还没有到来,因此: △ X = X 2 − X 1 △X=X2-X1 △X=X2−X1。
右图是在读取位置寄存器的时候,已经有索引脉冲复位了QPOSCNT,则 △ X = ( Q P O S M A X − X 1 ) + X 2 △X=(QPOSMAX-X1)+X2 △X=(QPOSMAX−X1)+X2
可以通过读取eQEP中断标志寄存器QFLG的标志位IEL来判断索引脉冲是否已经到来。
(1)T法(测周法)
测量固定脉冲数所用的时间,适用于电机低速测量

其中,t(k)是当前定时器的读数,t(k-1)是先前一刻定时器的读数,t(k)-t(k-1)是测量X个脉冲所花的时间。
测周法就是先设定好需要检测的脉冲数量N,然后通过捕获单元捕获这些脉冲,到达数量N后,读取捕获定时器的时间,从而计算电机的转速。
可以通过设置捕获控制寄存器QCAPCTL的UPPS 位来确定需要检测的脉冲数量N:
N = 2 U P P S N=2^{UPPS} N=2UPPS
可以通过设置捕获控制寄存器QCAPCTL的CPPS位来确定捕获定时器QCTMR的时钟频率:
f C A P = S Y S C L K O U T 2 U P P S f_{CAP}=\frac{SYSCLKOUT}{2^{UPPS}} fCAP=2UPPSSYSCLKOUT
当捕获到的脉冲数量为N时,会产生UPEVENT事件,每次UPEVENT触发脉冲都会将捕获定时器QCTMR中的值锁存到捕获周期寄存器QCPRD中,然后捕获定时器复位。
需要注意,QCTMR、QCTMRLAT、QCPRD、QCPRDLAT寄存器均是16位的。
此时,QEPSTS[UPEVENT]置位,表示QCPRD中已经锁存了一个新值,CPU可以读取这个值。在软件读取捕获周期寄存器QCPRD的值之前可以先检查此位,然后向此位写1便可以将其清零。
如果QEPCTL[QCLM]=0,那么在CPU读取QPOSCNT寄存器时,捕获定时器及捕获周期寄存器的值会被分别锁存到QCTMRLAT和QCPRDLAT中。如果 QEPCTL[QCLM]=1,那么在定时器基准单元超时事件发生时将位置计数器、捕获定时器、捕获周期寄存器的值分别锁存到QPOSLAT、QCTMRLAT、QCPRDLAT。
电机转速计算为:
4.中断
QEP 一共可以产生11个中断事件,分别是PCE、PHE、QDC、WTO、PCU、PCO、PCR、PCM、SEL、IEL、UTO。这些中断可以通过中断控制寄存器QEINT来设置使能或者禁止。如果每个中断都使能,那么中断源会产生中断脉冲送给PIE模块,进而送给CPU。这些中断标志可以通过中断清除寄存器QCLR来清除
三、寄存器汇总
(1)QEP解码控制寄存器(QDECCTL)


(2)QEP控制寄存器(QEPCTL)



(3)QEP位置比较控制寄存器(QPOSCTL)

(4)QEP捕获控制寄存器(QCAPCTL)
















四、配置步骤
(1)使能eQEP1外设时钟
c
EALLOW;
SysCtrlRegs.PCLKCR1.bit.EQEP1ENCLK=1; //eQEP1
EDIS;
(2)初始化GPIO为eQEP1功能,即选择GPIO复用功能
该部分可直接调用TI封装好文件名:DSP2833x_EQep.c的函数:
c
InitEQep1Gpio();
eQEP1外设相关参数设置,QEP计数模式、自由运行、QEP位置计数器在索引事件复位,单位事件使能、QEP模块使能等
(3)设定计数单位时间,定时周期设定
c
/* 根据CPU时钟频率配置单位定时器周期,以产生100Hz的基准频率 */
#if(CPU_FRQ_150MHZ)
/* 在150MHz系统时钟下,设置单位定时器周期为1500000,得到100Hz */
EQep1Regs.QUPRD = 1500000; // Unit Timer for 100Hz at 150MHz SYSCLKOUT
#endif
#if(CPU_FRQ_100MHZ)
/* 在100MHz系统时钟下,设置单位定时器周期为1000000,得到100Hz=10ms=0.01S */
EQep1Regs.QUPRD = 1000000; // Unit Timer for 100Hz at 100MHz SYSCLKOUT
#endif
(4) 配置QEP解码控制寄存器
c
EQep1Regs.QDECCTL.bit.QSRC = 0; //正交计数模式
EQep1Regs.QDECCTL.bit.XCR = 0; // 上下边沿计数
//(3)配置QEP控制寄存器
EQep1Regs.QEPCTL.bit.FREE_SOFT = 2; // 仿真时自由运行
EQep1Regs.QEPCTL.bit.PCRM = 3; // 单位事件时复位计数器
EQep1Regs.QEPCTL.bit.UTE = 1; // 使能单位定时器
EQep1Regs.QEPCTL.bit.QCLM = 1; // 单位定时器超时时锁存位置计数器
EQep1Regs.QPOSMAX = 0xFFFFFFFF; // 设置位置计数器的最大值
EQep1Regs.QEPCTL.bit.QPEN = 1; // 计数器使能使能
(5) 根据CPU频率配置捕获单元的分频系数
c
#if(CPU_FRQ_150MHZ)
/* 150MHz时,单位位置分频为1/4 */
EQep1Regs.QCAPCTL.bit.UPPS = 2; // 1/4 for unit position at 150MHz SYSCLKOUT
#endif
#if(CPU_FRQ_100MHZ)
/* 100MHz时,单位位置分频为1/8 */
EQep1Regs.QCAPCTL.bit.UPPS = 3; // 1/8 for unit position at 100MHz SYSCLKOUT
#endif
(6) 配置捕获控制寄存器
c
EQep1Regs.QCAPCTL.bit.CCPS = 7; // 捕获时钟分频为1/128
EQep1Regs.QCAPCTL.bit.CEN = 1; // 使能QEP捕获功能
EQep1Regs.QPOSMAX=937; //设定最大计数量即4倍线数(4N)
五、实验
实验要求:用eQEP模块实现直流电机M法测速
(1)硬件:将EQEP1A和EQEP1B对应28335的GPIO50和GPIO51连接到编码器的两根信号线上
(2)软件
eQEP的输入模式 和运行模式 分别配置为**正交计数模式和单位时间输出事件时复位,即正转计数器增,定时复位为0,反转计数器减少,定时复位为QPOSMAX。可以通过检测QEPSTS寄存器的QDF位判断时正转还是反转,然后进行相应的测速方式。
eQEP初始化函数、脉冲捕获函数、编码器M法测速函数:
c
#include "eQEP.h"
// 全局变量声明
volatile long g_lLastPulseCount = 0; // 上一次脉冲计数
volatile long g_lCurrentPulseCount = 0; // 当前脉冲计数
volatile float g_fRPM = 0.0; // 计算的转速值
volatile int DIR=0;
void eQEP_Init(void)
{
//1.使能eQEP1外设时钟
EALLOW;
SysCtrlRegs.PCLKCR1.bit.EQEP1ENCLK=1; //eQEP1
EDIS;
//2.初始化GPIO为eQEP1功能,即选择GPIO复用功能
InitEQep1Gpio();
//3.eQEP1外设相关参数设置
//QEP计数模式、自由运行、QEP位置计数器在索引事件复位
//单位事件使能、QEP模块使能等
//(1)设定计数单位时间,定时周期设定
/* 根据CPU时钟频率配置单位定时器周期,以产生100Hz的基准频率 */
#if(CPU_FRQ_150MHZ)
/* 在150MHz系统时钟下,设置单位定时器周期为1500000,得到100Hz */
EQep1Regs.QUPRD = 1500000; // Unit Timer for 100Hz at 150MHz SYSCLKOUT
#endif
#if(CPU_FRQ_100MHZ)
/* 在100MHz系统时钟下,设置单位定时器周期为1000000,得到100Hz=10ms=0.01S */
EQep1Regs.QUPRD = 1000000; // Unit Timer for 100Hz at 100MHz SYSCLKOUT
#endif
//(2) 配置QEP解码控制寄存器
EQep1Regs.QDECCTL.bit.QSRC = 0; //正交计数模式
EQep1Regs.QDECCTL.bit.XCR = 0; // 上下边沿计数
//(3)配置QEP控制寄存器
EQep1Regs.QEPCTL.bit.FREE_SOFT = 2; // 仿真时自由运行
EQep1Regs.QEPCTL.bit.PCRM = 3; // 单位事件时复位计数器
EQep1Regs.QEPCTL.bit.UTE = 1; // 使能单位定时器
EQep1Regs.QEPCTL.bit.QCLM = 1; // 单位定时器超时时锁存位置计数器
EQep1Regs.QPOSMAX = 0xFFFFFFFF; // 设置位置计数器的最大值
EQep1Regs.QEPCTL.bit.QPEN = 1; // 计数器使能使能
//(4) 根据CPU频率配置捕获单元的分频系数
#if(CPU_FRQ_150MHZ)
/* 150MHz时,单位位置分频为1/4 */
EQep1Regs.QCAPCTL.bit.UPPS = 2; // 1/4 for unit position at 150MHz SYSCLKOUT
#endif
#if(CPU_FRQ_100MHZ)
/* 100MHz时,单位位置分频为1/8 */
EQep1Regs.QCAPCTL.bit.UPPS = 3; // 1/8 for unit position at 100MHz SYSCLKOUT
#endif
//(5) 配置捕获控制寄存器
EQep1Regs.QCAPCTL.bit.CCPS = 7; // 捕获时钟分频为1/128
EQep1Regs.QCAPCTL.bit.CEN = 1; // 使能QEP捕获功能
EQep1Regs.QPOSMAX=937; //设定最大计数量即4倍线数(4N)
}
//计数器返回函数
long eQEP_GetPulseCount(void)
{
return EQep1Regs.QPOSLAT; // 读取锁存的位置计数器值
}
//M法 测速函数(其中g_lLastPulseCount 、 g_lCurrentPulseCount没用到,可进一步改进为T法)
Uint16 Get_SPeed(void)
{
Uint16 lPulseCount = 0;
// 1. 获取当前脉冲计数
lPulseCount = eQEP_GetPulseCount();
// 2. 计算单位时间内的脉冲变化量
// 注意:由于单位定时器超时后会自动复位计数器,QPOSLAT就是采样周期内的脉冲数
g_lCurrentPulseCount = lPulseCount;
// 3. 计算转速(M法)
// 公式:RPM = (脉冲数 / 采样时间) * 60 / 编码器线数
if(EQep1Regs.QEPSTS.bit.QDF==0)//反向速度
{
g_fRPM = ((EQep1Regs.QPOSMAX-lPulseCount) * 60) / (0.01*4*11*21.3);
}
else//正向速度
{
g_fRPM = (lPulseCount * 60) / (0.01*4*11*21.3);
}
// 4. 更新上次脉冲计数
g_lLastPulseCount = g_lCurrentPulseCount;
return g_fRPM;
}
主函数:
c
#include "DSP2833x_Device.h" // DSP2833x Headerfile Include File
#include "DSP2833x_Examples.h" // DSP2833x Examples Include File
#include "Key.h"
#include "led.h"
#include "Interrupt.h"
#include "SMG.h"
#include "eQEP.h"
void main()
{
InitSysCtrl();
InitPieCtrl();
IER=0x0000;
IFR=0x0000;
InitPieVectTable();
Led_Init();
SMG_Init();
eQEP_Init();
while(1)
{
SMG_DisplayInt(Get_SPeed());
}
}