搜索
bottom↓
回复: 49

增量式光电编码器 正交编码器四倍频电路的单片机高速算法

  [复制链接]

出0入0汤圆

发表于 2014-8-11 02:14:02 | 显示全部楼层 |阅读模式
增量式光电编码器 正交编码器四倍频电路的单片机高速算法:

参考资料:
http://wenku.baidu.com/link?url=GfdZzz1yE-KdLzFHjhYgNDxoAeLPtYlPUcMLl-41ekndlTDaGIlC7MpPVQhuxD-mxxDTEwVmh7_WhQmT_kvE13Dyrxe1XFoBLo_i9ZCGPEu

单片机: STM32F103

  1. u8 MotorX_EncoderStore;  //状态储存变量
  2. void MotorX_phase_check(void) // 编码器
  3. {
  4.         u8 Encoder_temp;

  5.         Encoder_temp= MotorX_EncoderStore;   //读出上次保存存数据
  6.         Encoder_temp=(Encoder_temp<<3)|XEnCoderA;         //读A 相状态
  7.         Encoder_temp=(Encoder_temp<<1)|XEnCoderB;  //读B相状态 ,组成低2位,合成4位状态数据
  8.         switch(Encoder_temp)
  9.         {
  10.                 case 1:  //00 01
  11.                                         MotorX_CounterEncoder--; //编码计数器自减
  12.                                 break;
  13.                
  14.                 case 2:  //00 10
  15.                                         MotorX_CounterEncoder++;//编码计数器自加
  16.                                 break;        
  17.                
  18.                 case 4:  //01 00
  19.                                         MotorX_CounterEncoder++;
  20.                                 break;        
  21.                
  22.                 case 7:  //01 11
  23.                                         MotorX_CounterEncoder--;//编码计数器自减
  24.                                 break;               
  25.                 case 8:  //10 00
  26.                                         MotorX_CounterEncoder--;
  27.                                 break;               
  28.                 case 11:  //10 11
  29.                                 MotorX_CounterEncoder++;
  30.                                 break;        
  31.                 case 13:  //11 01
  32.                                 MotorX_CounterEncoder++;
  33.                                 break;                        
  34.                 case 15:  //10 00
  35.                                         MotorX_CounterEncoder--;
  36.                                 break;        
  37.                 default:     //其他状态为错误,或抖动, 计数值不加减
  38.                                 break;        
  39.         }
  40.         MotorX_EncoderStore=(Encoder_temp&0x03);  //保存最后一次AB相位图
  41. }
复制代码


如果有更好的方法, 请高手指导。
当然不能是使用STM32F定时器自带的编码功能的话, 资源不够用才用普通IO口的。

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

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!

出0入0汤圆

发表于 2014-8-11 08:48:46 | 显示全部楼层
本帖最后由 xiaobendan 于 2014-8-11 09:18 编辑

楼主测试过吗?这个好用不?抗抖动性能怎样?
还有,速度怎样?

出0入0汤圆

发表于 2014-8-11 09:27:24 | 显示全部楼层
看那个资料,建立一个数组,char step[] = {0,-1,1,0,,1,0,0,-1,-1,0,0,1,0,1,-1,0},然后直接MotorX_CounterEncoder += step[Encoder_temp];会不会更快一些?

出0入0汤圆

发表于 2014-8-11 09:41:53 | 显示全部楼层
这个程序在正交编码器旋钮上好用, 1000线的编码器用局限很大,例如每秒10圈是600rpm,每个脉冲的周期是0.1ms,这个程序要求至少4倍采样,也就是0.025ms就要读一次IO口,单片机已经不用去干别的了

ps:本坛millwood大师在这个论坛发表过这个方法,我的旋钮一直在用这个序列表方法

出0入0汤圆

 楼主| 发表于 2014-8-12 15:07:44 | 显示全部楼层
本帖最后由 gy54321 于 2014-8-12 15:09 编辑
xiaobendan 发表于 2014-8-11 08:48
楼主测试过吗?这个好用不?抗抖动性能怎样?
还有,速度怎样?


我应该的场合还是挺好,因为脉冲频率不高,  30Hz还不到。 至于抗抖动性还可以。 对于错误的脉冲肯定计不会计数!

出0入0汤圆

 楼主| 发表于 2014-8-12 15:11:27 | 显示全部楼层
xiaobendan 发表于 2014-8-11 09:27
看那个资料,建立一个数组,char step[] = {0,-1,1,0,,1,0,0,-1,-1,0,0,1,0,1,-1,0},然后直接MotorX_Count ...

