bluetooth リモコンはちょっと休憩して
Python のクラスの勉強。
クラスと言うと
カプセル化、継承、多態性
だと思っていたのですが・・・最近は違うみたいで
C++のクラスで必ず書く
public:
private:
が無い。Pythonに無い。
なんでだろって思いながらググったら
どうもPythonにはクラス内 Private 変数 / メソッドという考えが無いらしく
「外から使う、使わないは自己責任で」
だそうです。
結構なカルチャーショックでした。
てな事もあって、クラスの練習。
ちょうど、GPIOに入力ボタンの処理が少々面倒と思ってたとこなので
これをクラスにしてみました。
入力ボタンで面倒なのが
1) チャタリングや押し続けた時の処理
2) PULL_UP と PUL_DOWN での値の違いの処理
1) の対策は直前の入力値と比較するのが簡単だけど
これを毎回書いてると、コードが長くなって見通しが悪くなります
2) はどういう事かというと
入力ピンの設定に PULL_UP を指定するとボタンが押された時は Pin.value() が 0 になり
入力ピンの設定に PULL_DOWN を指定するとボタンが押された時は Pin.value() が 1 になる
この違いが面倒というかバグの元になりそうなので
クラスで吸収したかったのです
今回作ったコード
from machine import Pin
SWITCH_OFF = 0
SWITCH_ON = 1
SWITCH_CHANGED = True
SWITCH_NOT_CHANGED = False
class inputSwitch:
_SW_STATE_OFF = 0
_SW_STATE_ON = 1
_SW_STATE_FALL = 2 # 前回 ON、今回 OFF への変化
_SW_STATE_RISE = 3 # 前回 OFF、今回 ON への変化
def __init__(self, pin_number, pull = Pin.PULL_UP):
self._input_switch = Pin(pin_number, Pin.IN, pull)
if pull == Pin.PULL_UP:
self._active_low = True
else:
self._active_low = False
self._SW_STATE_PREV = inputSwitch._SW_STATE_OFF
def Get(self):
# _active_low が True (PULL_UP) の場合: value()が0なら SWITCH_ON を、value()が1なら SWITCH_OFFを返す
# _active_low が False (PULL_DONW) の場合は逆
_switch_value = self._input_switch.value()
if self._active_low == True:
if _switch_value == 0:
_SW_STATE_CURRENT = SWITCH_ON
else:
_SW_STATE_CURRENT = SWITCH_OFF
else: # _active_low == False
if switch_value == 0:
_SW_STATE_CURRENT = SWITCH_ON
else:
_SW_STATE_CURRENT = SWITCH_OFF
if _SW_STATE_CURRENT == SWITCH_ON:
# 前回が RISE なら ON にする
# 前回が OFF または FALL RISE にする
if self._SW_STATE_PREV == inputSwitch._SW_STATE_OFF:
self._SW_STATE_PREV = inputSwitch._SW_STATE_RISE
return SWITCH_OFF, SWITCH_NOT_CHANGED
elif self._SW_STATE_PREV == inputSwitch._SW_STATE_ON:
self._SW_STATE_PREV = inputSwitch._SW_STATE_ON # 不要
return SWITCH_ON, SWITCH_NOT_CHANGED
elif self._SW_STATE_PREV == inputSwitch._SW_STATE_FALL:
self._SW_STATE_PREV = inputSwitch._SW_STATE_RISE
return SWITCH_ON, SWITCH_NOT_CHANGED
elif self._SW_STATE_PREV == inputSwitch._SW_STATE_RISE:
self._SW_STATE_PREV = inputSwitch._SW_STATE_ON
return SWITCH_ON, SWITCH_CHANGED
else: #SW_STATE_CURRENT == SWITCH_OFF:
# 前回が FALL なら OFF にする
# 前回が ON または RISE なら FALL にする
if self._SW_STATE_PREV == inputSwitch._SW_STATE_OFF:
self._SW_STATE_PREV = inputSwitch._SW_STATE_OFF # 不要
return SWITCH_OFF, SWITCH_NOT_CHANGED
elif self._SW_STATE_PREV == inputSwitch._SW_STATE_ON:
self._SW_STATE_PREV = inputSwitch._SW_STATE_FALL
return SWITCH_ON, SWITCH_NOT_CHANGED
elif self._SW_STATE_PREV == inputSwitch._SW_STATE_FALL:
self._SW_STATE_PREV = inputSwitch._SW_STATE_OFF
return SWITCH_OFF, SWITCH_CHANGED
elif self._SW_STATE_PREV == inputSwitch._SW_STATE_RISE:
self._SW_STATE_PREV = inputSwitch._SW_STATE_FALL
return SWITCH_OFF, SWITCH_NOT_CHANGED
上で書いたように Python には C++ のようなアクセス指定子が有りません
自己責任で・・・苦手
間違わないように、private な変数、メソッドは
名前を _ で始める事にしました
(ググったら、↑こういうアドバイスが有りました)
__init__ 内、17~20行目で
PULL_UP の場合は _active_low を True に設定しています
ボタンが押された時に low (value = 0) になるという意味です
22行目でプログラム起動時にボタンが押されていない事にしています
いま、これを書いてて気づきましたが
これって何の保証もないから
他の人も使う可能性がある環境では、よくないコードかも
今回は自分用(クラスの勉強用)なので。。。
24行目からの Get() 関数でボタンの状態を取得します
単純には PULL_UP (_active_low == True) かどうかを見て処理を変え
PULL_UP でも PULL_DOWN でも
ボタンが押されていたら SWITCH_ON (= 1) を
ボタンが押されていなかったら SWITCH_OFF (= 0) を 返します
そして、もう1つ
直前にボタンの状態が変化したかどうかも返します。
Python は慣れていないけど
複数の戻り値がある時、C みたいに参照渡しにしなくても
return 文に並べてかけるのは便利ですね
39行目以降、ながながと同じような事を書いていますが
チャタリング対策です
簡単に言うと、ボタンの状態がオンの場合
前回の状態がオフなら、状態を一旦 “RISE” にして
前回の状態が “RISE” なら、オンと判定します
逆に、ボタンの状態がオフの場合
前回の状態がオンなら、状態を一旦 “FALL” にして
前回の状態が “FALL” なら、オフと判定します
簡易な対策ですが、実際に使ってみるとチャタリングを
“ほぼ”
防げました
完全ではないです。簡易は簡易。。。
今回はここまで。
次回は入力スイッチにトグル機能を付けます。

コメント