아두이노 나노 ESP32 로터리 엔코더

이 가이드에서는 Arduino Nano ESP32와 로터리 엔코더를 사용하는 방법을 배울 것입니다. 배울 내용은 다음과 같습니다:

준비물

1×아두이노 나노 ESP32 아마존
1×USB 케이블 타입-C 쿠팡 | 아마존
1×로터리 엔코더 (Rotary Encoder) 쿠팡 | 아마존
1×브레드보드 쿠팡 | 아마존
1×점퍼케이블 쿠팡 | 아마존
1×(추천) 아두이노 나노용 스크루 터미널 확장 보드 쿠팡 | 아마존
1×(추천) 아두이노 나노용 브레이크아웃 확장 보드 쿠팡 | 아마존
1×(추천) 아두이노 나노 ESP32용 전원 분배기 쿠팡 | 아마존
공개: 이 섹션에서 제공된 링크 중 일부는 제휴 링크입니다. 이 링크를 통해 구매한 경우 추가 비용없이 수수료를 받을 수 있습니다. 지원해 주셔서 감사합니다.

로터리 엔코더에 관하여

라디오와 같은 회전식 노브는 신호를 보내 전기로 변환할 수 있습니다. 이는 노브가 얼마나 돌았는지와 어디에 위치해 있는지를 알 수 있도록 도와줍니다. 주요한 두 가지 유형이 있습니다:

  • 증분 엔코더: 이것은 빠른 신호를 사용하여 어떤 것의 위치가 얼마나 변경되었는지를 측정합니다.
  • 절대 엔코더: 이 유형은 각 위치에 대해 비밀 코드를 제공하여 전원이 끊겨도 어떤 것이 어디에 있는지를 찾을 수 있게 도와줍니다.

이 강의는 주로 첫 번째 유형인 점진적 인코더에 관한 것입니다.

로터리 엔코더 모듈 핀배열

로터리 엔코더 사용법 핀아웃

회전 엔코더 모듈은 4개의 핀이 있습니다:

  • CLK 핀(출력 A): 메인 펄스로, 얼마나 회전이 일어났는지 알려줍니다. 어느 방향으로든 노브를 한 노치(클릭) 돌릴 때마다, CLK 핀은 한 사이클을 완성하는 신호(LOW HIGH LOW)를 출력합니다.
  • DT 핀(출력 B): CLK 핀처럼 작동하지만 CLK 신호보다 90도 지연된 신호를 출력합니다. 이는 회전 방향(시계 방향 또는 반시계 방향)을 파악하는데 도움을 줍니다.
  • SW 핀: 엔코더의 버튼에서 나옵니다. 보통 열려 있습니다. 이 핀에 풀업 저항을 추가할 때, 노브가 눌리지 않았을 때 SW 핀은 HIGH이고 눌렸을 때는 LOW가 됩니다.
  • VCC 핀(+): VCC(3.3과 5 볼트 사이)에 연결해야 합니다.
  • GND 핀: GND(0V)에 연결해야 합니다.

로터리 엔코더 대 포텐쇼미터

로터리 엔코더를 아두이노 나노 ESP32 - 가변 저항기와 혼동할 수 있지만, 그들은 서로 다른 부품입니다. 다음은 그들 간의 비교입니다:

  • 로터리 엔코더는 포텐쇼미터의 현대 버전과 같지만, 더 많은 것을 할 수 있습니다.
  • 로터리 엔코더는 멈추지 않고 한 바퀴를 완전히 돌 수 있지만, 포텐쇼미터는 약 3/4원을 돌 수만 있습니다.
  • 로터리 엔코더는 펄스를 출력하는 반면, 포텐쇼미터는 아날로그 전압을 출력합니다.
  • 로터리 엔코더는 손잡이가 얼마나 움직였는지만 알아내야 할 때 유용합니다. 정확히 손잡이 위치가 어디인지 정말 알아야 할 때는 포텐쇼미터가 유용합니다.

로터리 엔코더가 작동하는 방식

로터리 엔코더 output

