05 IoT開発の概要を学ぶ
Mix.install([
{:circuits_i2c, "~> 2.0"}
])
はじめに
IoT開発の概要を学びます。
- IoTのよくあるシステム構成
- データシート
-
ハードウェアモジュールの通信方式
- GPIO, I2C, SPI, UART
- Elixir Circuits
IoTのよくあるシステム構成
IoTデバイスはリソース制約(メモリ、ストレージ、CPUなど)に制約があることが一般的です。そこでIoTデバイスではセンサー情報を取得し、それをインターネット経由でクラウドへ蓄積しクラウドで分析等(AIを活用)を行うシステム構成がよく採られます。
ハードウェアモジュールの通信方式
代表的な通信方式
- GPIO(General Purpose Input/Output)
- I2C(Inter-Integrated Circuit)
- SPI(Serial Peripheral Interface)
- UART(Universal Asynchronous Receiver-Transmitter)
本科目で使用する温度・湿度センサーAHT2はI2C方式です。
データシート
ハードウェアモジュールには、データシートと呼ばれる仕様書が付属します。データシートを読み込んでモジュールを制御するプログラムを作ります。ライブラリとして公開されている場合もあります。
この講義ではAHT20 Product manualsの5.3 Send Command以降を中心に読み解きます。
Circuits.I2C
ハードウェアモジュールの制御では、1ビットのオン/オフの信号をやりとりしたり、所定のビット長から成るバイト列をコマンドとして連䛽て送受信したりすることがよく行われます。 Elixir Circuitsは、Elixirでハードウェアモジュールを制御するライブラリ群です。 ハードウェアモジュールの代表的な通信方式(GPIO、I2C、SPI、UART)をサポートしています。 また特定のハードウェアモジュールに特化したライブラリが公開されている場合があります。本科目では、circuits_i2cパッケージを使ってAHT20から温度・湿度を読み取るプログラムを作ります。
circuits_i2cの提供する関数をいくつか紹介します。
-
Circuits.I2C.open/2
- I2C バスを開く
-
Circuits.I2C.read/4
- I2C デバイスから指定されたバイト長のデータを読み取る
-
Circuits.I2C.write/4
- I2C デバイスにデータを書き込む
-
Circuits.I2C.write_read/5
- I2C デバイスにデータを書き込んで、すぐに指定されたバイト長のデータを読み取る
詳細については公式ドキュメントをご参照ください。
AHT20 センサーと通信する準備
AHT20 センサーを任意の方法で Raspberry Pi 4 に接続してください。
I2C プロトコルを使用して AHT20 センサーと通信できるように準備します。
I2C バスを開く
{:ok, i2c_ref} = Circuits.I2C.open("i2c-1")
センサーのアドレスを確認
I2C バス上のデバイスには番地があります。データシートによると AHT20 センサーの住所は0x38
と決まっているようです。それを覚えておきます。
aht20_address = 0x38
AHT20 センサーから測定結果を受信する手順
Step 1: センサーの状態を確認し、必要に応じて初期化
原文
> Wait 40ms after power-on. Before reading the temperature > and humidity values, first check whether the calibration > enable bit Bit [3] of the status word is 1 (you can get a byte of > status word by sending 0x71). If not 1, need to send 0xbe > command (for initialization), this command parameter has > two bytes, the first byte is 0x08, the second byte is 0x00, > and then wait for 10ms.
日本語意訳
- 電源投入後、40ms 待つ
-
0x71
を送信しセンサーの状態を取得 -
「キャリブレーション有効ビット」 (
calibrated
)が1
でない場合は初期化(コマンド0xbe
を2バイトのパラメータ<<0x08, 0x00>>
と共に送信)が必要 - 初期化を実施した後、10ms 待つ
Elixir 意訳
Process.sleep(40)
<<_::1, _::3, calibrated::1, _::3>> =
Circuits.I2C.write_read!(i2c_ref, aht20_address, <<0x71>>, 1)
if calibrated == 0 do
Circuits.I2C.write!(i2c_ref, aht20_address, [<<0xBE>>, <<0x08, 0x00>>])
Process.sleep(10)
end
Step 2: 測定をトリガー
原文
> Send the 0xAC command directly (trigger measurement). > The parameter of this command has two bytes, the first byte > is 0x33 and the second byte is 0x00.
日本語意訳
-
測定トリガコマンドとして
0xAC
コマンドを送信 -
0xAC
コマンドのパラメータは 2 バイトで、1 バイト目は0x33
、2 バイト目は0x00
Elixir 意訳
Circuits.I2C.write!(i2c_ref, aht20_address, [<<0xAC>>, <<0x33, 0x00>>])
Step3: 測定完了を確認
原文
> Wait for 80ms to wait for the measurement to be completed. > If the read status word Bit [7] is 0, it indicates that the > measurement is completed, and then six bytes can be read > in a row; otherwise, continue to wait.
日本語意訳
- 測定が完了するまで 80 ミリ秒待つ
-
0x71
を送信しセンサーの状態を取得 -
測定ビジー状態 ビット が
1
であれば、まだ測定中なので待つ - 測定完了後、6 バイトの測定結果データを読み込み可能
Elixir 意訳
Process.sleep(80)
<> =
Circuits.I2C.write_read!(i2c_ref, aht20_address, <<0x71>>, 1)
case busy do
1 -> IO.puts("測定中")
0 -> IO.puts("測定完了")
end
Step 4: 測定結果を読み込み
原文
> After receiving six bytes, the next byte is the CRC check > data, the user can read it as needed, if the receiving end > needs CRC check, then send it after receiving the sixth byte > ACK response, otherwise NACK is sent out, CRC initial value > is 0XFF, CRC8 check polynomial is: …
日本語意訳
- 6 バイトの計測結果データと1バイトのCRC(巡回冗長検査、Cyclic Redundancy Check)を受信します
- CRC は受信データの誤り・破損を検出するのに適宜利用します
Elixir 意訳
<> =
Circuits.I2C.read!(i2c_ref, aht20_address, 7)
Step 5: 温度と湿度の値を計算
原文
> Calculate the temperature and humidity values. > Note: The calibration status check in the first step > only needs to be checked at power-on. No operation > is required during the normal acquisition process.
日本語意訳
- (6 バイトの計測結果データのうち)1バイト目にセンサーの状態が含まれていますが、それを毎回確認する必要はありません。
相対湿度の計算
AHT20 センサーから取得した相対湿度の生データを百分率に変換する計算を行います。
calc_humidity_rh_from_raw =
fn raw_humidity ->
raw_humidity / 1_048_576.0 * 100.0
end
calc_humidity_rh_from_raw.(raw_humidity)
温度の計算
AHT20 センサーから取得した温度の生データを摂氏度に変換する計算を行います。
calc_temperature_c_from_raw =
fn raw_temperature ->
raw_temperature / 1_048_576.0 * 200.0 - 50.0
end
calc_temperature_c_from_raw.(raw_temperature)