この文書ではI2Cで制御できる温湿度センサについて説明します.PICなどのマイコンと比べてPi4JではI2Cを簡単に扱うことができるようになっています.簡単にできますので気楽に取り組んでください.


回路構成

下の図は温湿度センサ周りの回路図となっています.HDC1000には3本の端子があり,そのうち2本(SDAとSCL)がI2Cのためのものです.ともに330[Ω]の抵抗でプルアップされております.この2本を使って温湿度を測定する指令を出したり,HDC1000の設定を行ったり,測定結果を受信したりします.RDY端子は温湿度を測定し始めるとHighになり終わるとLowとなりますので,測定終了をRPiで検知するときに用いられます.

 TempHumidSensor

 


I2C

I2Cはオランダのフィリップス社が中心となり制定された,2線式シリアル通信に分類される通信規格であり,SDAではデータを送受信し,SCLではクロックを送ります.この規格では基本的に1個のマスタデバイスとN個のスレーブデバイスがあり,すべての送受信はマスタが主導して行いますので,マスタがSCLを通じてクロックを送信します.マスタから見たとき送受信の区別は各スレーブに設定してあるアドレスと一緒に送る1ビットの信号で決められており,例えばスレーブアドレスが0x24(7ビット)のデバイスにマスタからデータを送信する場合には,前述の0x24に続き,Low(=0)をスレーブに送信します.つまり,アドレス(7ビット)+送信(1ビット)=0x48(8ビット)というようにマスターからスレーブへ送信するのです.その結果,0x24のアドレスを持つスレーブだけが反応し,そのスレーブがSDAをLowにします.その後,マスタからデータをSDAへ送信するようになっています.マスタがスレーブからのデータを受信するときには,アドレスに続きHighを出力しますので,0x49を送信し,その後はスレーブからデータがSDAを通じて送られてきます.送られてくるタイミングはすべてSCLに則っていますので,マスタはそのクロックを出しつつデータを受信すればよいのです.


プログラム

上記ではI2Cの送受信の仕組みについて説明しましたが,Pi4Jではその辺のことをうまくオブラートに包んでくれているため,実際のところ,上記のような仕組みを知らなくても通信を行えてしまいます.ここではPi4JによるI2Cデバイスの制御方法について説明します.

まずはI2Cバスのインスタンスを取得するため,クラスI2CFactoryのスタティックなメソッドgetInstanceを用いてインスタンスi2c_busとします.getInstanceにはI2Cのバスを引数にする必要があります.今回はI2CBus.BUS_1を引数にします.次にi2c_busにあるメソッドgetDeviceを使ってHDC1000のインスタンスhdc1000を得ます.このときHDC1000のアドレスは0x40ですのでこれをgetDeviceの引数にします.そしてhdc1000にあるメソッドwriteでRPiからHDC1000へ初期設定データを送ります.HDC1000への指令は下表のレジスタアドレスをHDC1000へ送ります.

ポインタ名前リセット時の値説明
0x00 温度 0x0000 温度

0x01

湿度 0x0000 湿度
0x02 コンフィギュレーション 0x1000 HDC1000の設定と状態
0xFB シリアルID デバイスによる シリアルIDの最初の2バイト
0xFC シリアルID デバイスによる シリアルIDの中間の2バイト
0xFD シリアルID デバイスによる シリアルIDの最後の2バイト
0xFE 製造者ID 0x5449 Texas InstrumentsのID
0xFF デバイスID 0x1000 HDC1000のID

 

この中にはコンフィギュレーションレジスタがありアドレス0x02に割り付けられており,このコンフィギュレーションレジスタには2バイトの値を設定できるようになっています.下表にコンフィギュレーションレジスタに設定できる2バイトの用途を示します.