这个搞抖动性是不强的,会计数出错的

出0入0汤圆

发表于 2014-8-12 15:43:59 | 显示全部楼层
gy54321 发表于 2014-8-12 15:11
这个搞抖动性是不强的,会计数出错的

有什么理由呢?

出0入0汤圆

 楼主| 发表于 2014-8-12 16:09:09 | 显示全部楼层

看链接资料里的波形,  有就是某相一直不变, 另一相一直有脉冲的时候, 这个时候其实是不应该加减计数的, 但是按那个数组的计算来看, 肯定是会做加减计算的。 所以就会出错了。

出0入0汤圆

发表于 2014-8-12 16:31:40 | 显示全部楼层
gy54321 发表于 2014-8-12 16:09
看链接资料里的波形,  有就是某相一直不变, 另一相一直有脉冲的时候, 这个时候其实是不应该加减计数的 ...

char step[] = {0,-1,1,0,,1,0,0,-1,-1,0,0,1,0,1,-1,0},然后直接MotorX_CounterEncoder += step[Encoder_temp];会不会更快一些?
中 0 表示不处理,与楼主的switch 效果是异曲同工的,速度更快一些。

出0入0汤圆

发表于 2014-8-12 23:59:08 | 显示全部楼层
这个方法不错,收藏了。

出0入0汤圆

发表于 2014-8-13 07:39:09 | 显示全部楼层
一相不变,另外一相抖动,有产生加减的话,应该还可以了,只怕是只加不减或者只减不加,就麻烦了。

出0入0汤圆

发表于 2014-8-16 09:55:56 | 显示全部楼层
3DA502 发表于 2014-8-11 09:41
这个程序在正交编码器旋钮上好用, 1000线的编码器用局限很大,例如每秒10圈是600rpm,每个脉冲的周期是0.1 ...

能给出本坛millwood大师 连接吗  我没有搜索到

出0入0汤圆

 楼主| 发表于 2014-8-20 01:45:06 | 显示全部楼层
xiaobendan 发表于 2014-8-11 09:27
看那个资料,建立一个数组,char step[] = {0,-1,1,0,,1,0,0,-1,-1,0,0,1,0,1,-1,0},然后直接MotorX_Count ...

仔细看了一下, 你的这个写法效果的确是一样的,

出0入0汤圆

发表于 2014-8-21 08:31:45 | 显示全部楼层
这个方法是挺有意思的,有空试试速度如何

出0入0汤圆

发表于 2014-8-21 08:35:35 来自手机 | 显示全部楼层
学习        

出0入0汤圆

发表于 2014-8-21 09:02:58 | 显示全部楼层
涨知识了,谢谢……

出0入0汤圆

发表于 2014-8-22 11:29:32 | 显示全部楼层
再问一下,这种方式如何加入信号异常检测,从而判断编码器是否损坏?

出0入0汤圆

发表于 2014-8-23 00:45:49 | 显示全部楼层
MARK收藏了哈

出0入0汤圆

发表于 2014-10-2 14:24:57 | 显示全部楼层
初步测试了一下,代码如下
  1. static uchar temp;
  2. temp <<= 2;
  3. if(IO_A)temp += 2;
  4. if(IO_B)temp += 1;
  5. switch(temp&0x0f){
  6.         case 2:case 4:case 11:case 13:
  7.         jczcd ++;                        //脉冲数增加
  8.         break;
  9.         case 1:case 7:case 8:case 14:
  10.         jczcd --;                //脉冲数减少
  11.         break;
  12.         case 3:case 6:case 9:case 12:
  13.         break;
  14.         }
复制代码

速度还是不错的,在50US的定时中断中调用,还不错的。可以在异常的4中状态下报告错误。
代码简洁,生成的HEX和很节省。
开始的地方的移位操作比较耗时。有没有办法可以更快?

出0入0汤圆

发表于 2014-10-2 15:45:27 | 显示全部楼层
但是当编码器的B损坏时,信号将在2和8之间变化,就是在++和--之间变化,那么实际上可能已经转动了很多,但是数字却没有变化,此时应该怎样报错?
实际情况是某一相甚至两相信号都同时丢失,基本上是输出0,因为输出的三极管击穿的很多。这种情况很多,导致出现很多不合格产品,甚至根本无法工作。
是否可以开个定时器,然后当一段时间发现数字变化小于2时,报警?

