Arduino MKR WiFi 1010をデータ入力に使う⑪I2C温湿度センサSi7021

 Silicon Labs社の湿度センサSi7021は、これまで扱ってきた温湿度センサに比べてそれほど良い特性ではありません。特徴は、分解能を低くして測定時間を短くできるところかもしれません。
 IC自体が1.8/3.3Vの低い電源で使うデバイスのため、5V->3.3VのレギュレータとI2Cの信号レベル変換回路が入っています。SDA/SCL信号のプルアップ抵抗は10kΩが入っています。1.8Vはあまり使ってほしくないニュアンスの説明があります。正式には1.9V以上の電源電圧で動作します。

湿度センサSi7021のおもなスペック

 データシート

  • 電源電圧  1.9~3.6V
  • 湿度 確度±2%RH、分解能0.025%RH
  • 温度 確度±0.3℃、分解能0.01℃
  • インターフェース I2C(0~400kHz)
  • スレーブ・アドレス 0x40(固定)

接続

 I2C専用の4ピンのコネクタでArduino MKR WiFi 1010と接続します。第4回の気圧センサLPS25HBの接続と同じです。

プログラム-step1

 Read RH/T User Register 1を読みます。


clear all
a = arduino('COM15', 'MKR1010', 'Libraries', 'I2C');
Si7021 = device(a, 'I2CAddress', 0x40);

userResister = 0xe7;
info = readRegister(Si7021, userResister, 1, 'uint8')
dec2bin(info)

 実行結果は111010でした。データシートによると、リセット後の値は0011_1010と書かれているので、正しく読み出せました。MSBとLSBの2ビットが測定時の分解能です。一番高い分解能にセットされていることがわかります。

D7;D0 湿度RH [ビット] 温度Temp [ビット]
00 12 14
01 8 12
10 10 13
11 11 11


プログラム-step2

 湿度と温度を読み出します。データシートのよれば、湿度は2通り、温度は3通りの方法が用意されています。ここでは、2通りの方法を実行します。

 一つは、SCLクロック・ストレッチを使う方法です。特に湿度は、測定時間がかかるので、測定コマンドを送ってから、データが用意されるまで、スレーブ・デバイスのSi7021はSCLをLowのまま時間を引き延ばします。

 もう一つは、測定コマンドを送って、なんどかスレーブ・アドレスを送ってから、読み出す方法です。なんどかスレーブ・アドレスだけを送る方法がないので、湿度は20ms、温度は10msの時間待ってから読み出します。

 残り一つの温度測定は、湿度を測るとき温度で補正をするので、その温度を読み出すものです。省略します。


clear all
a = arduino('COM15', 'MKR1010', 'Libraries', 'I2C');
Si7021 = device(a, 'I2CAddress', 0x40);

userResister = 0xe7;
info = readRegister(Si7021, userResister, 1, 'uint8');
dec2bin(info)

Hold_Master_Mode_MeasurementCommand_Humi = 0xe5;
Hold_Master_Mode_MeasurementCommand_Temp = 0xe3;
write(Si7021, Hold_Master_Mode_MeasurementCommand_Humi, 'uint8');
rdataH = read(Si7021, 3 ,'uint8')
write(Si7021, Hold_Master_Mode_MeasurementCommand_Temp, 'uint8');
rdataT = read(Si7021, 3 ,'uint8')

no_Hold_Master_Mode_MeasurementCommand_Humi = 0xf5;
no_Hold_Master_Mode_MeasurementCommand_Temp = 0xf3;
write(Si7021, no_Hold_Master_Mode_MeasurementCommand_Humi,'uint8');
pause(0.02);
rdataHn = read(Si7021, 3 ,'uint8')
write(Si7021, no_Hold_Master_Mode_MeasurementCommand_Temp, 'uint8');
pause(0.01);
rdataTn = read(Si7021, 3 ,'uint8')

humi = bitshift(rdataH(1), 8) + rdataH(2);
humidity = humi * 125 / 65536 - 6
temp = bitshift(rdataT(1), 8) + rdataT(2);
temperature = temp * 175.72 / 65536 - 46.85

