搜索
bottom↓
回复: 51

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

  [复制链接]

出0入0汤圆

发表于 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的值)

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出0入0汤圆

发表于 2013-9-10 15:10:04 | 显示全部楼层
收藏了。不过我还是倾向用中断来做。

出0入0汤圆

 楼主| 发表于 2013-9-10 16:00:04 | 显示全部楼层
无级电工 发表于 2013-9-10 15:10
收藏了。不过我还是倾向用中断来做。

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

出0入0汤圆

发表于 2013-9-10 18:04:01 | 显示全部楼层
就怕你发送太快,接收不过来阿

出0入0汤圆

发表于 2013-9-10 18:53:43 | 显示全部楼层
机器人天空 发表于 2013-9-10 16:00
当编码器旋转的太快时用中断会不会漏检

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

出0入0汤圆

发表于 2013-9-10 19:29:13 | 显示全部楼层
速度,,,,一般的51,在12M下,,,,会漏检的,

出0入0汤圆

发表于 2013-9-10 19:36:39 | 显示全部楼层
这种机械编码器,能有多快?小白,轻拍

出0入0汤圆

发表于 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.

出0入84汤圆

发表于 2013-9-10 20:21:00 | 显示全部楼层
jz701209李 发表于 2013-9-10 19:36
这种机械编码器,能有多快?小白,轻拍

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

出0入84汤圆

发表于 2013-9-10 20:24:06 | 显示全部楼层
编码器的极限一般我设定为40圈/s,就这样也会丢数据,当然,我用的四分频的,打算想办法设定成60圈/S的

出0入0汤圆

发表于 2013-9-10 20:33:56 | 显示全部楼层
czzhouyun 发表于 2013-9-10 20:21
一般工程使用以500脉冲为例,以每秒20圈来说就是10000个脉冲每秒,要分辨方向就必须读两根线,每根线都有 ...

了解啦,谢谢

出0入0汤圆

发表于 2013-9-10 23:18:02 | 显示全部楼层
好好学一下

出0入0汤圆

发表于 2013-9-11 00:00:55 | 显示全部楼层
好好学一下

出0入0汤圆

发表于 2013-9-11 00:15:36 | 显示全部楼层
工作遇到编码器 输出最高大200KHZ的脉冲 的

出0入0汤圆

发表于 2013-9-18 18:15:17 | 显示全部楼层
顶下啊啊啊啊啊

出0入0汤圆

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

出0入0汤圆

发表于 2013-9-24 00:10:13 | 显示全部楼层
czzhouyun 发表于 2013-9-10 20:21
一般工程使用以500脉冲为例,以每秒20圈来说就是10000个脉冲每秒,要分辨方向就必须读两根线,每根线都有 ...

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

出0入0汤圆

发表于 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.

出0入0汤圆

发表于 2013-9-24 07:31:14 来自手机 | 显示全部楼层
学习了,谢谢楼主

出0入84汤圆

发表于 2013-9-24 07:59:20 | 显示全部楼层
kmani 发表于 2013-9-24 00:10
编码器专用芯片贵不贵呢?

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

出0入0汤圆

发表于 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.

出0入0汤圆

发表于 2013-9-24 08:49:24 | 显示全部楼层
CPLD啊,就学了点皮毛,不懂

出0入0汤圆

发表于 2013-9-24 11:25:43 | 显示全部楼层
本帖最后由 kmani 于 2013-9-24 11:26 编辑
czzhouyun 发表于 2013-9-24 07:59
很贵,没什么性价比,相同功能用CPLD一样实现,而且估计都是停产的芯片


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

出0入0汤圆

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

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

出0入0汤圆

发表于 2013-9-24 11:32:46 | 显示全部楼层
kmani 发表于 2013-9-24 00:10
编码器专用芯片贵不贵呢?

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

出0入0汤圆

发表于 2013-9-24 13:12:01 | 显示全部楼层
学习,谢谢!!!

出0入0汤圆

发表于 2013-9-25 12:09:28 | 显示全部楼层
andy2003hunan 发表于 2013-9-24 11:30
确实,我弄的程序,转得慢没问题,转快了就有问题了

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

出0入0汤圆

发表于 2013-9-25 12:21:37 | 显示全部楼层
学习学习

出0入0汤圆

发表于 2013-9-25 16:19:24 | 显示全部楼层
xiaobendan001 发表于 2013-9-25 12:09
所以,要根据设备要求的精度,运行速度等参数综合考虑用多少分辨率的编码器 ...

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

出0入0汤圆

发表于 2013-9-25 17:07:45 | 显示全部楼层
andy2003hunan 发表于 2013-9-25 16:19
倒没有注意这个参数。一般车载影音的用多少分辨率的啊?

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