인코더 내부에는 C라고 불리는 핀에 연결된 슬롯이 있는 작은 디스크가 있으며, 이는 공통 접지처럼 작용합니다. A와 B라는 두 개의 추가 핀이 더 있습니다.

  • 노브를 돌리면 핀 A와 B가 공유 지상 핀 C에 닿지만, 그 순서는 노브를 돌리는 방향(시계 방향이든 반시계 방향이든)에 따라 달라집니다.
  • 이러한 접촉은 두 신호를 생성합니다. 한 핀이 다른 핀보다 먼저 지면에 닿기 때문에 타이밍이 조금 다릅니다. 이 신호들은 90도 차이로 동기화되지 않는데, 이를 쿼드러처 인코딩이라고 합니다.
  • 노브를 시계 방향으로 돌리면 핀 A가 핀 B보다 먼저 지면에 닿습니다. 하지만 반시계 방향으로 가면 핀 B가 핀 A보다 먼저 지면에 닿습니다.
  • 각 핀이 지면에 닿거나 지면에서 떨어지는 시기를 확인함으로써 노브가 어느 방향으로 돌아가는지 알아낼 수 있습니다. 이는 핀 A의 변화가 있을 때 핀 B에 무슨 일이 일어나는지 확인함으로써 이루어집니다.
how 로터리 엔코더 works

A가 LOW에서 HIGH로 상태가 바뀔 때:

  • B가 HIGH이면, 노브를 반시계 방향으로 돌립니다.
  • B가 LOW이면, 노브를 시계 방향으로 돌립니다.

※ 주의:

A핀과 B핀은 CLK핀과 DT핀에 연결됩니다. 그러나 제조업체에 따라 순서가 달라질 수 있습니다. 아래 제공된 코드는 DIYables에서 제공하는 로터리 엔코더로 테스트되었습니다.

로터리 인코더를 프로그래밍하는 방법

  • Arduino Nano ESP32는 CLK 핀에서 신호를 읽습니다.
  • 상태가 LOW에서 HIGH로 바뀌면, Arduino Nano ESP32는 DT 핀의 상태를 읽습니다.
    • DT 핀이 HIGH인 경우, 노브가 반시계 방향으로 돌아가면, Arduino Nano ESP32는 카운터를 1씩 증가시킵니다.
    • DT 핀이 LOW인 경우, 노브가 시계 방향으로 돌아가면, Arduino Nano ESP32는 카운터를 1씩 감소시킵니다.

선연결

아두이노 나노 ESP32 로터리 엔코더 연결 배선도

이 이미지는 Fritzing을 사용하여 만들어졌습니다. 이미지를 확대하려면 클릭하세요.

아두이노 나노 ESP32 코드 - 로터리 엔코더

아래의 아두이노 나노 ESP32 코드는 다음을 수행합니다:

인코더의 회전 방향과 양을 감지합니다.

  • 시계 방향으로 한 단계(클릭) 돌아간 손잡이를 감지하면 카운터를 하나 증가시킵니다.
  • 반시계 방향으로 한 단계(클릭) 돌아간 손잡이를 감지하면 카운터를 하나 감소시킵니다.
  • 버튼이 눌렸는지 감지합니다.
