利用EQEP实现编码器的位置与转速测量

您所在的位置:网站首页 2500编码器 利用EQEP实现编码器的位置与转速测量

利用EQEP实现编码器的位置与转速测量

2024-02-13 04:24| 来源: 网络整理| 查看: 265

零 前言

研究了这么久的电机控制,DSP28335的EQEP模块实际上了解的并不是特别多,因为之前做实验都是用的师兄整的代码。所以这回我觉得好好研究一下这玩意,正好我手上现在有一种光电式的,还有一种磁编码器,一起整理一下。然后实现了一下相关的代码,完成了转速和位置的测量。

“生活可真是艰难呢”

一 光电编码器 1 E6C2CWZ6C型光电编码器

E6C2-CWZ6C输出引脚包含A、B、Z三相,以及5-24V电源与地,输出状态为NPN集电极开路输出,对应实物照片及输出回路如下:

当三极管导通时,集电极输出低电平;当三级管关断时,集电极输出悬空。因此,该编码器在工作时,需要外部添加上拉电阻,如下图所示。因此,这边我额外在在编码器输入信号线上增加了上拉电阻。

当然也可以采用光耦隔离的方式,如下图所示。这边我的另外一个控制板采用的是这种光耦隔离的方案,本文中暂不涉及。

此时,输出信号定义如下,注意动作图中的ON、OFF晶体管开通或关断状态:

光电编码器我见过的应用主要是在感应电机的控制过程中,只要三根线就够了。其他的常见编码器引脚信号还有:A、B、Z信号的反相信号,这个是为了消除共模噪声干扰的;U、V、W信号(120度相位差),这个用在BLDC控制上的,和霍尔位置传感器类似,可参考[1]这里不做详述;或者只有计数时钟和方向信号的,这个28335是有对应的控制方式的。

2 硬件连接

输入信号与地并联噪声滤除电容,然后经过两次反相器,一方面是增强信号能力,另外编码器供电采用5V,这个SN74LVC14供电是个3.3V,还起到电平转换的效果。后面直接连接入DSP接口即可。

二 磁传感编码器 1 MT6825磁编码器

目前常见的小型伺服永磁电机,经过拆解可以发现,其使用的主要是磁角位置编码器,使用的我这边看到使用的芯片型号为MagnTek的MT6825磁编码芯片,再配上一些差分芯片及控制芯片,其输出引脚包含了正反的A、B、Z以及U、V、W信号。按照我早年做机器人的经验,这种编码器在转动处没有直接的机械连接,因此在具有较强机械振动的应用场合,比滑动电阻式以及光电编码器更有优势。根据数据手册,磁铁与芯片之间的间隙最好不要超过3mm。下面的是示意图和实物照片。

下图给出了A与反向A信号的波形,以及A与B信号的波形。

2 硬件连接

由于采用差分的输出方式,所以通常需要经过滤波,然后接差分转单端芯片,比如IT的AM26C32,这个用了很多年了,以及后接反相器做电平转换(如上部分所述)。

三 基于28335 EQEP单元实现位置与转速测量 1 我的编码器到底有多少线以及位置的确定

位置计数与控制单元(Position Counter and Control Unit, PCCU)通过QEPCTL和QPOSCTL寄存器,来实现编码器的计数设置。其中的一个运行模式是,位置计数器可以在Index事件时清零(正转)或者置为设定最大值QPOSMAX(反转)。因为我记得我这个编码器大概有2500线,这样我就可以测试一下是不是这样。具体的寄存器定义,只要把[4]这个文档整明白了,问题不大。中文翻译可以看[5]。

设置代码,让他在Z信号时刻清零位置计数器

EQep1Regs.QEPCTL.bit.PCRM=00;

可以得到如下结果

果然,大概在10000的位置,位置计数器清零,所以我的编码器确实是2500线。另外在这个模式下,每一圈的z信号都会让他清零。

与此同时,采用这个模式还可以实现旋转位置的测量,只要将QPOSMAX设置为最大位置脉冲数减一即可,我这里是9999。这样,不管他怎么转,都是在0到9999这个范围里。