出0入4汤圆

发表于 2014-10-3 06:44:59 来自手机 | 显示全部楼层
mark。            

出0入0汤圆

发表于 2016-4-30 14:50:40 | 显示全部楼层
Encoder_temp=(Encoder_temp<<3)|XEnCoderA;         //读A 相状态
应该是Encoder_temp=(Encoder_temp<<1)|XEnCoderA; 向左移1位。

出140入8汤圆

发表于 2016-5-28 10:43:52 | 显示全部楼层
stm32f1自带编码器接口

出0入0汤圆

 楼主| 发表于 2016-6-12 22:28:18 | 显示全部楼层
leiyitan 发表于 2016-5-28 10:43
stm32f1自带编码器接口

那个是要占用一个定时器的。
小项目还好, 大一点的项目定时器太不够用!   

出0入0汤圆

发表于 2017-9-2 10:53:52 | 显示全部楼层
xiaobendan 发表于 2014-10-2 14:24
初步测试了一下,代码如下

速度还是不错的,在50US的定时中断中调用,还不错的。可以在异常的4中状态下报 ...

测试了一下 这个代码   无法去掉 抖动问题  编码器不动  都会一直 ++ 或是 -- ,因为编码器也会有一定的干扰
我设置的定时器是100US  

我觉得编码器 速度快慢 会影响它

出0入0汤圆

发表于 2017-9-2 11:03:31 | 显示全部楼层
wind2100 发表于 2017-9-2 10:53
测试了一下 这个代码   无法去掉 抖动问题  编码器不动  都会一直 ++ 或是 -- ,因为编码器也会有一定的干 ...

干扰频率有多少?
这个代码很好用的

出0入0汤圆

发表于 2017-9-2 11:30:02 | 显示全部楼层
先解释一下 抖动     一个电平不变化 另一个电平变化 不计数   
200US周期   5KHZ  我改成50US中断 一样的效果
我尝试过 上升沿 和下降沿的 办法 也是抖动 会让计数 ++ --
或许是这个磁编码器的正交模式 干扰特大

出0入0汤圆

发表于 2017-9-2 11:30:51 | 显示全部楼层
xiaobendan 发表于 2017-9-2 11:03
干扰频率有多少?
这个代码很好用的

你的应该  速度范围是多少  速度慢 和快 没有影响吧

出0入85汤圆

发表于 2017-9-2 11:33:53 | 显示全部楼层
一直没搞明白如果是单纯的靠MCU倍频,这样做的目的是啥?编码器本质的分辨率没变,单靠MCU倍频能提高控制分辨率吗?

出0入0汤圆

发表于 2017-9-2 16:19:31 | 显示全部楼层
marshallemon 发表于 2017-9-2 11:33
一直没搞明白如果是单纯的靠MCU倍频,这样做的目的是啥?编码器本质的分辨率没变,单靠MCU倍频能提高控制分 ...

是编码器AB相输出信号处理后产生4倍频脉冲

出0入85汤圆

发表于 2017-9-2 22:16:41 | 显示全部楼层
zaldy30 发表于 2017-9-2 16:19
是编码器AB相输出信号处理后产生4倍频脉冲

是的,但这样作的目的是啥?这个能提高分辨率?有点想不通啊,编码器本身的分辨率都没变,倍频后会改善分辨率?

出0入0汤圆

发表于 2017-9-2 23:39:11 | 显示全部楼层
marshallemon 发表于 2017-9-2 22:16
是的,但这样作的目的是啥?这个能提高分辨率?有点想不通啊,编码器本身的分辨率都没变,倍频后会改善分 ...

N线的正交编码器每圈AB相只能各自输出N个脉冲,外部倍频后每圈脉冲数可以变成2N或者4N个,分辨率提高了

出0入0汤圆

发表于 2017-9-3 08:23:48 | 显示全部楼层
wind2100 发表于 2017-9-2 11:30
你的应该  速度范围是多少  速度慢 和快 没有影响吧

