プログラムコード
このプログラムでは、赤外線センサーを使って人の動きを始終監視し、何もない平時にはPicoのオンボードLEDを点滅させ、人の動きを感知した緊急時にブザーを鳴らすようにします。人間の動きはいつ感知されるか分からないので、While Trueの無限ループで、センサーの値をずっと監視します。
from machine import Pin
import utime
# 赤外線センサー
sensor = Pin(15, Pin.IN, Pin.PULL_DOWN)
# オンボードLED
onboard_led = Pin(25, Pin.OUT)
# ブザー
buzzer = Pin(14, Pin.OUT)
# オフでスタート
onboard_led.off()
buzzer.off()
# 非常時ブザーを鳴らす
def alarm_buzzer():
onboard_led.off()
buzzer.off()
# 50回、高速で点滅
for i in range(50):
buzzer.toggle()
onboard_led.toggle()
utime.sleep(0.1)
utime.sleep(0.5)
# 平時のオンボードLED点滅
def onboard_blink():
buzzer.off()
onboard_led.toggle()
utime.sleep(0.5)
while True:
utime.sleep(0.1)
if sensor.value()==1:
print("非常事態発生!!")
alarm_buzzer()
print("平時")
onboard_blink()
MicroPythonでも、Pythonと同じ要領で関数が定義できます。ここでは、非常時用のalarm_buzzer()関数と平時用のonboard_blink()関数を定義して、while Trueの無限ループで赤外線センサーの値を監視し、値が1のときにalarm_buzzer()を、そうでないときにonboard_blink()を呼び出しています。
LEDやブザーのtoggle()は、オンとオフを交互に切り替えるメソッドです。オンならオフに、オフならオンに切り替えることで、点滅や断続音が作り出せます。具体的に言うと、whileループのある呼び出しのときLEDを点灯させたonboard_led.toggle()は、次の呼び出しのときLEDを消します。これが繰り返されるので、点滅になります。
プログラムを実行すると、平時のオンボードLEDが点滅します。防犯装置の平時の点滅は「この辺りは監視されているぞ」ということを侵入者に示す効果があります。センサーに手をかざすとブザーが鳴り、しばらくすると止みます。もう一度手をかざすとブザーが鳴り、しばらくすると止みます。結果だけを見ると、動作に問題がないように思えますが、このプログラムは実はもう少し良くなります。
while Trueでは、繰り返しのたびに次の行でセンサーの値を調べていますが、これはPicoの負担で、もし誰かが代わってくれたらPicoは楽になります。
if sensor.value()==1:
その代わりの方法に割り込みがあります。
割り込み
割り込みを使用すると、while Trueで平時の動作を実行中、赤外線センサーが動きを感知したタイミングで割り込み、つまり“横入り”をして、while Trueのメインループを一時的に停めて、緊急時の動作を実行することが可能になります。

割り込みの設定は少しややこしく、割り込みを設定するには、赤外線センサーのirq()メソッドで、トリガーとハンドラと呼ばれるものを設定します。トリガーとは“引き起こすもの”という意味で、ここでは割り込みを引き起こすものを言います。ハンドラは“処理するもの”という意味で、ここではトリガーによって割り込みが引き起こされたときに呼び出される関数名を指します。
sensor.irq(trigger=Pin.IRQ_RISING, handler=alarm_buzzer)
トリガー(trigger)に指定しているPin.IRQ_RISINGは、ピンの値がロー(0)からハイ(1)に変化するときの「立ち上がり」の部分を言います。

専門用語が多く混乱されるでしょうが、ざっくり言うと、sensor.irq(trigger=Pin.IRQ_RISING, handler=alarm_buzzer)によって、センサーの値の監視が開始され、値がトリガーのIRQ_RISINGの状態に達したとき、つまりローからハイに上がり始めたとき、ハンドラのalarm_buzzer()関数が自動的に呼び出される、という仕組みです。
ハンドラのalarm_buzzer()関数では、パラメータ変数にpinを定義する必要があります。この変数はirq()メソッドで割り込みを設定したピンを指しています。
# ハンドラ関数
def alarm_buzzer(pin):
IRQはInterrupt ReQuestの略で、割り込み要求という意味です。
プログラムコード
割り込みを使ったプログラムは次のように記述できます。
from machine import Pin
import utime
sensor = Pin(15, Pin.IN, Pin.PULL_DOWN)
onboard_led = Pin(25, Pin.OUT)
buzzer = Pin(14, Pin.OUT)
# ハンドラ関数
def alarm_buzzer(pin):
if pin.value() == 1:
print("非常事態発生!!")
onboard_led.off()
buzzer.off()
# 50回、高速で点滅
for i in range(50):
print("IRQ")
buzzer.toggle()
onboard_led.toggle()
utime.sleep(0.1)
utime.sleep(0.5)
# 平時のオンボードLED点滅
def onboard_blink():
buzzer.off()
onboard_led.toggle()
utime.sleep(0.5)
# PIRセンサーの割り込み設定。
# 侵入者を感知したら、ハンドラ関数を呼び出す
sensor.irq(trigger=machine.Pin.IRQ_RISING, handler=alarm_buzzer)
# メインループでは、平時の動作を実行するだけ
while True:
print("Main")
onboard_blink()
utime.sleep(0.1)
割り込みを使用することで、whileループではセンサーの値を調べる必要がなくなり、Picoの負担が軽減されます。なお、sensor.irq()の行は、while True より先に記述する必要があります。プログラムはwhile Trueで無限ループに入るので、while Trueより後に書くと、プログラムの実行中、sensor.irq()は実行されない行になるからです。