LoginSignup
11
11

More than 5 years have passed since last update.

Raspberry Pi 2 Model B でI2C 気圧+温度センサーモジュール(BMP180)を使う

Last updated at Posted at 2015-05-21

概要

Raspberry pi 2 Model B (Raspbian)での aitendo M180-4P(BMP180使用 気圧センサモジュール) 設定覚書き


参考

参考にしました、ありがとうございます。


センサーモジュール接続

ここのピンアウト表を参照しました。今回は、1,3,5,9ピンを使用し設定します。
5Vトレラントなので、5Vで接続したほうが安定するかもしれません。
3.3Vで使ってみて様子をみます。

image

センサーモジュール設定情報

説明書を読んでみます。
このセンサーは、以下のようなレジスタ構成になっています。

image

  • MSB(out_msb), LSB(out_lsb), XLSB(out_xlsb)
    測定データが入ります。
    温度(UT)は、16ビットになります。MSBとLSBを使います。
    気圧(UP)は、モードにより16ビット〜19ビットになります。MSB, LSB, XLSBを使います。

  • ctrl_meas
    image

【oss(oversampling_setting)】:
2ビットで、温度測定時は、00。気圧測定時は、ここの設定でモードを決めます。
4種類のモードとソフトウェア的に精度を上げた(複数回計測しているだけですが)1計測毎内部サンプリング回数が32回のモードの5種類があります。
【sco】:
1ビットで、1の間は、計測中です。計測が完了すると0になります。
【measurement】:
5ビットで、温度測定は、"01110"。気圧測定は、"10100"です。

測定したいモードの設定値を0xF4のコントロールレジスタに(例えば、温度なら0x2E)書き込み、変換時間待ったのち、out_msb, out_lsb, out_xlsbから計測値を取得すればよいようです。

  • soft(Soft reset)
    0xB6を書き込むと電源リセットと同様のシーケンスでソフトリセットされます。

  • id
    0x55(固定値)です。接続確認などに使います。

  • calib21-calib0(補正値)
    各16ビットの11補正パラメータです。AC4, AC5, AC6がunsignedで、それ以外のパラメータは、signedです。
    補正値は、気温、気圧を計算する際、以下の計算式で使用します。
    結構、めんどくさい計算です。その分、正確な値が計測できるのかな。

【補正値 AC1, AC2, AC3, AC4, AC5, AC6, B1. B2, MB, MC, MD】
各補正値 = ((各補正値のMSB << 8) | 各補正値のLSB);

【気温 t】
UT = ((MSB << 8) | LSB);

X1 = ((UT - AC6) * AC5 >> 15);
X2 = ((MC << 11) / (X1 + MD));
B5 = (X1 + X2);
t = ((B5 + 8) >> 4);

t / 10.0 ℃

【気圧 p】
UP = ((MSB << 16) | (LSB << 8) | XLSB) >> (8 - oss)

B3の計算

B6 = (B5 - 4000);
X1 = ((B6 * B6) >> 12);
X1 = (X1 * B2);
X1 = (X1 >> 11);
X2 = (AC2 * B6);
X2 = (X2 >> 11);
X3 = (X1 + X2);
B3 = (AC1 * 4 + X3);
B3 = ((B3 << oss) + 2);
B3 = (B3 >> 2);

B4の計算

X1 = ((AC3 * B6) >> 13);
X2 = ((B6 * B6) >> 12);
X2 = ((B1 * X2) >> 16);
X3 = ((X1 + X2) + 2) >> 2;
B4 = (AC4 * (X3 + 32768)) >> 15;

pの計算

B7 = ((UP - B3) * (50000 >> oss));
if (B7 < 0x80000000) {
p = (B7 << 1) / B4;
} else {
p = (B7 / B4) << 1;
}
X1 = p >> 8;
X1 *= X1;
X1 = (X1 * 3038) >> 16;
X2 = (p * -7357) >> 16;
p += (X1 + X2 + 3791) >> 4;

p / 100.0 hPa

センサーモジュール設定手順

I2C有効

I2C有効
$ sudo raspi-config

「8 Advanced Options」 → 「A7 SPI」 → 「I2C enable」

I2Cモジュール設定

I2Cモジュール読み込み設定
$ sudo nano /etc/modules
snd-bcm2835
i2c-dev

I2Cライブラリインストール

I2Cライブラリインストール
$ sudo sudo apt-get install libi2c-dev

gitインストール

gitインストール
$ sudo apt-get install git-core

アップデート

アップデート
$ sudo apt-get update
$ sudo apt-get upgrade

センサーモジュールアドレス確認

たぶん、0x77だと思います。

アドレス確認
$ sudo i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- 77

センサーモジュール接続確認

データを取得できるか試すため、idを取得してみます。
0x55が返ってくれば正しく接続できています。

接続確認
$ sudo i2cget -y 1 0x77 0xD0 b
0x55

サンプルコード

このサンプルコードは、温度と気圧のソフトウェア精度モードを取得します。
BMP180は、扱いやすいセンサーのようです。
Pythonでadafruitのドライバを利用している方が多いようでした。
センサーの使い方を勉強するため、説明書を読んで、メーカーのドライバとadafruitのドライバのソースコードを読んでみました。

BMP085と下位互換があるようですので、Raspbianに入っているbmp085のカーネルモジュールで簡単に動作するのかもしれません。試してないです。

