深入解析正交编码器接口:从寄存器配置到电机控制实战
1. 项目概述:从寄存器手册到实际应用
在嵌入式运动控制领域,无论是驱动一个步进电机、控制一个机械臂关节,还是实现一个高精度的旋转平台,我们都需要一个可靠的“眼睛”来告诉我们:“现在动到哪里了?速度有多快?” 正交编码器(Quadrature Encoder)就是这双眼睛,而微控制器内部的正交编码器接口(QEI)模块,则是解读这双眼睛“看到”信息的大脑。
很多工程师拿到一份芯片数据手册,看到像“Table 17-3. QEI Register Map”这样的寄存器列表时,往往会感到头大。那一行行的偏移地址、读写类型、复位值,看起来冰冷而抽象。但事实上,每一个寄存器位都对应着硬件电路中的一个具体功能开关或数据锁存器。理解它们,就是理解如何与硬件对话,从而将编码器输出的两路相位差90度的脉冲信号(PhA和PhB),转化为我们程序里可以直接使用的位置计数和速度值。
本文将以德州仪器(TI)的Stellaris LM3S2950微控制器为例,带你穿透寄存器手册的表格,深入理解QEI模块从信号输入到数据产出的完整链条。我们不止步于“这个寄存器是干什么的”,更要探讨“为什么要这样设计”以及“在实际项目中如何配置和避坑”。无论你是正在调试第一个电机项目的新手,还是希望深化对硬件外设理解的老手,这篇文章都将从最底层的寄存器操作出发,为你构建一套清晰、可复用的QEI应用框架。
2. QEI核心原理与寄存器总览
在深入每个寄存器之前,我们必须先建立对QEI工作原理的直观认识。正交编码器通常输出两路方波信号:Phase A (PhA) 和 Phase B (PhB)。当轴旋转时,这两路信号会产生频率相同但相位相差90度的脉冲。这个90度的相位差是解码的关键。
2.1 方向与位置解码原理
想象一下PhA和PhB的波形。当轴正转时,PhA的上升沿到来时,PhB是低电平;而当轴反转时,PhA的上升沿到来时,PhB是高电平。硬件QEI模块内部有一个方向判断逻辑电路,实时监测这两个信号的边沿关系,从而确定当前的旋转方向。位置计数器(Position Integrator)则根据方向,对有效的边沿进行递增或递减计数。这里就引出了第一个重要的配置点:捕获模式(CapMode)。在LM3S2950的QEICTL寄存器中,CapMode位决定了哪些边沿被计数:
- CapMode = 0:仅对PhA的边沿(上升沿和下降沿)计数。每个完整的PhA周期(一个高电平+一个低电平)会产生2个计数。这是1x分辨率模式。
- CapMode = 1:对PhA和PhB两者的边沿都进行计数。由于两路信号相位错开,在一个PhA周期内,PhA和PhB共会产生4个边沿事件。这是4x分辨率模式,将位置测量的精度提高了四倍,但代价是位置计数器的计数范围减半(因为计数器位数固定,计数速度更快,更容易溢出)。
2.2 速度测量原理
速度测量的本质是计算单位时间内的位置变化量(脉冲数)。QEI模块采用了一种经典且高效的硬件测速方法:定时器捕获法。 模块内部有一个专用的速度定时器(Velocity Timer),它从一个预设值(QEILOAD)开始向下计数,减到0时产生溢出(即一个测量周期结束),并自动重载。与此同时,另一个硬件计数器(Velocity Counter, QEICOUNT)在这个定时器周期内,对编码器脉冲进行累加。 当一个测量周期结束时,硬件会自动将QEICOUNT中的累计值锁存到速度寄存器(QEISPEED)中,然后将QEICOUNT清零,开始下一个周期的累计。这样,软件只需要定期去读取QEISPEED寄存器,得到的值就是上一个完整周期内捕获的脉冲数。结合定时器周期时间,就能轻松计算出转速。
2.3 寄存器地图(Register Map)解析
LM3S2950的QEI模块寄存器从基地址0x4002.C000开始,以4字节(32位)为单位偏移。下表是对其核心寄存器的功能速览,这构成了我们后续所有操作的基础:
| 偏移地址 | 寄存器名称 | 类型 | 复位值 | 核心功能描述 |
|---|---|---|---|---|
| 0x000 | QEICTL | 读/写 | 0x0 | 总控制中心。启用模块、选择信号模式、设置捕获/复位模式、配置速度预分频等。 |
| 0x004 | QEISTAT | 只读 | 0x0 | 状态观察窗。实时反馈当前旋转方向(Direction位)和是否检测到相位错误(Error位)。 |
| 0x008 | QEIPOS | 读/写 | 0x0 | 位置积分器。核心位置数据寄存器,其值随编码器脉冲增减,也可软件写入进行位置预设或归零。 |
| 0x00C | QEIMAXPOS | 读/写 | 0x0 | 位置计数器模值。设置位置计数器的最大值,用于实现软件“电子齿轮”或限定计数范围,防止溢出混乱。 |
| 0x010 | QEILOAD | 读/写 | 0x0 | 速度定时器重载值。决定速度测量的采样周期。值 = 定时器时钟周期数 - 1。 |
| 0x014 | QEITIME | 只读 | 0x0 | 速度定时器当前值。可实时读取,用于调试或精确计时。 |
| 0x018 | QEICOUNT | 只读 | 0x0 | 速度脉冲累加器。在当前定时器周期内,对编码器脉冲的实时累加值。注意:读取此值可能与QEITIME不同步。 |
| 0x01C | QEISPEED | 只读 | 0x0 | 锁存的速度值。上一个完整定时器周期内捕获的脉冲数,是计算速度的稳定数据源。 |
| 0x020 | QEIINTEN | 读/写 | 0x0 | 中断使能开关。控制哪些事件(索引脉冲、定时器溢出、方向改变、相位错误)可以触发CPU中断。 |
| 0x024 | QEIRIS | 只读 | 0x0 | 原始中断状态。显示所有已发生的中断事件标志,无论是否使能中断。 |
| 0x028 | QEIISC | 读-写-1清除 | 0x0 | 中断状态与清除寄存器。读取可获知已触发中断的事件;向某位写1可清除该中断标志。 |
提示:
R/W1C(Read/Write-1-to-Clear)是一种常见的寄存器类型。意味着你可以读取它来查看状态,但清除中断标志的方法是向该位写入1,而不是写入0。这是一个常见的编程陷阱。
3. 关键寄存器深度解析与配置实战
理解了整体框架后,我们来逐一拆解最关键的几个寄存器,看看每个配置位在实际项目中如何发挥作用。
3.1 控制寄存器(QEICTL):模块的“大脑”
QEICTL寄存器是配置QEI模块行为的核心。它的每一位都像一个开关,决定了硬件如何处理输入信号。
- Enable (位0):QEI模块的总开关。必须置1,PhA/PhB信号输入才会被处理,位置计数器QEIPOS才会更新。在初始化序列中,建议最后才打开此位。
- SigMode (位3):信号模式选择。这是初学者容易困惑的地方。
0:正交相位模式(Quadrature Phase Mode)。即标准的正交编码器模式,PhA和PhB为两路相位差90度的脉冲,用于同时判断方向和计数。1:时钟-方向模式(Clock-Direction Mode)。此时PhA被解释为时钟脉冲(每个脉冲代表一个位置变化),PhB被解释为方向信号(高电平代表一个方向,低电平代表另一个方向)。这种模式常用于接收某些特定型号编码器或驱动器的输出。
- CapMode (位4):如前所述,选择1x或4x计数模式。对于追求高精度的应用,如高分辨率伺服电机,应选择4x模式。但需注意,如果编码器线数很高,电机转速又很快,4x模式可能导致位置计数器溢出加速,此时需要合理设置QEIMAXPOS或使用32位溢出处理。
- VelDiv (位8:6):速度预分频器。这是一个非常实用的功能。假设你的编码器线数很高(如每转1000线),在4x模式下每转产生4000个脉冲。电机高速旋转时,单位时间内的脉冲数可能超过速度计数器(QEICOUNT)的容量或导致计算出的速度值过大。VelDiv可以将输入脉冲进行2^N分频(N=0~7),再送给速度计数器。例如,设置VelDiv=3(÷8),可以大大降低高速时的脉冲频率,扩展速度测量范围,但会损失一些速度分辨率。
- INVA/INVB (位10, 11):信号输入反相。当实际接线导致电机正转时读数反而减少,可以通过设置INVA或INVB来纠正方向。这是一个硬件级的纠正,比在软件里对计数值取反更直接。
- STALLEN (位12):调试功能。当此位置1且单片机进入调试暂停(Halt)状态时,QEI模块也会暂停,便于在断点处观察静止的位置和速度值。
3.2 位置相关寄存器:QEIPOS与QEIMAXPOS
QEIPOS是一个32位可读写寄存器。它的值随着编码器脉冲实时变化。你可以读取它获得绝对位置(相对于上电或上次清零后的累计值)。你也可以写入它,这常用于:
- 系统归零(Homing):当机械装置找到参考点(如限位开关)后,将QEIPOS写入0或某个预设值。
- 多圈计数处理:32位计数器在高速高分辨率下也可能溢出。一种软件策略是使用一个64位的软件计数器,在QEIPOS溢出中断(需结合QEIMAXPOS)时,对软件计数器的高32位进行加减。
QEIMAXPOS定义了位置计数器的模值。其行为是:
- 正转时,当QEIPOS大于QEIMAXPOS,QEIPOS复位为0。
- 反转时,当QEIPOS小于0,QEIPOS复位为QEIMAXPOS。 这本质上创建了一个软件环形缓冲区。例如,将其设置为编码器每转产生的脉冲数减一(在4x模式下是
4 * 线数 - 1),那么QEIPOS的值将始终在0到(每转脉冲数-1)之间循环,直接反映了当前转内的相位角,非常适用于需要模运算的位置控制。
3.3 速度测量寄存器组:QEILOAD, QEITIME, QEICOUNT, QEISPEED
这是实现低CPU开销速度测量的精华所在。
- 设定采样周期(QEILOAD):速度测量的精度和实时性取决于采样周期。周期越短,速度更新越快,但对低速测量的分辨率越低(可能一个周期内捕获不到脉冲)。周期越长,低速分辨率高,但速度更新慢。QEILOAD = 定时器时钟周期数 - 1。假设系统时钟为50MHz,我们希望速度采样率为1kHz(周期1ms),则定时器需要计数50000个时钟周期。那么QEILOAD应设置为49999。
- 理解数据流:硬件自动完成以下流程:定时器从QEILOAD值开始递减 → QEICOUNT对编码器脉冲累加 → 定时器减到0瞬间,将QEICOUNT值锁存到QEISPEED,同时清零QEICOUNT,定时器重载 → 开始下一个周期。
- 读取速度:软件应始终读取QEISPEED寄存器来获取稳定速度值。QEICOUNT是“正在进行”的累加值,读取它可能得到不完整的周期数据,手册也明确说明其仅用于信息参考。
- 计算实际转速:得到QEISPEED值(记为
N_pulses)后,实际转速(RPM)计算公式为:速度 (RPM) = (N_pulses * 60) / (T * P * D)T: 定时器周期,单位秒。T = (QEILOAD + 1) / TimerClockFreqP: 编码器每转的脉冲数(线数 * 4,若为4x模式)。D: 速度预分频系数(VelDiv对应的分频比,如÷1, ÷2, … ÷128)。
3.4 中断系统寄存器:QEIINTEN, QEIRIS, QEIISC
中断是实现事件驱动、提高系统实时性的关键。
- QEIINTEN:你需要使能哪些中断?常见配置是使能“定时器溢出中断”(IntTimer)和“索引脉冲中断”(IntIndex)。前者用于定期读取速度,后者用于寻找零位。
- QEIRIS vs QEIISC:这是中断处理的关键。
QEIRIS是“原始状态”,只要事件发生,对应位就置1,不管中断是否使能。QEIISC是“屏蔽后状态”兼“清除寄存器”。当中断服务程序(ISR)被调用时,你应该读取QEIISC来确定是哪个中断源触发的,并在处理完成后,通过向QEIISC的相应位写1来清除中断标志。如果只读不写,会导致中断持续触发,CPU陷入死循环。
4. 从零构建:QEI模块驱动代码实现
理论必须付诸实践。下面我们以LM3S2950为例,展示一个典型的QEI模块初始化、数据读取和中断处理的C语言驱动框架。假设使用SysTick作为系统时钟源,QEI时钟已使能。
4.1 硬件初始化与引脚配置
首先,需要将编码器的PhA、PhB和Index信号连接到MCU的正确引脚。根据手册“Signal Tables”章节,对于QEI0模块:
- PhA0 对应 PC4 (引脚25)
- PhB0 对应 PH3 (引脚83)
- IDX0 对应 PD7 (引脚100)
我们需要配置这些引脚为外设功能,而非普通的GPIO。
#include "inc/hw_memmap.h" #include "inc/hw_types.h" #include "driverlib/sysctl.h" #include "driverlib/gpio.h" #include "driverlib/pin_map.h" // 包含引脚复用定义 #include "driverlib/qei.h" void QEI0_Init(void) { // 1. 使能外设时钟 SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC); // PhA SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOH); // PhB SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD); // Index SysCtlPeripheralEnable(SYSCTL_PERIPH_QEI0); // 等待外设就绪(良好习惯) while(!SysCtlPeripheralReady(SYSCTL_PERIPH_QEI0)); // 2. 配置PhA和PhB引脚为QEI功能 // PhA (PC4) 和 PhB (PH3) 配置为上拉输入,以增强抗干扰能力 GPIOPinTypeQEI(GPIO_PORTC_BASE, GPIO_PIN_4); // 该函数内部会配置引脚复用 GPIOPinTypeQEI(GPIO_PORTH_BASE, GPIO_PIN_3); // 对于Index引脚,同样配置为QEI输入 GPIOPinTypeQEI(GPIO_PORTD_BASE, GPIO_PIN_7); // 3. 配置QEI模块参数 // 使用正交相位模式(0), 4倍频计数(CAPMODE_4), 索引脉冲复位(RESMODE_IDX) // 不交换信号,不反相,速度捕获使能,预分频为1 QEIConfigure(QEI0_BASE, (QEI_CONFIG_CAPTURE_A_B | // 4x模式,计数PhA和PhB的边沿 QEI_CONFIG_NO_RESET | // 我们先不用索引复位,稍后软件清零 QEI_CONFIG_QUADRATURE | // 正交模式 QEI_CONFIG_NO_SWAP | // 不交换PhA/PhB QEI_CONFIG_NO_INVERT), // 不反相输入 0); // 最大位置值,暂不设置 // 4. 设置速度测量定时器周期 // 假设系统时钟50MHz,期望速度采样率500Hz (2ms周期) // 定时器计数值 = 50e6 / 500 = 100000 // QEILOAD = 计数值 - 1 = 99999 QEIVelocityConfigure(QEI0_BASE, QEI_VELDIV_1, 99999); // 5. 设置位置计数器最大值(可选,用于创建环形位置) // 假设编码器为1000线,4倍频下每转4000脉冲 // 设置最大位置为3999,则位置值在0-3999循环 QEIPositionSet(QEI0_BASE, 0); // 先清零位置 QEIMaximumPositionSet(QEI0_BASE, 3999); // 6. 使能QEI模块 QEIEnable(QEI0_BASE); }4.2 数据读取与速度计算
初始化完成后,我们就可以在主循环或定时中断中安全地读取位置和速度了。
// 全局变量用于存储位置和速度 volatile int32_t g_i32Position = 0; volatile int32_t g_i32SpeedRaw = 0; volatile float g_fSpeedRPM = 0.0f; void QEI0_ReadData(void) { // 读取当前位置(有符号数,便于处理反转) // QEIPositionGet()返回的是无符号数,我们需要根据方向将其转换为有符号数 uint32_t ui32Pos = QEIPositionGet(QEI0_BASE); uint32_t ui32MaxPos = QEIMaximumPositionGet(QEI0_BASE); // 简单处理:如果位置超过最大值一半,视为负向溢出(示例,实际需结合方向位) // 更稳健的方法是结合QEIDirectionGet()函数判断方向,进行累积计算 g_i32Position = (int32_t)ui32Pos; // 本例先简单转换 // 读取锁存的速度脉冲数 g_i32SpeedRaw = QEIVelocityGet(QEI0_BASE); // 读取QEISPEED寄存器 // 计算实际转速 (RPM) // 参数:定时器周期T=2ms=0.002s, 编码器每转脉冲数P=4000, 预分频D=1 const float fPeriodSec = 0.002f; // 2ms const float fPulsesPerRev = 4000.0f; if(g_i32SpeedRaw != 0) { g_fSpeedRPM = (g_i32SpeedRaw * 60.0f) / (fPeriodSec * fPulsesPerRev); } else { g_fSpeedRPM = 0.0f; } }4.3 中断服务程序(ISR)实现
使用中断可以更及时地响应速度更新或索引脉冲事件。
// 全局标志位 volatile uint8_t g_ui8SpeedUpdated = 0; volatile uint8_t g_ui8IndexDetected = 0; void QEI0_IntHandler(void) { uint32_t ui32Status; // 读取中断状态并清除标志 ui32Status = QEIIntStatus(QEI0_BASE, true); // 读取QEIISC寄存器 QEIIntClear(QEI0_BASE, ui32Status); // 清除已触发的中断 // 判断中断源 if(ui32Status & QEI_INTTIMER) { // 速度定时器溢出,新速度值已就绪 g_ui8SpeedUpdated = 1; // 可以在这里直接读取速度,但注意ISR应尽量短小 // g_i32SpeedRaw = QEIVelocityGet(QEI0_BASE); } if(ui32Status & QEI_INTINDEX) { // 检测到索引脉冲(编码器零位) g_ui8IndexDetected = 1; // 通常在此将位置计数器设为0,实现硬件归零 // QEIPositionSet(QEI0_BASE, 0); } if(ui32Status & QEI_INTDIR) { // 方向改变,可以记录或处理 } if(ui32Status & QEI_INTERROR) { // 相位错误!可能编码器信号质量差或接线有问题 // 应进行错误处理,如报警、停止电机等 } } void QEI0_IntEnable(void) { // 使能“定时器溢出”和“索引脉冲”中断 QEIIntEnable(QEI0_BASE, QEI_INTTIMER | QEI_INTINDEX); // 注册中断处理函数到向量表(具体方法取决于你的开发环境和启动文件) // 例如:IntRegister(INT_QEI0, QEI0_IntHandler); // IntEnable(INT_QEI0); }5. 高级应用与调试技巧
掌握了基础配置后,我们探讨几个提升系统鲁棒性和性能的高级话题。
5.1 处理高速与高分辨率下的溢出
当电机转速很高且编码器分辨率很高时,即使使用32位位置计数器,也可能在长时间运行后溢出。解决方案是使用一个64位的软件扩展位置计数器。
volatile uint64_t g_ui64ExtendedPosition = 0; uint32_t g_ui32LastRawPos = 0; void QEI_PositionUpdateTask(void) { uint32_t ui32CurrentPos = QEIPositionGet(QEI0_BASE); int32_t i32Delta; // 计算自上次读取以来的变化量,考虑计数器溢出 if(ui32CurrentPos >= g_ui32LastRawPos) { i32Delta = (int32_t)(ui32CurrentPos - g_ui32LastRawPos); // 检查是否可能发生了正向溢出(从接近最大值跳转到小值) // 如果差值异常大(超过最大值一半),更可能是发生了溢出 if(i32Delta > 0x7FFFFFFF) { // 假设MAXPOS很大,这里用另一种策略 // 更通用的方法是结合方向标志和最大值判断 } } else { i32Delta = -((int32_t)(g_ui32LastRawPos - ui32CurrentPos)); // 检查是否可能发生了负向溢出 } // 更新扩展位置 g_ui64ExtendedPosition += i32Delta; g_ui32LastRawPos = ui32CurrentPos; }5.2 优化速度测量精度与滤波
直接从QEISPEED读取的脉冲数可能因为电机瞬时抖动或噪声而波动。常用的软件滤波方法有:
- 移动平均滤波:维护一个速度值的历史数组,每次取平均值。
- 低通滤波:
speed_filtered = alpha * speed_new + (1 - alpha) * speed_filtered,其中alpha是滤波系数(0<alpha<1),值越小越平滑,但响应越慢。 - 动态调整采样周期:低速时使用较长的采样周期(增大QEILOAD)以提高分辨率;高速时自动切换到较短周期(减小QEILOAD)以提高更新率。这需要在中断中根据当前速度值动态重载QEILOAD。
5.3 信号质量诊断与错误处理
QEISTAT寄存器中的Error位是宝贵的诊断工具。当硬件检测到PhA和PhB在同一时钟沿同时变化(违反正交编码规则)时,此位置1。这通常意味着:
- 编码器电源不稳定。
- 信号线过长,受到严重干扰。
- 编码器本身损坏。
- 引脚配置错误(例如误配置为输出)。
在中断中监控此错误,并累计错误次数。当错误率超过阈值时,触发系统保护,例如降速、停机并报警。
volatile uint32_t g_ui32PhaseErrorCount = 0; // 在QEI中断处理函数中 if(ui32Status & QEI_INTERROR) { g_ui32PhaseErrorCount++; if(g_ui32PhaseErrorCount > ERROR_THRESHOLD) { // 触发严重错误处理流程 System_HaltWithError(ERR_QEI_SIGNAL); } }5.4 利用索引脉冲实现精准归零
索引脉冲(Index或Z信号)是编码器每转产生一次的脉冲,是绝对的机械参考点。配置ResMode=1(索引复位模式)可以让硬件在检测到索引脉冲时自动将QEIPOS复位为0,实现硬同步。但在某些精密定位中,我们可能希望将索引脉冲到来时的位置设为一个非零的偏置值。这时可以:
- 配置为
ResMode=0(最大值复位模式)或使用软件复位。 - 使能索引脉冲中断(IntIndex)。
- 在中断服务程序中,读取当前QEIPOS值,计算出与目标零位的偏差,并将此偏差作为后续所有位置读数的软件偏移量。
6. 常见问题排查与实战心得
在实际项目中,QEI模块调试可能会遇到各种问题。下面是一个快速排查指南:
| 现象 | 可能原因 | 排查步骤与解决方案 |
|---|---|---|
| 位置计数器不变化 | 1. QEI模块未使能(QEICTL.Enable=0)。 2. 引脚配置错误,未映射到QEI功能。 3. 编码器无供电或信号线断开。 4. 信号模式(SigMode)设置错误。 | 1. 检查QEICTL配置,确认Enable位已置1。 2. 使用示波器或逻辑分析仪测量PhA/PhB引脚是否有波形。 3. 检查编码器电源和接线。 4. 确认SigMode与编码器类型匹配(通常为0,正交模式)。 |
| 位置计数方向相反 | 电机物理旋转方向与计数方向不符。 | 交换PhA和PhB的接线,或者设置QEICTL中的INVA或INVB位进行信号反相。 |
| 速度值始终为0或异常小 | 1. 速度捕获未使能(QEICTL.VelEn=0)。 2. 速度定时器周期(QEILOAD)设置过长,在周期内无脉冲。 3. 预分频(VelDiv)设置过大,滤掉了所有脉冲。 | 1. 确认VelEn位已置1。 2. 缩短QEILOAD值,降低采样周期。 3. 检查VelDiv设置,高速时适当增加,低速时应设为÷1。 |
| 速度值波动剧烈(噪声大) | 1. 编码器信号有噪声。 2. 采样周期太短,统计脉冲数少,量化误差大。 | 1. 检查编码器屏蔽线是否接地,信号线是否远离动力线。 2. 适当增加采样周期(增大QEILOAD)或启用软件滤波。 |
| 索引脉冲中断不触发 | 1. 索引中断未使能(QEIINTEN.IntIndex=0)。 2. 索引引脚配置错误或信号问题。 3. 索引脉冲太窄,可能被滤波掉(检查MCU输入滤波设置)。 | 1. 确认中断使能寄存器配置。 2. 测量索引引脚信号。 3. 查阅数据手册,看GPIO是否有可配置的输入滤波,必要时禁用或调整。 |
| 读取的位置值偶尔跳变 | 1. 32位位置计数器溢出未处理。 2. 在多任务或中断环境中,读取32位值被高/低半字读取中断打断。 | 1. 实现软件64位扩展位置计数器(见5.1节)。 2. 在读取QEIPOS时临时关闭中断,或连续读取两次直到值稳定。 |
个人实战心得:
- 上电初始化顺序很重要:先配置GPIO引脚复用功能,再配置QEI模块寄存器,最后才使能(Enable)模块。避免使能后信号输入导致寄存器处于不确定状态。
- 善用状态寄存器QEISTAT:在调试初期,定期打印或读取Direction和Error位,可以快速判断信号是否正常接入以及方向逻辑是否正确。
- 速度环的定时器选择:LM3S2950的QEI速度定时器是专用的。确保你设置的速度采样率(由QEILOAD决定)与控制算法的周期相匹配。通常,速度采样率是电流/位置环控制频率的1/5到1/10即可。
- 关于“抖动”:在极低速或静止时,由于机械振动或电气噪声,编码器可能会输出零星脉冲,导致位置微微漂移。如果应用对静止稳定性要求高,可以在软件中设置一个“死区”,当速度低于某个极小阈值时,忽略位置计数的微小变化。
- 文档版本:本文基于LM3S2950的数据手册。不同系列的TI Stellaris/Tiva C/MSP432微控制器,其QEI模块寄存器名称、位域可能略有差异。务必以你正在使用的芯片的最新版数据手册为准。
