2008-08-29 43 views
5

我无法使旋转编码器与AVR微控制器一起正常工作。编码器是机械ALPS encoder,我使用的是Atmega168使用带AVR微控制器的旋转编码器

澄清

我一直在使用一个外部中断听针试过,但是看起来实在是太慢了。当引脚A变高时,中断程序开始,然后检查引脚B是否为高电平。这个想法是,如果引脚B为高电平引脚A变高的时刻,那么它逆时针旋转。如果引脚B为低电平,那么它正在按照时钟顺序旋转。但是看起来像AVR花费太长时间来检查引脚B,所以它总是被读取为高。

我也试图创建一个程序,只是阻止,直到引脚B或引脚A的变化。但是,编码器旋转时可能会有太多噪音,因为这也不起作用。我最后一次尝试是有一个计时器,它将最后8个值存储在缓冲区中,并检查它是否从低到高。这也没有用。

我已经尝试了编码器的范围,并且它似乎使用2到4ms之间从第一个引脚变化,直到其他引脚变化。

回答

10

我有一个关于rotary encoders and how to use them的网页,您可能会觉得它有用。

不幸的是,没有更多的信息,我无法解决您的特定问题。

哪个微控制器引脚连接到编码器,以及当前用于解码脉冲的代码是什么?

好的,你正在处理几个不同的问题,第一个问题是这是一个机械编码器,所以你必须处理开关噪声(反弹,颤振)。 data sheet表示部件停止反弹并产生错误输出可能需要3mS。

您需要创建一个去抖动程序。其中最简单的就是不断检查A是否升高。如果是,请启动计时器并在3 ms内再次检查。如果它仍然很高,那么你可以检查B - 如果它不高,那么你忽略虚假脉冲并继续寻找A high。当你检查B时,你看它,启动一个计时器3 ms,然后再看看B.如果两次都是相同的,那么你可以使用该值 - 如果它在3毫秒内发生变化,那么你必须重新做一次(读取B,等待3毫秒,然后再次阅读并查看它是否匹配)。

atmega速度足够快,您不必担心这些检查进行得很慢,除非您的运行速度很慢。

一旦你处理了机械噪音,那么你想看看一个合适的灰色代码例程 - 你所遵循的算法将不起作用,除非当B变低时A也变小。通常人们存储两个输入的最后一个值,然后将它与两个输入的新值进行比较,并使用一个小函数根据此值进行递增或递减。 (查看我在上面提到的网站上的标题“高分辨率阅读”)。我将两个读数组合成一个四位数字,并使用一个简单的数组来告诉我是递增还是递减计数器,但是有更高级的解决方案,并针对代码大小,速度或易于维护的代码进行了优化。

0

究竟是什么问题?我假定您已经能够根据您提供的Farnell页面上链接的技术规范,将编码器的引脚连接到PIC上,读取数据时也存在问题?你没有从编码器得到任何数据吗?你不知道如何解释你回来的数据?

1

速度不应该是一个问题。大多数情况下,所有机械开关都需要去抖动程序。如果你想用中断来做到这一点,当它触发时关闭中断,启动一个定时器,在几秒钟后它将重新打开。将保持您的程序无轮询> :)

0
/* into 0 service rutine */ 
if(CHB) 
{ 
    if(flagB) 
    Count++; 
    FlagB=0; 
} 
else 
{ 
    if(FlagB) 
    count--: 
    FlagB=0: 
} 

/* into 1 service rutine */ 
FlagB=1; 

/* make this give to you a windows time of 1/4 of T of the encoder resolution 
    that is in angle term: 360/ (4*resolution) 
*/ 
5

添加一个模拟低通滤波器可大大改善信号。通过低通滤波器,AVR上的代码非常简单。

 _________ 
     |   | 
     | Encoder | 
     |_________| 
      | | | 
      | | | 
    100n | O | 100n 
GND O-||-+ GND +-||-O GND 
      |  | 
      \ /
     3K3/ \ 3K3 
      \ /
      |  |  
VCC O-/\/-+  +-\/\-O VCC 
    15K |  | 15K 
      |  | 
      O  O 
      A  B 

啊,ASCII艺术的奇迹:P

这里是关于AVR该程序。连接A和B以在AVR上输入PORTB:

#include <avr/io.h> 

#define PIN_A (PINB&1) 
#define PIN_B ((PINB>>1)&1) 

int main(void){ 
    uint8_t st0 = 0; 
    uint8_t st1 = 0; 
    uint8_t dir = 0; 
    uint8_t temp = 0; 
    uint8_t counter = 0; 
    DDRD = 0xFF; 
    DDRB = 0; 
    while(1){ 
    if(dir == 0){ 
     if(PIN_A & (!PIN_B)){ 
      dir = 2; 
     }else if(PIN_B & (!PIN_A)){ 
      dir = 4; 
     }else{ 
      dir = 0; 
     } 
    }else if(dir == 2){ 
     if(PIN_A & (!PIN_B)){ 
      dir = 2; 
     }else if((!PIN_A) & (!PIN_B)){ 
      counter--; 
      dir = 0; 
     }else{ 
      dir = 0; 
     } 
    }else if(dir == 4){ 
     if(PIN_B & (!PIN_A)){ 
      dir = 4; 
     }else if((!PIN_A) & (!PIN_B)){ 
      counter++; 
      dir = 0; 
     }else{ 
      dir = 0; 
     } 
    }else if(PIN_B & PIN_A){ 
     dir = 0; 
    } 
     PORTD = ~counter; 
    } 
    return 0; 
} 

此代码的工作原理除非您真的快速旋转编码器。然后,它可能会错过一两步,但这并不重要,因为使用编码器的人不知道他们转换了多少步。

+1

作为一个“业余爱好者”的解决方案可以。然而,额外的硬件(电阻器/电容器)不容小觑。这就是为什么软件反弹是一个“更好”的解决方案(恕我直言)。 – 2009-02-02 22:45:23