SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

C#ではじめるラズパイIoTプログラミング

C#でラズパイに接続した温湿度センサーで計測しよう

C#ではじめるラズパイIoTプログラミング 第5回

  • X ポスト
  • このエントリーをはてなブックマークに追加

測定の流れ

 今回の温湿度センサーモジュールでは、温湿度を測定するモードとして、単発測定するモードと、自動で周期的に連続して測定するモードがあります。単発測定モードでは、単発測定用コマンドを送信し、測定が完了した後に、データを読み出すといった流れになります。連続測定モードでは、測定開始コマンドで周期的な測定が開始されます。そして、測定値読み出しコマンドを送信してデータの受信、最後に連続測定停止コマンドを送信します。なお各コマンドは、2バイトのデータとなります。

SHT31温湿度センサーモジュール制御クラス

 センサーモジュール制御クラスのデータメンバとコンストラクタは、以下のようになります。

[リスト2]Program.csの一部
// SHT31温湿度センサーモジュール制御クラス
public class Sht31
{
    // 温度
    public float Temp { get; private set; }
    // 相対湿度
    public float Rhum { get; private set; }
    // 受信データバッファ
    private readonly byte[] Buff = new byte[6];

    // I2Cファイルディスクリプタ
    private int I2cfd { get; }
    public Sht31(int fd) => I2cfd = fd;
}

 I2C通信のファイルディスクリプタ、温度、湿度のプロパティ、受信データ用のバイト配列を定義しています。

 コマンドを送信するメソッドは、次のように定義しました。

[リスト3]Sht31クラスの一部
// 単発測定
public void OneshotCmd()
{
    WiringPi.I2CWriteReg8(I2cfd, 0x2C, 0x06);   // 単発測定コマンド
    Read(); // データ受信
}
// 連続測定開始
public void StartCmd()
{
    WiringPi.I2CWriteReg8(I2cfd, 0x22, 0x36);   // 2回/秒周期で測定
}
// 連続測定値読み出し
public void ReadCmd()
{
    WiringPi.I2CWriteReg8(I2cfd, 0xE0, 0x00);   // 測定値取り込みコマンド
    Read(); // データ受信
}
// 連続測定停止
public void StopCmd()
{
    WiringPi.I2CWriteReg8(I2cfd, 0x30, 0x93);   // 連続測定停止コマンド
}

 連続測定を開始するコマンドでは、測定頻度を指定することができます。今回は、1秒に2回の頻度で連続測定する設定にしました(1秒あたり、0.5、1、2、4、10回の設定が可能)。

 OneshotCmdメソッドでは、温湿度測定コマンド送信後、データ読み出しを行います。

データ受信

 単発測定用コマンド、または連続測定値読み出しコマンドを送信すると、センサーモジュールからは測定データ(温度・湿度それぞれ2バイト)とチェックサムデータ(それぞれ1バイトCRC)の計6バイトが送られてきます。

 データを受信するメソッドは、次のように定義しました。

[リスト4]Sht31クラスの一部
// データ受信
private void Read()
{
    int cnt = WiringPi.Read(I2cfd, Buff, Buff.Length);  // データ受信(6バイト)
    if (Buff.Length < cnt) return;                      // 6バイト未満なら終了(1)

    if (Checksum(Buff[0], Buff[1]) == Buff[2])      // CRC確認
    {
        float rawt = (Buff[0] << 8) | Buff[1];      // 温度データ取り出し(2)
        Temp = -45 + rawt * 175 / 65535;            // 温度に変換(3)

    }
    if (Checksum(Buff[3], Buff[4]) == Buff[5])      // CRC確認
    {
        float rawrh = (Buff[3] << 8) | Buff[4];     // 湿度データ取り出し
        Rhum = 100 * rawrh / 65535;                 // 湿度に変換
    }
}

 最初に、WiringPi.Readメソッドを使ってデータを受信します。6バイト分受信できなかったら、そこで終了にしています(1)。

 センサーモジュールから送られてくるデータ6バイトは、次の順になります。

  • 温度測定値(MSB)→ 温度測定値(LSB)→ CRCチェックサム(温度)→湿度測定値(MSB)→ 湿度測定値(LSB)→ CRCチェックサム(湿度)

 各測定値のデータ長は、16ビットです。そのためMSB(最上位バイト)の値を8ビットシフトして、LSB(最下位バイト)に加算しています(2)。また測定データは、正の整数値に変換されていますので、正しい値に復元しています(3)。

CRC

 各測定値の後には、チェックサム(CRC)データ1バイトが続きます。

 このチェックサムデータは、測定値の誤り検出のための符号で、CRCとは、巡回冗長検査(Cyclic Redundancy Check)の略です。CRCでは、データを特定の定数(生成多項式)で割り算し、その余りをデータ確認用の符号として用います。送信側は、この符号を検査データとして付加し、受信側では、同じようにデータを計算して、符号が合致するかどうかを確認します。合致しない場合は、通信上で何らかのデータの破損があったことになります。

 CRCのアルゴリズムは、いくつかあります。今回のセンサーモジュールでは、「CRC-8-Dallas/Maxim」と呼ばれる多項式を利用する仕様で、気温、湿度それぞれの16ビットデータから8ビットの値を算出します。

 CRCを計算するクラスを、次のように静的クラスとして定義しました。

[リスト5]Program.csの一部
// CRC-8計算クラス
public static class CRC8
{
    static readonly byte[] table = new byte[256]; // Lookup Table
    const byte poly = 0x31; // x8 + x5 + x4 + 1

    static CRC8()
    {
        // Lookup Tableの計算(1)
        for (int i = 0; i < table.Length; i++)
        {
            int temp = i;
            for (int j = 0; j < 8; j++)
            {
                if ((temp & 0x80) != 0)
                {
                    temp = (temp << 1) ^ poly;
                }
                else
                {
                    temp <<= 1;
                }
            }
            table[i] = (byte)temp;
        }
    }

    // CRCチェックサムの計算
    public static byte Checksum(params byte[] bytes)
    {
        byte crc = 0xFF; // 初期値
        foreach (byte b in bytes)
        {
            crc = table[crc ^ b];
        }
        return crc;
    }
}

 あらかじめコンストラクタで、1バイト分(0~255の値に対応)の計算結果をテーブルにすることで、都度の計算を省略しています(1)。

 Checksumメソッドでは、CRCを計算したいデータ1バイトごとに引数に指定します。例えば、0xBE、0xEFというデータなら、次のようになります。

Console.WriteLine(CRC8.Checksum(0xBE, 0xEF).ToString("X")); // 出力値:92

 Sht31クラスのReadメソッドでは、CRCをチェックして、合致しない場合は、気温・湿度を更新しないようにしています。

次のページ
測定

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
C#ではじめるラズパイIoTプログラミング連載記事一覧

もっと読む

この記事の著者

WINGSプロジェクト 高江 賢(タカエ ケン)

WINGSプロジェクトについて>有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2018年11月時点での登録メンバは55名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂きたい。著書記事多数。 RSS X: @WingsPro_info(公式)、@WingsPro_info/wings(メンバーリスト) Facebook

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるReact実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/11995 2020/02/28 11:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング