おもちゃラボ

Unityで遊びを作ってます

【Arduino】マウスホイール(ロータリーエンコーダ)の回転量を取得する

マウスホイール(ロータリーエンコーダ)がどれだけ回転したかをArduinoで調べる方法を紹介します。

f:id:nn_hokuson:20170326102120j:plain

まずはマウスを分解して、ホイール部分だけ取り出しました。

f:id:nn_hokuson:20170326082121p:plain:w350

取り出したホイールとロータリーエンコーダはこんな感じです。ロータリーエンコーダの足にはワイヤをつけています。

f:id:nn_hokuson:20170326083121j:plain:w350

ロータリーエンコーダの仕組み

ロータリーエンコーダには3本の足があり、1本はGNDで、残り2本からパルス(A相とB相)が出力されます。出力される2相の信号は位相が90度がずれるように作られています。
2相の信号の出力を見ることで、正回転と逆回転を判別することができます。

正回転の場合は下図のように、A相がB相に対して位相が90度進みます。
そこで前回と今回のA相B相の値が(1110、0100、0010、1011)になっている場合は正回転しているとみなすことができます。

f:id:nn_hokuson:20170326091440p:plain:w300

一方、逆回転の場合はA相がB相に対して90度遅れるので下図のようになります。そこで、前回と今回のA相B相の値が(1110、1000、0001、0111)になっている場合には逆回転とみなします。

f:id:nn_hokuson:20170326091446p:plain:w300

マウスホイールとArduinoをつなぐ回路図

マウスホイールのロータリーエンコーダとArduinoをつなぐ回路図は次のようになります。

f:id:nn_hokuson:20170326093205j:plain:w300

ここではロータリーエンコーダのA相とB相をArduinoの2番ポートと3番ポートに接続しています。ロータリーエンコーダから出ているもう一本はGNDに接続します。

Aruduinoのプログラム

ロータリーエンコーダの値を検出するArduinoのプログラムは次のとおりです。

volatile int value = 0;
volatile uint8_t prev = 0;

void setup() 
{
  pinMode(2, INPUT); 
  pinMode(3, INPUT);
  
  attachInterrupt(0, updateEncoder, CHANGE);
  attachInterrupt(1, updateEncoder, CHANGE);
  digitalWrite(2, HIGH);
  digitalWrite(3, HIGH);
  
  Serial.begin(9600);
}

void updateEncoder()
{
  uint8_t a = digitalRead(2);
  uint8_t b = digitalRead(3);
 
  uint8_t ab = (a << 1) | b;
  uint8_t encoded  = (prev << 2) | ab;

  if(encoded == 0b1101 || encoded == 0b0100 || encoded == 0b0010 || encoded == 0b1011){
    value ++;
  } else if(encoded == 0b1110 || encoded == 0b0111 || encoded == 0b0001 || encoded == 0b1000) {
    value --;
  }

  prev = ab;
}

void loop()
{
   Serial.println(value);
}

今回は波形が変化したタイミングでロータリーエンコーダからの値を読み出したいので、割り込みの仕組みを使っています。割り込みを使うことで、ピンに入力されている値が変化したタイミングで、指定した関数を実行することができます。

Arduinoで割り込みを使うにはattachInterrupt関数を使います。第一引数には使用するポートのインデックス(2番ポートならインデックスは0、3番ポートならインデックスは1になります・・・ややこしい!)を指定します。

第二引数に呼び出す割り込み用の関数名、第三引数には値がどのように変化(LOW, RISING, FALLING, CHANGE)したときに割り込みの関数を呼び出すかを指定します。

  • LOW ピンがLOWのとき発生
  • CHANGE ピンの状態が変化したときに発生
  • RISING ピンの状態がLOWからHIGHに変わったときに発生
  • FALLING ピンの状態がHIGHからLOWに変わったときに発生

f:id:nn_hokuson:20170326094506p:plain:w200

ここでは2番ポートと3番ポートを割り込みに使用して、波形が変化(CHANGE)した場合にupdateEncoder関数を呼びだしています。

updateEncoder関数の中では2番ポートと3番ポートから、ロータリーエンコーダのA相とB相の値を読み出し、前回のA相B相の値と繋げて4bitの値にして、正回転か逆回転かを判定しています。

実行結果

マウスのホイールを回した結果がこちらです。分かりやすいように、エンコードした値が偶数のときにはLEDを点灯、奇数の場合には消灯しています。

www.youtube.com

今回はこちらの記事を参考にさせていただきました!
マウスホイールでトイレットペーパの使用量を調べるって・・・・斬新w
面白いなぁ〜^^/
eleclog.quitsq.com

おまけ

使うマイコンによっては割り込みを使えない場合もあります。その場合は次のようにloop関数の中で割り込みをエミュレートしましょう。

void loop()
{
    int a = (PIND & _BV(2))>>2;
    int b = (PIND & _BV(3))>>3;

    if( a != prevA || b != prevB ){
      updateEncoder(a, b);
    }

    prevA = a;
    prevB = b;
}

ポート2とポート3の入力を調べるときにdigitalRead関数を使うかわりに、PIND & _BV(N)を使って高速化しています。

また、これで得られる値は0x00010や0x00100なので、1/0に変換するためにビットシフトしています。詳しくは次のサイトが参考になりました。

ehbtj.com