机器人天空 发表于 2013-9-10 14:29:24

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

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的值)

无级电工 发表于 2013-9-10 15:10:04

收藏了。不过我还是倾向用中断来做。

机器人天空 发表于 2013-9-10 16:00:04

无级电工 发表于 2013-9-10 15:10 static/image/common/back.gif
收藏了。不过我还是倾向用中断来做。

当编码器旋转的太快时用中断会不会漏检

qiaoqiang 发表于 2013-9-10 18:04:01

就怕你发送太快,接收不过来阿

xiaobendan001 发表于 2013-9-10 18:53:43

机器人天空 发表于 2013-9-10 16:00 static/image/common/back.gif
当编码器旋转的太快时用中断会不会漏检

不管中断还是扫描,信号太快都会漏的。
实际上中断能适应更高的频率
我一般这样,一个信号用中断,一个用IO,中断里面检测IO状态,高电平加一,低电平减一,但是抗干扰始终是问题。

jetli 发表于 2013-9-10 19:29:13

速度,,,,一般的51,在12M下,,,,会漏检的,{:sweat:}

jz701209李 发表于 2013-9-10 19:36:39

这种机械编码器,能有多快?小白,轻拍

millwood0 发表于 2013-9-10 20:06:31

"                     if (PINA==1) WheelNow=WheelNow+1;  // 读 PINA"

Good concept and bad implementation.

You could have used a 4-bit array to reduce it down to a couple lines.

I posted a version of it a few years ago.

czzhouyun 发表于 2013-9-10 20:21:00

jz701209李 发表于 2013-9-10 19:36 static/image/common/back.gif
这种机械编码器,能有多快?小白,轻拍

一般工程使用以500脉冲为例,以每秒20圈来说就是10000个脉冲每秒,要分辨方向就必须读两根线,每根线都有10000个脉冲,也就是说如果两根线都是接入中断的那么一次中断周期就是50us,如果是四倍频则是25us进一次中断,如果用指令周期为1us的单片机来说,只要你有足够的技巧处理25us中断一次的数据,那么普通的读编码器就没有问题,关键的问题是很多时候加速或刹车的时候转动速度会超过20圈每秒,表现的现象是重复几次相同位置的数据总在变化,加一或减一,误差在不断累计,或者电路的不稳定,有干扰,停在那数字在不断变化,其实编码器在临界点上不断地颤动,一般工程应用不提倡使用IO口直接读写,而使用CPLD或编码器专用芯片,要不然产生的问题会一直无法解决

czzhouyun 发表于 2013-9-10 20:24:06

编码器的极限一般我设定为40圈/s,就这样也会丢数据,当然,我用的四分频的,打算想办法设定成60圈/S的

jz701209李 发表于 2013-9-10 20:33:56

czzhouyun 发表于 2013-9-10 20:21 static/image/common/back.gif
一般工程使用以500脉冲为例,以每秒20圈来说就是10000个脉冲每秒,要分辨方向就必须读两根线,每根线都有 ...

了解啦,谢谢

dtdzlujian 发表于 2013-9-10 23:18:02

好好学一下

mdj-fish 发表于 2013-9-11 00:00:55

好好学一下

281229961 发表于 2013-9-11 00:15:36

工作遇到编码器 输出最高大200KHZ的脉冲 的

Pao_fu 发表于 2013-9-18 18:15:17

顶下啊啊啊啊啊

无衣师伊 发表于 2013-9-24 00:01:53

我也考虑了很久.用单片机做确实很吃力
有些客户会接上1600线的编码器.单片机根本跟不上.
一开始我用的是:1个中断+IO.STM8/16M,效果很好.
查了百度文献之后发现原来可以做到2倍频的.中断变成上升+下降中断.
之后我浏览别人的产品.发现人家都说4倍频。再查资料才发现人家是2个中断.每个中断都说上升+下降中断.就4倍频了
用单片机做出4倍频确实很吃力。毕竟单片机还要做其他事情.通信或读IIC等等
想了很久.折中点的方案是双核.2个单片机.
一个单片机只负责编码器计数.另一个单片机就读.但这个方案要是遇到1600线四倍频.那就完蛋了.
现在真正尝试CPLD+MCU。

