아두이노 나노 ESP32 - 로터리 엔코더 | Arduino Nano ESP32 - Rotary Encoder

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

준비물

1×Arduino Nano ESP32 Amazon
1×USB Cable Type-C 쿠팡 | Amazon
1×Rotary Encoder 쿠팡 | Amazon
1×Breadboard 쿠팡 | Amazon
1×Jumper Wires Amazon
1×(Recommended) Screw Terminal Expansion Board for Arduino Nano 쿠팡 | Amazon
공개: 이 섹션에서 제공된 링크 중 일부는 제휴 링크입니다. 이 링크를 통해 구매한 경우 추가 비용없이 수수료를 받을 수 있습니다. 지원해 주셔서 감사합니다.

로터리 엔코더에 관하여

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

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

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

로터리 엔코더 모듈 핀배열

rotary encoder pinout

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

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

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

로터리 엔코더를 포텐쇼미터와 혼동할 수 있지만, 그들은 서로 다른 부품입니다. 다음은 그들 간의 비교입니다:

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

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

rotary encoder output

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

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

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

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

※ NOTE THAT:

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씩 감소시킵니다.

선연결

Arduino Nano ESP32 rotary encoder Wiring Diagram

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

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

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

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

  • 시계 방향으로 한 단계(클릭) 돌아간 손잡이를 감지하면 카운터를 하나 증가시킵니다.
  • 반시계 방향으로 한 단계(클릭) 돌아간 손잡이를 감지하면 카운터를 하나 감소시킵니다.
  • 버튼이 눌렸는지 감지합니다.
/* * 이 Arduino Nano ESP32 코드는 newbiely.kr 에서 개발되었습니다 * 이 Arduino Nano 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 코드입니다.

/* * 이 Arduino Nano ESP32 코드는 newbiely.kr 에서 개발되었습니다 * 이 Arduino Nano 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: 여기에 당신의 다른 작업 }

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

※ NOTE THAT:

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

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

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

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

동영상

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

함수 참조들

관련 튜토리얼

※ OUR MESSAGES

  • Please feel free to share the link of this tutorial. However, Please do not use our content on any other websites. We invested a lot of effort and time to create the content, please respect our work!