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

Share on:

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

Encorderクラス

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

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

 1class Encorder():
 2    def __init__(self, pin_a, pin_b):
 3        self.pin_a, self.pin_b = pin_a, pin_b
 4        self.position, self.value, self.direction = 0, 0, 0
 5        self.table = [
 6             0, 1,-1, 0,
 7            -1, 0, 0, 1,
 8             1, 0, 0,-1,
 9             0,-1, 1, 0
10        ]
11        
12    def check(self, pin):
13        self.value = (self.value << 2) + self.pin_a.value() + (self.pin_b.value() << 1)
14        self.value = self.value & 0x0F
15        self.direction = self.table[self.value]
16        self.position += self.direction

入力設定

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

 1# GPIO settings
 2pin32 = Pin(32, Pin.IN)
 3pin35 = Pin(35, Pin.IN)
 4
 5# Encoorder settings
 6encorder = Encorder(pin32, pin35)
 7
 8# Interrupt settings
 9pin32.irq( encorder.check )
10pin35.irq( encorder.check )

PCにデータを送る処理

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

1tmp = 0
2
3while True:
4    if tmp != encorder.position:
5        tmp = encorder.position
6        print(encorder.position, encorder.direction)

出力内容

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

ソースコード

 1import time
 2from machine import Pin
 3
 4class Encorder():
 5    def __init__(self, pin_a, pin_b):
 6        self.pin_a, self.pin_b = pin_a, pin_b
 7        self.position, self.value, self.direction = 0, 0, 0
 8        self.table = [
 9             0, 1,-1, 0,
10            -1, 0, 0, 1,
11             1, 0, 0,-1,
12             0,-1, 1, 0
13        ]
14        
15    def check(self, pin):
16        self.value = (self.value << 2) + self.pin_a.value() + (self.pin_b.value() << 1)
17        self.value = self.value & 0x0F
18        self.direction = self.table[self.value]
19        self.position += self.direction
20
21# GPIO settings
22pin32 = Pin(32, Pin.IN)
23pin35 = Pin(35, Pin.IN)
24
25# Encoorder settings
26encorder = Encorder(pin32, pin35)
27
28# Interrupt settings
29pin32.irq( encorder.check )
30pin35.irq( encorder.check )
31
32print('start')
33
34tmp = 0
35
36while True:
37    if tmp != encorder.position:
38        tmp = encorder.position
39        print(encorder.position, encorder.direction)

関連記事