ADT7410とpigpioライブラリを使ったi2c通信

RaspberryPiと定番らしい温度センサモジュールADT7410使ったi2c通信。
ADT7410の詳細は秋月のサイトに詳しい資料があるので気になる場合は参照。

使用するライブラリはpigpio
c言語pythonに対応しているので両方試してみました。
温度分解能はデフォルトの13ビット設定で十分。

基本的に素人なので内容に間違いがあっても気にしない精神で

前準備

ADT7410の配線は基板に記載されている通りラズパイと繋げばよい。
SCLとSCL、SDAとSDA、GNDとGNDをそれぞれ接続。
VDDは仕様書を確認するとDC +2.7 - +5.5Vだったのでなんとなくラズパイの3.3Vに接続。

特に確認用のランプとかあるわけではないですが...まぁ間違わないだろってことでしょう

pigpioのデーモンを起動する。

$ sudo pigpiod

接続するi2cデバイスのアドレスを調べる、今回はADT7410初期設定の0x48

$ i2cdetect -y 1

python

import time
import pigpio

# pigpioデーモンに接続しコマンドの送信と受信ができるようにする
# 必ず呼ばなければならない
pi = pigpio.pi()

# カウント用
i = 0

# i2c_open(i2c_bus, i2c_address, i2c_flags)
# i2cで接続するアドレスをopenする
# i2c_busは0と1が使えるが基本的に1を使う
# i2c通信先のアドレスは事前に調べておく
# flagsは特に定義されていないそうなので0としておくって関数の説明に書いてた
adt7410 = pi.i2c_open(1, 0x48, 0)

# とりあえず10回ほど表示させてみる
while i < 10:

    # i2c_read_i2c_block_data(handle, reg, count)
    # データを読み込む
    # handleはopenした通信先を指定
    # regは接続デバイスのレジスタ このあたりは取説を読んで確認
    # countは読み込むバイト数
    (b, d) = pi.i2c_read_i2c_block_data(adt7410, 0x00, 2)
    # bは読み取ったバイト数のタプル、dは読み込んだバイト列を返す

    # 数値の調整
    temp = (d[0] << 8 | d[1]) >> 3
    # 13ビット目が符号ビットなので4096以上の場合マイナスに調整
    if temp >= 4096:
        temp -= 8192

    # 取説に16で割れって書いてあったのでその通りにする
    print(temp / 16)

    # カウントを進める
    i += 1

    # 2秒タイマ
    time.sleep(2)

c言語(pigpioデーモンを使用する場合)

#include <stdio.h>
// pigpioのヘッダファイル読み込み
#include <pigpiod_if2.h>

int main() {
    // int pigpio_start(char *addrStr, char *portStr)
    // pigpioデーモンへの接続ストリーム
    // *addStr ローカルホストの場合はNULL
    // *portStr ローカルホストの場合は"8888"
    int pi = pigpio_start(NULL, "8888");

    // int i2c_open(int pi, unsigned i2c_bus,
    //              unsigned i2c_addr, unsigned i2c_flags)
    // 接続デバイスをオープン
    // pi pigpioデーモンへの接続ストリーム
    // i2c_bus 0と1が使えるが基本的に1を使用
    // i2c_addr 接続アドレス
    // i2c_flags 特に定義されていないそうなので0としておくらしい
    int i2c = i2c_open(pi, 1, 0x48, 0);

    // データ保存用のbuf
    char buf[2];

    // カウント用
    int i = 0;

    // 10回ほど表示する
    while (i < 10) {
        // int i2c_read_i2c_block_data(int pi, unsigned handle,
        //              unsigned i2c_reg, char *buf, unsigned count)
        // データの読み込み
        // pi pigpioデーモンへの接続ストリーム
        // handle オープンしたデバイスの指定
        // i2c_reg 接続先のレジスタを0-255で指定
        // *buf データの読み込み先bufを指定
        // count 読み込むバイト数を指定
        i2c_read_i2c_block_data(pi, i2c, 0, buf, 2);

        // バイト数の調整
        float temp = (buf[0] << 8 | buf[1]) >> 3;
        // 13ビット目が符号ビットなので4096以上の場合マイナスに調整
        if(temp >= 4096) {
            temp -= 8192;
        }
        // 取説に16で割れって書いてあったのでその通りにして表示
        printf("%.3f\n", temp / 16);

        // カウント進めて
        i++;

        // 待って
        time_sleep(2);
        
    }

    // int i2c_close(int pi, unsigned handle)
    // i2cの接続デバイスを閉じる
    // piとhandleは上記と同じ
    i2c_close(pi, i2c);

    return 0;
}

