5ドル!ラズパイ・ゼロ(Raspberry pi Zero)でIoT (27) ディジタル光センサ1 I2C TSL2561

■luxを測れる

 TAOS(現在ams)というメーカの受光デバイスTSL2561を3.3Vと5Vの両方で利用できるようにしたモジュールがAdafruitから販売されています。 

 TLS2561には受光波長領域が異なる二つのフォト・ダイオードが搭載されていて、luxを計算するときに誤差を生む赤外線の影響を排除できるようになっていますが、計算が複雑です。

 luxはlxと略されることがあるそうです。luxは「ルーメン毎平方メートル」の単位で、1m×1mの面積に当たる光の量を表しています。ルーメン(im)は光源の出す光の量で、40W白熱球は約500ルーメンです。

TLS2561のスペック

  • 電源電圧 2.7~5V
  • インターフェース I2C(最大400kHz)
  • アドレス 0x29、0x39、0x49から選択
  • ダイナミック・レンジ 0.1~40000lux
  • 50/60Hzの照明リプル自動排除

TLS2561モジュールのスペック

 スレーブ・アドレスを設定するADDRSEL端子は、プリント基板の裏面で、はんだブリッジでショートする場所により+3.3V、GND、開放の3種類が選択できます。開放のままにします。

ショートする部分 アドレス
GND 0x29
開放 0x39
3.3V 0x49

 プリント基板上にはレギュレータICがあり、Vinに5Vをつないだときに、3vo端子に3.3Vを出力します。SDA/SCLの信号線は3.3Vと5Vのレベル・コンバータ回路があり、どちらの電圧にも対応しています。

 3.3Vと5Vの両方のSDA/SCL信号は、それぞれ10kΩでプルアップされています。ラズパイには不要なのですが、3.3V用の抵抗がどれか判別できないので、四つともはんだゴテで温めて取り去ります。

接続

TSL2561 ラズパイ
SCL 5番ピン
GND 9番ピン
SDA 3番ピン
3vo 1番ピン 3.3V

テスト・プログラム

 デバイスは電源が入った後スリープしています。0x03コードを送って起こします。

 デバイスへは、二つの項目を設定します。

  • 利得;デフォルト16倍の高利得設定、低利得はx1
  • 積分時間;デフォルトの402ms、それ以外に101ms13.7msがある。

 デフォルト値と異なる設定をしたときは、読み出したA-Dコンバータの結果に倍率(scale)を掛けて変更します。

 次の表は0x81のTimingレジスタの内容で、利得と積分時間を設定します。0x12はデフォルト(高利得、402ms)の設定です。

b7 b6 b5 b4 b3 b2 b1 b0
0 0 0

0;x1
1;x16

Manual

0 00;13.7ms
01;101ms
10;402ms
11;for mamual

  ※b1,b0が11(手動で設定)のとき以外、b3は無視される。

#!/usr/bin/env python
import smbus
import time
bus = smbus.SMBus(1)
addr = 0x39

bus.write_byte_data(addr , 0x80, 0x03) #wakeup
bus.write_byte_data(addr , 0x81, 0x12) #初期化コマンド
time.sleep(0.5)
data = bus.read_i2c_block_data(addr , 0x8c, 2)  #ch0の読み出し
data1 = bus.read_i2c_block_data(addr , 0x8e, 2)  #ch1の読み出し  

ch0 = data[1] *256 + data[0]
ch1 = data1[1] *256 + data1[0]

print "Full",ch0*0.03
print "IR",ch1*0.03
print (ch0 - ch1)*0.03,"lux"

  読み出すデータは、ch0とch1の2チャネルあり、それぞれ「下位8ビット+上位8ビット」で構成されています。

 ch0は赤外線を含む広い波長領域を検知し、ch1は赤外線だけを測るセンサです。赤外線はluxの値に影響を与えるので補正が必要です。その補正は、ch1/ch0の比率によってパラメータが異なります。これは、実測したデータで補正パラメータが決められています。

 補正される量の違いはほんの少しなので、テストでは無視します。おおよその補正値0.03を読み出した値に掛けます。luxはch0-ch1で求まります。机の上で測ると、100から400luxの明るさが得られれば、読み出しはうまくいっていると推測できます。

 実行すると350lux前後が得られました。

