MicroPython的午睡(24) ラズパイPico、CDSセンサをADCに接続

Joseph Halfmoon

さて今回は、ラズパイPicoのADCを使ってみたいと思います。12ビットのADコンバータであります。真面目に精度を出そうと思うとチョッと大変そうですが、今回はとりあえず精度は気にせず。明るい、暗いがアナログ値で分かれば良いだろ~ということでCdSセンサを接続。

※「MicroPython的午睡」投稿順 Indexはこちら

(末尾に今回の実験に使用のMicroPythonコード全文を置きました。)

CdS(硫化カドミウム)センサは、光に反応して抵抗値が大きく変動するセンサです。感度もよく、お値段もお手頃。明るい、暗いを識別するには定番のデバイスではないかと思います。

ラズパイPicoとCdSセンサの接続

ラズパイPicoのようにADコンバータを搭載しているマイコンに接続する場合は簡単、以下のような感じで「ザックリした」値は読み取れるかと思います。12ビットのADC使うのは勿体ない感じもしますが。

RPiPico_CDS_SchematicラズパイPicoの回路図をみると、精度のためにはADC_VREF端子に3.0Vの参照電圧を与えよといったことも書かれているのですが、今回は「明るい、暗い」が識別できれば良いでしょ、という程度なので、そのまま放置であります。

ラズパイPicoの場合3チャネル(RP2040的には4チャネル)のアナログ入力端子が使用できます。今回は、チャネル0(GP26)を使用。現物はこんな感じ。

RPiPico_CDSCdSセンサの特性

今回使用したCdSセンサは、お楽しみの中華部品キットKuman社K4キット所蔵の品であります。型番5506ぞなもし。しかし、「例によって」データシートPDFは存在するのですが、センサのメーカー名が不詳。怪しい一品です。該当のデータシートから照度と抵抗値の関係を示すグラフ一枚を引用させていただきます。

CDS_RES_LUX1Luxから100Luxという「比較的狭い」範囲でかなり大きく抵抗値が変動することが分かります。感覚的には「暗い」と「薄暗い」くらいの間で大きく変化するのであります。薄暗いあたりの様子は捕捉しやすいけれど、明るければどこまでいっても明るい、という感じでしょうかね。

照度とその目安を示す資料が以下に公開されていたので参照させていただきました。

大阪市立科学館 照度と明るさの目安

1Luxは月明り、100Luxは街灯の下ですか。いずれにせよ夜の範疇であります。

実験用プログラム

ラズパイPicoのMicroPythonのADC関数では、ADCからの読み取り値を16ビットの符号なし整数表現で返してきます。ADCのハードウエア的には12ビット4096段階のレゾリューションの筈なのですがね。別に4096の倍数でもないみたいだし、下の桁の方は詳細不明。またノイスも乗ってくるのでないかい、ということで、末尾に掲げた実験用プログラムでは、読み取った生の値の移動平均をとってから値を返すようになっています。そのまま走らせると測定は1秒に1回、3回分の測定値を移動平均(ローパスフィルタ)かけています。また、生の読み取り値から電圧とCdSセルの抵抗値に換算してみています。フルスケール3.3V、CdSに直列に接続した抵抗33kΩとみなしてのテキトーな換算です。

プログラム動作しているときの様子がこちら。途中、黒いフェルトの布をかぶせて「真っ暗」にして、再び布を外しています。遷移のところで中間的な値が出るのは布の出し入れの速度とローパスフィルタのせいですね。

RAW: 64751 AVG: 64708.3 VOLTAGE: 3.26 [V] R: 0.4 [k Ohm]
RAW: 64687 AVG: 64671.0 VOLTAGE: 3.26 [V] R: 0.4 [k Ohm]
 <==黒い布で覆った