公式ドキュメントを参考にgccコンパイル

$ gcc -Wall -pthread -o prog prog.c -lpigpiod_if2 -lrt

prog.cというソースファイルからprog実行ファイルを生成する。
あとは実行すればok

$ ./prog

もし実行権限がどうとか聞かれたらchmodとかで権限を付与する。(たぶん大丈夫)

c言語(pigpioデーモンを使わない場合)

pigpioデーモンを起動していなくても使える。
起動している場合はkillコマンドで停止。 プロセスIDはtopコマンドかなんかで調べておく。

#include <stdio.h>
// ヘッダファイルがちょっと違う
#include <pigpio.h>

int main() {
    // ライブラリの初期化、必ず実行しなければならない
    gpioInitialise();

    // あとは関数名が少し違うだけでほとんど同じ

    // int i2cOpen(unsigned i2cBus, unsigned i2cAddr, unsigned i2cFlags)
    int i2c = i2cOpen(1, 0x48, 0);
    char buf[2];
    int i = 0;

    while (i < 10) {
        // int i2cReadI2CBlockData(unsigned handle, unsigned i2cReg,
        //                                  char *buf, unsigned count)
        i2cReadI2CBlockData(i2c, 0, buf, 2);
        float temp = (buf[0] << 8 | buf[1]) >> 3;

        if(temp >= 4096) {
            temp -= 8192;
        }

        printf("%.3f\n", temp / 16);
        i++;
        time_sleep(2);
    }
    // int i2cClose(unsigned handle)
    i2cClose(i2c);
    return 0;
}

コンパイルのコマンドも少し違う

$ gcc -Wall -pthread -o prog prog.c -lpigpio -lrt

実行時には管理者権限をつけないと怒られる

$ sudo ./prog

数値調整について

ADT7410の測定温度は取説によると0x00が上位ビット、0x01が下位ビットを表すので
演算して調整する必要があります。
私の部屋の場合
0x00 = 13 (pythonでのd[0], cでのbuf[0]) だったので1バイトの2進数にすると
[0 0 0 0 1 1 1 0]

同じように 0x01 = 88 (pythonでのd[1], cでのbuf[1]) だったので
[0 1 0 1 1 0 0 0]

この2数値を換算します。
取説によると温度は13ビット目を符号ビットとして13ビットで表現します。
とりあえず、一度16ビットにして3ビットずらすのが簡単だと思うので
コードで書いた通り順番に進めます。

まず、16ビットで表す。
0x00 = [0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0]
0x01 = [0 0 0 0 0 0 0 0 0 1 0 1 1 0 0 0]

0x00を << 8 で8ビットシフト
0x00 = [0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0]
0x01 = [0 0 0 0 0 0 0 0 0 1 0 1 1 0 0 0]

0x00と0x01をor演算
temp = [0 0 0 0 1 1 1 0 0 1 0 1 1 0 0 0]

tempを >> 3 で3ビットシフト
temp = [0 0 0 0 0 0 0 1 1 1 0 0 1 0 1 1]

計算すると 256 + 128 + 64 + 8 + 2 + 1 = 459
取説通り16で割ると28.6875

...暑いな...なんかすこし高いような気もしますが...誤差!ってことで

コンパイル時のオプションについて

メモ

-Wall           # 警告オプション。いっぱい怒られるようにする
-pthread        # POSIXスレッドを使ってコンパイルするとかなんとか
-o              # 最適化オプション。コンパイル時にプログラムの最適化を行う
-lpigpio        # pigpioのライブラリを指定
-lpigpiod_if2   # pigpiod_if2のライブラリを指定
-lrt            # rtライブラリの指定(librt) これもPOSIX関係?よくわからん