Elixir Circuits I2Cで温度測定 (ADT7410)

#1.はじめに

Elixirを使って、RaspberryPiのハードウェア制御の練習をしてみました。

今回は、[Elixir Circuits.I2C](https://github.com/elixir-circuits/circuits_i2c)から、温度センサADT7410を制御してみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145581/8e67c850-94ec-fa94-7e40-7f708695ecf8.png)

##動作環境

ここでのハードウェア環境は、以下を想定しています。

- Raspberry Pi 4
- Raspbian Buster （2020年9月版）
- Elixir 1.10.3

```bash:コマンドライン
$ uname -a
Linux raspi4 5.4.51-v7l+ #1333 SMP Mon Aug 10 16:51:40 BST 2020 armv7l GNU/Linux
$ iex
Erlang/OTP 22 [erts-10.5.4] [source] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe]
Interactive Elixir (1.10.3) - press Ctrl+C to exit (type h() ENTER for help)
```

#2.ハードウェア

##(1)センサ

アナログ・デバイセズ社のI2C接続温度センサ**ADT7410**を使用します。

- 購入：[秋月電子さん](https://akizukidenshi.com/catalog/g/gM-06675/)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145581/e31b7d5f-699a-46fa-8712-011454e9fdc9.png)

##(2)GROVEプロトシールド

**※センサとRaspberryPiを直結する場合は読み飛ばしてください**

Raspberry Pi本体には、[Grove Base HAT](https://wiki.seeedstudio.com/jp/Grove_Base_Hat_for_Raspberry_Pi/)を使いたいので、今回使うセンサをGROVE規格に対応させます。

- 購入：[共立電子産業さん](https://eleshop.jp/shop/g/gK58121/)
- 購入：[秋月電子さん](https://akizukidenshi.com/catalog/g/gM-13879/)（Zero向けの小型版）

[GROVE - プロトシールド](https://jp.seeedstudio.com/Grove-Protoshield.html)を使うと、小さなユニバーサル基板とGROVEコネクタ・ケーブルが付属していて、簡単にGROVE対応センサを作る事ができます。

- 購入：[スイッチサイエンスさん](https://www.switch-science.com/catalog/799/)
- 購入：[マルツさん](https://www.marutsu.co.jp/pc/i/829164/)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145581/dc76bb1c-0c4e-0b83-7412-212135be97f7.png)

**配置・配線例**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145581/3002522e-85d3-2771-9f9a-814f3888e377.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145581/f0e9a2e5-4e50-19f7-e616-961eef2d6f85.png)

|ADT7410端子|GROVEコネクタ記号|
|:--:|:--:|
|VDD|V|
|SCL|S0 (SCL)|
|SDA|S1 (SDA)|
|GND|G|

RaspberryPiに接続したら、`i2cdetect`を実行して通信できるか確認します。

- ADT7410のアドレス：`0x48`
- Grove Base HATのアドレス：`0x04`（Grove Base HATを使用している場合に表示）

```bash:コマンドライン
 $ i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- 04 -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- 48 -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --                         
```

#3.ソフトウェア

##(1)下準備

プロジェクトを作ります。

```bash:コマンドライン
$ cd gitwork
$ mix new i2ctemp
* creating README.md
* creating .formatter.exs
* creating .gitignore
* creating mix.exs
* creating lib
* creating lib/i2ctemp.ex
* creating test
* creating test/test_helper.exs
* creating test/i2ctemp_test.exs

Your Mix project was created successfully.
You can use "mix" to compile it, test it, and more:

    cd i2ctemp
    mix test

Run "mix help" for more commands.
$ cd i2ctemp/
```

mix.exsを編集します。

```elixir:mix.exs 
defmodule I2ctemp.MixProject do
  use Mix.Project

  def project do
    [
      app: :i2ctemp,
      version: "0.1.0",
      elixir: "~> 1.10",
      start_permanent: Mix.env() == :prod,
      deps: deps()
    ]
  end

  # Run "mix help compile.app" to learn about applications.
  def application do
    [
      extra_applications: [:logger]
    ]
  end

  # Run "mix help deps" to learn about dependencies.
  defp deps do
    [
      #ここの先頭のコメントアウトを外す↓
      {:dep_from_hexpm, "~> 0.3.0"},
      # {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
      #ここを追加↓
      {:circuits_i2c, "~> 0.3", override: true}
    ]
  end
end
```

`mix deps.get`を実行します。

```bash:コマンドライン
$ mix deps.get
Resolving Hex dependencies...
Dependency resolution completed:
New:
  circuits_i2c 0.3.6
  dep_from_hexpm 0.3.0
  elixir_make 0.6.1
* Getting dep_from_hexpm (Hex package)
* Getting circuits_i2c (Hex package)
* Getting elixir_make (Hex package)
$
```

##(2)コード

```elixir
defmodule I2ctemp do
  @moduledoc """
  Documentation for `I2ctemp`.
  """

  #ここから追加↓

  alias Circuits.I2C
  require Logger
  use Bitwise

  @doc """
  温度の取得

  ## Examples
      iex> I2ctemp.gettemp()
  """
  def gettemp() do

    # I2Cアドレス
    address_adt7410 = 0x48

    # I2Cを開く
    {:ok, ref} = Circuits.I2C.open("i2c-1")

    # 初期化コマンド：13bitモードに設定
    Circuits.I2C.write(ref, address_adt7410, <<0x03, 0x00>>)
    # 現在温度を読み出す
    {_, <<rawdata_h, rawdata_l>>} =
      Circuits.I2C.write_read(ref, address_adt7410, <<0x00>>, 2)
      #上位ビットと下位ビットの和を求める
      data_raw = rawdata_h * 256 + rawdata_l
      #3ビットだけシフトする
      data_raw = data_raw >>> 3
      #摂氏温度に変換する
      data = data_raw / 16
      #表示
      Logger.info(" RAW H: #{rawdata_h * 256}, RAW L: #{rawdata_l}, RAW: #{data_raw}, temp(degree Celsius): #{data}")
    end

  #ここまで追加↑

  @doc """
  Hello world.

  ## Examples

      iex> I2ctemp.hello()
      :world

  """
  def hello do
    :world
  end
end
```

コードの中でビットの演算がありますので、[Bitwise](https://hexdocs.pm/elixir/Bitwise.html)をuseで呼び出してください。

##(3)実行結果

`temp(degree Celsius):`のところに摂氏温度が表示されます。
(RAW...は取得した生の数値を表示しています)

```bash:コマンドライン
 $ iex -S mix
Erlang/OTP 22 [erts-10.5.4] [source] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe]

Remember to keep good posture and stay hydrated!
Interactive Elixir (1.10.3) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> I2ctemp.gettemp()

01:08:08.202 [info]   RAW H: 2560, RAW L: 200, RAW: 345, temp(degree Celsius): 21.5625
:ok
iex(2)> I2ctemp.gettemp()

01:08:14.776 [info]   RAW H: 3328, RAW L: 64, RAW: 424, temp(degree Celsius): 26.5
:ok

iex(3)> I2ctemp.gettemp()

01:08:22.032 [info]   RAW H: 3840, RAW L: 8, RAW: 481, temp(degree Celsius): 30.0625
:ok
iex(4)> 
```

#4.おわりに

Elixir Circuits.I2Cを使って、簡単に温度センサを制御する例を紹介しました。


#参考資料

- https://qiita.com/myasu/items/a4d033b5034cc3fb97c0