伺服轴回零后位置总差几个脉冲,换编码器也没用。本文按 dsPIC30F 参考手册拆解 QEI 的 x2/x4 倍频、MAXCNT 与索引复位、CNTERR 查错,以及数字滤波分频和 4 级捕捉 FIFO 的取舍。
一台包装机的伺服轴,回零后连续跑 200 个循环,累计位置总会差三五个脉冲,换了编码器和线束都没解决。结论先给:编码器本身没坏,问题出在 QEI 的配置上——倍频选错、索引复位的状态没锁住、数字滤波分频把高速边沿吃掉,这三件事任意一件出问题,计数都会慢慢偏。
本文按 Microchip《dsPIC30F 系列参考手册》(DS70060C_CN)第 13 章输入捕捉与第 16 章正交编码器接口(QEI)整理,寄存器定义、模式编码与实例数值均取自该手册。
增量式编码器输出三路信号:A 相、B 相和每转一次的索引脉冲。A 超前 B 记为正向,B 超前 A 记为反向,两路信号组合出四种状态,走完四种状态算一个正交周期。QEI 模块把这四路状态翻译成"加一"或"减一"的计数脉冲,再送到 16 位位置计数器 POSCNT,同时给出方向状态 UPDN。
模式由 QEICON 的 QEIM<2:0> 选择,这张表值得贴在工位上,配置错一位就是"能计数但不准":
| QEIM<2:0> | 含义 | 位置计数器复位方式 | 每转计数 |
|---|---|---|---|
| 111 | QEI 使能,x4 倍频 | 与 MAXCNT 匹配 | 4N |
| 110 | QEI 使能,x4 倍频 | 索引脉冲(POSRES=1) | 4N |
| 101 | QEI 使能,x2 倍频 | 与 MAXCNT 匹配 | 2N |
| 100 | QEI 使能,x2 倍频 | 索引脉冲(POSRES=1) | 2N |
| 001 | QEI 关闭,作 16 位定时器 | 与 MAXCNT 周期匹配 | — |
| 000/010/011 | 模块关闭或未使用 | — | — |
注意 x4 与 x2 的差别不在分辨率,而在计数时钟:x4 对 A、B 两相的上升沿和下降沿都计数;x2 只数 A 相的两个边沿,B 相仅用来判方向。同一只 4096 线编码器,x4 每转 16384 个计数,x2 只有 8192 个。
倍频选高的代价是计数率成倍上涨。手册给的上限很明确:正交频率最高为 FCY/3,FCY=30 MHz 时 A、B 两相最高 10 MHz。手册里的两个算例可以直接套:6000 RPM 配 4096 线编码器,计数率为 (6000/60)×(4096×4)=1.6384 MHz;10000 RPM 配 8192 线,则是 (10000/60)×(8192×4)=5.46 MHz,已经接近上限的一半。
| 工况 | x4 计数率 | x2 计数率 | 16 位计数器可覆盖圈数 |
|---|---|---|---|
| 4096 线,3000 RPM | (3000/60)×4096×4 = 819.2 kHz | 409.6 kHz | 65536÷16384 = 4 圈 |
| 8192 线,3000 RPM | 1.6384 MHz | 819.2 kHz | 65536÷32768 = 2 圈 |
第二列的数字说明一件事:16 位 POSCNT 在 x4 模式下只能撑几圈,超过就必须靠 MAXCNT 或者软件高位扩展。手册给出的取值规则是 MAXCNT = 4N−1(x4)或 2N−1(x2),N 为编码器每转线数;4096 线对应 0x3FFF,写 16384 就是典型错法,计数器会在 0 到 16383 之间少算一个点。
QEIM0=1 时用 MAXCNT 复位。正向旋转时 POSCNT 与 MAXCNT 相等,下一个递增沿把 POSCNT 清 0;反向旋转减到 0 时,下一个递减沿把 MAXCNT 装入 POSCNT,两个方向都会产生一次中断。这种模式适合行程有限的设备,比如丝杆工作台,用 0xFFFF 作 MAXCNT 就等价于"只借中断做高位扩展"。
QEIM0=0 时用索引脉冲复位,前提是 POSRES 位为 1:正向遇到索引脉冲清 0,反向遇到索引脉冲装入 MAXCNT。如果 POSRES=0,计数器不会因索引复位,只会在计满或下溢时翻转,但索引事件依然产生中断——很多"回零后位置差一截"的问题就出在这里,代码以为索引在复位,其实只拿到了一个中断。
索引脉冲的宽度各厂不一致:整周期或半周期的叫非门控,四分之一周期的叫门控。手册的处理办法是"锁存第一次":QEI 在第一个索引脉冲到来时记下当时所处的正交状态转换,之后正转反转都用同一个转换点复位,保证两个方向的零点重合。带 IMV<1:0> 的器件可以手动指定匹配状态,没有该位的器件自动选取。
索引复位模式下,QEI 还会做边界自检:向上计数时把 POSCNT 与 MAXCNT+1 比较,向下计数时与 0xFFFF 比较,命中就置位 CNTERR(QEICON<15>),并按 CEID(DFLTCON<8>,默认 0 使能)决定是否产生中断。手册的例子很直观:100 线编码器 x4 模式,计数器应走 0~399(0x018E),一旦出现 0xFFFF 或 0x0190,就说明中间丢了边沿或者线序接反。
CNTERR 一旦置位会一直保持,后续同类事件不再重复中断,必须由软件清零。所以它适合做成上电自检和回零校验:回零完成后清一次,跑一段再看有没有再置位,比事后量波形快得多。
QEA/QEB/INDX 输入都带可编程数字滤波器,规则是"连续三个滤波周期采到同一电平才允许输出变化"。滤波时钟由 FCY 分频得到,QECK<2:0> 与 INDCK<2:0> 提供 1:1 到 1:256 八档。分频越大抗干扰越好,但延时也越大:FCY=30 MHz 时,1:1 的一个滤波周期约 33 ns,三个周期 0.1 µs;1:256 的一个周期约 8.5 µs,三个周期就是 25.6 µs。
| QECK 分频 | 滤波时钟周期(FCY=30 MHz) | 三周期延时 | 适用场合 |
|---|---|---|---|
| 1:1 | 33 ns | 约 0.1 µs | 高速编码器,线缆短 |
| 1:4 | 133 ns | 约 0.4 µs | 机内走线,常规伺服 |
| 1:64 | 2.13 µs | 约 6.4 µs | 长线、变频器旁 |
| 1:256 | 8.53 µs | 约 25.6 µs | 低速轴、强干扰现场 |
选档的硬约束是:三个滤波周期的总延时要明显小于编码器最小半周期。819.2 kHz 的计数率对应半周期约 0.61 µs,这时只能停在 1:1 或 1:4,用 1:256 会把正常边沿一起滤掉,表现就是"低速正常、一提速就丢步"。另外 DFLTCON 的位定义在不同型号上有差异:dsPIC30F6010 把索引通道单独做成 INDOUT/INDCK,其他器件用 QEOUT/QECK 统一控制三路,移植代码时要按器件手册核对。
只有一路脉冲的场合——霍尔测速、流量计、单相编码器——用输入捕捉比占用 QEI 划算。ICM<2:0> 支持下降沿、上升沿、每 4 个上升沿、每 16 个上升沿、双边沿五种捕捉,另有 111 的"仅中断"模式。捕获值进入 4 级 FIFO,ICBNE 表示缓冲非空,ICOV 表示溢出:缓冲满 4 个后第 5 个事件到来时,ICOV 置位、第 5 个值被丢弃,而且之后的事件都不再改写缓冲,必须连续读 4 次才能恢复。
中断频率由 ICI<1:0> 控制,可选择每 1~4 次捕捉事件中断一次;双边沿模式例外,每个边沿都产生中断,且不置 ICOV。还有一个容易被忽略的时序细节:时基每个 TCY 加 1 时,捕捉到的值可能比真实边沿晚 1~2 个指令周期,把时基预分频后这个偏差就被消除。切换捕捉模式时预分频计数器不会清零,手册建议先把 ICM 写 000 关闭模块,再写新模式,否则第一次捕捉可能提前触发。
低功耗场景要特别注意:休眠时捕捉模块只能当外部中断用,必须配成 ICM=111,其他模式下的边沿不会唤醒器件。UART 自动波特率也借用捕捉通道,此时必须工作在双边沿模式,由 RX 引脚内部接入,外部捕捉引脚被断开。
/* dsPIC30F QEI 初始化:4096 线编码器,x4 倍频,MAXCNT 复位 */
#define ENC_LINES 4096
#define ENC_MAXCNT (4 * ENC_LINES - 1) /* 16383 = 0x3FFF,不是 16384 */
void QEI_Init(void)
{
QEICON = 0x0000; /* 先关模块,避免切换时误计数 */
DFLTCONbits.QEOUT = 1; /* 使能 QEA/QEB/INDX 数字滤波 */
DFLTCONbits.QECK = 2; /* 滤波时钟 1:4,三周期约 0.4 µs */
MAXCNT = ENC_MAXCNT;
POSCNT = 0; /* 按字写入,不要用字节访问 */
QEICONbits.POSRES = 0; /* MAXCNT 复位模式下该位无效 */
QEICONbits.QEISIDL = 0; /* 空闲模式继续计数 */
QEICONbits.QEIM = 7; /* x4 倍频,MAXCNT 匹配复位 */
IFS2bits.QEIIF = 0;
IEC2bits.QEIIE = 1; /* 计满/下溢中断 */
}
| 现象 | 常见根因 | 改法 |
|---|---|---|
| 回零后每圈都差固定几个计数 | MAXCNT 写成 4N 而不是 4N−1 | 按 4N−1 或 2N−1 重写周期值 |
| 正转反转的回零点不重合 | 索引复位状态未锁存,或 IMV 配错 | 检查 POSRES,按索引脉宽核对 IMV |
| 低速正常,一提速就丢步 | 滤波分频过大,吃掉真实边沿 | 把 QECK 降到 1:1 或 1:4 |
| 位置值偶尔跳一大截 | 字节方式读 POSCNT,高低字节不同步 | 统一按字读取,或读两次比对 |
| 回零动作做了,位置却没清 | 只开了索引中断,POSRES=0 | 置 POSRES=1,或改用 MAXCNT 复位 |
| 休眠后编码器事件唤不醒 | 捕捉模式不是 ICM=111 | 唤醒前切换为仅中断模式 |
一句话总结:QEI 的所有"计数不准",几乎都能归到三笔账上——倍频与计数率、复位方式与零点、滤波与边沿宽度。把 MAXCNT 写成 4N−1、把 POSRES 打开、把滤波延时压到半周期以下,编码器就不需要靠换件来解决丢步。
还想接着看:dsPIC30F2010 的 MCPWM 死区、FLTA 保护与 ADC 同步采样、dsPIC33FJ16MC102 电流环的 Q15 定点化与饱和回写、STM32 TIM1 与编码器接口的关节 FOC 配置。
本文基于 Microchip《dsPIC30F 系列参考手册》(DS70060C_CN)第 13 章、第 16 章技术资料整理优化。
沧州艾诺威电子 — 国家高新技术企业,20+项国家专利
嵌入式系统开发 · 物联网方案 · AI智能硬件 · 一站式交付
电话:13930711029 | 邮箱:tech@czinv.com | 24小时内响应