Arduino EC11编码器入门指南:从硬件连接到防抖处理

1次阅读
没有评论

共计 2595 个字符,预计需要花费 7 分钟才能阅读完成。

image.webp

认识 EC11 旋转编码器

EC11 是一种增量式旋转编码器,通过内部机械结构产生两路相位差 90°的 正交信号(CLK 和 DT)。旋转时:

Arduino EC11 编码器入门指南:从硬件连接到防抖处理

  • 顺时针转动:CLK 引脚先产生低电平,DT 引脚随后变化
  • 逆时针转动:DT 引脚先产生低电平,CLK 引脚随后变化

编码器还带有一个 按键开关(SW),按下时会将公共端(通常接地)与 SW 引脚导通。

硬件连接方案

EC11 引脚说明:------------------
| 引脚 | 功能  |
|------|-------|
| CLK  | 脉冲 A |
| DT   | 脉冲 B |
| SW   | 按键  |
| +    | VCC   |
| GND  | 地线  |
------------------

推荐连接方式(需接10K 上拉电阻):

Arduino       EC11
-------------------
5V     ——    + (VCC)
GND    ——    GND
D2     ——    CLK (接 10K 上拉)
D3     ——    DT (接 10K 上拉)
D4     ——    SW (接 10K 上拉)

基础轮询实现

const int pinCLK = 2;  // 接 EC11 的 CLK
const int pinDT = 3;   // 接 EC11 的 DT
const int pinSW = 4;   // 接 EC11 的 SW

int lastCLK = HIGH;

void setup() {pinMode(pinCLK, INPUT_PULLUP); // 启用内部上拉
  pinMode(pinDT, INPUT_PULLUP);
  pinMode(pinSW, INPUT_PULLUP);
  Serial.begin(9600);
}

void loop() {int currentCLK = digitalRead(pinCLK);

  if (currentCLK != lastCLK) {if (digitalRead(pinDT) != currentCLK) {Serial.println("顺时针旋转");
    } else {Serial.println("逆时针旋转");
    }
    lastCLK = currentCLK;
  }

  if (digitalRead(pinSW) == LOW) {delay(50); // 简单防抖
    if (digitalRead(pinSW) == LOW) {Serial.println("按键按下");
      while(digitalRead(pinSW) == LOW); // 等待释放
    }
  }
}

高级优化方案

中断驱动实现

volatile int encoderPos = 0;

void setup() {attachInterrupt(digitalPinToInterrupt(pinCLK), encoderISR, CHANGE);
}

void encoderISR() {if (digitalRead(pinCLK) == digitalRead(pinDT)) {encoderPos++;} else {encoderPos--;}
}

状态机消抖算法

enum EncoderState {IDLE, CLK_LOW, DT_LOW};
EncoderState state = IDLE;

void checkEncoder() {switch(state) {
    case IDLE:
      if (digitalRead(pinCLK) == LOW) state = CLK_LOW;
      break;

    case CLK_LOW:
      if (digitalRead(pinDT) == LOW) {
        state = DT_LOW;
        // 确认旋转方向
      } else if (digitalRead(pinCLK) == HIGH) {state = IDLE;}
      break;

    case DT_LOW:
      // 等待信号恢复
      if (digitalRead(pinCLK) == HIGH && digitalRead(pinDT) == HIGH) {state = IDLE;}
      break;
  }
}

常见问题解决

  1. 机械抖动问题
  2. 硬件方案:在 CLK/DT 引脚对地接0.1μF 电容
  3. 软件方案:采用状态机或延时确认

  4. 中断冲突预防

  5. 避免在中断服务程序中执行耗时操作
  6. 使用 volatile 修饰共享变量

  7. 长线传输建议

  8. 使用双绞线
  9. 信号线串接 100Ω 电阻

完整示例代码

#include <Arduino.h>

// 引脚定义
#define ENC_CLK 2
#define ENC_DT 3
#define ENC_SW 4

// 全局变量
volatile int encoderPos = 0;
int lastPos = 0;

void encoderISR() {
  static unsigned long lastInterrupt = 0;
  unsigned long now = millis();

  // 消抖时间间隔(ms)
  if (now - lastInterrupt > 5) {if (digitalRead(ENC_CLK) == digitalRead(ENC_DT)) {encoderPos++;} else {encoderPos--;}
  }
  lastInterrupt = now;
}

void setup() {
  // 引脚初始化
  pinMode(ENC_CLK, INPUT_PULLUP);
  pinMode(ENC_DT, INPUT_PULLUP);
  pinMode(ENC_SW, INPUT_PULLUP);

  // 中断设置
  attachInterrupt(digitalPinToInterrupt(ENC_CLK), encoderISR, CHANGE);

  Serial.begin(115200);
}

void loop() {
  // 检测位置变化
  if (encoderPos != lastPos) {Serial.print("Position:");
    Serial.println(encoderPos);
    lastPos = encoderPos;
  }

  // 检测按键
  if (digitalRead(ENC_SW) == LOW) {delay(50);
    if (digitalRead(ENC_SW) == LOW) {Serial.println("Button pressed!");
      while(digitalRead(ENC_SW) == LOW);
    }
  }
}

性能对比测试

检测方式 CPU 占用率 响应延迟
轮询 ~15% 1-2ms
中断 <1% <50μs

实测建议:
– 简单项目可用轮询
– 需要快速响应或多任务时推荐中断

经验总结

经过实际项目验证,EC11 编码器的稳定性主要取决于三点:合理的硬件滤波、有效的软件消抖、以及正确的中断处理。建议初次使用时先用示波器观察信号质量,再逐步添加防抖措施。对于需要精确计数的场景,可以结合光电编码器使用,但 EC11 在大多数旋钮交互场合已经足够可靠。

正文完
 0
评论(没有评论)