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
実行結果です。