Date

adafruit より Adafruit BME280 I2C or SPI Temperature Humidity Pressure Sensor が発売されている。 Bosch のBME280 というセンサーを搭載したブレイクアウト基板で、気温、湿度、気圧を計測することができる。通信方式は I2C と SPI に対応している。

Adafruit BME280 I2C or SPI Temperature Humidity Pressure Sensor

これを Netduino 3 Wifi と接続し、計測結果を I2C で取得してみる。

回路を作成する

ブレイクアウト基板にヘッダピンをハンダ付けしたら、ブレッドボードに挿し込む。 Netduino と次のようにジャンパーワイヤで接続する。

1
2
3
4
5
Netduino3 wifi        BME280
3V3     <------------>  VIN
GND     <------------>  GND
SD      <------------>  SDI
SC      <------------>  SCK

接続した回路

プロジェクトを作成する

Visual Studio 2013 でプロジェクトを新規作成する。 テンプレートは Visual C# - Micro Framework 内にある Netduino Application (Universal) を選択する。

I2C で通信するための準備

I2C で通信するには、まず設定を I2CDevice.Configuration として作成する。ここでは、デバイスに設定されているアドレス とクロック周波数(単位:khz)を指定する。次に I2CDeviceI2CDevice.Configuration を引数として作成する。

今回使用する BME280 のアドレスは 0x77 である。 クロック周波数は 100khz を使うことにする。初期化コードは以下のようになる。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
public class BME280 : IDisposable
{
  private I2CDevice Device = null;
  private const ushort ADDRESS = 0x77;

  public BME280()
  {
    const int clockKhz = 100;
    var conf = new I2CDevice.Configuration(ADDRESS, clockKhz);
    this.Device = new I2CDevice(conf);
  }

……

}

読み書きは I2CDevice.I2CTransaction の配列で表されるトランザクション単位で行う。配列の要素は I2CDevice.I2CWriteTransaction または I2CDevice.I2CReadTransaction となる。その名の通り、それぞれ書き込み、読み込みを表す。トランザクションを実行するには、この配列を引数としてI2CDevice.Execute を呼び出す。

単に requestSize で指定した分だけ読み出すトランザクションを実行するコードは以下のようになる。

1
2
3
4
5
var readBuffer = new byte[requestSize];
var i2ctx = new I2CDevice.I2CTransaction[] {
  I2CDevice.CreateReadTransaction(readBuffer),
};
var transferred = Device.Execute(i2ctx, TIMEOUT);

デバイスの特定のレジスタを読みだすには、読みだしたいレジスタの番号を書き込み、続けて読み込む処理を 1 つのトランザクションで行う。

1
2
3
4
5
6
var readBuffer = new byte[requestSize];
var i2ctx = new I2CDevice.I2CTransaction[] {
  I2CDevice.CreateWriteTransaction(writeBuffer),
  I2CDevice.CreateReadTransaction(readBuffer),
};
var transferred = Device.Execute(i2ctx, TIMEOUT);

計測を準備する

チップID を取得する

接続しているデバイスが BME280 であることを確認するため、レジスタ 0xd0 を読みだし、 0x60 が返ってくるか確認する。

キャリブレーションデータを取得する

BME280 から計測データを取得する前に、キャリブレーションデータを取得する必要がある。データシート の Table 16 (Page 22) に載っている値を読み込む。 dig_T1…3, dig_P1…9, dig_H1…6 と名前付けされており、 T? は気温, P? は気圧, H? は湿度に関するキャリブレーションデータである。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// キャリブレーションデータを`BME280` クラスのメンバ変数として保存しておく
private void calibration()
{
  this.T1 = readU16LE((byte)Register.dig_T1);
  this.T2 = readS16LE((byte)Register.dig_T2);
  this.T3 = readS16LE((byte)Register.dig_T3);

  this.P1 = readU16LE((byte)Register.dig_P1);
  this.P2 = readS16LE((byte)Register.dig_P2);
  this.P3 = readS16LE((byte)Register.dig_P3);
  this.P4 = readS16LE((byte)Register.dig_P4);
  this.P5 = readS16LE((byte)Register.dig_P5);
  this.P6 = readS16LE((byte)Register.dig_P6);
  this.P7 = readS16LE((byte)Register.dig_P7);
  this.P8 = readS16LE((byte)Register.dig_P8);
  this.P9 = readS16LE((byte)Register.dig_P9);

  this.H1 = read8((byte)Register.dig_H1);
  this.H2 = readS16LE((byte)Register.dig_H2);
  this.H3 = read8((byte)Register.dig_H3);
  this.H4 = (short)(((int)read8((byte)Register.dig_H4) << 4) | ((int)read8((byte)Register.dig_H4 + 1) & 0xf));
  this.H5 = (short)(((int)read8((byte)Register.dig_H5 + 1) << 4) | ((short)read8((byte)Register.dig_H5) >> 4));
  this.H6 = (sbyte)read8((byte)Register.dig_H6);
}

計測モードを設定する

レジスタ 0xf4 "ctrl_meas" に気温と気圧を計測するときの oversampling 係数と、センサーモードを設定する。気温と気圧は16倍オーバーサンプリング、センサーモードは normal を指定したいので 11011011 = 0x3f を指定する。レジスタ 0xf2 "ctrl_hum" に湿度を計測するときの oversampling 係数を設定する。同様に 16 倍オーバーサンプリングとしたいので 101 = 0x05 を指定する。値の詳細はデータシートを参照のこと。

BME280 は sleep, normal, forced の 3 つのモードがある。このうち sleep は計測を行わない最も消費電力が少ない状態。forced は 1 回だけ計測し、その結果をレジスタに書き込んだら sleep モードに遷移するので、より少ない消費電力で運用したいときに選択すると良い。sleep に遷移した後で計測するには再度 forced に設定する。

気温を計測する

気温を計測するにはレジスタ 0xfa から 3 バイト読み取って 18 ビットの値を取得する。バイトオーダーはビッグエンディアンなので注意すること。その後、データシートのサンプルコードに従ってキャリブレーションデータをもとに気温を求める。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
public double readTemp()
{
  int adc_T1 = read8((byte)Cmd.READ_TEMP);
  int adc_T2 = read8((byte)Cmd.READ_TEMP + 1);
  int adc_T3 = read8((byte)Cmd.READ_TEMP + 2);
  int adc_T = (((adc_T1 << 8) + adc_T2) << 4) + (adc_T3 >> 14);
  double adc_Td = (double)adc_T;

  double var1, var2, T;
  var1 = ((adc_Td) / 16384.0 - ((double)this.T1) / 1024.0) * ((double)this.T2);
  var2 = (((adc_Td) / 131072.0 - ((double)this.T1) / 8192.0) *
  (adc_Td / 131072.0 - ((double)this.T1) / 8192.0)) * ((double)this.T3);
  T = (var1 + var2) / 5120.0;

  return T;
}

T に気温(単位: ℃) が代入されているので、あとはこれを Debug.Print したり Azure に投げたりすればよい。

気圧と湿度もデータシートにサンプルコードが載っているので、同様に実装できる。

サンプルコード

https://github.com/mahorigahama/Netduino_BME280 からどうぞ。


Comments

comments powered by Disqus