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も選択に入れてみてください。ロータリーエンコーダの使い方
汎用のロータリーエンコーダには固定ピン以外に3つの端子があります。真ん中の端子はArduinoのGNDへ接続します。両端のピンが出力ピンです。出力は1か0のデジタル信号になります。これら2つの__出力ピンは、必ずプルアップ__させてください。抵抗でプルアップする場合は、10kΩを介して3V3の電圧へ繋ぎます。また、内蔵プルアップ抵抗が使える場合は pinMode(RE_A, INPUT_PULLUP) でプルアップします。M5StickC PLUSには内蔵プルアップが設定されますので、今回はそれを使用します。
ちなみにAmazonでよく売られているスイッチ付きのロータリーエンコーダですが、こちらもA相・B相ありますから、この記事で行う方法と同じ扱いで大丈夫です。
ロータリーエンコーダを回転させるとステップごとに出力は表のように変化します。
Step | #1 | #2 | #3 | #4 |
---|---|---|---|---|
A | 0 | 1 | 1 | 0 |
B | 0 | 0 | 1 | 1 |
A相とB相が1/4周期ずれることで、どちらに回転されたかプログラムで判断が可能になってます。ただし、冒頭にも述べたとおり実際にプログラムするとかなりややこしいです。優れたライブラリがありましたので、今回はこちらを利用します。 GitHub-mathertel / Rotary Encoder : Rotary Encoder Arduino Library GitHubからzipファイルをダウンロードして解答し、Arduinoのlibrariesディレクトリへ移して使ってください。または、srcにあるRotaryEncoder.hとRotaryEncoder.cppだけを.inoファイルのあるディレクトリへ配置しても動きます。
RotaryEncoder.cppを覗けば、ロータリーエンコーダの処理の大変さが実感できるでしょう。Arduinodえロータリーエンコーダを使ってみよう
それでは、実際にArduino(M5StickC PLUS)を使ってロータリーエンコーダを使ってみましょう。
ピンの状態を監視するには割り込み処理を使用します。こちらがその設定です。
attachInterrupt(digitalPinToInterrupt(RE_A), checkPosition, CHANGE);
attachInterrupt(digitalPinToInterrupt(RE_B), checkPosition, CHANGE);
指定したピンの状態が変化すればcheckPosition関数が呼ばれます。状態変化の指定には他にも次のようなものがあります。
項目 | 動作 |
---|---|
LOW | ピンがLOWのとき発生 |
CHANGE | ピンの状態が変化したときに発生 |
RISING | ピンの状態がLOWからHIGHに変わったときに発生 |
FALLING | ピンの状態がHIGHからLOWに変わったときに発生 |
また、割り込み処理の関数checkPositionをIRAM_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()で簡単に取得できます。#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;
}
}
ロータリーエンコーダは、ポテンショメータ(可変抵抗)よりも微細な値を読み取ることができますので、ステッピングモータと組み合わせたりして正確に制御する場合に使えます。