まずは、シェルスクリプトで気温の値が取得できるか挑戦してみました。
実は、16bitのsignedの扱いでそうとう苦労しました。
あまり綺麗な方法でないと思っています。
何か良い計算方法があったら教えて下さい。

bmp180_test.sh
#!/bin/bash

AC5_MSB=$(sudo i2cget -y 1 0x77 0xB2 b)
AC5_LSB=$(sudo i2cget -y 1 0x77 0xB3 b)
AC5=$((AC5_MSB<<8|AC5_LSB))

AC6_MSB=$(sudo i2cget -y 1 0x77 0xB4 b)
AC6_LSB=$(sudo i2cget -y 1 0x77 0xB5 b)
AC6=$((AC6_MSB<<8|AC6_LSB))

MC_MSB=$(sudo i2cget -y 1 0x77 0xBC b)
MC_LSB=(sudo i2cget -y 1 0x77 0xBD b)
MC=$(printf "0x%x" $((MC_MSB<<8|MC_LSB)))
if [ $(printf "%d" $MC) -gt 32767 ];then
    MC=$((((MC^0xffff)+1)*-1))
else
    MC=$(printf "%d" $MC)
fi

MD_MSB=$(sudo i2cget -y 1 0x77 0xBE b)
MD_LSB=$(sudo i2cget -y 1 0x77 0xBF b)
MD=$((MD_MSB<<8|MD_LSB))

sudo i2cset -y 1 0x77 0xF4 0x2E b
sleep 1

UT_MSB=$(sudo i2cget -y 1 0x77 0xF6 b)
UT_LSB=$(sudo i2cget -y 1 0x77 0xF7 b)
UT=$((UT_MSB<<8|UT_LSB))

X1=$((((UT-AC6)*AC5)>>15))
X2=$(((MC<<11)/(X1+MD)))
B5=$((X1+X2))
TEMPERATURE=$(((B5+8)>>4))

printf "Temprature: %.2f C\n" $(echo "scale=2;$TEMPERATURE / 10.0" | bc)

exit 0

サンプルコードは、WiringPiBoschのドライバを利用しています。

気になるところや間違いなどあればコメントいただけると助かります。

ドライバダウンロード
$ cd
$ git clone git://git.drogon.net/wiringPi
$ cd wiringPi
$ ./build
$ cd ..
$ git clone https://github.com/BoschSensortec/BMP180_driver.git
$ cd BMP180_driver
bmp180_sample.c
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <wiringPi.h>
#include <wiringPiI2C.h>
#include "bmp180.h"

s8 BMP180_I2C_bus_read(u8 dev_addr, u8 reg_addr, u8 *reg_data, u8 cnt);
s8 BMP180_I2C_bus_write(u8 dev_addr, u8 reg_addr, u8 *reg_data, u8 cnt);
void BMP180_delay_msek(u32 msek);

int main(void)
{
    struct bmp180_t bmp180;

    s32 com_rslt = E_BMP_COMM_RES;
    u16 v_uncomp_temp_u16 = BMP180_INIT_VALUE;
    u32 v_uncomp_press_u32 = BMP180_INIT_VALUE;

    bmp180.bus_write = BMP180_I2C_bus_write;
    bmp180.bus_read = BMP180_I2C_bus_read;
    bmp180.dev_addr = BMP180_I2C_ADDR;
    bmp180.delay_msec = BMP180_delay_msek;

    com_rslt = bmp180_init(&bmp180);
    if(com_rslt < 0) {
        printf("error: Initialization failed\n");
    }

    bmp180.sw_oversamp = BMP180_SW_OVERSAMP_U8X;
    bmp180.oversamp_setting = BMP180_OVERSAMP_SETTING_U8X;

    v_uncomp_temp_u16 = bmp180_get_uncomp_temperature();
    v_uncomp_press_u32 = bmp180_get_uncomp_pressure();

    printf("temp: %.2f C\n", bmp180_get_temperature(v_uncomp_temp_u16) / 10.0);
    printf("press: %.2f hPa\n", bmp180_get_pressure(v_uncomp_press_u32) / 100.0);

    return 0;
}

s8 BMP180_I2C_bus_read(u8 dev_addr, u8 reg_addr, u8 *reg_data, u8 cnt)
{
    int fd;

    s32 iError = BMP180_INIT_VALUE;
    u8 stringpos = BMP180_INIT_VALUE;

    fd = wiringPiI2CSetup(dev_addr);

    for (stringpos = BMP180_INIT_VALUE; stringpos < cnt; stringpos++) {
        *(reg_data + stringpos) = wiringPiI2CReadReg8(fd, reg_addr + stringpos);
    }
    return (s8)iError;
}

s8 BMP180_I2C_bus_write(u8 dev_addr, u8 reg_addr, u8 *reg_data, u8 cnt)
{
    int fd;

    s32 iError = BMP180_INIT_VALUE;
    u8 stringpos = BMP180_INIT_VALUE;

    fd = wiringPiI2CSetup(dev_addr);

    for (stringpos = BMP180_INIT_VALUE; stringpos < cnt; stringpos++) {
        iError = wiringPiI2CWriteReg8(fd, reg_addr + stringpos, *(reg_data + stringpos));
    }
    return (s8)iError;
}

void BMP180_delay_msek(u32 msek)
{
    usleep(msek * 1000);
}
実行
$ gcc -Wall -lwiringPi bmp180.c bmp180_sample.c -o bmp180_sample
$ sudo ./bmp180_sample
temp: 15.10 C
press: 1004.03 hPa

以上

11
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
11