出110入8汤圆

发表于 2013-9-25 18:52:53 | 显示全部楼层
分辨率高了的编码开关贵的很,若真须用到那就用单独用个便宜的STM8S的MCU加施密特触发整形就可以了,用不了那么先进的CPLD了吧!

出0入0汤圆

发表于 2013-9-25 19:01:51 | 显示全部楼层
无衣师伊 发表于 2013-9-24 00:01
我也考虑了很久.用单片机做确实很吃力
有些客户会接上1600线的编码器.单片机根本跟不上.
一开始我用的是:1 ...

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

出0入0汤圆

发表于 2013-10-16 20:43:08 | 显示全部楼层
这里说的编码器就是一键飞梭,并不是脉冲编码器,不会太快的。

出0入24汤圆

发表于 2013-10-18 19:34:54 | 显示全部楼层
学习之,感谢楼主思路

出0入0汤圆

发表于 2013-10-19 03:02:47 | 显示全部楼层
学习了!!!

出0入0汤圆

 楼主| 发表于 2013-10-19 08:29:36 | 显示全部楼层
mcu-avr 发表于 2013-10-16 20:43
这里说的编码器就是一键飞梭,并不是脉冲编码器,不会太快的。

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

出0入0汤圆

发表于 2013-10-19 14:43:08 | 显示全部楼层
楼主的程序到是没有什么逻辑问题,但怎么考虑“防抖”的?如果“防抖”处理的到位也可以抗干扰。
不知道你是怎么处理“防抖”的?

出0入0汤圆

发表于 2013-10-26 21:42:59 | 显示全部楼层
楼主的程序没有做防抖处理, 机械编码器会出问题的.

出0入0汤圆

发表于 2013-10-27 00:15:14 | 显示全部楼层
czzhouyun 发表于 2013-9-10 20:21
一般工程使用以500脉冲为例,以每秒20圈来说就是10000个脉冲每秒,要分辨方向就必须读两根线,每根线都有 ...

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

出0入0汤圆

发表于 2014-11-13 13:40:24 | 显示全部楼层
学习,谢谢分享!

出0入0汤圆

发表于 2014-11-25 23:25:57 | 显示全部楼层
学习了,做个记号

出0入4汤圆

发表于 2014-12-16 22:29:53 | 显示全部楼层
有个疑惑,是不是用PLC的高速计数器可以不漏检?是不是因为PLC的扫描速度更快,还是因为PLC内部的固件程序设计的巧妙?

出0入0汤圆

发表于 2015-2-5 09:44:17 | 显示全部楼层
有没有关于编码开关的精华贴啊

出0入0汤圆

发表于 2015-2-5 10:33:21 | 显示全部楼层
中断+扫描

出0入0汤圆

 楼主| 发表于 2015-2-5 11:03:45 | 显示全部楼层

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

出0入0汤圆

发表于 2015-3-16 22:31:19 | 显示全部楼层
收藏,谢谢

出0入0汤圆

发表于 2015-3-16 22:32:28 | 显示全部楼层
xiaobendan001 发表于 2013-9-10 18:53
不管中断还是扫描,信号太快都会漏的。
实际上中断能适应更高的频率
我一般这样,一个信号用中断,一个用 ...

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

出0入0汤圆

发表于 2015-3-18 17:13:25 | 显示全部楼层
这个有技术含量

出0入0汤圆

发表于 2015-3-19 19:57:28 | 显示全部楼层
make,手里正好有编码器,有时间试一试

出0入0汤圆

发表于 2015-3-24 09:12:39 | 显示全部楼层
用过1800线的,精密计数用,其实也不用CPLD
提供个简单替代CPLD方案,老产品用的。
用52单片机的T2口增减计数,配个双稳态,加减计数无忧虑,高速光脉冲廉价方案

出0入0汤圆

发表于 2017-8-3 18:03:31 | 显示全部楼层
mark!!!!!

出0入34汤圆

发表于 2017-8-9 14:30:51 | 显示全部楼层
这旋转编码器我在近十年前也有用 5ms 中断方式写了个带飞梭加速并带其机械式容易发生错误讯号的旋转编码器可揪其错误的小小程序在公司的产品上使用。
程序虽然小,但是在于飞梭加速换档的处理上却搞了许久,因为要找了其他国外类似有带飞梭加速的产品一起来进行比对,除此之外...
我还找了公司内长官近十人测试其操作的手感不同而一直修正了一个多月才搞定。最后终于知道程序易搞,而〔人〕才是其中最难搞的!哈哈~
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-6-16 01:45

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表