/* * 이 아두이노 나노 esp32 코드는 newbiely.kr 에서 개발되었습니다 * 이 아두이노 나노 esp32 코드는 어떠한 제한 없이 공개 사용을 위해 제공됩니다. * 상세한 지침 및 연결도에 대해서는 다음을 방문하세요: * https://newbiely.kr/tutorials/arduino-nano-esp32/arduino-nano-esp32-rotary-encoder */ #include <ezButton.h> // SW 핀을 사용하기 위한 라이브러리 #define CLK_PIN D2 // 로터리 인코더의 CLK 핀에 연결된 아두이노 나노 ESP32 핀 D2 #define DT_PIN D3 // 로터리 인코더의 DT 핀에 연결된 아두이노 나노 ESP32 핀 D3 #define SW_PIN D4 // 로터리 인코더의 SW 핀에 연결된 아두이노 나노 ESP32 핀 D4 #define DIRECTION_CW 0 // 시계 방향 #define DIRECTION_CCW 1 // 반시계 방향 int counter = 0; int direction = DIRECTION_CW; int CLK_state; int prev_CLK_state; ezButton button(SW_PIN); // 핀 7에 대한 ezButton 객체를 생성한다; void setup() { Serial.begin(9600); // 인코더 핀을 입력으로 설정 pinMode(CLK_PIN, INPUT); pinMode(DT_PIN, INPUT); button.setDebounceTime(50); // 디바운스 시간을 50 밀리초로 설정한다 // 로터리 인코더의 CLK 핀의 초기 상태를 읽는다 prev_CLK_state = digitalRead(CLK_PIN); } void loop() { button.loop(); // 가장 먼저 loop() 함수를 호출해야 한다 // 로터리 인코더의 CLK 핀의 현재 상태를 읽는다 CLK_state = digitalRead(CLK_PIN); // CLK의 상태가 변경되면, 펄스 발생 // 중복 계산을 피하기 위해 상승 에지(LOW에서 HIGH로)에만 반응한다 if (CLK_state != prev_CLK_state && CLK_state == HIGH) { // DT 상태가 HIGH이면 // 인코더가 반시계 방향으로 회전 중임 => 카운터 감소 if (digitalRead(DT_PIN) == HIGH) { counter--; direction = DIRECTION_CCW; } else { // 인코더가 시계 방향으로 회전 중임 => 카운터 증가 counter++; direction = DIRECTION_CW; } Serial.print("Rotary Encoder:: direction: "); if (direction == DIRECTION_CW) Serial.print("Clockwise"); else Serial.print("Counter-clockwise"); Serial.print(" - count: "); Serial.println(counter); } // 마지막 CLK 상태 저장 prev_CLK_state = CLK_state; if (button.isPressed()) { Serial.println("The button is pressed"); } }

버튼 디바운싱을 위한 코드를 간소화하기 위해 ezButton 라이브러리가 사용됩니다.

사용 방법

아두이노 나노 ESP32를 처음 사용하는 경우, 아두이노 IDE에서 아두이노 나노 ESP32 환경 설정 방법을 확인하십시오 아두이노 나노 ESP32 - 소프트웨어 설치.

  • Arduino IDE에 ezButton 라이브러리를 설치하세요.
  • 위의 코드를 복사하고 Arduino IDE로 열어주세요
  • Arduino IDE에서 Upload 버튼을 클릭하여 코드를 Arduino Nano ESP32에 업로드하세요
  • 손잡이를 시계 방향으로 돌린 다음, 반시계 방향으로 돌려주세요
  • 손잡이를 누르세요
  • 시리얼 모니터에서 결과를 확인하세요.
COM6
Send
Rotary Encoder:: direction: CLOCKWISE - count: 1 Rotary Encoder:: direction: CLOCKWISE - count: 2 Rotary Encoder:: direction: CLOCKWISE - count: 3 Rotary Encoder:: direction: CLOCKWISE - count: 4 Rotary Encoder:: direction: CLOCKWISE - count: 5 Rotary Encoder:: direction: ANTICLOCKWISE - count: 4 Rotary Encoder:: direction: ANTICLOCKWISE - count: 3 Rotary Encoder:: direction: ANTICLOCKWISE - count: 2 Rotary Encoder:: direction: ANTICLOCKWISE - count: 1 Rotary Encoder:: direction: ANTICLOCKWISE - count: 0 The button is pressed
Autoscroll Show timestamp
Clear output
9600 baud  
Newline  

코드 설명

코드의 줄별 주석을 확인하세요.

아두이노 나노 ESP32 코드 - 인터럽트를 사용한 로터리 엔코더

이전 코드에서 폴링을 사용하여 핀의 상태를 지속적으로 확인하는 것은 아두이노 나노 ESP32의 자원 낭비를 초래하고 다른 코드 실행이 느린 경우 누락된 계수를 초래할 수 있습니다.

효과적인 해결책은 폴링의 필요성을 없애는 인터럽트를 사용하는 것입니다. 이를 통해 아두이노 나노 ESP32가 카운트를 놓치지 않고 다른 작업을 수행할 수 있습니다. 아래는 회전 엔코더에서 방향과 위치를 읽기 위해 인터럽트를 사용하는 아두이노 나노 ESP32 코드입니다.