速度太快,当然不行了,比如你500US才读一次IO,你的信号在500US的时间已经变化超过一次了,那你肯定是丢失了正确的你应该得到的信号啊
500US一次,最快就是周期1MS的信号了,就是1000HZ的信号,实际上要略低于这一个频率才行。而且是占空比保证为50%的。
如果你的占空比不是50%,那么占比小的状态的时间一定要超过500US的,这样实际上的频率就到不了1000HZ了,而实际上现在很多编码器尤其是便宜的那些,占空比都不是很理想。
长于这个扫描时间的信号,是可以都被计数的。
四倍频是增加了分辨率了,其实有时候鉴于速度问题,你也可以选择2倍频或者不倍频。
你说的抖动,是很普遍的问题了,因为正交信号在任何一个位置,都至少有一个信号是稳定的,所以才能抗干扰。
比如A处于稳态,B处于临界态,由于转轴或者电磁干扰产生的信号跳动,产生的计数是+1-1+1-1+1-1这样的,就是不会有实际上的数字产生,最多就是一个字的跳动。

出0入85汤圆

发表于 2017-9-3 18:42:28 | 显示全部楼层
zaldy30 发表于 2017-9-2 23:39
N线的正交编码器每圈AB相只能各自输出N个脉冲,外部倍频后每圈脉冲数可以变成2N或者4N个,分辨率提高了 ...

这个明白,但我不明白的是,如果是位置闭环,编码器的本质分辨率没提高,只是单纯的倍频后的分辨率提高了,这样有意义吗?控制精度能提高吗?如果没意义,这倍频的本质目的又是为了啥?

出0入0汤圆

发表于 2017-9-4 00:03:12 | 显示全部楼层
marshallemon 发表于 2017-9-3 18:42
这个明白,但我不明白的是,如果是位置闭环,编码器的本质分辨率没提高,只是单纯的倍频后的分辨率提高了 ...

我的理解是4倍频后的分辨率才是正交编码器的本来分辨率,能提高控制精度

出0入85汤圆

发表于 2017-9-4 11:22:10 | 显示全部楼层
zaldy30 发表于 2017-9-4 00:03
我的理解是4倍频后的分辨率才是正交编码器的本来分辨率,能提高控制精度
...

这个问题我也注意过,我看伺服经过倍频后的 控制分辨率的确是可以提高的,例如编码器时2000线,4倍频后是8000线,控制要求8000线时实际的分辨率7998线;但我比较奇怪的是,理论上编码器输出如果是1999线的话,4倍频后应该是7996才对,怎么会出现7998,难道编码器还能输出小数点?

出10入23汤圆

发表于 2017-9-4 11:24:01 来自手机 | 显示全部楼层
marshallemon 发表于 2017-9-4 11:22
这个问题我也注意过,我看伺服经过倍频后的 控制分辨率的确是可以提高的,例如编码器时2000线,4倍频后是 ...

你看看ab相的波形就知道为什么了

出10入23汤圆

发表于 2017-9-4 11:28:08 来自手机 | 显示全部楼层
marshallemon 发表于 2017-9-4 11:22
这个问题我也注意过,我看伺服经过倍频后的 控制分辨率的确是可以提高的,例如编码器时2000线,4倍频后是 ...

传统的编码器计数方式是只计算a/b相的上升沿/下降沿,这样子的做法可以很容易用d触发器硬件实现
四倍频的计数方式是计算a和b相的上升沿和下降沿
看懂上面的话就明白了

出0入0汤圆

发表于 2017-9-5 20:04:02 | 显示全部楼层
xiaobendan 发表于 2017-9-3 08:23
速度太快,当然不行了,比如你500US才读一次IO,你的信号在500US的时间已经变化超过一次了,那你肯定是丢 ...

但是单片机 没办法处理太复杂的 抖动

就那个程序上去   直接 一直++ 或是--   就算你定时器快到50US  要么记不准.

光电编码器 则没有这样的干扰.  当然可以 +  - 位置是对的   +1 又-1  

出0入0汤圆

发表于 2017-9-6 07:23:16 | 显示全部楼层
wind2100 发表于 2017-9-5 20:04
但是单片机 没办法处理太复杂的 抖动

就那个程序上去   直接 一直++ 或是--   就算你定时器快到50US  要 ...

所以优良的信号还是要的啊,你要是把信号搞成了乱八七糟的信号,用示波器都看不出来是什么波形,那再好的算法恐怕也无济于事吧
选用优质的零件,是保证设备正常运行的先决条件

出0入0汤圆

发表于 2017-9-6 08:38:38 | 显示全部楼层
坛子里搞伺服电机的牛人也出来说说,造福我们这些小白。

出0入0汤圆

发表于 2017-9-6 11:53:49 | 显示全部楼层
xiaobendan 发表于 2017-9-6 07:23
所以优良的信号还是要的啊,你要是把信号搞成了乱八七糟的信号,用示波器都看不出来是什么波形,那再好的 ...