補正

 データシートによると、次のようにch1/ch0の比率を条件に補正をします。Adafruitの使っているTSL2561の実装されているパッケージがデータシートに書かれていないのですが、FNパッケージの補正式を使います。LEDライトをセンサの直前まで近づけてとても明るくしないと、最初の条件式が適用されるようです。

  • 0 < (ch1/ch0) <= 0.50 の場合、 Lux = 0.0304 × ch0 - 0.062 × ch0 × ((ch1 / ch0)^1.4)
  • 0.50 < (ch1/ch0) <= 0.61 の場合、 Lux = 0.0224 × ch0 - 0.031 × ch1
  • 0.61 < (ch1/ch0) <= 0.80 の場合、 Lux = 0.0128 × ch0 - 0.0153 × ch1
  • 0.80 < (ch1/ch0) <= 1.30 の場合、 Lux = 0.00146 × ch0 - 0.00112 × ch1
  • (ch1/ch0) > 1.30 の場合、 Lux = 0

 

プログラム

 条件は、高利得、積分時間は402msで、送るコードは0x12です。

#!/usr/bin/env python
import smbus
import time
bus = smbus.SMBus(1)
addr = 0x39 #TSL2561-FN
while 1:
bus.write_byte_data(addr , 0x80, 0x03)
bus.write_byte_data(addr , 0x81, 0x12)
time.sleep(0.5)
data = bus.read_i2c_block_data(addr , 0x8c, 2)
data1 = bus.read_i2c_block_data(addr , 0x8e, 2)
ch0 = data[1] *256 + data[0]
ch1 = data1[1] *256 + data1[0]
R = 1.0*ch1/ch0
if 0 < R <= 0.5:
Lux = 0.0304*ch0 - 0.062*ch0*(R**1.4)
elif 0.5 < R <= 0.61:
Lux = 0.0224*ch0 - 0.031*ch1
elif 0.61 < R <= 0.8:
Lux = 0.0128*ch0 - 0.0153*ch1
elif 0.8 < R <= 1.3:
Lux = 0.0146*ch0 - 0.00112*ch1
elif R > 1.3:
Lux = 0

print round(Lux,2),"lux"
time.sleep(1)

(2020/09/04)15行目のif文 if 0 < R <= 80.5: の80.5がミスタイプだったのを修正しました。

 市販のメータ(TASI-8720)と比較しました。

場所 TSL2561[lux] メータ表示[lux]
机の上  380  415
ディスプレイの上縁  880  998

 条件を、低利得、積分時間は402msの0x02に変更しました。print文の得られたLuxに16を掛けました。

 市販のメータと比較しました。

場所 TSL2561[lux] メータ表示[lux]
机の上  362  438
ディスプレイの上縁  915  1020

※プログラムを仮にtsl2561.pyと/home/piに保存すると、sudo chmod 755 tsl2561.py で実行権を付け、ターミナルから、python tsl2561.pyで実行します。I2CやSPIのグループにpiユーザが属しているので、sudoは不要です。
 プログラム・リストは、表示の関係でTabキーが無視されるので、スペースに代えてあります。また、リスト中を2回クリックすると全選択になるので、CTRL-Cでコピーし、テキスト・エディタにCTRL-Vで貼り付けて利用してください。ラズパイに持っていくと、リターン・コードなどが化けていることがあるので、一度消して、ラズパイのテキスト・エディタで改行してください。

※I2Cの有効化は、1-Wireの説明を参照ください。1-Wireと同じく、I2CもEnableにチェックを入れています。