/* * 이 아두이노 나노 esp32 코드는 newbiely.kr 에서 개발되었습니다 * 이 아두이노 나노 esp32 코드는 어떠한 제한 없이 공개 사용을 위해 제공됩니다. * 상세한 지침 및 연결도에 대해서는 다음을 방문하세요: * https://newbiely.kr/tutorials/arduino-nano-esp32/arduino-nano-esp32-rotary-encoder */ #include <ezButton.h> // SW 핀을 위한 라이브러리 사용 #define CLK_PIN D2 // 로터리 인코더의 CLK 핀에 연결된 아두이노 나노 ESP32 핀 D2 #define DT_PIN D3 // 로터리 인코더의 DT 핀에 연결된 아두이노 나노 ESP32 핀 D3 #define SW_PIN D4 // 로터리 인코더의 SW 핀에 연결된 아두이노 나노 ESP32 핀 D4 #define DIRECTION_CW 0 // 시계 방향 #define DIRECTION_CCW 1 // 반시계 방향 volatile int counter = 0; volatile int direction = DIRECTION_CW; volatile unsigned long last_time; // 디바운싱을 위함 int prev_counter; ezButton button(SW_PIN); // 핀 7을 위한 ezButton 객체 생성; void IRAM_ATTR ISR_encoder() { if ((millis() - last_time) < 50) // 디바운스 시간은 50ms return; if (digitalRead(DT_PIN) == HIGH) { // 인코더가 반시계 방향으로 회전 중 => 카운터 감소 counter--; direction = DIRECTION_CCW; } else { // 인코더가 시계 방향으로 회전 중 => 카운터 증가 counter++; direction = DIRECTION_CW; } last_time = millis(); } void setup() { Serial.begin(9600); // 인코더 핀들을 입력으로 설정 pinMode(CLK_PIN, INPUT); pinMode(DT_PIN, INPUT); button.setDebounceTime(50); // 디바운스 시간을 50 밀리초로 설정 // CLK 핀에 대한 인터럽트 사용 충분 // CLK 핀이 LOW에서 HIGH로 바뀌면 ISR_encoder() 호출 attachInterrupt(digitalPinToInterrupt(CLK_PIN), ISR_encoder, RISING); } void loop() { button.loop(); // loop() 함수를 반드시 먼저 호출해야 함 if (prev_counter != counter) { Serial.print("Rotary Encoder:: direction: "); if (direction == DIRECTION_CW) Serial.print("CLOCKWISE"); else Serial.print("ANTICLOCKWISE"); Serial.print(" - count: "); Serial.println(counter); prev_counter = counter; } if (button.isPressed()) { Serial.println("버튼이 눌렸습니다"); } // TO DO: 여기에 당신의 다른 작업 }

이제 노브를 돌리면, 이전 코드에서 봤던 것처럼 시리얼 모니터에 정보가 나타나는 것을 확인할 수 있습니다.

※ 주의:

  • 다른 웹사이트의 튜토리얼에서 하나의 엔코더에 두 개의 인터럽트를 사용하는 것을 볼 수 있지만, 이는 불필요하고 낭비입니다. 인터럽트는 하나만으로 충분합니다.
  • 인터럽트에서 사용하는 전역 변수에 volatile 키워드를 사용하는 것이 중요합니다. 이를 무시하면 예상치 못한 문제가 발생할 수 있습니다.
  • 인터럽트 내의 코드를 가능한 한 간단하게 유지하세요. 인터럽트 내에서 Serial.print()Serial.println()을 사용하는 것을 피하세요.

아두이노 나노 ESP32 로터리 엔코더 응용 프로그램

로터리 엔코더를 사용하여 다음과 같은 응용 프로그램들을 할 수 있지만 이에 국한되지 않습니다:

  • 아두이노 나노 ESP32 - 로터리 인코더가 서보 모터의 위치를 제어합니다.
  • 아두이노 나노 ESP32 - 로터리 인코더가 LED의 밝기를 제어합니다.
  • 아두이노 나노 ESP32 - 로터리 인코더가 스테퍼 모터의 속도를 제어합니다.

동영상

비디오 제작은 시간이 많이 걸리는 작업입니다. 비디오 튜토리얼이 학습에 도움이 되었다면, YouTube 채널 을 구독하여 알려 주시기 바랍니다. 비디오에 대한 높은 수요가 있다면, 비디오를 만들기 위해 노력하겠습니다.

함수 참조들

관련 튜토리얼