搞定了   人家还说 都是这样设计,  明明磁铁太远,杂波太多  ,靠近一点,就好了.
一般2MM内   他们搞成了 2.5mm+
开始想滤波 这复杂 还浪费我MCU宝贵的时间  

不过针对干扰大一点 这个算法估计要加入一定的滤波, 这样做只是简单的鉴相.  

出100入101汤圆

发表于 2017-9-6 13:25:04 | 显示全部楼层
几年的帖子,还讨论这么热烈

出0入0汤圆

发表于 2017-10-19 00:07:53 | 显示全部楼层
本帖最后由 wind2100 于 2017-10-19 00:10 编辑
xiaobendan 发表于 2014-10-2 14:24
初步测试了一下,代码如下

速度还是不错的,在50US的定时中断中调用,还不错的。可以在异常的4中状态下报 ...


这是谁写的 原理怎么来的?   为什么开始是<<2 位 相当于*4 然后 A+=2  B+=1;
验证  如果无干扰的情况下 正交逻辑是对的.

我想改进一下  增加一个抗干扰性 ,速度可以低一点,  打算采样四次 才执行编码器 ++ -- , 也就是如果高电平连续检测二次或是三次 才认为是高,这样能提高抗干扰性  
现在这个是采样一次 就依据前面的逻辑状态判断是+ OR -

注: 后面发现 电机跑久了 仍然会有丢编码器脉冲的时候,  我已经将定时扫描中断级别设置最高了, 本来计划是用外部中断的,资源不够用.

出0入0汤圆

发表于 2017-10-19 07:43:05 | 显示全部楼层
wind2100 发表于 2017-10-19 00:07
这是谁写的 原理怎么来的?   为什么开始是

哈哈,原理是楼主发的那链接里面看到的啊
我的代码和楼主的一样,只是简化写法了。
你还可以试试把SWITCH开关换成我在3楼写的那种方法
正交信号只是抗抖动,就是说某个信号在临界点抖动或者比较容易被干扰另外一个信号肯定是在稳态的情况下,是不会出现错误的。
如果你的信号的交叉相位很差,或者两个信号同时有被干扰,实际上就是失去了正交特性。此时算法上是没办法解决的。
用外中断是要支持上下沿的,否则更加不好用,而且实际上也快不了多少。

出0入0汤圆

发表于 2017-10-19 07:45:23 | 显示全部楼层
wind2100 发表于 2017-10-19 00:07
这是谁写的 原理怎么来的?   为什么开始是

你说的抗干扰,检测几次再确认信号状态,是信号检测的问题,和这个代码不冲突的。
在这个代码之前去做就行了。虽然实际上除了耽误时间外,没什么效果!

出0入0汤圆

发表于 2017-10-19 08:43:44 | 显示全部楼层
这个算法很好啊,纯C实现,移植方便。又提供了理论出处。

出0入0汤圆

发表于 2017-10-19 10:02:08 | 显示全部楼层
xiaobendan 发表于 2017-10-19 07:45
你说的抗干扰,检测几次再确认信号状态,是信号检测的问题,和这个代码不冲突的。
在这个代码之前去做就 ...

多谢  你的回复 ,
看那资料 看明白了, 主要左移二位 是保存上一次的状态    A+=2 B+=1    0x0000 0011B 这样的 理解了.

本来STM32是有编码器接口的 可是不够用 用了其它 的功能占用了 没办法只有IO模拟编码器接口了.  这编码器位置一错, 整个就乱了.

将文件上传上来   




本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2017-10-19 10:26:36 | 显示全部楼层
本帖最后由 wind2100 于 2017-10-19 12:47 编辑

1.前面那个办法 是增加判断电平次数, 不要一次就认为高 也不要一次就认为低,排除干扰.

2.我想到一个办法  ,还是他这个原理  左移四位( 他只保存一个状态,所以左移二位 ) , 保存四个状态,  然后用这四个AB状态 来散转.  就成了0xff 个散转地址.
降低一点速度.  这样就实现了 采集多次状态  来鉴相.

出0入0汤圆

发表于 2017-10-19 12:29:51 | 显示全部楼层
wind2100 发表于 2017-10-19 10:26
1.前面那个办法 是增加判断电平次数, 不要一次就认为高 也不要一次就信为低,排除干扰.

2.我想到一个办法   ...

不太懂你说的
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2024-4-26 11:24

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

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