2 等时间长度采样法(也称M法)实现转速计算

计算公式如下

这种方法一般书里都描述对应于低速并不合适,也就是说如果编码器线数较低,他可能在一个采样周期转不过两根线。例如,考虑一个2500线的编码器,那么编码器转一周在28335内部经过四倍可以得到10000个脉冲,也就是一个脉冲间隔对应0.0001个圆周。这时候,如果用100Hz的等时间采样来计及编码器的计数,那么理论上最低速度是0.0001*100=0.01rps,即0.6rpm。我觉得这种分辨率对我来说已经足够了(200rpm左右),所以我就用这个方法就好了。

这边我再多描述一些,在eqep模块里,他有一个计数器模块,这个可以用来实现等时间的脉冲计数采样,也就是M法。另外,他还有一个捕捉模块,这个模块可以用来实现几个固定脉冲位置之间的时间采集,也就是T法。这里只用定时实现计数就完了。

28335的EQEP里面配有一个Unit Timer Base,他是一个SYSCLKOUT驱动的32bit计时器,并且还带有中断功能。当timer的计数器QUTMR等于设置的周期值QUPRD时,单位时间中断出现(QFLG[UTO]置位)。与此同时,设置周期值QUPRD恰好为单周总脉冲-1,并设计z信号清除QPOSCNT,即可实现每周清除一次位置计数器,并且位置计数器正好对应编码器的空间绝对位置。

3 利用首次z信号中断实现编码器绝对位置计算

这边我想实现一个从一开始编码器实际旋转,就确定的绝对位置功能。可是,在实际运行时,可能出现这样的现象,编码器开始运动时,经过不到半圈就遇到了0信号,此时对应的QPOSCNT清零。这就会出现一个问题,即编码器z信号定义的空间位置和我们以编码器起始转动的0位置不对应。当然,可以将编码器先转到z信号位置,然后再开始运转,但这种起始很明显不符合我们需要的逻辑,并且实现起来并不容易。

为了将这个问题剖析的更清楚,我试着绘制了如下正反转流程图,如果有人发现我哪里理解错了,务必告知,谢谢。

在正转启动的过程中,可以看到POSCNT从0开始累加,当达到某点(这里认为8000)的时候,z信号使得计数器清零,也就是说它实际上没有达到最大线数(这里是9999)。但是在后面的计数过程中,每次都能达到满值。这里将第一次遇到z信号前后的时刻描述为图中“采集POSCNT”,与之对应的“希望Theta”是我实际想要得到的计数。这里整了一个中间变量ThetaShift,在第一次z信号中断生成,并记录了z信号时刻的计数器值,只要在后面将希望Theta赋值为ThetaShift+POSCNT+1就行了。

反转这边我其实有一点迷的,如下图所示,刚开始POSCNT是0,但是在反转的下一线,立刻反向溢出变为最大值(也就是9999),并逐渐递减,直到z信号到达(这里假定减少到了8000),同样为了使得希望Theta能够继续降低,这边同样定义一个与正转一样的ThetaShift,并且连赋值都跟正转一样。但是,神奇的是,Thtea的幅值少了一个加一,为ThetaShift+POSCNT。

这种不和谐的确令人难受,所以我在实际写程序的时候,无论正反转,我都让他不加一,反正就1线的误差。当然好像可以根据正反转区分对待,但是在实验中还不如我统一的效果,所以这里就这样了。如果有人能帮我指出错我,那么谢谢了。

下面这个实验波形,一个通道是位置,一个通道是瞬时转速,是我用手转的。

最后测试一个大约500rpm旋转得到的电机正反转波形,如下图所示。看上去还不错。

4 代码

Eqep寄存器配置部分

