TOPに戻る

センサ・シリーズ 温度①確度±0.1℃ TMP117 その3 アラートでLED点灯

 使用環境
  • Raspberry Pi Raspberry Pi 4 Model B 2MB
  • OS Raspberry Pi OS(32ビット)5.4.51
  • Python3 3.7.3
  • smbusライブラリ 4.1-1
  • RPi.GPIOライブラリ 0.7.0
  • エディタ Mu

 前回、温度センサTMP117のもつアラートの設定をしました。上限設定温度31℃を超えるとアラートをコンソールに表示しました。ここでは、GPIOピンにLEDをつないで、アラートの表示をします。

LEDの電流制限抵抗

 白色LEDの中身は青色LEDです。順方向電圧Vfは約3Vです。したがって、GPIOのHighの電圧が3.3Vとの電位差がほとんどありません。下記のように電流制限抵抗Rの値を計算します。

  R = (3.3 - 3.0) / 5[mA] = 60[Ω]

  R = (3.3 - 3.0) / 1[mA] = 300[Ω]

 白色LEDが出始めた昔は、10~20mAの電流を流して光らせていましたが、最近の製品は1mA程度で明るく光ります。多くの小信号用LEDは、1mA以下で光り始め、電流を増やすと明るさが増し、10~20mA付近で明るさが増えなくなり、30~70mAを超えると破壊する製品が多いようです。

 赤色や緑色のLEDのVfは当初1.7V付近でしたが、最近の製品では2.0V前後です。

  R = (3.3 - 1.7) / 1[mA] = 1.6[kΩ]

  R = (3.3 - 1.7) / 3[mA] = 530[Ω]

  R = (3.3 - 2.0) / 1[mA] = 1.3[kΩ]

  R = (3.3 - 2.0) / 3[mA] = 430[Ω]

 アマゾンで購入したLEDには規格は不明です。これらの計算から、白色と青色は300Ω赤色、緑色、黄色、オレンジ色は1kΩにしましょう。

 ラズパイのGPIOが流せる電流は最大5mAぐらいといわれています。なので、少ない分にはマイコンにダメージを与えません。

LEDの接続には2通りある

 マイコンのI/Oピン=ディジタル入出力ポートは、電流を吐き出す(source)と電流を吸い込む(sink)の両方の機能があります。マイコンによっては、扱える電流が異なります。2~5mAのデバイスが多いようです。

 どちらも、マイコン内部に電流が流れるので、少ないほうが発熱は少ないです。

GPIOピンにLEDをつなぐ

 上の図(b)ではGPIOのポートをHighにしたときに電流が流れ、LEDが点灯します。電流が流れだす接続が、次の図(c)です。GPIO17(11番)に抵抗1kと赤色LEDをつなぎます。

(c) GPIO17にLEDをつなぐ

 図(b)のソース電流を流す回路を採用した上記の回路では、LEDを点灯するためのプログラムを書かなくてはなりません。
 しかし、図(a)のシンク電流を流す回路採用し、図(d)のようにLEDをALRT信号につなげれば、プログラムは変更せずに済みます。ALRTは、アクティブLowでしたから。

 LEDには1~2mAが流れます。ALRTのsink電流をデータシートで見ると、0.8Vまで電圧が上昇してもよいなら約25mAの電流を吸い込めます。こんなに電流を流すとデバイスが発熱するので、2mA程度ならよいかもしれません。

(d) GPIO4にLEDをつなぐ

 最初に、図(d)の接続図通り実際にLEDを接続して、前回のプログラムを動かします。LEDの抵抗は、1番ではなく17番の3.3Vへつなぎました。

LEDの用意

 左のLEDは抵抗入りです。右は普通のLEDです。抵抗は1kΩ1/2Wです。もちろん電流は流れないので1/4WでもOKです。

 リード線をはんだ付けします。足の短いほうのカソードは黒色のリード線です。この後、シュリンク・チューブ(スミチューブ)でむき出しの部分を覆い、ヒート・ガンで熱して密着させます。

GPIO4にLEDをつないだ回路

 前回の最後のプログラムでは、上限温度を超えると、ALRT信号がHigh->Lowになります。割り込みがかかり、コンソールに「at High temp」を表示します。図(d)の回路では、その時にLEDが点灯するはずです。

 実際に動かすと、瞬間にぴかっと光ります。短すぎます。しかし、割り込み関数内は、基本はすぐに抜けるようにプログラムを作るのがセオリです。それは、割り込みはいつかかるかわからないし、複数の割り込み源が存在することもあるからです。

 したがって、「at High temp」を表示した後、同じ割り込み処理関数内で、少しの時間待ってからアラート・フラグをクリアするわけにはいきません。

GPIO17にLEDをつないだ回路

 次に、図(c)を試します。上限温度を超えるとGPIO17を制御するプログラムを追加します。LEDはGPIO17がHighになると点灯します。

 プログラムです。上限温度を超えていたらLEDはONになり、1秒間キープします。