ビット名前用途01
15 RST ソフトウェアリセットビット ノーマル動作 1を書き込むとリセットされます.リセット動作後
ノーマル動作に移行した場合,自動的に0になります.
14~13  Reserved 予約ビット  必ず0に設定してください.
12 MODE モード設定ビット 温度,湿度16bitを個別に取りこみます. 温度,湿度の順で32bitを一度に取り込みます.
11 BTST 電源電圧状態表示ビット 電圧>2.8[V](リードのみ) 電圧<2.8[V](リードのみ)
10 TRES 温度の分解能設定ビット 14ビット分解能 11ビット分解能
9~8 HRES 湿度の分解能設定ビット 00=14ビット分解能,01=11ビット分解能,10=8ビット分解能
7~0 Reserved 予約ビット 必ず0に設定してください.

今回,温度と湿度を16bitを個別に取り込み,分解能は14bitにします.従いまして0x00, 0x00とします.まとめますと,コンフィギュレーションレジスタのアドレス0x02に続き,0x00と0x00をHDC1000へ送信すればよいですので,メソッドwriteは次のようになります.

 I2CBus i2c_bus = I2CFactory.getInstance(I2CBus.BUS_1);
I2CDevice hdc1000_pins = i2c_bus.getDevice(0b1000000);
hdc1000_pins.write(new byte[] { 0x02, 0x00, 0x00 }, 0, 3);

HDC1000にはI2C以外にRDY端子を用いますので,これをインスタンス化して プライベートなフィールド _readyとします.この端子は通常の入力端子ですのでスイッチと同様にクラスGpioPinDigitalInputのインスタンスにしてください.

演習

上記のプログラムをクラスHDC1000のコンストラクタに記載してください.ただし,hdc1000_pinsは他のメソッドでも使用しますので,名称を変更し,プライベートなフィールド _hdc1000Pinsとしてください.下にクラスHDC1000の外枠のみ示します.

{code}package jp.ac.nanano_nct.ashida_lab.hdc1000;

import java.io.IOException;

import com.pi4j.io.gpio.GpioController;
import com.pi4j.io.gpio.GpioFactory;
import com.pi4j.io.gpio.GpioPinDigitalInput;
import com.pi4j.io.gpio.PinPullResistance;
import com.pi4j.io.gpio.RaspiPin;
import com.pi4j.io.i2c.I2CBus;
import com.pi4j.io.i2c.I2CDevice;
import com.pi4j.io.i2c.I2CFactory;

public class HDC1000 {

    private GpioPinDigitalInput _ready;
    private I2CDevice _hdc1000Pin;

    public HDC1000() throws IOException{
        /* ここに記載 */
    }
}
{highlight}{end-code}

 

次に温度を取得するメソッドgetTempをHDC1000に追加します.温度を得るにレジスタは先ほど示した表の中にあるように,アドレス0x00に割り当てられていますのでこの値をHDC1000へ送ります.すると計測が始まり,RDY端子がHighになります.計測が終わるとRDY端子がLowになりますのでそれまで待ちます.今回はRDYがLowになるまでずっとその処理を行うことにしたいので,_readyの中にあるメソッドisHighを用います.スイッチのプログラムの時には,イベントリスナを使ったものでしたが,今回のようにずっとピンの状態を見張り続けるスタイルをポーリングといいます.HDC1000で温度を取得できましたら,_hdc1000Pinsにあるメソッドreadを用いて温度データを得ます.このメソッドには3個の引数があり,第1引数にはデータを格納する配列を,第2引数には配列の開始番号を,第3引数には読み込みデータ個数を指定します.今回は2バイトのbyte型配列 _bufをプライベートなフィールドとし,第1引数に用います.そして第2引数は0,第3引数を2にします._buf[0]には上位8ビット,_buf[1]には下位8ビットが格納が格納されますので,これにもとづき int型のraw_dataとします.このとき,_bufはbyte型なのでキャストを忘れずに行ってください.

最後に得たデータを摂氏に変換します.変換式は下のとおりです.

{jmimetex}\frac{165 \times raw\_data}{2^{16}}-40{/jmimetex}

変換した結果をgetTempからreturnしてください.

演習

パブリックなメソッドgetTempをHDC1000に追加してください.