Arduino ESP32 旋转编码器

本文介绍如何使用Arduino开发板和ESP32实现旋转编码器的功能,包括编码器的基本原理、接线方法及程序示例。文章还探讨了解决编码器抖动问题的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


前言

编码器(encoder) 是将信号(如 比特流 )或 数据 进行编制、转换为可用以通讯、传输和存储的信号形式的设备。. 编码器把角位移或直线位移转换成电信号,前者称为码盘 ,后者称为码尺。.

按照读出方式编码器可以分为接触式和非接触式两种;按照工作原理编码器可分为增量式和绝对式两类。. 增量式编码器是将位移转换成周期性的电信号,再把这个电信号转变成计数脉冲,用脉冲的个数表示位移的大小。绝对式编码器 的每一个位置对应一个确定的数字码,因此它的示值只与测量的起始和终止位置有关,而与测量的中间过程无关。

本文主要介绍旋转编码器在Arduino开发中的应用。

Arduino ESP32

  1. 旋转编码器

编码器接线图:

KY-040 模块包括两个内部上拉电阻,将引脚 CLK 和 DT 上拉到 VCC(+5V)。

引脚定义:

CLK

Rotary encoder pin A

DT

Rotary encoder pin B

SW

Push button pin. Normally openundefined shorted to GND on press

VCC

Voltage supply

GND

Ground

旋转编码器提供两种交互方式:

  • 旋转- 您可以通过单击箭头来旋转旋钮。上箭头顺时针旋转一级,下箭头逆时针旋转一级。旋转旋钮将在 DT 和 CLK 引脚上产生数字信号,如下所述。

  • 按钮- 单击旋钮以按下按钮。按下时,按钮将 SW 引脚与 GND 引脚连接起来。

每次用户旋转旋钮时,它都会在 DT 和 CLK 引脚上产生一个 LOW 信号:

  • 顺时针旋转会导致 CLK 引脚首先变低,然后 DT 引脚也变低。

  • 逆时针旋转会导致 DT 引脚先变低,然后 CLK 引脚变低。

两个引脚将在几毫秒内返回高电平。下图说明了这一点:

使用wokwi仿真:

#define ENCODER_CLK 4
#define ENCODER_DT  2


void setup() {
  Serial.begin(115200);
  pinMode(ENCODER_CLKundefined INPUT);
  pinMode(ENCODER_DTundefined INPUT);
}


int lastClk = HIGH;


void loop() {
  int newClk = digitalRead(ENCODER_CLK);
  if (newClk != lastClk) {
    // There was a change on the CLK pin
    lastClk = newClk;
    int dtValue = digitalRead(ENCODER_DT);
    if (newClk == LOW && dtValue == HIGH) {
      Serial.println("Rotated clockwise ⏩");
    }
    if (newClk == LOW && dtValue == LOW) {
      Serial.println("Rotated counterclockwise ⏪");
    }
  }
}

但是在实际过程中,我们得到的效果并没有如仿真一样,编码器会发生抖动,读取时并不准确。

在使用Arduino 开发ESP32设计旋转编码器程序时。

使用到的库:BasicEncoder

52a4562310de7839adb593c3417503b0.png

跑一个测试程序试试:

#include <Arduino.h>
#include <BasicEncoder.h>


const int8_t pinA = 2;
const int8_t pinB = 5;


BasicEncoder encoder(pinAundefined pinB);


void setup() {
  Serial.begin(115200);
  Serial.println(F("Polling in loop()"));
}


void loop() {
  encoder.service();
  int encoder_change = encoder.get_change();
  if (encoder_change) {
    Serial.println(encoder.get_count());
  } 
  // Even a short delay here will affect performance.
  // Uncomment and change the delay to see what happens.
  //delay(10);
}

如果在编译过程中遇到报错,有提到SREG,那就在库函数里帮它定义一下。

找到库所在的位置打开并进行修改,其他的坑我还没有碰到过。

f64575df3187b73d065e6b349e5d2a7c.png

说了那么多,感觉上面的手不好用,试试下面的:

#include "OneButton.h"