humi = bitshift(rdataHn(1), 8) + rdataHn(2);
humidity = humi * 125 / 65536 - 6
temp = bitshift(rdataTn(1), 8) + rdataTn(2);
temperature = temp * 175.72 / 65536 - 46.85

 実行結果です。どちらの読み出し方法でも読めたようです。

SCLクロック・ストレッチ

 次のプログラムを動かして、クロック・ストレッチの波形を観測します。オシロスコープの波形の上がクロックSCL、下がデータSDAです。


clear all
a = arduino('COM15', 'MKR1010', 'Libraries', 'I2C');
Si7021 = device(a, 'I2CAddress', 0x40);

Hold_Master_Mode_MeasurementCommand_Humi = 0xe5;
for i=1:1000
    write(Si7021, Hold_Master_Mode_MeasurementCommand_Humi, 'uint8');
    rdataH = read(Si7021, 3 ,'uint8')
    pause(0.01);
end

 全体です。SDA/SCLの信号は、何もやり取りをしていないときはどちらもHighです。

  最初のスレーブ・アドレス0x40と測定コマンド0xe5の部分を拡大しました。

 スレーブ・アドレスを出した直後に、SCLのクロックのLowを伸ばしています。

 約12ms後に3バイトのデータが送られてきました。

プログラム-step2

 CRCの計算をします。CRCの初期値は、ほかと異なり0x00です。

 CRCの計算を実際にしているのは、no_Hold_Master_Mode_MeasurementCommandのほうだけです。


clear all
a = arduino('COM15', 'MKR1010', 'Libraries', 'I2C');
Si7021 = device(a, 'I2CAddress', 0x40);

userResister = 0xe7;
info = readRegister(Si7021, userResister, 1, 'uint8');
dec2bin(info)

Hold_Master_Mode_MeasurementCommand_Humi = 0xe5;
Hold_Master_Mode_MeasurementCommand_Temp = 0xe3;
write(Si7021, Hold_Master_Mode_MeasurementCommand_Humi, 'uint8');
rdataH = read(Si7021, 3 ,'uint8')
write(Si7021, Hold_Master_Mode_MeasurementCommand_Temp, 'uint8');
rdataT = read(Si7021, 3 ,'uint8')

no_Hold_Master_Mode_MeasurementCommand_Humi = 0xf5;
no_Hold_Master_Mode_MeasurementCommand_Temp = 0xf3;
write(Si7021, no_Hold_Master_Mode_MeasurementCommand_Humi,'uint8');
pause(0.02);
rdataHn = read(Si7021, 3 ,'uint8')
write(Si7021, no_Hold_Master_Mode_MeasurementCommand_Temp, 'uint8');
pause(0.01);
rdataTn = read(Si7021, 3 ,'uint8')

humi = bitshift(rdataH(1), 8) + rdataH(2);
humidity = humi * 125 / 65536 - 6
temp = bitshift(rdataT(1), 8) + rdataT(2);
temperature = temp * 175.72 / 65536 - 46.85

humi = bitshift(rdataHn(1), 8) + rdataHn(2);
humidity = humi * 125 / 65536 - 6
temp = bitshift(rdataTn(1), 8) + rdataTn(2);
temperature = temp * 175.72 / 65536 - 46.85

data = [rdataHn(1),rdataHn(2)];
fprintf('Humi readCRC is 0x%s 0x%s <-calculated ' ...
    ,dec2hex(rdataHn(3)),dec2hex(CalcCrc(data)) );
data = [rdataTn(1),rdataTn(2)];
fprintf('Temp readCRC is 0x%s 0x%s <-calculated ' ...
    ,dec2hex(rdataTn(3)),dec2hex(CalcCrc(data)) );


function crcResult =  CalcCrc(data) 
    crc8A = 0x00;
    for i = 1:length(data)
        crc8A = bitxor(crc8A, data(i));
        for bit = 8:-1:1
            if bitand(crc8A, 0x80)
                crc8A = bitxor(bitshift(crc8A , 1) , 0x31);
            else
                crc8A = bitshift(crc8A , 1);
            end
        end
    end
    crcResult = crc8A;
end

 実行結果です。 

前へ

Arduino MKR WiFi 1010をデータ入力に使う⑩I2C温湿度センサAHT20

次へ

Arduino MKR WiFi 1010をデータ入力に使う<番外編1>PWM出力