秋月のMPL115A2使用大気圧センサーモジュール(I2C)(丸ピン実装済み完成品)を用いました。

気圧を測ってみよう

Barometerクラス



Barometer.cs
    class Barometer
    {
        // Set Constants for Address and Clock Frequency
        const ushort ADDRESS = 0x60;
        const int CLOCK_FREQ = 100;       // kHz   max 400 
        const int TIMEOUT = 100; 

         //Init I2C Device Config
        I2CDevice.Configuration config = 
            new I2CDevice.Configuration(ADDRESS, CLOCK_FREQ);

        I2CDevice i2c;

        public Barometer()
        {
            i2c = new I2CDevice(config);
            ReadCoef();
        }

        public void Write(byte control, byte data)
        {
            i2c.Execute(new I2CDevice.I2CTransaction[1] {
                I2CDevice.CreateWriteTransaction(new Byte[] { control, data }) }, TIMEOUT);
        }

        public int Read(byte Address)
        {
            byte[] Data = new byte[2];
            i2c.Execute(new I2CDevice.I2CTransaction[1] { I2CDevice.CreateWriteTransaction(new Byte[] { Address }) }, TIMEOUT);
            i2c.Execute(new I2CDevice.I2CTransaction[1] { I2CDevice.CreateReadTransaction(Data) }, TIMEOUT);
            return Data[0] << 8 + Data[1];
        }
        public void Read(byte Address, byte[] Data)
        {
            i2c.Execute(new I2CDevice.I2CTransaction[1] { I2CDevice.CreateWriteTransaction(new Byte[] { Address }) }, TIMEOUT);
            i2c.Execute(new I2CDevice.I2CTransaction[1] { I2CDevice.CreateReadTransaction(Data) }, TIMEOUT);
        }
        
        double a0;
        double b1;
        double b2;
        double c12;
        public double temperature { get; set; }
        
        public void ReadCoef()
        {
            byte[] data = new byte[8];
            Read(4, data);
            a0 = ((short)((data[0] << 8) | data[1])) / 8.0;
            b1 = ((short)((data[2] << 8) | data[3])) / 8192.0;
            b2 = ((short)((data[4] << 8) | data[5])) / 16384.0;
            c12 = ((data[6] << 8) + data[7]) / (double)(1<<(9+13+2));
        }

        public double GetPressure()
        {
            Write(0x12, 1);
            CPU.delay(3);
            byte[] data = new byte[4];
            Read(0,data);
            int Padc =  ((data[0] << 8) | data[1])>>6 ;
            int Tadc = ((data[2] << 8) | data[3])>>6;
            double Pcomp = a0 + (b1 + c12 * Tadc) * Padc +b2 * Tadc;
            temperature = 25 + ((Tadc - 497.0) / -5.35);  // 472 counts at 25ºC, -5.35 counts/ºC
            return (((650.0/1023.0)*Pcomp)+500);
        }

        public double GetTemperature()
        {
            return temperature;
        }
    }


printfみたいなものを作ってみる

.Net MFにはC言語のprintfに相当するものはありません。特に可変引数はまだできていません。
そこで、double型一つだけのformat擬きができるメソッドを作ってみます。

sprintf
    class Stdout
    {
        public static String sprintf(String fmt, double val)
        {
            char ch;
            int j = 0;
            char[] str = new char[40];
            String Value;
            bool sign = val < 0 ? true : false;
            if (sign) val = -val;
            for (int i = 0; i < fmt.Length; i++)
            {
                ch = fmt[i];
                if (ch == '%')
                {
                    int k = fmt.IndexOf('.', i);
                    int column = int.Parse(fmt.Substring(i + 1, k - 1 - i));
                    k++;
                    i = fmt.IndexOf('f', i);
                    String sn = fmt.Substring(k, i - k);
                    Value = val.ToString("f" + sn);
                    int space = column - Value.Length;
                    if (sign) space--;
                    for (int m = 0; m < space; m++) str[j++] = ' ';
                    if (sign) str[j++] = '-';
                    foreach (char x in Value)
                        str[j++] = x;
                }
                else str[j++] = ch;
            }
            return new String(str);
        }
    }
 1 標準出力のつもり
 2 ここでは、出力はしないで文字列を返す
 3 メソッドにする。その最大文字数は勝手に40
 4 とした。
 5 
 6 
 7 
 8 
 9 
10 
11 
12 
13 
14 %の出現は1回のみ、多くすると面白いことが起こる。
15 チェックすべきだが、そういう馬鹿はいないことにする。
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 文字が来たらそのままコピー
30 
31 
32 
33 


メインプログラム

MPL115A2は±10hPaと精度が良くないと思われます。絶対値もおかしな値です。
50~115kPaまで測れるとのことですが、軽くこの値を超える数値をはじき出してくれます。
これは天気予報みたいなことはできないでしょう。このデバイスは、 ある時間間隔で、大きな変化を検出するためのものかと思います。
また、ADコンバーターからの値もかなりばらついていたりします。
従って、移動平均を計算してノイズを減らしています。
下にある値よりサンプリング間隔を短くし、平滑化定数を小さくすると、さらに現実的な値になるようです。(それでも精度はよろしくない)

main.cs
    public partial class Program
    {
        public void main()
        {
            Barometer pr = new Barometer();
            double alpha = 0.05;
            double pressure = pr.GetPressure();
            double temperature = pr.temperature;
            while (true)
            {
                double p = pr.GetPressure();
                pressure = (1 - alpha) * pressure + p * alpha;
                double t = pr.GetTemperature();
                temperature = (1 - alpha) * temperature + t * alpha;
                Debug.Print("気圧= " + Stdout.sprintf("%7.2f", pressure) + 
                    "[hPa]" + " 温度= " + Stdout.sprintf("%4.1f",temperature)+"[℃]");          
                CPU.delay(1000);
            }
        }
    }
 1 
 2 
 3 
 4 
 5 コンストラクタ
 6 平滑定数
 7 初回の気圧と温度を測定する
 8 
 9 
10 
11 
12 平滑化
13 
14 
15 printf擬きを使ってみる
16 
17 
18 
19 
20