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

이 튜토리얼은 아두이노 나노와 로터리 인코더를 사용하는 방법을 지시합니다. 다룰 내용은 다음과 같습니다:

준비물

1×Arduino Nano Amazon
1×USB A to Mini-B USB cable 쿠팡 | Amazon
1×Rotary Encoder 쿠팡 | 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가 낮으면, 노브를 시계 방향으로 돌립니다.
  • B가 높으면, 노브를 반시계 방향으로 돌립니다.

※ NOTE THAT:

A핀과 B핀은 CLK 및 DT 핀에 연결되어 있습니다. 그러나 제조업체에 따라 순서가 다를 수 있습니다. 아래 제공된 코드는 DIYables의 회전 엔코더와 함께 테스트되었습니다.

로터리 엔코더를 위한 프로그래밍 방법

  • CLK 핀에서 신호를 확인하세요.
  • 상태가 LOW에서 HIGH로 바뀌면 DT 핀의 상태를 확인하세요.
    • DT 핀의 상태가 HIGH이면, 노브가 반시계 방향으로 돌아간 것이므로 카운터를 1만큼 증가시키세요.
    • DT 핀의 상태가 LOW이면, 노브가 시계 방향으로 돌아간 것이므로 카운터를 1만큼 감소시키세요.

선연결

Arduino Nano rotary encoder Wiring Diagram

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

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

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

  • 엔코더의 회전 방향과 회전량을 감지합니다.
    • 시계 방향으로 한 단계(클릭) 돌린 것을 감지하면 카운터를 1 증가시킵니다.
    • 반시계 방향으로 한 단계(클릭) 돌린 것을 감지하면 카운터를 1 감소시킵니다.
  • 버튼이 눌렸는지 감지합니다.
/* * 이 Arduino Nano 코드는 newbiely.kr 에서 개발되었습니다 * 이 Arduino Nano 코드는 어떠한 제한 없이 공개 사용을 위해 제공됩니다. * 상세한 지침 및 연결도에 대해서는 다음을 방문하세요: * https://newbiely.kr/tutorials/arduino-nano/arduino-nano-rotary-encoder */ #include <ezButton.h> // SW 핀을 사용하기 위한 라이브러리 #define CLK_PIN 2 #define DT_PIN 3 #define SW_PIN 4 #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); 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("Twisted direction: "); if (direction == DIRECTION_CW) Serial.print("CLOCKWISE"); else Serial.print("ANTICLOCKWISE"); Serial.print(" - counter: "); Serial.println(counter); } // 마지막 CLK 상태 저장 prev_CLK_state = CLK_state; if (button.isPressed()) { Serial.println("The button is pressed"); } }

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

사용 방법

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

코드 설명

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

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

이전 예제 코드에서는 폴링 방식을 사용하여 지속적으로 핀의 상태를 확인합니다. 이 방식은 두 가지 단점이 있습니다:

  • 아두이노 나노 자원 낭비
  • 다른 코드가 실행하는 데 시간이 오래 걸리면 일부 카운터가 누락될 수 있습니다.

이를 처리하는 한 가지 방법은 인터럽트를 사용하는 것입니다. 인터럽트는 특정 이벤트를 지속적으로 확인할 필요를 없애줍니다. 이를 통해 아두이노 나노가 다른 작업을 수행하면서도 이벤트를 놓치지 않고 처리할 수 있습니다.

다음은 인터럽트를 사용하여 로터리 인코더를 읽는 방법의 예입니다.

/* * 이 Arduino Nano 코드는 newbiely.kr 에서 개발되었습니다 * 이 Arduino Nano 코드는 어떠한 제한 없이 공개 사용을 위해 제공됩니다. * 상세한 지침 및 연결도에 대해서는 다음을 방문하세요: * https://newbiely.kr/tutorials/arduino-nano/arduino-nano-rotary-encoder */ #include <ezButton.h> // SW 핀을 사용하기 위한 라이브러리 #define CLK_PIN 2 // 아두이노 나노 핀 D2를 로터리 인코더의 CLK 핀에 연결 #define DT_PIN 3 // 아두이노 나노 핀 D3를 로터리 인코더의 DT 핀에 연결 #define SW_PIN 4 // 아두이노 나노 핀 D4를 로터리 인코더의 SW 핀에 연결 #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); void INTERRUPT_handler() { if ((millis() - last_time) < 50) // 디바운스 시간이 10ms임 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로 변경될 때 INTERRUPT_handler() 호출 attachInterrupt(digitalPinToInterrupt(CLK_PIN), INTERRUPT_handler, RISING); } void loop() { button.loop(); // 반드시 loop() 함수를 먼저 호출해야 함 if (prev_counter != counter) { Serial.print("Twisted direction: "); if (direction == DIRECTION_CW) Serial.print("CLOCKWISE"); else Serial.print("ANTICLOCKWISE"); Serial.print(" - counter: "); Serial.println(counter); prev_counter = counter; } if (button.isPressed()) { Serial.println("The button is pressed"); } // 여기에 다른 작업을 수행하십시오. }

이제 볼륨을 돌리면, 이전 코드에서 보았던 것처럼 시리얼 모니터에 정보가 나타나는 것을 알 수 있습니다.

※ NOTE THAT:

인터럽트를 사용하려면 인코더의 CLK 핀을 인터럽트를 처리할 수 있는 아두이노 나노 핀에 연결해야 합니다. 하지만 모든 아두이노 나노 핀이 이를 수행할 수 있는 것은 아닙니다. 예를 들어, 아두이노 나노에서는 오직 2번과 3번 핀만 인터럽트와 함께 작동할 수 있습니다.

다른 웹사이트의 튜토리얼에서 하나의 인코더에 대해 두 개의 인터럽트를 사용하는 경우를 볼 수 있지만, 이것은 불필요하고 낭비입니다. 단 하나의 인터럽트만으로 충분합니다.

인터럽트에서 사용되는 전역 변수에는 volatile 키워드를 사용하는 것이 중요합니다. 이를 무시하면 예상치 못한 문제가 발생할 수 있습니다.

인터럽트 내의 코드를 가능한 한 단순하게 유지하세요. 인터럽트 내에서 Serial.print() 또는 Serial.println()을 사용하는 것은 피하세요.

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

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

  • Arduino Nano - 로터리 엔코더가 서보 모터의 위치를 제어합니다.
  • Arduino Nano - 로터리 엔코더가 LED의 밝기를 제어합니다.
  • Arduino Nano - 로터리 엔코더가 스테퍼 모터의 속도를 제어합니다.

동영상

비디오 제작은 시간이 많이 걸리는 작업입니다. 비디오 튜토리얼이 학습에 도움이 되었다면, 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!