EQep1Regs.QUPRD=QEP_QUPRD; // 中断周期 Unit Timer at 150 MHz SYSCLKOUT EQep1Regs.QDECCTL.bit.QSRC=00; // 正交计数模式 QEP quadrature count mode EQep1Regs.QEPCTL.bit.FREE_SOFT=2; // 仿真挂起时位置计数器继续运行 Unaffected by emulation suspend EQep1Regs.QEPCTL.bit.PCRM=00; // 在z信号index到达时,位置计数器复位 Position Counter Reset on Unit Time out Event EQep1Regs.QEPCTL.bit.UTE=1; // 使能单位定时器 Enable unit timer EQep1Regs.QEPCTL.bit.QCLM=1; // 当单位时间事件发生时,锁存数据 // Latch on unit time out. Position counter, capture timer and capture period values are latched // into QPOSLAT, QCTMRLAT and QCPRDLAT registers on unit time out. EQep1Regs.QPOSMAX=0x270F; // 最大脉冲数减一 EQep1Regs.QEPCTL.bit.QPEN=1; // QEP enable EQep1Regs.QDECCTL.bit.SWAP=0; // 正交时钟交换禁止 改变输入信号的方向0-正常,1-反方向 // Quadrature-clock inputs are not swapped //中断配置步骤-----1 中断使能寄存器 EQep1Regs.QEINT.bit.UTO=1; // 单位时间事件中断使能 Unit time out interrupt enable EQep1Regs.QEINT.bit.IEL=1; // 索引时间锁存中断使能 //中断配置步骤-----2 重映射中断服务函数 // Interrupts that are used in this example are re-mapped to // ISR functions found within this file. EALLOW; PieVectTable.EQEP1_INT = &eqep1int_isr; //EQEP1 EDIS; //中断配置步骤-----3 连接CPU中断Y IER |= M_INT5; //中断配置步骤-----4 连接Y中断里的第几位 PieCtrlRegs.PIEIER5.bit.INTx1 = 1; // Enable INT5.1 EQEP 优先级9.1

中断函数部分,这里说明一下,因为它这个所有EQEP的中断都会进到一个中断函数里,所以我这边用了两种中断,函数内需要判断一下。

// 认为启动时遇到第一个z信号之前保持运动方向不变 if (EQep1Regs.QFLG.bit.IEL==1 && qep1.ThetaSyncFlag==0) // 索引时间锁存中断标志 { // 更新方向 qep1.MechDirection = EQep1Regs.QEPSTS.bit.QDLF; // 因此利用一次z信号索引中断,获得角度偏差 qep1.MechThetaShift = EQep1Regs.QPOSLAT * QEP_DEG_PER_PULSE; // 标志角度差建立,防止再次进入 qep1.ThetaSyncFlag = 1; EQep1Regs.QCLR.bit.IEL = 1; // Clear interrupt flag EQep1Regs.QCLR.bit.INT=1; //clear both UTO and INT EALLOW; EQep1Regs.QEINT.bit.IEL = 0; // 索引时间锁存中断关闭 EDIS; } if (EQep1Regs.QFLG.bit.UTO==1) // 单位时间锁存中断标志 { qep1.TimeCounter++; qep1.MechDirection = EQep1Regs.QEPSTS.bit.QDF; // 更新方向 qep1.PosCounter = EQep1Regs.QPOSLAT; // 更新脉冲个数 // 更新角度位置 qep1.MechTheta = qep1.MechThetaShift +QEP_DEG_PER_PULSE +qep1.PosCounter*QEP_DEG_PER_PULSE; // 更新角度 if (qep1.MechDirection==1) { // 正转 if (qep1.MechTheta>360.0) qep1.MechTheta = qep1.MechTheta - 360.0; if (qep1.MechTheta= qep1.MechThetaPre) qep1.MechSpeed = (qep1.MechTheta-qep1.MechThetaPre) / QEP_SAMPLE_TIME / 6.0; } else { // 反转 if (qep1.MechTheta360.0) qep1.MechTheta = qep1.MechTheta - 360.0; // 如果正转情况下当前角度小于上一回合角度,说明正转溢出回零或周期内运动方向变化,这一步的转速不更新 if (qep1.MechTheta


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3