【问题标题】:Using a rotary encoder with AVR Micro controller使用带有 AVR 微控制器的旋转编码器
【发布时间】:2025-07-31 13:55:01
【问题描述】:

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

澄清

我曾尝试使用外部中断来监听引脚,但似乎太慢了。当引脚 A 变为高电平时,中断程序开始,然后检查引脚 B 是否为高电平。这个想法是,如果在引脚 A 变高的那一刻引脚 B 为高,那么它会逆时针旋转。如果引脚 B 为低电平,则它正在顺时针旋转。但似乎 AVR 需要太长时间来检查 Pin B,所以它总是被读取为高。

我还尝试创建一个程序,该程序仅在 Pin B 或 Pin A 更改之前阻塞。但是可能是编码器旋转时噪音太大,因为这也不起作用。我最后一次尝试是有一个计时器,它将最后 8 个值存储在缓冲区中,并检查它是否从低到高。这也不起作用。

我尝试过确定编码器的范围,从第一个 Pin 更改到另一个 Pin 更改,它似乎使用了 2 到 4 毫秒。

【问题讨论】:

    标签: microcontroller avr encoder atmega


    【解决方案1】:

    您到底遇到了什么问题?我假设您已经能够根据您提供的 Farnell 页面上链接的技术规范将编码器的引脚连接到您的 PIC,那么读取数据有问题吗?你没有从编码器得到任何数据吗?您不知道如何解释您返回的数据吗?

    【讨论】:

      【解决方案2】:

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

      很遗憾,如果没有更多信息,我无法解决您的特定问题。

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

      好的,您正在处理几个不同的问题,第一个问题是这是一个机械编码器,因此您必须处理开关噪声(弹跳、颤动)。 data sheet 表示部件停止弹跳和创建错误输出可能需要长达 3 毫秒的时间。

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

      atmega 足够快,您不必担心这些检查会缓慢进行,除非您的时钟速度也很慢。

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

      【讨论】:

      • 第一个链接似乎(不再?)包含任何信息。
      【解决方案3】:

      速度应该不是问题。大多数机械开关都需要去抖动程序。如果您想通过中断执行此操作,请在触发时关闭中断,请启动一个计时器,该计时器将在几毫秒后将其重新打开。将使您的程序免于轮询>:)

      【讨论】:

        【解决方案4】:
        /* 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;
          }
          

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

          【讨论】:

          • 作为“爱好者”解决方案是可以的。但是,不可低估额外的硬件(电阻器/电容器)。这就是为什么软件去抖动是一个“更好”的解决方案(恕我直言)。
          • 硬件解决方案的好处在于,它提供了额外的保护,免受用户的 ESD 伤害。当然,没有为此优化,但有一点好处。
          • 我认为您的电路没有显示从编码器到 µC 的无源 LP 滤波器。你必须交换电阻和电容的位置。
          • 注意这个过滤器会在开关打开时产生VCC,在开关闭合时产生18%的VCC。像this bourns datasheet 中推荐的过滤器将干净地连接到 VCC 和 GND,并使用更少的部分值。