ESP32のMicroPythonでロータリーエンコーダの読み取り

MicroPythonのファームウェアを入れたESP32でロータリーエンコーダを読み取るプログラムを作成してみました。使用した機能はGPIOの入力と外部割込みです。



Encorderクラス

エンコーダの処理のためにクラスを作成しました。コンストラクタでは入力ピンの設定やテーブル、変数の初期化をしています。check関数は外部割込みで実行する関数で、前回のエンコーダの値と現在のエンコーダの値、テーブルから回転方向と位置を計算する関数です。計算内容はネットにいろいろ書いているのでそれらを参考にしました。

外部割込みの処理内容が増えるとESP32が割り込み処理ばかりしてしまうので気を付けないといけません。この辺りはコンパイルしてマイコンに書き込む場合はわかりやすいかもしれませんが、MicroPythonの場合は実際に動作させてみないとわからなそうです。

class Encorder():
    def __init__(self, pin_a, pin_b):
        self.pin_a, self.pin_b = pin_a, pin_b
        self.position, self.value, self.direction = 0, 0, 0
        self.table = [
             0, 1,-1, 0,
            -1, 0, 0, 1,
             1, 0, 0,-1,
             0,-1, 1, 0
        ]
        
    def check(self, pin):
        self.value = (self.value << 2) + self.pin_a.value() + (self.pin_b.value() << 1)
        self.value = self.value & 0x0F
        self.direction = self.table[self.value]
        self.position += self.direction

入力設定

エンコーダに接続するGPIOはPin.INで入力設定にしています。それらのピンをEncorderクラスに渡してEncorderクラスで処理すべきピンを指定しています。外部割込み時に実行するメソッドはPin.irq()で指定します。エンコーダのどちらかのピンの入力が変わった場合にEncorder.check()を実行するように記述しています。

# GPIO settings
pin32 = Pin(32, Pin.IN)
pin35 = Pin(35, Pin.IN)

# Encoorder settings
encorder = Encorder(pin32, pin35)

# Interrupt settings
pin32.irq( encorder.check )
pin35.irq( encorder.check )

PCにデータを送る処理

while True:で無限ループを作成してデータを送信しています。送信するタイミングは、前回と現在のencorder.positionと異なる場合としています。

tmp = 0

while True:
    if tmp != encorder.position:
        tmp = encorder.position
        print(encorder.position, encorder.direction)

出力内容

エンコーダを回すとシリアル通信で現在位置と回転方向が送られてきます。

ソースコード

import time
from machine import Pin

class Encorder():
    def __init__(self, pin_a, pin_b):
        self.pin_a, self.pin_b = pin_a, pin_b
        self.position, self.value, self.direction = 0, 0, 0
        self.table = [
             0, 1,-1, 0,
            -1, 0, 0, 1,
             1, 0, 0,-1,
             0,-1, 1, 0
        ]
        
    def check(self, pin):
        self.value = (self.value << 2) + self.pin_a.value() + (self.pin_b.value() << 1)
        self.value = self.value & 0x0F
        self.direction = self.table[self.value]
        self.position += self.direction

# GPIO settings
pin32 = Pin(32, Pin.IN)
pin35 = Pin(35, Pin.IN)

# Encoorder settings
encorder = Encorder(pin32, pin35)

# Interrupt settings
pin32.irq( encorder.check )
pin35.irq( encorder.check )

print('start')

tmp = 0

while True:
    if tmp != encorder.position:
        tmp = encorder.position
        print(encorder.position, encorder.direction)

コメント

タイトルとURLをコピーしました