旋转编码器解码的工作原理与应用源码

[复制链接]
查看1581 | 回复0 | 2011-5-2 21:59:00 | 显示全部楼层 |阅读模式
旋转编码器的信号输出有A相,B相,Z相,其中Z为零脉冲,计数模块中不使用。计数模块使用A,B来进行计数。编码器结构以及计数原理如下: 结构:玻璃码盘,上排为A,下排为B,灰色的不透光,白色的透光。 编码器转动后经过码盘和光电二极管的作用可以得到如下的波形: 上图为编码器的工作原理,图中A相超前B相90度,如果转动方向相反,则A相滞后B相90度。B_A为B&A的组合,若A相超前B相90度设定为正向旋转,则编码器正向转动一个码的距离,B_A变化过程为01-11-10-00。 根据这个原理计数模块根据B_A变化过程来计数: 若当前B_A为00状态,下一个状态为01则计数器加1。 若当前B_A为00状态,下一个状态为10则计数器减1。 其余状态不符合编码器的工作原理,计数器的值不变。 此时计数器的结果是编码器实际移动一个码距离的4倍。由于编码器加工精度的原因,这个结果与实际的位置相比,不是非常准确。 通常的增量式光电编码器产生的周期性的方波信号理论的占空比是1:1,即50%。但是由于码盘加工精度,安装精度等原因的影响,在编码器匀速转动时产生信号的占空比不是1:1,是40%-60%,即信号占空比的误差是10%。 但是其信号的周期误差,即高电平与低电平时间总和的误差比较小,为1%。所以通常用编码器信号测量速度应该测量信号的整个周期来计算,这样测量的误差才较小。 只有把计数结果右移两位(除以4),得到的结果才是准确的编码器移动一个码的距离。 /*旋转编码器解码程序 PC4,PC5为左右输入,内部上拉,公共脚接地。 1ms调用一次 //修改: */ #define Knob_In_PIN PINC #define Knob_In_PORT PORTC #define Knob_In_DDR DDRC #define Knob_In_L PC4 #define Knob_In_R PC5 //输出结果:0不动作;1左转一格;2右转一格。 enum direct {STOP,LEFT,RIGHT}D_OUT; const unsigned char direct_left[5] PROGMEM ={3,2,0,1,3}; const unsigned char direct_right[5] PROGMEM ={3,1,0,2,3}; //初始化。 void Knob_Init(void) { Knob_In_DDR &= ~((1<<Knob_In_L)|(1<<Knob_In_R)); //输入 Knob_In_PORT |=(1<<Knob_In_L)|(1<<Knob_In_R); //上拉 } //编码器解码 void knob_scan(void) { unsigned char knob_ary[3]; unsigned char knob_count; unsigned char knob_value; bit knob_update; knob_value = Knob_In_PIN&((1<<Knob_In_L)|(1<<Knob_In_R)); //取端口C管脚信号 knob_value =knob_value>>4; if(knob_value==knob_ary[0]) { ++knob_count; if(knob_count==1) { knob_ary[2]=knob_ary[1]; knob_ary[1]=knob_ary[0]; update=1; } if(knob_count==0xff) //停留,不转动。 { knob_count=2; } } else { knob_ary[0]=knob_value; knob_count=0; } //如果转动产生新数据,判断方向。 //左转为 11 10 00 01 11 3 2 0 1 3 //右转为 11 01 00 10 11 3 1 0 2 3 if(update) { update=0; for(i=0;i<4;i++) { if((knob_ary[2]==pgm_read_byte(direct_left+i))&&(knob_ary[1]==pgm_read_byte(direct_left+i+1))) { D_OUT=LEFT; } else if((knob_ary[2]==pgm_read_byte(direct_right+i))&&(knob_ary[1]==pgm_read_byte(direct_right+i+1))) { D_OUT=RIGHT; } else D_OUT=STOP; } } }
您需要登录后才可以回帖 登录 | 注册哦

本版积分规则