kmani 发表于 2013-9-24 00:10:13

czzhouyun 发表于 2013-9-10 20:21 static/image/common/back.gif
一般工程使用以500脉冲为例,以每秒20圈来说就是10000个脉冲每秒,要分辨方向就必须读两根线,每根线都有 ...

编码器专用芯片贵不贵呢?

millwood0 发表于 2013-9-24 04:55:50

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

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

Right thought process. Terrible implementation.

What you have done is to suggest that if you receive a 4-bit sequency 0110 you should return +1; for 1001 you should return -1 and others you should return 0 indicating invalid pulse.

That can be done with a couple statements + a look-up array in C. No "if" statements at all.

jiaoyi 发表于 2013-9-24 07:31:14

学习了,谢谢楼主

czzhouyun 发表于 2013-9-24 07:59:20

kmani 发表于 2013-9-24 00:10 static/image/common/back.gif
编码器专用芯片贵不贵呢?

很贵,没什么性价比,相同功能用CPLD一样实现,而且估计都是停产的芯片

millwood0 发表于 2013-9-24 08:33:32

这种机械编码器,能有多快?

30 rpm tops (1/2 turn per second). A mcu can easily process 10x of that, assuming the encoder doesn't break.

xiaobendan001 发表于 2013-9-24 08:49:24

CPLD啊,就学了点皮毛,不懂

kmani 发表于 2013-9-24 11:25:43

本帖最后由 kmani 于 2013-9-24 11:26 编辑

czzhouyun 发表于 2013-9-24 07:59 static/image/common/back.gif
很贵,没什么性价比,相同功能用CPLD一样实现,而且估计都是停产的芯片

CPLD每秒钟最多能接受并处理多少个脉冲呢? 能达到200KHz吗?
对了,CPLD是不是可以同时接几个编码器呢?
常用的CPLD是A家的还是X家的呢?
先谢了。

andy2003hunan 发表于 2013-9-24 11:30:54

xiaobendan001 发表于 2013-9-10 18:53 static/image/common/back.gif
不管中断还是扫描,信号太快都会漏的。
实际上中断能适应更高的频率
我一般这样,一个信号用中断,一个用 ...

确实,我弄的程序,转得慢没问题,转快了就有问题了

andy2003hunan 发表于 2013-9-24 11:32:46

kmani 发表于 2013-9-24 00:10 static/image/common/back.gif
编码器专用芯片贵不贵呢?

这个没有必要用专用芯片吧

dory_m 发表于 2013-9-24 13:12:01

学习,谢谢!!!

xiaobendan001 发表于 2013-9-25 12:09:28

andy2003hunan 发表于 2013-9-24 11:30 static/image/common/back.gif
确实,我弄的程序,转得慢没问题,转快了就有问题了

所以,要根据设备要求的精度,运行速度等参数综合考虑用多少分辨率的编码器

lixiaowei0129 发表于 2013-9-25 12:21:37

学习学习

andy2003hunan 发表于 2013-9-25 16:19:24

xiaobendan001 发表于 2013-9-25 12:09 static/image/common/back.gif
所以,要根据设备要求的精度,运行速度等参数综合考虑用多少分辨率的编码器 ...

倒没有注意这个参数。一般车载影音的用多少分辨率的啊?

xiaobendan001 发表于 2013-9-25 17:07:45

andy2003hunan 发表于 2013-9-25 16:19 static/image/common/back.gif
倒没有注意这个参数。一般车载影音的用多少分辨率的啊?

你说的是那种类似电位器的东西了,这个速度很低,分辨率也低,一般的单片机都够用了吧。
他们说的是那种比较大的光电的或者霍尔的那种分辨率很高的例如2000线的,就是转一圈有2000个脉冲的那种,这样的东西当转动又比较快时,输出频率是非常高的,通常设计机器时要考虑采用哪种,或者你来帮客户选定型号。

angler12 发表于 2013-9-25 18:52:53

分辨率高了的编码开关贵的很,若真须用到那就用单独用个便宜的STM8S的MCU加施密特触发整形就可以了,用不了那么先进的CPLD了吧!

