如何使用Arduino旋转编码器

  • 内容
  • 评论
  • 相关

很久以前在立体收音机中发现过一个可以360度旋转的电位器,记得好像是ALPS制造的。后来我了解到这是一个旋转编码器(多谢互联网),于是我从网上买了一个。

旋转编码器

旋转编码器(RT)

旋转编码器(RT)是一种可以无限旋转的装置。在大多数的旋转编码器上,当我们旋转它时,会感觉到它内部有一个个凸点(称为steps),一般凸点有12个,有些有24个。

旋转编码器的脉冲

通常,旋转编码器(RT)有两个方波输出。上面所示的图形描述了旋转编码器(RT)顺时针(→)或逆时针(←)旋转时,各阶段(A和B)间的关系。每次A信号脉冲从正到零,我们就读取B脉冲的值。我们看到,当编码器顺时针旋转时,B脉冲总是正的。当编码器逆时针旋转时,B脉冲为负。这样,我们通过单片机监测输出,就可以知道旋转编码器旋转的方向和它转动的距离,此外,还可以计算脉冲的频率来确定转动速度。从外观上看,旋转编码器和模拟电位器很像,通过功能解读,我们可以看到旋转编码器比普通电位器有很多优点。

旋转编码器是一个旋转传感器(或选择器),它的外观看起来像电位器,它可以连续地旋转,而每旋转一周又可以均匀的分成多个部分。旋转时每个部分都会有一种轻微阻挡的感觉,同时,每一个顺时针或逆时针的旋转,会引发两个内置开关的打开和关闭。很多旋转编码器还内置了“push-on”瞬时开关,在旋转编码器的两侧,一侧有3个引脚,两个编码引脚和一个通用/接地引脚,另一侧有2个引脚(N/O开关触点)用于“push-on”开关。

旋转编码器的引脚

如前所述,旋转编码器有2个编码引脚,它们的状态不是高电平(1)就是低电平(0)。如果将引脚的值视为二进制,则可以读取为00、01、10或11(顺时针旋转时编码器输出的顺序为00、01、11、10)。如果当前读数值是01,下一个读数可能是00也可能是 11,这是由旋钮编码器转动的方向决定的。

旋转编码器(RT)的控制

现在旋转编码器硬件方面我们简单的了解了,接下来了解Arduino如何处理编码器的信号。我们现在将使用旋转编码器来做一个简单的测试,通过改变pwm信号值,使用它来控制led的亮度。我们将使用最简单的方法来读取编码器。首先,要确定要采用旋转速度。假设我们最多可以在1/10秒内将编码器旋转180度,那编码器就会在1/10秒内产生6个脉冲每秒或者60个脉冲每秒的信号。事实上,旋转速度不可能这么快。我们只是需要检测高电平值和低电平值,这样做编码器就可以给我们一个120Hz的最小频率,这里我们采用200Hz的频率(原因:由于旋转编码器也是机械结构的,有可能发生回弹。使用这个频率的目的是允许我们有效地过滤掉任何回弹。)每次编码器触发时,我们都会去比较当前脉冲与先前脉冲的值,如果它从正到零,然后我们检查B脉冲的值,看看它是正还是零。根据结果,我们可以增加编码器的衰减量。然后我们用它来控制PWM值,来增加或减少LED的亮度。原理图如下:

 

旋转编码器电路

实物连接图

Arduino连接旋转编码器控制LED

源代码如下所示。我们使用millis()函数给我们一个定时时间间隔。但是这里使用5ms作为运行检查时间(5ms = 200Hz)。

/*
** Rotary Encoder 示例
**
** 采样编码器 200Hz 使用 millis() 函数
*/

int brightness = 120;    // LED初始亮度,120为一半。
int fadeAmount = 10;    // 定义LED改变亮度的值
unsigned long currentTime;
unsigned long loopTime;
const int pin_A = 12;  // pin 12
const int pin_B = 11;  // pin 11
unsigned char encoder_A;
unsigned char encoder_B;
unsigned char encoder_A_prev=0;

void setup()  {
  // 声明 pin 9 作为输出:
  pinMode(9, OUTPUT);
  pinMode(pin_A, INPUT);
  pinMode(pin_B, INPUT);
  currentTime = millis();
  loopTime = currentTime; 
} 

void loop()  {
  // 获取经过的时间
  currentTime = millis();
  if(currentTime >= (loopTime + 5)){
    // 5ms = 200Hz  
    encoder_A = digitalRead(pin_A);    // 读取编码器 pins
    encoder_B = digitalRead(pin_B);   
    if((!encoder_A) && (encoder_A_prev)){
      // A从高到低 
      if(encoder_B) {
        // B 高电平,顺时针
        // 增加亮度,不要超过255
        if(brightness + fadeAmount <= 255) brightness += fadeAmount;               
      }   
      else {
        // B 低电平,逆时针      
        // 降低亮度,不要低于0
        if(brightness - fadeAmount >= 0) brightness -= fadeAmount;               
      }   

    }   
    encoder_A_prev = encoder_A;     // Store value of A for next time    
    
    // 设置亮度 pin 9:
    analogWrite(9, brightness);   
   
    loopTime = currentTime;  // Updates loopTime
  }
  // 其他补充的代码,可以从这里开始.
                           
}