M5StickC PLUSとロータリーエンコーダ

M5StickC PLUSとロータリーエンコーダの配線
M5StickC PLUSとロータリーエンコーダの配線

この記事では、ロータリーエンコーダをArduinoで使う方法をご説明します。ここではA相・B相の2相出力の汎用ロータリーエンコーダを使用しました。 実は、ロータリーエンコーダを使っていざプログラミングしようとするとかなり大変です。そのため、ここではArduinoライブラリを使用しました。 なお、ArduinoボードはArduino互換機であるESP32 PICOが搭載されたM5StickC PLUSを使用しました。M5StickC PLUSは、バッテリーやLCD他いろいろなセンサがパッケージされたM5Stackシリーズ製品の一つです。一般のArduinoと同じようにArduino IDEで開発できます。 Arduino互換機であれば本記事の内容で動作します。また、M5StickC PLUSの使い方は M5StickC PLUSでArduinoをはじめよう! をご覧ください。

▼ 半導体不足のため入手困難な場合は、ひとつ前のモデルのM5StickCも選択に入れてみてください。

ロータリーエンコーダの使い方

M5StickC PLUSとロータリーエンコーダの配線
M5StickC PLUSとロータリーエンコーダの配線
汎用のロータリーエンコーダには固定ピン以外に3つの端子があります。真ん中の端子はArduinoのGNDへ接続します。両端のピンが出力ピンです。出力は1か0のデジタル信号になります。これら2つの__出力ピンは、必ずプルアップ__させてください。抵抗でプルアップする場合は、10kΩを介して3V3の電圧へ繋ぎます。また、内蔵プルアップ抵抗が使える場合は pinMode(RE_A, INPUT_PULLUP) でプルアップします。M5StickC PLUSには内蔵プルアップが設定されますので、今回はそれを使用します。

ちなみにAmazonでよく売られているスイッチ付きのロータリーエンコーダですが、こちらもA相・B相ありますから、この記事で行う方法と同じ扱いで大丈夫です。

ロータリーエンコーダを回転させるとステップごとに出力は表のように変化します。

Step#1#2#3#4
A0110
B0011

A相とB相が1/4周期ずれることで、どちらに回転されたかプログラムで判断が可能になってます。ただし、冒頭にも述べたとおり実際にプログラムするとかなりややこしいです。優れたライブラリがありましたので、今回はこちらを利用します。 GitHub-mathertel / Rotary Encoder : Rotary Encoder Arduino Library GitHubからzipファイルをダウンロードして解答し、Arduinoのlibrariesディレクトリへ移して使ってください。または、srcにあるRotaryEncoder.hRotaryEncoder.cppだけを.inoファイルのあるディレクトリへ配置しても動きます。

RotaryEncoder.cppを覗けば、ロータリーエンコーダの処理の大変さが実感できるでしょう。

Arduinodえロータリーエンコーダを使ってみよう

ロータリーエンコーダちM5StickC PLUS
ロータリーエンコーダちM5StickC PLUS
それでは、実際にArduino(M5StickC PLUS)を使ってロータリーエンコーダを使ってみましょう。

ピンの状態を監視するには割り込み処理を使用します。こちらがその設定です。

cpp
attachInterrupt(digitalPinToInterrupt(RE_A), checkPosition, CHANGE);
attachInterrupt(digitalPinToInterrupt(RE_B), checkPosition, CHANGE);

指定したピンの状態が変化すればcheckPosition関数が呼ばれます。状態変化の指定には他にも次のようなものがあります。

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

また、割り込み処理の関数checkPositionIRAM_ATTRで指定してます。IRAM_ATTRを使用すると、コンパイルされたコードはがESP32の内部RAM領域に配置され、割り込み処理を高速化できます。ただし、ESP32以外のArduinoボードでは使えない場合があります。その際はIRAM_ATTRの記述を削除してください。

new RotaryEncoder(RE_A, RE_B, RotaryEncoder::LatchMode::TWO03); でRotaryEncoderクラスの初期化を行います。LatchModeの指定は、こちらの公式サイトで説明されてますが、いまいちよく分かりませんでした。 A Library for the Arduino environment forusing a rotary encoder as an input.loop関数内のencoder->tick()は、出力ピンの状態を観察してます。出力に変化があればクラス内部でポジションを加算・減算させているようです。 現在のポジション値は、encoder->getPosition()で簡単に取得できます。
arduino
#include <M5StickCPlus.h>
#include <RotaryEncoder.h>

#define RE_A 0
#define RE_B 26

RotaryEncoder* encoder = nullptr;

IRAM_ATTR void checkPosition() { // ビルドに失敗する場合はIRAM_ATTRを削除してください
    encoder->tick(); // just call tick() to check the state.
}

void setup() {
    M5.begin();
    M5.Axp.ScreenBreath(9);
    M5.Lcd.setRotation(3);
    M5.Lcd.fillScreen(WHITE);
    M5.Lcd.setTextColor(BLACK);

    pinMode(RE_A, INPUT_PULLUP);
    pinMode(RE_B, INPUT_PULLUP);

    attachInterrupt(digitalPinToInterrupt(RE_A), checkPosition, CHANGE);
    attachInterrupt(digitalPinToInterrupt(RE_B), checkPosition, CHANGE);

    encoder = new RotaryEncoder(RE_A, RE_B, RotaryEncoder::LatchMode::TWO03);
    M5.Lcd.fillScreen(WHITE);
    M5.Lcd.setCursor(0, 10);
    M5.Lcd.setTextSize(2);
    M5.Lcd.println("Setup is complete! Rotate the rotary encoder!");

}

void loop() {

    static int pos = 0;

    encoder->tick(); // just call tick() to check the state.

    int newPos = encoder->getPosition();
    if (pos != newPos) {
        M5.Lcd.fillScreen(WHITE);
        M5.Lcd.setCursor(0, 10);
        M5.Lcd.setTextSize(4);
        M5.Lcd.printf(" pos:%d\n", newPos);
        M5.Lcd.printf(" dir:%d\n", (int)(encoder->getDirection()));
        pos = newPos;
    }
}

ロータリーエンコーダは、ポテンショメータ(可変抵抗)よりも微細な値を読み取ることができますので、ステッピングモータと組み合わせたりして正確に制御する場合に使えます。

関連記事

最後までご覧いただきありがとうございます!

▼ 記事に関するご質問やお仕事のご相談は以下よりお願いいたします。
お問い合わせフォーム

人気のArduino互換機
Arduinoで人気の周辺パーツ
あると便利な道具
Arduinoのオススメ参考書

▼ Arduino初心者向きの内容です。ほかのArduino書籍と比べて図や説明がとてもていねいで読みやすいです。Arduinoで一通りのセンサーが扱えるようになります。

▼ 外国人が書いた本を翻訳したものです。この手の書籍は、目からうろこな発見をすることが多いです。

▼ Arduinoの入門書を既に読んでいる方で、次のステップを目指したい人向きの本です。C言語のプログラミングの内容が中心です。ESP32だけでなく、ふつうのArduinoにも役立つ内容でした。