机械式旋转编码器解码程序

2020-01-15 19:20发布

1. 算法介绍: 解码程序共处理四种状态,分别是:



a.两条线都是高电平时表示编码器无动作,退出.
                                                      
b.先检测测的两条线是01,后检测两条线是10时为正转.
                                                      
c.先检测测的两条线是10,后检测两条线是01时为反转.

d.两条线都是低电平时退出,不处理低电平区.

(两个状态为一个周期,如正转时,先保存旧值01,然后检测新值为10时就为一个成功检测周期. )



使用时请先定义好两个IO口 PINA,PINB,和一个周期数cycle,这两个脚可以是任意两个IO脚,cycle 是指编码器旋转多少格(多少周期)动作一次,一般设置为 1 或 2 .该函数返回三个值,返回0时编码器没有动作,返回1时为正转,返回2时为反转,如果在使用时正反转颠倒,可以交换两个IO口的定义. 不管编码器有无动作该函数都会返回一个值!!!!!!!!!!





//========================================================================================
                    
                  #include<reg52.h>
                  typedef unsigned char uchar;
                  sbit PINA   =   P2^2;  //定义IO
                  sbit PINB   =   P2^3;
                  #define cycle       1           //定义动作周期,编码器旋转多少格有效
                  #define NULL       0          //定义编码器不动作时的还回值
                  #define E_RIGHT     0x0e        //定义右旋转还回值
                  #define E_LEFT      0x0f        //定义左旋转还回值
                  uchar WheelNow,WheelOld,RightCount,LeftCount,num;
//========================================================================================
                  uchar WheelRight()
                  {
                      LeftCount=0;
                      RightCount++;
                      if (RightCount>=cycle){
                          RightCount=0;
                          return(E_RIGHT);
                      }  else return(NULL);
                  }
//========================================================================================
                  uchar WheelLeft()
                  {
                      RightCount=0;
                      LeftCount++;
                      if (LeftCount>=cycle){
                          LeftCount=0;
                          return(E_LEFT);
                      } else return(NULL);
                  }
//========================================================================================
                  uchar EncoderProcess()
                  {
                      uchar keytmp;
                      PINA = 1;
                      PINB = 1;
                      WheelNow=WheelNow<<1;
                      if (PINA==1) WheelNow=WheelNow+1;  // 读 PINA
                      WheelNow=WheelNow<<1;
                      if (PINB==1) WheelNow=WheelNow+1;  // 读 PINB
                      WheelNow=WheelNow & 0x03;   // 将 WheelNow 的 2 - 7 位清零,保留 0- 1 两个位的状态.
                      if (WheelNow==0x00) return(NULL); //当  PINA 和 PINB都为低电平时退出,低电平区不做处理
                      keytmp=WheelNow;
                      keytmp ^=WheelOld; // 判断新读的数据同旧数据
                      if (keytmp==0) return(NULL); // 新读的数据同旧数据一样时退出.
                     
                      if (WheelOld==0x01 && WheelNow==0x02){ // 是左旋转否
                              WheelOld=WheelNow;
                              return(WheelLeft()); //左旋转
                          }
                      else if (WheelOld==0x02 && WheelNow==0x01){ // 是右旋转否
                              WheelOld=WheelNow;
                              return(WheelRight()); //右旋转
                      }
                      WheelOld=WheelNow; // 保存当前值
                      return(NULL); // 当  PINA 和 PINB 都为高电平时表示编码器没有动作,退出
                  }
//========================================================================================
                  void inc()
                  {
                      num++;   
                      if (num > 99){
                          num=0;
                      }
                  } // 在此处设置断点看 num 加的变化
//========================================================================================
                  void dec()
                  {
                      num--;
                      if (num > 99){
                          num=99;
                      }  
                  } // 在此处设置断点看 num 减的变化
//========================================================================================
                  void main()
                  {
                      while (1){
                          switch(EncoderProcess()){
                              case E_RIGHT:  inc(); break;
                              case E_LEFT:   dec(); break;
                          }
                      }
                  }
//========================================================================================

(注:使用定时器每隔1ms读取此函数时,不管编码器转多块也不会丢失num的值)

友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
52条回答
add00
1楼-- · 2020-01-21 19:54
用过1800线的,精密计数用,其实也不用CPLD
提供个简单替代CPLD方案,老产品用的。
用52单片机的T2口增减计数,配个双稳态,加减计数无忧虑,高速光脉冲廉价方案
tiantang46800
2楼-- · 2020-01-21 21:46
 精彩回答 2  元偷偷看……
xyz543
3楼-- · 2020-01-22 02:24
这旋转编码器我在近十年前也有用 5ms 中断方式写了个带飞梭加速并带其机械式容易发生错误讯号的旋转编码器可揪其错误的小小程序在公司的产品上使用。
程序虽然小,但是在于飞梭加速换档的处理上却搞了许久,因为要找了其他国外类似有带飞梭加速的产品一起来进行比对,除此之外...
我还找了公司内长官近十人测试其操作的手感不同而一直修正了一个多月才搞定。最后终于知道程序易搞,而〔人〕才是其中最难搞的!哈哈~
wctmdgcd
4楼-- · 2020-01-22 05:06
非常好用,谢谢LZ。

一周热门 更多>