Arduino Nano R4の活用 ⑪ I2C 湿度・温度センサHS3003 のスケッチ スケッチの説明<第5回>
前回、Arduino Nano R4のI2Cバスに湿度・温度センサHS3003をつないで、センサ・データをWrieライブラリを使って読みだしました。ここではそのスケッチを説明します。
●スケッチの構造
このスケッチでは大きく四つのブロックで構成されます。
① 最初が、include文や定数の宣言、グルーバル変数の宣言を行う部分です。
② 次が初期化などを行うsetup()、③ その次がメインのloop()です。
④ 最後が、センサのデータを読みだす関数readSensor()です。
readSensor()関数が、main関数(loop[())の後ろにあるように見えます。C言語だと、最初のあたりにプロトタイプ宣言を書いておかなければなりませんが、Arduinoでは不要です。
もちろん、loop()関数の前にreadSensor()関数を記述してもかまいません。
湿度humidityと温度temperatureはグローバル変数として最初に宣言してあるので、Arduinoでは、readSensor()関数を実行した時点で、内容が更新されます。
① include文や定数の宣言、グルーバル変数の宣言を行う部分
#include <Wire.h>
Wireライブラリを使えるようにincludeします。
const uint8_t HS3003_address = 0x44;
センサHS3003のスレーブ・アドレスを定数で宣言しました。
uint8_t result[4];
センサ・データは、14ビットの湿度、14ビットの温度で読み取れるので、4バイトの配列を確保します。
float humidity, temperature;
センサから読み取った湿度と温度の実数の変数を宣言します。グローバル変数なので、関数内で使って更新しても、どこからでも参照できます。
uint8_t status;
センサから読み取った最初の2ビットが最新データであることを示すステータスなので、8ビットのグローバル変数を宣言します。
② setup()
Wire1.begin();
Wireライブラリで、Qwiicコネクタに接続されたI2Cバスを初期化します。
Serial.begin(9600);
delay(1000);
Serial.println("\nstart ");
PCとつないでいるUSBシリアル通信を初期化します。
③ loop()
Wire1.beginTransmission(HS3003_address);
Wire1.write((uint8_t)0);
Wire1.endTransmission();
Wireライブラリの書き込みを行います。これは、データシートに書かれているように、0を書き込みますが、(uint8_t)でキャストをしているので、絶対に8ビットの0になります。過去、Arduinoのスケッチで0と書いた時に8ビットでないことがあったための名残です。
delay(35); // 14bit
湿度のデータが用意される時間が35msなので、待ちます。例えば25msだと、温度だけは用意されました。
status = readSensor();
Serial.print(status);Serial.print(" ");
// need SENSOR_BUSY delay
readSensor()関数を呼び出し、returnの8ビットの変数statusに代入します。
Serial.print(result[0],HEX);Serial.print(" ");
Serial.print(result[1],HEX);Serial.print(" ;");
Serial.print(humidity);
センサから読みだした最初の2バイトと、計算した湿度を表示します。
Serial.print("\t\t\t");
Serial.print(result[2],HEX);Serial.print(" ");
Serial.print(result[3],HEX);Serial.print(" ;");
Serial.println(temperature);
センサから読みだした後半の2バイトと、計算した温度を表示します。
delay(3000);
3秒待って、繰り返します。
●readSensor()
センサのデータ4バイトを読み取る関数です。
Wire1.requestFrom(HS3003_address, 4);
result[0] = Wire1.read();
result[1] = Wire1.read();
uint16_t raw_humidity = ((result[0] & 0x3f) << 8 | result[1]);
2バイトを読み取り、15,14ビットはステータスなので湿度データには不要なので捨てます。
humidity = (raw_humidity / (pow(2,14) - 1)) * 100.0;
データシートにしたがって、RH%の実数に変換します。整数値に実数を乗じているので、結果は実数になります。昔のArduino UNO 3などではこのような記述をしましたが、今確認すると、単に100を乗じても実数の答えになりました。
result[2] = Wire1.read();
result[3] = Wire1.read();
uint16_t raw_temperature = (result[2] << 8 | result[3]) >> 2;
残りの2バイトを読み取り、1,0ビットは不要なので捨てます。
本来、4バイトをまとめて一気に読み込むべきかもしれませんが、Wireライブラリでは、どこかのバッファに保存されているのを読み込むらしいので、2回に分けています。
temperature = (raw_temperature / (pow(2,14) - 1)) * 165.0 - 40;
データシートにしたがって、摂氏℃の実数に変換します。
return (result[0] >> 6);
関数の戻り値は、ステータスの2ビットです。4バイト読み取った最初のバイトの最上位2ビットがステータスです。