// 编码器 A B 引脚
const int8_t Encoder_IOA = 26;
const int8_t Encoder_IOB = 27;

#if defined(ESP32)
#define PIN_INPUT 14     // 编码器按键
void IRAM_ATTR checkTicks() {
    button.tick();
}
#endif

OneButton button(PIN_INPUT, true);    // 创建按键工程

// 单击
void singleClick() {
    Serial.println("singleClick() detected.");
} 

// 双击
void doubleClick() {
    Serial.println("doubleClick() detected.");
}

void setup() {
    Serial.begin(115200);
    pinMode(Encoder_IOA, INPUT_PULLUP);
    pinMode(Encoder_IOB, INPUT_PULLUP);

    // 中断配置
    attachInterrupt(digitalPinToInterrupt(Encoder_IOA), IOA_attachInterrupt, FALLING);
    attachInterrupt(digitalPinToInterrupt(Encoder_IOB), IOB_attachInterrupt, FALLING);
    attachInterrupt(digitalPinToInterrupt(PIN_INPUT), checkTicks, FALLING);

    // 按键单击 双击初始化
    button.attachClick(singleClick);
    button.attachDoubleClick(doubleClick);
}

void loop() {
    button.tick();
}

// 编码器 中断函数
void IOA_attachInterrupt() {
    if(digitalRead(Encoder_IOA) == 0) {
        if(digitalRead(Encoder_IOB) == 0) {
            Serial.println("Encoder_Count++");
            }
        }
    }
// 编码器 中断函数
void IOB_attachInterrupt() {
    if(digitalRead(Encoder_IOB) == 0) {
        if(digitalRead(Encoder_IOA) == 0) {
            Serial.println("Encoder_Count--");
            }
        }
    }

​​​​​​​

### ESP32 使用旋转编码器 对于希望在ESP32上集成并使用旋转编码器的应用场景,可以采用MicroPython旋转编码器驱动来简化开发过程。此驱动程序不仅适用于多种开发板,而且特别优化了对ESP32的支持[^1]。 #### 安装 MicroPython 到 ESP32 为了能够在ESP32上运行MicroPython脚本,首先需要将MicroPython固件刷入到ESP32设备中。这一步骤可以通过官方文档获取详细的安装指南。 #### 连接硬件 根据提供的信息,在ESP32上的具体接线方式如下: | 编码器引脚 | ESP32 GPIO | | --- | --- | | CLK | GPIO14 | | DT | GPIO12 | | SW | GPIO19 | | VCC | 3V3 | | GND | GND | 这种连接方法能够确保编码器与ESP32之间的通信顺畅无阻[^2]。 #### 示例代码 下面是一段基于上述配置编写的简单示例代码,用于展示如何利用MicroPython读取来自旋转编码器的数据变化情况。 ```python from machine import Pin, Timer import time class RotaryEncoder: def __init__(self, clk_pin=14, dt_pin=12, sw_pin=19): self.clk_last = None self.position = 0 self.clk = Pin(clk_pin, Pin.IN, Pin.PULL_UP) self.dt = Pin(dt_pin, Pin.IN, Pin.PULL_UP) self.sw = Pin(sw_pin, Pin.IN, Pin.PULL_UP) self.timer = Timer(-1) self._setup_interrupts() def _setup_interrupts(self): self.clk.irq(trigger=Pin.IRQ_RISING | Pin.IRQ_FALLING, handler=self.update_position) def update_position(self, pin=None): clk_state = self.clk.value() dt_state = self.dt.value() if clk_state != dt_state and not clk_state: self.position += 1 elif clk_state == dt_state and not clk_state: self.position -= 1 print(f'Position: {self.position}') encoder = RotaryEncoder() try: while True: pass except KeyboardInterrupt: encoder.timer.deinit() ``` 这段代码定义了一个`RotaryEncoder`类,该类初始化时会设置好相应的GPIO引脚,并注册中断服务函数以响应编码器转动事件的发生。每当检测到CLK或DT信号发生变化时,都会调用`update_position()`方法更新当前位置计数器的值,并打印出来以便观察效果。
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值