旋转编码器是一种安装在旋转轴上并检测其运动的传感器。常用的设备包括鼠标(球型)和滚轮。对于工业用途,它们内置于伺服电机中并用于检测电机的角度位置。通用旋转编码器的输出格式主要有两种,如下所示。
增量型 如图所示,输出正交二相脉冲,仅检测旋转方向和计数的类型。它结构简单,因此价格低廉。有些具有原点输出(每转一个脉冲)以获得参考位置。有机械接触式和非接触式(光传感器、磁传感器)。请注意,一些廉价产品没有波形整形功能。
型 将角度以超过 10 位的格雷码输出。输出代码直接指示角度,因此您永远不会忘记自己的位置。其结构复杂且相当昂贵。格雷码用于消除对齐错误对每一位的影响。 增量式旋转编码器 改变方向 0→0寂静 0→1+1 0→2-1 0→3无效的 1→0-1 1→1寂静 1→2无效的 1→3+1 2→0+1 2→1无效的 2→2寂静 2→3-1 3→0无效的 3→1-1 3→2+1 3→3寂静 这次我将介绍如何使用增量类型,增量类型结构简单,应用广泛。对于电机控制,通常使用带有缓冲计数器或两相脉冲输入的机械控制微控制器,但本示例显示了将其直接连接到通用 PIO 的使用技巧。 首先,如果将 A 相和 B 相视为二进制代码(如右图所示),您会发现它们的值重复 0 → 1 → 3 → 2 → 0(在正向旋转的情况下)为发生旋转。因此,通过定期对输出进行采样并将其与之前的值进行比较,您可以找出它旋转的方向。变化模式共有16种,其对应关系如右表所示。
当转速(计数率)超过采样频率时,会出现无效代码。在这种情况下,旋转方向信息将会丢失,从而产生错误。此错误通常会导致系统错误(如位置信息丢失)。如果是拨号盘(用户I/F),即使忽略也没有问题。另外,通过对无效代码进行特殊处理(与上次相同的方向计数2),可以提供高达采样频率两倍以下的超速阻力。 可使用以下方法根据编码器输出的变化模式确定旋转方向。 使用比较/分支指令查找每个。 这是个想到的方法,但由于必须判断至少8种模式,因此过程变得复杂。 通过表格转换查找 使用“(先前值 << 2) + 当前值”将表转换为 4 位索引值,该值显示所有更改的组合。对于大多数微控制器来说,这种方法可能是简单的。 计算得出 (1) 如果索引值的奇偶性为偶数,则没有变化或没有变化,如果为奇数,则有变化。如果没有变化,与0b0101进行与,奇偶校验为偶数则静态,奇数校验无效。如果有变化,与0b0110进行与,如果奇偶校验为偶数,则为+方向,如果为奇数,则为-方向。这种方法只需要两次测试,但需要带有奇偶校验标志的处理器。 计算得出 (2) 编码器输出从0→1→3→2变化(以二进制形式),因此很难按原样使用。这可以说是2位格雷码,但如果转换成二进制码的话,顺序就是0→1→2→3,通过与之前的差值就可以检测出旋转方向一。为了转换为二进制,通过对采样值的位 0 和位 1 进行异或操作来交换 2 和 3,从而产生连续的二进制代码。由于它是一个 2 位值,因此可以获得 -2 到 +1 范围内的结果,其中 -2 表示错误。 旋转编码器编码示例(表格转换) 这是一个使用表转换来确定操作的示例。Sample_encoder() 在后台进程中定期调用,例如定时器中断(计数率 < 调用率)。旋转编码器的旋转量实时反映在Encoder结构的位置上,并在每次检测到移动时进行移动设置。 易失性结构{ 多头位置; /* 轴位置 */ int moving; /* 移动标志 */ } 编码器; 无效样本编码器(无效) { static const int dir[] = { 0,1,-1,0,-1,0,0,1,1,0,0,-1,0,-1,1,0 }; /* 旋转方向表*/ 静态 int i; /* 索引 */ 整数 n; i = (i << 2) + (PA.PIN.BYTE & 3); /* 使用先前值和当前值作为索引 */ n = dir[i & 15]; /* 从变化模式中获取运动 */ if (n) { /* 如果有移动则更新位置 */ 编码器.position += n; 编码器.moved = 1; } } 旋转编码器编码实例(二) 这是用户界面中经常使用的慢速拨号计数处理的示例。每次单击移动时都会生成命令代码。 某些制动型缓动盘具有 2 或 4 计数增量的制动位置。这意味着每步计数 2 或 4 次,这可能很难处理。在这种情况下,可以从转换表中删除不必要的转换。由于计数条件减少,因此使用比较/分支指令跳过比使用表转换更好。如果您使用慢速拨盘,则几百到 1kHz 的采样率是合适的。 u_char CMD; /* 按键命令 */ 无效样本编码器() { 静态 u_char i; /* 索引 */ i = (i << 2) + (PA.PIN.BYTE & 3); /* 使用先前值和当前值作为索引 */ 我 &= 15; switch (i) { /* 假设制动位置为“0” */ 情况 0x7: /* 1→3 */ CMD = 前进;中断; 情况 0xd: /* 3→1 */ CMD = 向后;中断; } }