RAW: 34600 AVG: 54679.3 VOLTAGE: 2.75 [V] R: 6.6 [k Ohm]
RAW: 19364 AVG: 39550.3 VOLTAGE: 1.99 [V] R: 21.7 [k Ohm]
RAW: 17604 AVG: 23856.0 VOLTAGE: 1.20 [V] R: 57.7 [k Ohm]
RAW: 16532 AVG: 17833.3 VOLTAGE: 0.90 [V] R: 88.3 [k Ohm]
RAW: 16147 AVG: 16761.0 VOLTAGE: 0.84 [V] R: 96.0 [k Ohm]
RAW: 15795 AVG: 16158.0 VOLTAGE: 0.81 [V] R: 100.8 [k Ohm]
RAW: 15619 AVG: 15853.7 VOLTAGE: 0.80 [V] R: 103.4 [k Ohm]
RAW: 15587 AVG: 15667.0 VOLTAGE: 0.79 [V] R: 105.0 [k Ohm]
RAW: 15379 AVG: 15528.3 VOLTAGE: 0.78 [V] R: 106.3 [k Ohm]
RAW: 15235 AVG: 15400.3 VOLTAGE: 0.78 [V] R: 107.4 [k Ohm]
RAW: 15107 AVG: 15240.3 VOLTAGE: 0.77 [V] R: 108.9 [k Ohm]
RAW: 15107 AVG: 15149.7 VOLTAGE: 0.76 [V] R: 109.8 [k Ohm]
RAW: 13299 AVG: 14504.3 VOLTAGE: 0.73 [V] R: 116.1 [k Ohm]
 <==黒い布外した
RAW: 20965 AVG: 16457.0 VOLTAGE: 0.83 [V] R: 98.4 [k Ohm]
RAW: 63919 AVG: 32727.7 VOLTAGE: 1.65 [V] R: 33.1 [k Ohm]
RAW: 65087 AVG: 49990.3 VOLTAGE: 2.52 [V] R: 10.3 [k Ohm]
RAW: 64927 AVG: 64644.3 VOLTAGE: 3.26 [V] R: 0.5 [k Ohm]
RAW: 64815 AVG: 64943.0 VOLTAGE: 3.27 [V] R: 0.3 [k Ohm]

明るい、暗いの判定は確実にできると思います。しかし、CdSセルでは、暗いときにどのくらい暗いかとか、明るいときにどのくらい明るいかとか調べるのは大変。まあ、そういう目的には他にもっと良いセンサあるし。

とりあえずPicoのADコンバータのテストとしてはOKですかね。

MicroPython的午睡(23) ラズパイPico、Passive Buzzer接続 へ戻る

MicroPython的午睡(25) ラズパイPico、Timer周波数設定の上限? へ進む

CDSセンサの値読み取りサンプルプログラム
import machine
import time

adcCH0 = machine.ADC(26)
resistor = 33000
avdd = 3.3
fullscale = 65535

class MovingAVG:
    
    def __init__(self, ival=0, inum=3):
        if inum < 3:
            inum = 3
        self.buf = [ival] * inum
        self.nSample = 0
        self.nBuf = inum
        self.ok = False
        self.avg = None
        
    def set(self, dat):
        if type(dat) not in (float, int):
            return None
        self.nSample += 1
        self.buf.append(dat)
        self.buf.pop(0)
        self.avg = sum(self.buf) / self.nBuf
        if self.nSample >= self.nBuf:
            self.ok = True
        return self.ok

avgCalc = MovingAVG()

while True:
    cdsRawValue = adcCH0.read_u16()
    avgCalc.set(cdsRawValue)
    if avgCalc.ok:
        volt = avdd * (avgCalc.avg / fullscale)
        res  = ((avdd - volt) / volt) * resistor / 1000 
        print("RAW: {0} AVG: {1:5.1f} VOLTAGE: {2:1.2f} [V] R: {3:3.1f} [k Ohm]".format(cdsRawValue,avgCalc.avg, volt, res))
    time.sleep(1.0)