1. 项目概述与QEI核心价值
在嵌入式运动控制领域,无论是驱动一个精密的伺服电机,还是为一个移动机器人提供里程计反馈,获取精确、实时的旋转位置和速度信息都是系统闭环控制的基础。过去,我们可能需要依赖软件中断来捕获编码器脉冲,这不仅消耗宝贵的CPU周期,在高转速下还极易丢失脉冲,导致位置累积误差。而像Tiva™ TM4C123GH6ZRB这类微控制器内置的正交编码器接口(QEI)模块,正是为了解决这一痛点而生的硬件外设。
简单来说,QEI模块就是一个专为旋转编码器设计的“硬件协处理器”。它接管了A、B两相正交脉冲的解码、方向判断、位置计数和速度计算等所有繁琐且实时性要求高的任务。你只需要在初始化时配置好寄存器,它就能在后台默默工作,你随时可以读取一个32位的位置值和一个计算好的速度值,CPU得以解放出来处理更高级的控制算法。这对于实现高性能的PID控制、轨迹规划至关重要。本文将以TM4C123GH6ZRB的QEI模块为例,抛开库函数,深入到寄存器层面,手把手带你理解每一个配置位的含义,并构建出稳定可靠的编码器数据采集框架。无论你是正在调试一台3D打印机,还是设计一个自主导航小车,这里的细节都至关重要。
2. QEI模块工作原理与寄存器全景
在深入每个寄存器之前,我们必须先理解QEI模块是如何“思考”的。它接收来自增量式编码器的两路信号:Phase A (PhA) 和 Phase B (PhB)。这两路信号在电机旋转时产生相位差90度的方波(即“正交”)。模块的核心逻辑就是解码这两路信号的边沿和相位关系。
2.1 两种核心工作模式
模块通过QEICTL寄存器的SIGMODE位支持两种解码模式:
- 正交相位模式(SIGMODE = 0):这是最常用的模式。模块内部对PhA和PhB的上升沿和下降沿都进行检测。在一个完整的四步循环(A↑, B↑, A↓, B↓)中,位置计数器会变化4次。因此,其分辨率是编码器物理线数的4倍,这就是所谓的“4倍频”解码。同时,通过比较A、B信号的相对相位,硬件自动判断旋转方向(
DIRECTION位)。 - 时钟/方向模式(SIGMODE = 1):在此模式下,PhA被当作时钟脉冲(CLK),PhB被当作方向信号(DIR)。PhA的每个有效边沿(可配置)会使位置计数器递增或递减,具体方向由PhB的电平决定。这种模式分辨率较低(通常为1倍频),但兼容一些输出为“脉冲+方向”格式的驱动器或传感器。
2.2 位置管理与速度计算
位置信息存储在32位的QEIPOS寄存器中,它会根据解码结果实时更新。你可以随时读取它,也可以直接写入一个值来预设初始位置,这在寻找机械零点时非常有用。
速度计算是另一个亮点。模块内部有一个可编程的定时器(通过QEILOAD设置周期)和一个脉冲计数器(QEICOUNT)。在每个定时周期内,模块会计数通过的编码器脉冲(或边沿)数量。周期结束时,这个计数值被捕获并更新到QEISPEED寄存器中,同时产生中断(如果使能)。这样,你得到的是一个“上一个测量周期内的平均速度”,避免了软件频繁采样和计算的负担。
2.3 寄存器映射总览
TM4C123GH6ZRB提供了两个独立的QEI模块(QEI0和QEI1),它们具有完全相同的寄存器结构,只是基地址不同(QEI0: 0x4002.C000, QEI1: 0x4002.D000)。以下是所有寄存器的快速索引,我们将逐一拆解:
| 偏移量 | 名称 | 类型 | 复位值 | 核心功能简述 |
|---|---|---|---|---|
| 0x000 | QEICTL | R/W | 0x0000.0000 | 控制寄存器,配置工作模式、使能、滤波器等。 |
| 0x004 | QEISTAT | RO | 0x0000.0000 | 状态寄存器,只读,反映当前方向和有否错误。 |
| 0x008 | QEIPOS | R/W | 0x0000.0000 | 位置寄存器,可读可写,32位位置计数器。 |
| 0x00C | QEIMAXPOS | R/W | 0x0000.0000 | 最大位置值,用于设置位置计数器的模(循环范围)。 |
| 0x010 | QEILOAD | R/W | 0x0000.0000 | 定时器装载值,设置速度测量的采样周期。 |
| 0x014 | QEITIME | RO | 0x0000.0000 | 定时器当前值,只读,用于调试。 |
| 0x018 | QEICOUNT | RO | 0x0000.0000 | 速度脉冲计数器,当前周期内的实时脉冲数(不稳定,慎读)。 |
| 0x01C | QEISPEED | RO | 0x0000.0000 | 速度值,上一个完整周期内捕获的脉冲数,是稳定的速度读数。 |
| 0x020 | QEIINTEN | R/W | 0x0000.0000 | 中断使能寄存器,控制哪些事件可以产生中断。 |
| 0x024 | QEIRIS | RO | 0x0000.0000 | 原始中断状态,无论中断是否使能,事件发生即置位。 |
| 0x028 | QEIISC | R/W1C | 0x0000.0000 | 中断状态与清除寄存器,读可查看已使能的中断状态,写1清除对应中断标志。 |
注意:
R/W1C类型(Write-1-to-Clear)是中断处理中的关键。要清除一个中断标志,必须向QEIISC的对应位写1,写0无效。这是一个常见的踩坑点。
3. 核心寄存器深度解析与配置实战
理解了全局框架,我们现在进入最核心的部分:如何配置这些寄存器来实现特定功能。我会结合常见应用场景,解释每个关键配置位的实际意义。
3.1 QEI控制寄存器(QEICTL)—— 模块的大脑
QEICTL寄存器是配置的起点,它决定了QEI模块以何种方式运行。我们按功能域来分解:
- 位0 - ENABLE:模块总开关。这里有一个非常重要的硬件特性:一旦将此位置1使能模块,无法通过清除此位来关闭模块。唯一的关闭方法是复位整个QEI模块(通过系统控制模块中的
SRQEI位)。因此,在初始化时,应最后配置此位。 - 位1 - SWAP:交换PhA和PhB信号。如果你的电机旋转方向与预期相反,除了调换电机线或修改软件方向判断,也可以简单地设置此位来反转方向。
- 位2 - SIGMODE:选择上文提到的两种信号模式。
0为正交模式,1为时钟/方向模式。 - 位3 - CAPMODE:捕获模式,仅在
SIGMODE=0时有效。0表示只对PhA的边沿计数(2倍频),1表示对PhA和PhB的边沿都计数(4倍频)。为了获得最高分辨率,通常设为1。 - 位4 - RESMODE:位置计数器复位模式。
0=达到QEIMAXPOS值时复位;1=检测到索引脉冲(IDX)时复位。索引脉冲是编码器每转一圈产生的一个脉冲,用于确定绝对机械零点。在需要周期性清零位置(例如每转归零)的应用中,此模式非常有用。 - 位5 - VELEN:速度捕获使能。必须置1才能使用速度测量功能。注意:要使能速度捕获,必须先使能正交编码器(
ENABLE=1且SIGMODE=0)。 - 位[8:6] - VELDIV:速度预分频器。它决定了多少编码器脉冲才会计入速度计数器。分频系数为
2^VELDIV。例如,对于高线数的编码器(如2000线),电机一转会产生2000 * 4 = 8000个计数。如果直接测量,速度寄存器很快就会溢出。此时可以设置VELDIV=3(÷8),那么每8个脉冲才计1次,扩展了速度测量的范围。 - 位9, 10 - INVA, INVB:分别反相PhA和PhB信号。用于纠正因传感器安装或接线导致的信号相位反相。
- 位12 - STALLEN:调试停止使能。当微控制器被调试器(如JTAG/SWD)暂停时,此位决定QEI是否也停止计数。在调试运动控制程序时,建议设为
1,这样暂停时位置不会“偷偷”变化,便于分析。 - 位13 - FILTEN:输���数字滤波器使能。强烈建议在可能有电气噪声的环境下启用(置1)。滤波器要求信号在3个连续的采样时钟边沿保持稳定,才会被确认,能有效消除毛刺。
- 位[19:16] - FILTCNT:输入滤波器采样预分频数。它和系统时钟共同决定滤波器的采样窗口。公式为:采样周期 = (FILTCNT + 2) * 系统时钟周期。例如,系统时钟为80MHz(12.5ns),
FILTCNT=0xF(15),则采样窗口为(15+2)*12.5ns = 212.5ns。任何短于此时间的脉冲都会被滤除。你需要根据编码器信号的最大频率来设置此值,确保有效信号能通过,噪声被滤除。
一个典型的4倍频、带滤波、使能速度捕获的配置代码片段(基于直接寄存器操作)如下:
// 假设使用QEI0,系统时钟已配置 #define QEI0_BASE 0x4002C000 #define QEI_CTL_OFFSET 0x000 void QEI0_Init(void) { // 1. 先禁用模块(虽然此时ENABLE位可能为0,但遵循先配置后使能的流程) // 2. 配置控制寄存器:4倍频、使能速度捕获、使能输入滤波器 uint32_t ctlValue = 0; ctlValue |= (0x1 << 3); // CAPMODE = 1: 4倍频 ctlValue |= (0x1 << 5); // VELEN = 1: 使能速度捕获 ctlValue |= (0x1 << 13); // FILTEN = 1: 使能数字滤波器 ctlValue |= (0x5 << 16); // FILTCNT = 5: 设置滤波器采样窗口 (5+2)=7个系统时钟 // 注意:此时不设置ENABLE位 HWREG(QEI0_BASE + QEI_CTL_OFFSET) = ctlValue; // 3. 配置其他寄存器,如QEILOAD, QEIMAXPOS等(见后续章节) // ... // 4. 最后,通过读-修改-写操作置位ENABLE位 HWREG(QEI0_BASE + QEI_CTL_OFFSET) |= 0x1; }3.2 位置与速度相关寄存器
QEIPOS & QEIMAXPOS:
QEIPOS是核心的位置数据源。它是一个32位有符号整数(在软件层面解释),正向旋转时递增,反向时递减。QEIMAXPOS定义了其计数范围。当RESMODE=0时,计数器达到MAXPOS后会归零(正向)或从MAXPOS值开始递减(反向),实现循环计数。例如,对于一个1000线(4倍频后为4000计数/转)的编码器,若想实现每转位置归零,可设置QEIMAXPOS = 3999。当QEIPOS达到4000时,硬件自动将其复位为0。QEILOAD, QEITIME, QEICOUNT, QEISPEED:这是速度测量的“流水线”。
QEILOAD:设定速度测量的时间窗口。关键公式:装载值 = 期望的定时周期时钟数 - 1。例如,系统时钟80MHz,希望每10ms(0.01s)计算一次速度,则所需时钟数 = 80,000,000 Hz * 0.01 s = 800,000。那么QEILOAD应设置为 799,999。QEITIME:递减计数器,从LOAD值开始减到0,然后重载。主要用于调试,观察定时是否正常。QEICOUNT:在当前未完成的定时周期内,实时累加的脉冲数。注意:由于读取时刻的不确定性,这个值可能正在变化,不适合直接用于速度计算。数据手册也明确提示其“精度不可知”。QEISPEED:这是你要读取的稳定速度值。它锁存了上一个完整定时周期内QEICOUNT的最终值。当定时器归零时,QEICOUNT的值被捕获到QEISPEED,然后QEICOUNT清零并开始下一个周期的计数。因此,读取QEISPEED总能得到一个完整周期内的有效脉冲数。
速度计算示例:假设
VELDIV=0(不分频),QEILOAD设置为10ms周期,某次读取到QEISPEED = 1200。这意味着在10ms内捕获了1200个编码器计数。如果编码器是1000线(4倍频后每转4000计数),则转速为:(1200 counts / 0.01s) / (4000 counts/rev) = 30 rev/s,即1800 RPM。
3.3 中断系统寄存器(QEIINTEN, QEIRIS, QEIISC)
QEI模块提供了4种中断源,通过三个寄存器协同管理:
- 索引脉冲中断(INTINDEX):当检测到编码器索引脉冲时触发。用于寻找绝对零点。
- 定时器中断(INTTIMER):当速度定时器(
QEITIME)计数到0时触发。这是周期性读取QEISPEED寄存器以更新速度的理想时机。 - 方向改变中断(INTDIR):当旋转方向发生变化时触发。
- 相位错误中断(INTERROR):仅在正交模式下,当检测到非法的相位变化(如A、B两相同时跳变)时触发,表明信号可能受到严重干扰。
- QEIINTEN:中断使能开关。你想让哪个事件触发中断,就把对应的位置1。
- QEIRIS:原始中断状态。只要事件发生,对应位就被硬件置1,无论
QEIINTEN是否使能。它反映了最底层的事件状态。 - QEIISC:这是你在中断服务程序(ISR)中主要交互的寄存器。它的状态是
QEIRIS & QEIINTEN的结果。只有使能了且发生了的事件,这里才为1。清除中断标志的方法:向QEIISC中对应位写1。例如,清除定时器中断标志:HWREG(QEI0_BASE + QEI_ISC_OFFSET) = 0x2;。
一个典型的中断服务程序框架如下:
void QEI0_IntHandler(void) { uint32_t status = HWREG(QEI0_BASE + QEI_ISC_OFFSET); // 读取中断状态 if (status & 0x1) { // 索引脉冲中断 // 处理零点位置,例如将QEIPOS清零或设置为某个值 // ... HWREG(QEI0_BASE + QEI_ISC_OFFSET) = 0x1; // 写1清除标志位 } if (status & 0x2) { // 定时器中断(最常用) g_current_speed = HWREG(QEI0_BASE + QEI_SPEED_OFFSET); // 读取稳定速度值 // 进行速度计算、滤波或控制律运算 // ... HWREG(QEI0_BASE + QEI_ISC_OFFSET) = 0x2; // 写1清除标志位 } if (status & 0x4) { // 方向改变中断 // 处理方向改变逻辑 // ... HWREG(QEI0_BASE + QEI_ISC_OFFSET) = 0x4; } if (status & 0x8) { // 相位错误中断 // 报告错误,可能需要检查编码器接线或电源 // ... HWREG(QEI0_BASE + QEI_ISC_OFFSET) = 0x8; } }4. 完整配置流程与实战代码示例
现在,我们将所有知识点串联起来,形成一个从引脚复用、模块初始化到数据读取的完整流程。假设我们要用QEI0接口连接一个1000线的增量式编码器,实现4倍频解码、带数字滤波、每10ms更新一次速度,并使用索引脉冲中断进行零位校准。
4.1 硬件连接与引脚复用
首先,查阅芯片数据手册的引脚复用表(即你提供的信号表部分)。找到QEI0对应的引脚。例如:
PhA0可能复用在PD6(A3) 或PH4(J3) 等引脚上。PhB0可能复用在PD7(B3) 或PH5(H4) 等引脚上。IDX0可能复用在PJ2(A9) 或PH1(K4) 等引脚上。
你需要根据PCB布局选择一组,并通过GPIO的AFSEL(备选功能选择)和PCTL(端口控制)寄存器将其配置为QEI功能。以使用PD6和PD7为例:
#include <stdint.h> #include "inc/tm4c123gh6pm.h" // 包含寄存器定义的头文件 void PinMux_Config(void) { // 1. 使能GPIO端口D的时钟 SYSCTL->RCGCGPIO |= (1 << 3); // 端口D在bit 3 while(!(SYSCTL->PRGPIO & (1 << 3))); // 等待时钟稳定 // 2. 解锁PD7引脚(如果需要,某些引脚可能被锁定) // GPIO_PORTD_LOCK_R = 0x4C4F434B; // 解锁GPIO D // GPIO_PORTD_CR_R |= (1 << 7); // 允许更改PD7配置 // 3. 设置PD6和PD7为数字功能,并启用备选功能 GPIO_PORTD_DEN_R |= (1 << 6) | (1 << 7); // 数字使能 GPIO_PORTD_AFSEL_R |= (1 << 6) | (1 << 7); // 启用备选功能 // 4. 配置引脚为QEI0功能(查阅数据手册表,PD6/7的QEI0功能编码可能是0x4) // 清除PD6和PD7的端口控制位域(每个引脚占4bit,PD6在bits 27:24, PD7在bits 31:28) GPIO_PORTD_PCTL_R &= ~(0xFF << 24); // ���置PD6和PD7为QEI0功能(假设编码为0x4) GPIO_PORTD_PCTL_R |= (0x4 << 24) | (0x4 << 28); // 5. 禁用上下拉(编码器通常有外部电阻,或使用开漏输出) GPIO_PORTD_PUR_R &= ~((1 << 6) | (1 << 7)); GPIO_PORTD_PDR_R &= ~((1 << 6) | (1 << 7)); }4.2 QEI模块初始化完整代码
#define QEI0_BASE 0x4002C000 #define SYSCTL_RCGCQEI_R (*((volatile uint32_t *)0x400FE644)) void QEI0_Complete_Init(void) { // 0. 使能QEI0模块的时钟 SYSCTL_RCGCQEI_R |= 0x01; // 通常需要插入少量延时等待外设时钟稳定 __asm__ volatile("nop"); __asm__ volatile("nop"); // 1. 先禁用QEI模块(通过复位或确保ENABLE=0) // 使用软件复位是最干净的方式 SYSCTL->SRQEI = 0x01; // 复位QEI0模块 while(SYSCTL->SRQEI & 0x01); // 等待复位完成 // 2. 配置最大位置值(1000线编码器,4倍频,每转4000计数) // 如果想在0-3999之间循环,则MAXPOS设为3999 HWREG(QEI0_BASE + 0x00C) = 3999; // QEIMAXPOS // 3. 配置速度定时器周期(假设系统时钟80MHz,10ms周期) // 装载值 = 80,000,000 * 0.01 - 1 = 799,999 HWREG(QEI0_BASE + 0x010) = 799999; // QEILOAD // 4. 配置控制寄存器QEICTL uint32_t ctlConfig = 0; ctlConfig |= (1 << 0); // ENABLE: 最后再置位,这里先占位 // ctlConfig |= (1 << 1); // SWAP: 默认不交换相位 // ctlConfig |= (0 << 2); // SIGMODE: 0-正交模式(默认) ctlConfig |= (1 << 3); // CAPMODE: 1-4倍频(A&B边沿计数) ctlConfig |= (0 << 4); // RESMODE: 0-达到MAXPOS复位(循环计数) ctlConfig |= (1 << 5); // VELEN: 1-使能速度捕获 ctlConfig |= (0 << 6); // VELDIV[0]: 预分频=1(不分频) ctlConfig |= (0 << 7); // VELDIV[1] ctlConfig |= (0 << 8); // VELDIV[2] // ctlConfig |= (0 << 9); // INVA: 默认不反相 // ctlConfig |= (0 << 10);// INVB: 默认不反相 // ctlConfig |= (0 << 11);// INVI: 默认不反相索引 // ctlConfig |= (0 << 12);// STALLEN: 0-调试时不停止(根据需求设置) ctlConfig |= (1 << 13); // FILTEN: 1-使能输入滤波器 ctlConfig |= (0x5 << 16);// FILTCNT: 设置滤波器采样窗口为(5+2)=7个系统时钟周期 // 先写入配置,但不使能模块(ENABLE位为0) HWREG(QEI0_BASE + 0x000) = ctlConfig & ~(0x01); // 5. 配置中断(例如,使能定时器中断和索引中断) HWREG(QEI0_BASE + 0x020) = (1 << 1) | (1 << 0); // QEIINTEN: 使能定时器和索引中断 // 清除任何可能存在的 pending 中断标志 HWREG(QEI0_BASE + 0x028) = 0xF; // 向QEIISC所有位写1以清除 // 6. 在NVIC中使能QEI0中断(中断号需查数据手册,假设为33) NVIC->ISER[33 / 32] = (1 << (33 % 32)); // 设置中断优先级(可选) // NVIC->IP[33] = (NVIC->IP[33] & ~0xFF) | (priority << 5); // 7. 最后,置位ENABLE位以启动QEI模块 HWREG(QEI0_BASE + 0x000) |= 0x01; } // 中断服务例程 volatile int32_t g_absolute_position = 0; volatile int32_t g_speed_raw = 0; void QEI0_Handler(void) { uint32_t intStatus = HWREG(QEI0_BASE + 0x028); // 读取QEIISC if (intStatus & 0x01) { // 索引脉冲中断 // 遇到索引脉冲,可以将当前位置设为已知值(例如0) // 注意:QEIPOS是硬件计数器,我们用一个软件变量来记录绝对位置 // 假设我们想在索引处将绝对位置归零 int32_t hardware_pos = HWREG(QEI0_BASE + 0x008); // 读取QEIPOS g_absolute_position = 0; // 软件绝对位置归零 // 如果需要,也可以将硬件计数器QEIPOS清零 // HWREG(QEI0_BASE + 0x008) = 0; HWREG(QEI0_BASE + 0x028) = 0x01; // 清除索引中断标志 } if (intStatus & 0x02) { // 定时器中断 g_speed_raw = HWREG(QEI0_BASE + 0x01C); // 读取QEISPEED // 在这里可以进行速度单位转换、滤波等 // 例如:转速RPM = (g_speed_raw * 60) / (4000 * 0.01) HWREG(QEI0_BASE + 0x028) = 0x02; // 清除定时器中断标志 } // ... 处理其他中断 } // 主循环中获取位置(处理溢出) int32_t GetAbsolutePosition(void) { static int32_t last_hw_pos = 0; int32_t current_hw_pos = HWREG(QEI0_BASE + 0x008); // 读取QEIPOS int32_t delta = current_hw_pos - last_hw_pos; // 处理硬件计数器在MAXPOS处的循环翻转 // 这是一个简化的处理,假设速度不会过快导致一次变化超过MAXPOS/2 if (delta > 2000) { // 假设MAXPOS=3999,正向溢出 delta -= 4000; } else if (delta < -2000) { // 反向溢出 delta += 4000; } g_absolute_position += delta; last_hw_pos = current_hw_pos; return g_absolute_position; }5. 高级应用、调试技巧与常见问题排查
掌握了基础配置后,我们探讨一些进阶应用和实践中必然会遇到的坑。
5.1 高分辨率与高转速的权衡
对于极高线数的编码器(如17位,131072线/转),4倍频后每转将产生超过50万个计数。此时,32位的QEIPOS寄存器在高速下仍可能很快溢出。策略如下:
- 使用VELDIV预分频:在
QEICTL中设置VELDIV,让多个脉冲才计一次位置。这会降低位置分辨率,但扩大了计数范围。例如,VELDIV=2(÷4)将使每转计数变为约13万,仍在32位整数安全范围内。 - 软件扩展:在中断服务程序中,用软件变量(如64位)来扩展位置计数。在定时器中断里,读取
QEISPEED(速度)并积分,同时结合QEIPOS的溢出中断(通过RESMODE和MAXPOS设置)来修正。这是更复杂但更精确的方法。
5.2 速度测量的精度与响应时间
速度测量的精度由QEILOAD设定的定时窗口决定。窗口越长,对单个脉冲的量化误差越小(例如,10ms窗口内少计1个脉冲,误差是100个脉冲/秒;而1ms窗口内少计1个脉冲,误差是1000个脉冲/秒)。但窗口越长,速度更新的延迟也越大,不利于快速响应。因此,需要在控制系统的带宽和速度测量精度之间做权衡。一个常见的做法是使用较短的定时窗口(如1-5ms),然后在软件中对QEISPEED进行滑动平均滤波。
5.3 常见问题与排查清单
| 现象 | 可能原因 | 排查步骤 |
|---|---|---|
| 位置计数器不变化 | 1. QEI模块未使能(ENABLE位)。2. 引脚复用未正确配置(仍是GPIO)。 3. 编码器无信号或供电问题。 4. 信号极性反相(A、B接反或需要 INVA/INVB)。 | 1. 检查QEICTL寄存器ENABLE位是否为1。2. 用示波器或逻辑分析仪检查PhA/PhB引脚是否有波形。 3. 检查编码器电源和接地。 4. 尝试设置 SWAP位或交换A、B接线。 |
| 位置计数方向错误 | 1. 编码器A、B相序接反。 2. 电机旋转方向与预期相反。 | 1. 交换PhA和PhB接线,或设置SWAP位。2. 检查 QEISTAT寄存器的DIRECTION位是否与实际匹配。 |
| 速度值(QEISPEED)始终为0 | 1. 速度捕获未使能(VELEN位)。2. 定时器装载值( QEILOAD)设置过大或为0。3. 未使能定时器中断,且未在正确时机读取。 | 1. 确认QEICTL的VELEN=1。2. 计算并设置正确的 QEILOAD值。3. 在定时器中断中读取 QEISPEED,或确保在主循环中读取的周期远大于QEILOAD设定的周期。 |
| 中断无法触发 | 1. 中断未在QEIINTEN中使能。2. NVIC中断未使能。 3. 中断标志未正确清除,导致后续中断被屏蔽。 4. 中断优先级过低,被其他中断阻塞。 | 1. 检查QEIINTEN寄存器。2. 检查NVIC的ISER寄存器对应位。 3.重点检查:在ISR中是否向 QEIISC对应位写1以清除标志。4. 检查并设置合适的中断优先级。 |
| 位置值跳动或出现巨大误差 | 1. 电气噪声干扰导致误触发。 2. 编码器信号边沿有振铃或毛刺。 3. 未启用输入数字滤波器。 | 1. 检查编码器信号线是否远离电机动力线,是否使用双绞线或屏蔽线。 2. 用示波器观察信号质量,必要时在输入端增加RC滤波。 3.启用 FILTEN并适当增加FILTCNT值。 |
| 索引脉冲中断不触发 | 1. 编码器索引信号未连接或损坏。 2. 索引信号极性问题(尝试 INVI位)。3. 索引脉冲过窄,被滤波器滤除。 | 1. 检查索引信号线连接,用示波器确认有脉冲输出。 2. 尝试设置或清除 QEICTL的INVI位。3. 减小 FILTCNT或暂时禁用滤波器测试。 |
5.4 软件层面的优化建议
- 位置跟踪:对于长距离绝对位置跟踪,建议使用一个64位的软件位置变量。在定时器中断中,不仅读取速度,也读取
QEIPOS的硬件值。通过比较前后两次的硬件值,处理可能发生的计数器溢出(超过MAXPOS或低于0),来更新64位的软件位置。这比单纯积分速度更准确。 - 速度滤波:
QEISPEED是瞬时速度,可能因脉冲间隔不均匀而有噪声。在中断服务程序或低速任务中,实施一个简单的移动平均滤波或一阶低通数字滤波,可以显著提高速度环的控制稳定性。 - 资源管理:TM4C123有两个QEI模块。如果项目需要多个编码器,可以合理分配。注意它们的引脚是复用的,需仔细规划。