提交 c0984ad1 编写于 作者: A Antonio Garcia 提交者: Krzysztof Wicher

Add bmp180 device (#184)

* Add BMP180 device binding

* Create README.md

* Remove StartupObject and OutputType

* Remove nuget.config file, isn't required

* Fix project setup

* Fix ProjectReference

* Changes based in feedback

* added Units.csproj

* Added Iot.Units
Fix "Sapling" -> "Sampling"
Fix extra space
Change Dispose method

* Implement Temperature - Iot.Units

* Remove CommunicationProtocol , BMP180 only have i2c

* Remove CommunicationProtocol

* Remove duplicate

* Fix namespace

* Fix README

* Remove initialized
Remove "this" keyword
Add space

* Fix brace style

* add space between get and set

* - Remove LangVersion
- Remove MSBuildThisFileDirectory

* Removed duplicate logic

* - Changed B7 type
- Add seaLevelPressure = 103125

* - Add units
- Fix tempValue.Celsius

* simplify temperature formula

* Remove shift operator
Simplify pressure formula

* Change return value
Implement Span

* add comment referencing  datasheet  time constant

* Update Bmp180.cs

Fix space

* Update Register.cs

change access modifier

* Update Bmp180.csproj

convert to -> Version="$(SystemDeviceGpioPackageVersion)"
上级 53a37c39
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
// Ported from https://github.com/adafruit/Adafruit_Python_BMP/blob/master/Adafruit_BMP/BMP085.py
// Formulas and code examples can also be found in the datasheet https://cdn-shop.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf
using System;
using System.Device.I2c;
using System.Buffers.Binary;
using System.Threading;
using Iot.Units;
namespace Iot.Device.Bmp180
{
public class Bmp180 : IDisposable
{
private I2cDevice _i2cDevice;
private readonly CalibrationData _calibrationData;
private Sampling _mode;
public const byte DefaultI2cAddress = 0x77;
public Bmp180(I2cDevice i2cDevice)
{
_i2cDevice = i2cDevice;
_calibrationData = new CalibrationData();
//Read the coefficients table
_calibrationData.ReadFromDevice(this);
SetSampling(Sampling.Standard);
}
/// <summary>
/// Sets sampling to the given value
/// </summary>
/// <param name="mode">Sampling Mode</param>
public void SetSampling(Sampling mode)
{
_mode = mode;
}
/// <summary>
/// Reads the temperature from the sensor
/// </summary>
/// <returns>
/// Temperature in degrees celsius
/// </returns>
public Temperature ReadTemperature()
{
return Temperature.FromCelsius((CalculateTrueTemperature() + 8) / 160.0);
}
/// <summary>
/// Reads the pressure from the sensor
/// </summary>
/// <returns>
/// Atmospheric pressure in Pa
/// </returns>
public double ReadPressure()
{
// Pressure Calculations
int B6 = CalculateTrueTemperature() - 4000;
int B62 = (B6 * B6) / 4096;
int X3 = (((short)_calibrationData.B2 * B62) + ((short)_calibrationData.AC2 * B6)) / 2048;
int B3 = ((((short)_calibrationData.AC1 * 4 + X3) << (short)Sampling.Standard) + 2) / 4;
int X1 = ((short)_calibrationData.AC3 * B6 ) / 8192;
int X2 = ((short)_calibrationData.B1 * B62) / 65536;
X3 = ((X1 + X2) + 2) / 4;
int B4 = _calibrationData.AC4 * (X3 + 32768) / 32768;
uint B7 = (uint)(ReadRawPressure() - B3) * (uint)(50000 >> (short)Sampling.Standard);
int p = (B7 < 0x80000000) ? (int)((B7 * 2) / B4) : (int)((B7 / B4) * 2);
X1 = (((p * p) / 65536 ) * 3038) / 65536;
return p + ( ((((p * p) / 65536 ) * 3038) / 65536) + ((-7357 * p) / 65536) + 3791) / 8;
}
/// <summary>
/// Calculates the altitude in meters from the specified sea-level pressure(in hPa).
/// </summary>
/// <param name="seaLevelPressure">
/// Sea-level pressure in hPa
/// </param>
/// <returns>
/// Height in meters from the sensor
/// </returns>
public double ReadAltitude(double seaLevelPressure = 101325.0)
{
return 44330.0 * (1.0 - Math.Pow(((double)ReadPressure() / seaLevelPressure), (1.0 / 5.255)));
}
/// <summary>
/// Calculates the pressure at sealevel when given a known altitude in meter
/// </summary>
/// <param name="altitude" >
/// altitude in meters
/// </param>
/// <returns>
/// Pressure in Pascals
/// </returns>
public double ReadSeaLevelPressure(double altitude = 0.0)
{
return (double)ReadPressure() / Math.Pow((1.0 - (altitude / 44333.0)), 5.255);
}
/// <summary>
/// Calculate true temperature
/// </summary>
/// <returns>
/// Coefficient B5
/// </returns>
private int CalculateTrueTemperature()
{
// Calculations below are taken straight from section 3.5 of the datasheet.
int X1 = (ReadRawTemperature() - _calibrationData.AC6) * _calibrationData.AC5 / 32768;
int X2 = _calibrationData.MC * (2048) / (X1 + _calibrationData.MD);
return X1 + X2;
}
/// <summary>
/// Reads raw temperatue from the sensor
/// </summary>
/// <returns>
/// Raw temperature
/// </returns>
private short ReadRawTemperature()
{
// Reads the raw (uncompensated) temperature from the sensor
Span<byte> command = stackalloc byte[] { (byte)Register.CONTROL, (byte)Register.READTEMPCMD };
_i2cDevice.Write(command);
// Wait 5ms, taken straight from section 3.3 of the datasheet.
Thread.Sleep(5);
return (short)Read16BitsFromRegisterBE((byte)Register.TEMPDATA);
}
/// <summary>
/// Reads raw pressure from the sensor
/// Taken from datasheet, Section 3.3.1
/// Standard - 8ms
/// UltraLowPower - 5ms
/// HighResolution - 14ms
/// UltraHighResolution - 26ms
/// </summary>
/// <returns>
/// Raw pressure
/// </returns>
private int ReadRawPressure()
{
// Reads the raw (uncompensated) pressure level from the sensor.
_i2cDevice.Write(new[] { (byte)Register.CONTROL, (byte)(Register.READPRESSURECMD + ((byte)Sampling.Standard << 6))});
if (_mode.Equals(Sampling.UltraLowPower))
{
Thread.Sleep(5);
}
else if (_mode.Equals(Sampling.HighResolution))
{
Thread.Sleep(14);
}
else if (_mode.Equals(Sampling.UltraHighResolution))
{
Thread.Sleep(26);
}
else
{
Thread.Sleep(8);
}
int msb = Read8BitsFromRegister((byte)Register.PRESSUREDATA);
int lsb = Read8BitsFromRegister((byte)Register.PRESSUREDATA + 1);
int xlsb = Read8BitsFromRegister((byte)Register.PRESSUREDATA + 2);
return ((msb << 16) + (lsb << 8) + xlsb) >> (8 - (byte)Sampling.Standard);
}
/// <summary>
/// Reads an 8 bit value from a register
/// </summary>
/// <param name="register">
/// Register to read from
/// </param>
/// <returns>
/// Value from register
/// </returns>
internal byte Read8BitsFromRegister(byte register)
{
_i2cDevice.WriteByte(register);
byte value = _i2cDevice.ReadByte();
return value;
}
/// <summary>
/// Reads a 16 bit value over I2C
/// </summary>
/// <param name="register">
/// Register to read from
/// </param>
/// <returns>
/// Value from register
/// </returns>
internal ushort Read16BitsFromRegister(byte register)
{
Span<byte> bytes = stackalloc byte[2];
_i2cDevice.WriteByte(register);
_i2cDevice.Read(bytes);
return BinaryPrimitives.ReadUInt16LittleEndian(bytes);
}
/// <summary>
/// Reads a 16 bit value over I2C
/// </summary>
/// <param name="register">
/// Register to read from
/// </param>
/// <returns>
/// Value (BigEndian) from register
/// </returns>
internal ushort Read16BitsFromRegisterBE(byte register)
{
Span<byte> bytes = stackalloc byte[2];
_i2cDevice.WriteByte(register);
_i2cDevice.Read(bytes);
return BinaryPrimitives.ReadUInt16BigEndian(bytes);
}
public void Dispose()
{
_i2cDevice?.Dispose();
_i2cDevice = null;
}
}
}
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<EnableDefaultItems>false</EnableDefaultItems>
</PropertyGroup>
<ItemGroup>
<Compile Include="Bmp180.cs" />
<Compile Include="CalibrationData.cs" />
<Compile Include="Register.cs" />
<Compile Include="Sampling.cs" />
<PackageReference Include="System.Device.Gpio" Version="$(SystemDeviceGpioPackageVersion)" />
<ProjectReference Include="..\Units\Units.csproj" />
<None Include="README.md"/>
</ItemGroup>
</Project>
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace Iot.Device.Bmp180
{
internal class CalibrationData
{
public short AC1 { get; set; }
public short AC2 { get; set; }
public short AC3 { get; set; }
public ushort AC4 { get; set; }
public ushort AC5 { get; set; }
public ushort AC6 { get; set; }
public short B1 { get; set; }
public short B2 { get; set; }
public short MB { get; set; }
public short MC { get; set; }
public short MD { get; set; }
internal void ReadFromDevice(Bmp180 bmp180)
{
AC1 = (short)bmp180.Read16BitsFromRegisterBE((byte)Register.AC1);
AC2 = (short)bmp180.Read16BitsFromRegisterBE((byte)Register.AC2);
AC3 = (short)bmp180.Read16BitsFromRegisterBE((byte)Register.AC3);
AC4 = bmp180.Read16BitsFromRegisterBE((byte)Register.AC4);
AC5 = bmp180.Read16BitsFromRegisterBE((byte)Register.AC5);
AC6 = bmp180.Read16BitsFromRegisterBE((byte)Register.AC6);
B1 = (short)bmp180.Read16BitsFromRegisterBE((byte)Register.B1);
B2 = (short)bmp180.Read16BitsFromRegisterBE((byte)Register.B2);
MB = (short)bmp180.Read16BitsFromRegisterBE((byte)Register.MB);
MC = (short)bmp180.Read16BitsFromRegisterBE((byte)Register.MC);
MD = (short)bmp180.Read16BitsFromRegisterBE((byte)Register.MD);
}
}
}
# Using BMP180
BMP180 is a device that read barometic pressure, altitude and temperature. I2C can be used to communicate with the device.
[Datasheet](https://cdn-shop.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf) for the BMP180.
An example on how to use this device binding is available in the [samples](samples) folder.
The following fritzing diagram illustrates one way to wire up the BMP180 with a Raspberry Pi using I2C.
![Raspberry Pi Breadboard diagram](samples/rpi-bmp180_i2c_bb.png)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace Iot.Device.Bmp180
{
internal enum Register : byte
{
AC1 = 0xAA,
AC2 = 0xAC,
AC3 = 0xAE,
AC4 = 0xB0,
AC5 = 0xB2,
AC6 = 0xB4,
B1 = 0xB6,
B2 = 0xB8,
MB = 0xBA,
MC = 0xBC,
MD = 0xBE,
CONTROL = 0xF4,
READTEMPCMD = 0x2E,
READPRESSURECMD = 0x34,
TEMPDATA = 0xF6,
PRESSUREDATA = 0xF6,
}
}
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace Iot.Device.Bmp180
{
public enum Sampling : byte
{
/// <summary>
/// Skipped (output set to 0x80000)
/// </summary>
UltraLowPower = 0b000,
/// <summary>
/// oversampling x1
/// </summary>
Standard = 0b001,
/// <summary>
/// oversampling x2
/// </summary>
HighResolution = 0b010,
/// <summary>
/// oversampling x4
/// </summary>
UltraHighResolution = 0b011,
}
}
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Device.I2c;
using System.Device.I2c.Drivers;
using System.Threading;
using Iot.Device.Bmp180;
using Iot.Units;
namespace Iot.Device.Bmp180.Samples
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello Bmp180!");
//bus id on the raspberry pi 3
const int busId = 1;
var i2cSettings = new I2cConnectionSettings(busId, Bmp180.DefaultI2cAddress);
var i2cDevice = new UnixI2cDevice(i2cSettings);
var i2cBmp280 = new Bmp180(i2cDevice);
using (i2cBmp280)
{
//set samplings
i2cBmp280.SetSampling(Sampling.Standard);
//read values
Temperature tempValue = i2cBmp280.ReadTemperature();
Console.WriteLine($"Temperature {tempValue.Celsius} °C");
double preValue = i2cBmp280.ReadPressure();
Console.WriteLine($"Pressure {preValue} Pa");
double altValue = i2cBmp280.ReadAltitude();
Console.WriteLine($"Altitude {altValue:0.##} m");
Thread.Sleep(1000);
//set higher sampling
i2cBmp280.SetSampling(Sampling.UltraLowPower);
//read values
tempValue = i2cBmp280.ReadTemperature();
Console.WriteLine($"Temperature {tempValue.Celsius} °C");
preValue = i2cBmp280.ReadPressure();
Console.WriteLine($"Pressure {preValue} Pa");
altValue = i2cBmp280.ReadAltitude();
Console.WriteLine($"Altitude {altValue:0.##} m");
}
}
}
}
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<None Remove="rpi-bmp180_i2c.fzz" />
<None Remove="rpi-bmp180_i2c_bb.png" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Bmp180.csproj" />
</ItemGroup>
</Project>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册