jetli 发表于 2013-9-25 19:01:51

无衣师伊 发表于 2013-9-24 00:01 static/image/common/back.gif
我也考虑了很久.用单片机做确实很吃力
有些客户会接上1600线的编码器.单片机根本跟不上.
一开始我用的是:1 ...

记得,流明 的M0有 正交编码器输入口,专用的

mcu-avr 发表于 2013-10-16 20:43:08

这里说的编码器就是一键飞梭,并不是脉冲编码器,不会太快的。

ycwjl728 发表于 2013-10-18 19:34:54

学习之,感谢楼主思路

bosia仔 发表于 2013-10-19 03:02:47

学习了!!!

机器人天空 发表于 2013-10-19 08:29:36

mcu-avr 发表于 2013-10-16 20:43 static/image/common/back.gif
这里说的编码器就是一键飞梭,并不是脉冲编码器,不会太快的。

是的,到目前为止这个程序还没出过问题

mcu-avr 发表于 2013-10-19 14:43:08

楼主的程序到是没有什么逻辑问题,但怎么考虑“防抖”的?如果“防抖”处理的到位也可以抗干扰。
不知道你是怎么处理“防抖”的?

caihui315 发表于 2013-10-26 21:42:59

楼主的程序没有做防抖处理, 机械编码器会出问题的.

cityfuture 发表于 2013-10-27 00:15:14

czzhouyun 发表于 2013-9-10 20:21 static/image/common/back.gif
一般工程使用以500脉冲为例,以每秒20圈来说就是10000个脉冲每秒,要分辨方向就必须读两根线,每根线都有 ...

有哪些读取编码器的专用芯片呢

ZYBing 发表于 2014-11-13 13:40:24

学习,谢谢分享!

powerxia 发表于 2014-11-25 23:25:57

学习了,做个记号

thepresent 发表于 2014-12-16 22:29:53

有个疑惑,是不是用PLC的高速计数器可以不漏检?是不是因为PLC的扫描速度更快,还是因为PLC内部的固件程序设计的巧妙?

fbestwish1 发表于 2015-2-5 09:44:17

有没有关于编码开关的精华贴啊

dgdzas 发表于 2015-2-5 10:33:21

中断+扫描

机器人天空 发表于 2015-2-5 11:03:45

dgdzas 发表于 2015-2-5 10:33
中断+扫描

其实我这种方法并可取,需要cpu每隔1ms不断的扫描,导致占用cpu带宽。
用外部中断就比较好{:lol:}

1125526801 发表于 2015-3-16 22:31:19

收藏,谢谢

1125526801 发表于 2015-3-16 22:32:28

xiaobendan001 发表于 2013-9-10 18:53
不管中断还是扫描,信号太快都会漏的。
实际上中断能适应更高的频率
我一般这样,一个信号用中断,一个用 ...

用中断,我也遇到这个问题

dgbin 发表于 2015-3-18 17:13:25

这个有技术含量

wtiechen1969 发表于 2015-3-19 19:57:28

make,手里正好有编码器,有时间试一试

add00 发表于 2015-3-24 09:12:39

用过1800线的,精密计数用,其实也不用CPLD
提供个简单替代CPLD方案,老产品用的。
用52单片机的T2口增减计数,配个双稳态,加减计数无忧虑,高速光脉冲廉价方案

tiantang46800 发表于 2017-8-3 18:03:31

mark!!!!!

xyz543 发表于 2017-8-9 14:30:51

这旋转编码器我在近十年前也有用 5ms 中断方式写了个带飞梭加速并带其机械式容易发生错误讯号的旋转编码器可揪其错误的小小程序在公司的产品上使用。
程序虽然小,但是在于飞梭加速换档的处理上却搞了许久,因为要找了其他国外类似有带飞梭加速的产品一起来进行比对,除此之外...
我还找了公司内长官近十人测试其操作的手感不同而一直修正了一个多月才搞定。最后终于知道程序易搞,而〔人〕才是其中最难搞的!哈哈~ {:biggrin:}
页: [1]
查看完整版本: 机械式旋转编码器解码程序