import RPi.GPIO as gpio
from time import sleep
import smbus
bus = smbus.SMBus(1)

tmp117_addr = 0x48
TemperatureRegister   = 0x00
ConfigurationRegister = 0x01
THigh_LimitRegister   = 0x02
High_Limit_temp_dec   = 31
High_Limit_temp_list  = [0x0f, 0x80]
ALRT_pin = 4  # 7pin
ALRT_LED_pin = 17  # 11pin

def sign16(x):  # 16ビットの2の補数形式。符号処理
    return (-(x & 0b1000000000000000) | (x & 0b0111111111111111))

def callback_alert(ALRT_pin):  # 割り込みで呼ばれる関数
    print('at High temp')
    bus.read_i2c_block_data(tmp117_addr, ConfigurationRegister, 2)  # clear alert flag

gpio.setmode(gpio.BCM)  # GPIOxxという名称のxxという数字を使う
gpio.setup(ALRT_pin, gpio.IN, pull_up_down=gpio.PUD_UP)  # 割り込みピンは入力に設定し、プルアップする
gpio.add_event_detect(ALRT_pin, gpio.FALLING, callback=callback_alert, bouncetime=20)  # 20msは割り込み禁止
gpio.setup(ALRT_LED_pin, gpio.OUT) # LED用ピンは出力に設定
gpio.output(ALRT_LED_pin, False)  # set Low

print('reset')
bus.write_i2c_block_data(tmp117_addr, ConfigurationRegister, [0x00, 0x02])  # soft reset
sleep(1)
kakunin0 = bus.read_i2c_block_data(tmp117_addr, ConfigurationRegister, 2)
print("ConfigurationRegister is %s %s" % (bin(kakunin0[0]), bin(kakunin0[1])))

bus.write_i2c_block_data(tmp117_addr, ConfigurationRegister, [0x02, 0x60]) # 64回平均
kakunin1 = bus.read_i2c_block_data(tmp117_addr, ConfigurationRegister, 2)
print("ConfigurationRegister is %s %s" % (bin(kakunin1[0]), bin(kakunin1[1])))
sleep(0.5)
bus.write_i2c_block_data(tmp117_addr, THigh_LimitRegister, High_Limit_temp_list) # 上限温度を設定
kakunin2 = bus.read_i2c_block_data(tmp117_addr, THigh_LimitRegister, 2)
print("THigh_LimitRegister is   %s %s" % (hex(kakunin2[0]), hex(kakunin2[1])))
temp = kakunin2[0] <<8 | kakunin2[1]
temperature = sign16(temp) * 0.0078125
print(' setting High temp Limit %s' % temperature)
sleep(5) # 準備終了
try:
    while 1:
# ポーリング data = bus.read_i2c_block_data(tmp117_addr , TemperatureRegister, 2) # 温度の読み出し temp = data[0] <<8 | data[1] temperature = sign16(temp) * 0.0078125 print("\nTemp is %.5f `C" % temperature) if temperature > High_Limit_temp_dec: gpio.output(ALRT_LED_pin, True) # 上限温度を超えていたらLED ON else: gpio.output(ALRT_LED_pin, False) # off sleep(1) # ポーリングのループの繰り返し時間 except KeyboardInterrupt: # CTRL-Cの中断割り込み print('\n end') gpio.cleanup() # RPi.GPIOライブラリの正常終了処理

割り込みとポーリング

 アラート信号を受けて割り込みでコンソールに「at High temp」を表示しました。
 forループの中で温度を測定して、31℃を超えていたら、LEDを点灯しました。これをポーリングと呼びます。

 どちらも上限温度31度を超えたら動作します。今回の割り込みは、実測で100us(※1)ぐらいで動作しました。ポーリングはsleep(0.01)とすれば、20ms程度(※2)の間隔で温度を測定できます。

(※1)割り込み処理関数の先頭にGPIO21をONする処理を追加し、ALRTのGPIO4の両方をオシロスコープで観測し、差の時間を測定した。

(※2)実測。print文が入っているので10msより長めになった。

 割り込みのメリットは、forループでいろいろなことをやっていても、リアルタイムで反応できるところです。ポーリングは、forループ内で時間がかかる処理があれば、31℃の上限を超えたことに気づくのにタイムラグが生じます。

 今回の制御の対象が温度と、比較的変化の度合いが緩やかなので、割り込みを使う必要はないかもしれません。

 なお、どちらの処理もprint文が入っていますが、処理時間がかかるので、デバッグが終わったらコメントアウトします。

連載 ラズパイ センサ・シリーズ

(1) 温度①確度±0.1℃ TMP117 その1 温度の読み出し

(2) 温度①確度±0.1℃ TMP117 その2 アラートの設定

(3) 温度①確度±0.1℃ TMP117 その3 アラートでLED点灯

(4) 温度①確度±0.1℃ TMP117 その4 アラートでリレー駆動

(5) 温度②温度調節器 その1 Modbusの設定

(6) 温度②温度調節器 その2 Modbusで読み書き

(7) 温湿度①SHT31 その1 測定準備