ESP32-FreeRTOSにて、ロータリーエンコーダのイベントを検出する


はじめに

前回、スイッチのイベントの検出を記載しました。
今回は、ロータリーエンコーダの検出について記載します。

開発環境

以下が確認した環境となります。

  • windows10 64bit
  • Arduino IDE 1.8.10
    • Esplora Built-In by Arduino 1.0.4
    • FreeRTOS by Richard Barry 10.2.0-3
    • RotaryEncoder by Matthias Hertel 1.3.0 - Github - RotaryEncoder
  • vscode 1.41.1
    • PlatformIO - Home 3.0.1, Core 4.1.0

本コードは、RotaryEncoderライブラリを使用しています。

./lib下に、RotaryEncoderのライブラリを配置する必要があります。


./SampleRe/lib/RotaryEncoder-master/RotaryEncoder.cpp
./SampleRe/lib/RotaryEncoder-master/RotaryEncoder.h

※Arduino IDEでも動くことは確認しましたが、
 Arduino IDEで動かす場合は、main.cppを.inoファイルに置き換える必要があります。
 また、Arduino IDE時は、ライブラリマネージャーよりインストールすることができます。

機材と接続図

2種類のロータリーエンコーダで確認したので、それぞれ記載します。

  • フルカラーRGB LED付ロータリーエンコーダを使用
  • HiLetgo 回転式のエンコーダモジュールを使用

フルカラーRGB LED付ロータリーエンコーダ時のの機材

※型名が購入先のリンクになっています。

項目 型名 備考
ESP32-WROOM-32 開発ボード NodeMCU-32S ESP32-WROOM-32 -
ロータリーエンコーダ EC12PLRGBSDVBF-D-25K-24-24C-61 DIP化基板とはんだ付け必要
ロータリーエンコーダDIP化基板 RECNV-2 AE-RECNV-2
抵抗 10kΩ x 2
ブレッドボード 指定なし
ジャンパーケーブル 指定なし

フルカラーRGB LED付ロータリーエンコーダ時の接続図

↓が実際の写真です。ユニバーサルボードにのっていますが。

HiLetgo 回転式のエンコーダモジュール時の機材

※型名が購入先のリンクになっています。

項目 型名 備考
ESP32-WROOM-32 開発ボード NodeMCU-32S ESP32-WROOM-32 -
ロータリーエンコーダ HiLetgo 回転式のエンコーダモジュール はんだ付け不要
ブレッドボード 指定なし
ジャンパーケーブル 指定なし

HiLetgo 回転式のエンコーダモジュール時の接続図

↓が実際の写真です。

シーケンス図

作成するプログラムのシーケンス図は、以下となります。

コードの配置場所

コードは、下記に配置してあります。
esp32Samples - SampleRe

シーケンスとコードコードの紐づけ

シーケンスとコードの関連箇所を抜粋して記載します。

初期化処理

REのインスタンスの作成

  • 使用するPINの定義
Sytem_Re.h
#define RE_ASGN_SIGNAL_A    (4)
#define RE_ASGN_SIGNAL_B    (2)
  • インスタンスの生成
ApiRe.cpp
#include <RotaryEncoder.h>

static RotaryEncoder s_xRotaryEncoder(RE_ASGN_SIGNAL_A, RE_ASGN_SIGNAL_B);

RE用割り込みのアタッチ

ApiRe.cpp
    // 割り込み関連の設定
    attachInterrupt(digitalPinToInterrupt(RE_ASGN_SIGNAL_A), vIsrCallbackRe, CHANGE);
    attachInterrupt(digitalPinToInterrupt(RE_ASGN_SIGNAL_B), vIsrCallbackRe, CHANGE);
  • vIsrCallbackRe
    • 割り込み時の処理(後述)
  • CHANGE
    • A相, B相の変化点が必要のため、CHANGEを指定

RE用タイマーの生成

ApiRe.cpp
#define RE_CHECK_TIME           (50)        //ロータリーエンコーダチェック間隔:50msec
...

static TimerHandle_t s_xTimerRe = NULL;

...

ErType_t xInitRe(void)
{
    ...
    s_xTimerRe = xTimerCreate
                    (   cName,                      //text name
                        RE_CHECK_TIME,              //timer period
                        pdTRUE,                     //auto-reload
                        ( void * ) 0,               //number of times
                        vTimerCallbackRe                //callback
                    );

xTimerReset(    s_xTimerRe, RE_CHECK_TIME)

  • auto-reload : pdTRUE
    • 50msec毎に定期的にコールするために指定

回転イベントの検出

割り込みの発生/回転数の保持

ApiRe.cpp
/**
 * @brief ロータリーエンコーダ割り込み処理
 */
static void IRAM_ATTR vIsrCallbackRe()
{
    s_xRotaryEncoder.tick(); // just call tick() to check the state.
}

割り込みが発生した場合、上記の関数がコールされます。
tick()をコールし、回転数が保持されます。

回転数の取得/回転状態を送信

ApiRe.cpp

/**
 * @brief ロータリーエンコーダのタイマーコールバック関数
 */
static void vTimerCallbackRe( TimerHandle_t xTimer)
{
    static int32_t pos;

    pos = s_xRotaryEncoder.getPosition();
    if( pos != s_slBakRePosition )
    {
        Serial.printf("%s - (%d), (%d)\n",__func__ ,pos ,(pos - s_slBakRePosition));
        s_slBakRePosition = pos;
    }

    return;
}

50msec毎に、上記の関数がソフトウェアタイマータスク内で処理されます。
前回の状態と異なる場合、Serial.printf()でユーザに通知します。

実行結果例

  • 時計回りを実施
vTimerCallbackRe - (11), (1)
vTimerCallbackRe - (12), (1)
vTimerCallbackRe - (13), (1)
vTimerCallbackRe - (14), (1)
vTimerCallbackRe - (17), (3)
vTimerCallbackRe - (18), (1)
  • 反時計回りを実施
vTimerCallbackRe - (25), (-1)
vTimerCallbackRe - (23), (-2)
vTimerCallbackRe - (21), (-2)
vTimerCallbackRe - (20), (-1)

参考