正交编码器一般指的是增量式光栅(磁栅)编码器,通常有三路输出信号,A相、B相、Z相,俗称ABZ编码器。所谓正交,即是A相信号和B相信号相位相差90°,根据AB相位的前后,即可判断旋转机构正转还是反转。Z相信号,是旋转一圈后输出的信号,也称为零点信号。
一般情况下使用专门的编码器接口,即是支持正交计数的定时器,由CPU硬件上实现脉冲计数和方向判断,用户只需从定时器寄存器获取脉冲计数和方向,相比使用GPIO模拟效率和精度高。定时器接口还支持边缘采集,可以实现2倍频、4倍频信号;例如5000线编码器,通过4倍频后,单圈实现20000脉冲,最低识别精度为360/20000°。
正交编码器接口定时器计数,与定时器位数密切关联;通常定时器有8位、6位、32位;目前主流ARM处理定时器以16位为主,高端处理器支持32位。对于8位计数器,溢出大小为2^8=255;16位计数器溢出大小为2 ^16=65535;32位计数器溢出大小为2 ^32=4294967294。
以50000线编码为例,经过4倍频后,单圈为20000脉冲;如果是8位计数器,单圈则溢出78次;16位计数器,3圈后溢出。对于高速场景,是不允许的。
以主流16位定时器为例,分别实现以上两个方式溢出处理。
如果速度不高,或者中断频率容忍度在设计范围,不影响其他任务的正常执行,则可以开启溢出中断,增加一个圈数计算变量,实现起来是非常方便的。实现步骤如下:
伪代码
int64_t count = 0;/* init encoder timer *//* reset encoder timer count *//* IRQ handler */
void irq_handler(void)
{if (direct == CCW){count--;}else{count++;}
}/* read real pos */
int64_t read_real_pos(void)
{int64_t pos= 0;temp = count*(2^16 + 1) + (int64_t)__HAL_TIM_GET_COUNTER(&timer);return pos;
}
注意有符号数运算,初始值为0;正转时易于理解。对于反正:初始值计数为0,翻转值65530,产生溢出中断一次,实际值为-36636+65530=-6。
对于高速场景,高频中断占用大量CPU资源,导致其他任务未能及时执行,这是不允许的。定时器计数溢出后归零,在未开启溢出中断时,用户无法感知溢出多少次。因此,我们只需保证处理周期内最多允许一次溢出,处理周期依赖于实际软件复杂度、编码器线数、最大转速。先上伪代码。
#define MAX_COUNT (50000*4)
#define TURN_COUNT (MAX_COUNT/2) int64_t pos_fun(void)
{static int64_t last_pos = 0;int64_t temp_pos = 0;int64_t real_pos = 0;int64_t current_pos = timer_read_pos();temp_pos = current_pos - last_pos;if (temp_pos >= MAX_COUNT){temp_pos -= TURN_COUNT;}else if (temp_pos < -MAX_COUNT){temp_pos += TURN_COUNT;}last_pos = current_pos;real_pos += temp_pos;return real_pos;
}
实现原理:
MAX_COUNT
为单圈计数值TURN_COUNT
为一个计算临界值,通常取单圈数值的一半实质上,该方式也适用于一些绝对式编码器场景;如单圈绝对式编码器,该类编码器以数字接口(SSI、CAN、BISS、并口)输出位置信息,最大支持记录一圈的绝对位置,超出单圈位置后归零。