1. 세월은 변했지만...
아날로그 세상에서 디지털 세상으로 세월이 변했지만, 아날로그에 대한 향수는 지울수 없다. 감성과 사용의 편리성을 고려하면 로터리 인코더는 아주 오랜 세월을 나와 함께 할것 같다.
이 모델은 연결핀이 5개 이며, 중심부는 버튼 스위치 기능이 있다.
각핀을 Wemos D1 mini에 아래와 같이 연결하였다.
Wemos Encoder
D1 ------------------ CLK
D2 ------------------ DT
D3 ------------------ SW
3.3 ------------------ +
GND --------------- GND
허허.. 연결을 하고 코드를 실행하니, 난리도 아니였다. 버튼을 한번 눌렀다가 떼었는데 2번 눌렸다 뗀걸로 신호가 잡히고, 시계 방향으로 돌리고 있는데 반시계 방향 신호가 잡히는 둥 사용하기 껄끄러운 상태였다.
Rotary360Potentiometer.h file
Rotary360Potentiometer.cpp file
360도 회전 가능한 로터리 인코더 |
이 모델은 연결핀이 5개 이며, 중심부는 버튼 스위치 기능이 있다.
2. 연결은 해보았지만...
연결이 어려운 것도 아니고, 저항 두개와 점퍼케이블만 있으면 가능하니, 바로 연결해 보았다. 아래의 그림처럼 연결하고 각 핀의 이름은 인터넷을 뒤적 뒤적하여 매칭했다.
신호를 좀더 제대로 처리하고 싶다면, 아래와 같이 연결하면 될듯 하다.
(난 저항만 쓰고 나머지는 S/W로 해결)
Wemos Encoder
D1 ------------------ CLK
D2 ------------------ DT
D3 ------------------ SW
3.3 ------------------ +
GND --------------- GND
허허.. 연결을 하고 코드를 실행하니, 난리도 아니였다. 버튼을 한번 눌렀다가 떼었는데 2번 눌렸다 뗀걸로 신호가 잡히고, 시계 방향으로 돌리고 있는데 반시계 방향 신호가 잡히는 둥 사용하기 껄끄러운 상태였다.
3. S/W 방식으로 보완을...
아마도 내가 구입한 인코더가 워낙 싼 모델 인듯 하여 소프트웨어 방식으로 보정을 했다. 0.01초 이내에 버튼 신호가 2회 연속 들어오면 뒤의 버튼 신호를 무시하는 방식이다. 회전신호 역시 0.01초 이내의 신호는 무시하는 방식이다. 결론은 아주 성공적이었다. 물론 완벽한 신호를 원한다면, 더 좋은 모듈을 사서 사용하는 것을 권장한다.4. 사용 방법 및 소스코드는...
사용 방법은 어려울 것도 없다. 그냥 헤더 파일을 인클루드 하고 신호핀 3개만 잘 정의해 주면 된다. 아래와 같이 사용한다. ( loop 함수에 feed() 호출 필수)
/*------------------------------------------------------------------
360도 회전 가능한 로터리 인코더 사용 예제
------------------------------------------------------------------*/
#include "Rotary360Potentiometer.h"
// 신호를 받기 위하여 D1, D2, D3
핀을 사용한다
Rotary360Potentiometer
pot(D1, D2, D3);
void setup() {
Serial.begin (115200);
}
void loop() {
switch (pot.feed()) {
case POTNET_NEUTRAL:
break;
case POTNET_CW:
Serial.println("Potentiometer
CW");
break;
case POTNET_CCW:
Serial.println("Potentiometer
CCW");
break;
case POTNET_BTN_DN:
Serial.println("Potentiometer
BTN DN");
break;
case POTNET_BTN_UP:
Serial.println("Potentiometer
UP");
break;
}
}
Rotary360Potentiometer.h file
/*------------------------------------------------------------------
BSD License
Copyright (c) 2018 terminal0070@gmail.com
360도 회전 가능한 로터리 포텐셔미터를 위한 클래스
5개의 핀을 가지는 포텐셔 미터용이다.
아래의 외형을 가지며, 각핀의 명칭은 아래와 같다.
+--------------+
A (CLK) --| |-- SW
C (GND) --|
( ) |
B
(DT)--| |-- VCC
+--------------+
------------------------------------------------------------------*/
#ifndef POTENTIOMETER_360_H
#define POTENTIOMETER_360_H
enum
{POTNET_NEUTRAL, POTNET_CW, POTNET_CCW, POTNET_BTN_DN, POTNET_BTN_UP};
class
Rotary360Potentiometer
{
public:
Rotary360Potentiometer(uint8_t clk_pin, uint8_t dt_pin, uint8_t sw_pin = 255);
uint8_t feed(void);
private:
uint8_t m_dClkPin,
m_dDtPin; // pin A, B 정의
uint8_t m_dSwPin = 255; // 버튼핀을 사용하는 경우와 사용하지 않는 경우가 있음..
int8_t
m_dPrevClkPinVal; // CLK(A) Pin의 최종 상태
int8_t
m_dPrevBtnStatus; // 버튼의 최종상태
// 버튼을 한번 누르지만 연속으로 누르는 것처럼 되는 것을 막기 위해서..
uint32_t m_dPrevBtnUpTime =
10;
// 아래 두개 변수는 로터리를 빠르게 돌리면 가끔씩 역방향으로 돌아 갔다고 센싱하길래
// 소프트웨어 적으로 보정하는데 사용함.
uint32_t m_dPrevStatusTime
= 10; // 마지막으로 회전을 확인한 시간
};
#endif //
POTENTIOMETER_360_H
Rotary360Potentiometer.cpp file
/*------------------------------------------------------------------
BSD License
Copyright (c) 2018 terminal0070@gmail.com
------------------------------------------------------------------*/
#include <Arduino.h>
#include "Rotary360Potentiometer.h"
Rotary360Potentiometer::Rotary360Potentiometer(uint8_t clk_pin, uint8_t dt_pin, uint8_t sw_pin) {
m_dClkPin = clk_pin;
m_dDtPin = dt_pin;
m_dSwPin = sw_pin;
pinMode(m_dClkPin, INPUT);
pinMode(m_dDtPin, INPUT);
m_dPrevClkPinVal = digitalRead(m_dClkPin);
if (m_dSwPin != 255) { // Switch 핀을 사용한다면
pinMode(m_dSwPin, INPUT);
m_dPrevBtnStatus = digitalRead(m_dSwPin);
}
}
uint8_t Rotary360Potentiometer::feed(void) {
int8_t status =
POTNET_NEUTRAL;
uint32_t now = millis();
// 로터리 상태 체크
int nowClkVal = digitalRead(m_dClkPin);
if (nowClkVal !=
m_dPrevClkPinVal) { // 돌리고 있는 상황이면
// CLK(A)핀이 먼저 바뀌엇다. -> 시계 방향으로 회전중
if (digitalRead(m_dDtPin) !=
nowClkVal) {
status = POTNET_CW;
} else {// DT(B) 핀이 먼저 바뀌었다.. -> 반시계 방향으로 회전중
status = POTNET_CCW;
}
m_dPrevClkPinVal = nowClkVal;
// 로터리 신호를 소프트웨어적으로 보정
// 0.01초 이내의 회전 신호가 다시 잡히면 무시한다.
// 빠른시간내에 회전 신호가 들어온다는 것은 대부분
// 잘못된 신호이다.
if (now -
m_dPrevStatusTime > 10)
{
m_dPrevStatusTime = now;
} else {
status = POTNET_NEUTRAL;
}
}
// 버튼 처리
// 코드상 나중이지만, 결론은 버튼 상태가 로터리 보다 우선되는 형태이다
if (m_dSwPin != 255) {
int nowBtn = digitalRead(m_dSwPin);
if (m_dPrevBtnStatus
!= nowBtn) {
// 역시 0.01초 이내에 버튼 신호가 연속으로 잡히면.. 결론은 무시한다.
if (now -
m_dPrevBtnUpTime > 10) {
if (nowBtn) {
status = POTNET_BTN_UP;
} else {
status = POTNET_BTN_DN;
}
m_dPrevBtnStatus = nowBtn;
m_dPrevBtnUpTime = now;
}
}
}
return status;
}