Class: Denko::Sensor::BMP180
- Inherits:
-
Object
- Object
- Denko::Sensor::BMP180
- Includes:
- Behaviors::Lifecycle, Behaviors::Poller, I2C::Peripheral, PressureHelper, TemperatureHelper
- Defined in:
- lib/denko/sensor/bmp180.rb
Constant Summary collapse
- I2C_ADDRESS =
0x77- SOFT_RESET =
Write this to register 0xE0 for soft reset
0xB6
- OVERSAMPLE_FACTORS =
Pressure Oversample Setting Values
General formula:
2 ** n, where n is the decimal value of the bits, up to 8x pressure oversampling. { 1 => 0b00, 2 => 0b01, 4 => 0b10, 8 => 0b11, }
Constants included from Behaviors::Lifecycle
Behaviors::Lifecycle::CALLBACK_METHODS
Constants included from Behaviors::Reader
Behaviors::Reader::READ_WAIT_TIME
Constants included from I2C::Peripheral
I2C::Peripheral::I2C_FREQUENCY, I2C::Peripheral::I2C_REPEATED_START
Instance Attribute Summary collapse
-
#calibration_data_loaded ⇒ Object
readonly
Calibration Methods.
-
#measurement_time ⇒ Object
readonly
Returns the value of attribute measurement_time.
Attributes included from Behaviors::Threaded
Attributes included from I2C::Peripheral
#i2c_frequency, #i2c_repeated_start
Attributes included from Behaviors::Component
Instance Method Summary collapse
- #_read ⇒ Object
- #_read_pressure ⇒ Object
-
#_read_temperature ⇒ Object
Reading Methods.
- #decode_pressure(bytes, b5) ⇒ Object
-
#decode_reading(bytes) ⇒ Object
Decoding Methods.
- #decode_temperature(bytes) ⇒ Object
- #get_calibration_data ⇒ Object
- #pre_callback_filter(data) ⇒ Object
- #pressure_samples=(factor) ⇒ Object
- #process_calibration(bytes) ⇒ Object
-
#read(*args, **kwargs, &block) ⇒ Object
Workaround for :read callbacks getting automatically removed on first reading.
- #reading ⇒ Object
-
#soft_reset ⇒ Object
Configuration Methods.
- #state ⇒ Object
- #update_measurement_time ⇒ Object
- #update_state(reading) ⇒ Object
- #write_settings ⇒ Object
Methods included from PressureHelper
#pressure, #pressure_atm, #pressure_bar
Methods included from TemperatureHelper
#temperature, #temperature_f, #temperature_k
Methods included from Behaviors::Lifecycle
Methods included from Behaviors::Poller
Methods included from Behaviors::Threaded
#enable_interrupts, included, #mruby_thread_check, #stop, #stop_thread, #threaded, #threaded_loop
Methods included from Behaviors::Reader
#read_busy?, #read_nb, #read_raw, #read_using, #update
Methods included from Behaviors::Callbacks
#add_callback, #callbacks, #remove_callback, #update
Methods included from I2C::Peripheral
#address, #i2c_default, #i2c_read, #i2c_read_raw, #i2c_write
Methods included from Behaviors::BusPeripheralAddressed
Methods included from Behaviors::BusPeripheral
Methods included from Behaviors::Component
Instance Attribute Details
#calibration_data_loaded ⇒ Object (readonly)
Calibration Methods
194 195 196 |
# File 'lib/denko/sensor/bmp180.rb', line 194 def calibration_data_loaded @calibration_data_loaded end |
#measurement_time ⇒ Object (readonly)
Returns the value of attribute measurement_time.
55 56 57 |
# File 'lib/denko/sensor/bmp180.rb', line 55 def measurement_time @measurement_time end |
Instance Method Details
#_read ⇒ Object
105 106 107 108 109 110 |
# File 'lib/denko/sensor/bmp180.rb', line 105 def _read get_calibration_data unless calibration_data_loaded _read_temperature _read_pressure end |
#_read_pressure ⇒ Object
90 91 92 93 94 95 |
# File 'lib/denko/sensor/bmp180.rb', line 90 def _read_pressure @register = 0x34 | (@oss << 6) write_settings sleep(@measurement_time) i2c_read(3, register: 0xF6) end |
#_read_temperature ⇒ Object
Reading Methods
83 84 85 86 87 88 |
# File 'lib/denko/sensor/bmp180.rb', line 83 def _read_temperature @register = 0x2E write_settings sleep(@measurement_time) i2c_read(2, register: 0xF6) end |
#decode_pressure(bytes, b5) ⇒ Object
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 |
# File 'lib/denko/sensor/bmp180.rb', line 164 def decode_pressure(bytes, b5) # Pressure is bytes [2..3], MSB first. up = ((bytes[2] << 16) | (bytes[3] << 8) | (bytes[4])) >> (8 - @oss) # Calibration compensation from datasheet b6 = b5 - 4000 x1 = (@calibration[:b2] * (b6 * b6 / 4096)) / 2048 x2 = @calibration[:ac2] * b6 / 2048 x3 = x1 + x2 b3 = (((@calibration[:ac1]*4 + x3) << @oss) + 2) / 4 x1 = @calibration[:ac3] * b6 / 8192 x2 = (@calibration[:b1] * (b6 * b6 / 4096)) / 65536 x3 = (x1 + x2 + 2) / 4 b4 = (@calibration[:ac4] * ((x3+32768) & 0xFFFF_FFFF)) / 32768 b7 = ((up & 0xFFFF_FFFF) - b3) * (50000 >> @oss) if (b7 < 0x8000_0000) p = (b7 * 2) / b4 else p = (b7 / b4) * 2 end x1 = (p / 256) * (p / 256) x1 = (x1 * 3038) / 65536 x2 = (-7357 * p) / 65536 p = p + (x1 + x2 + 3791) / 16 pressure = p.to_f end |
#decode_reading(bytes) ⇒ Object
Decoding Methods
140 141 142 143 144 145 |
# File 'lib/denko/sensor/bmp180.rb', line 140 def decode_reading(bytes) temperature, b5 = decode_temperature(bytes) reading[:temperature] = temperature reading[:pressure] = decode_pressure(bytes, b5) reading end |
#decode_temperature(bytes) ⇒ Object
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 |
# File 'lib/denko/sensor/bmp180.rb', line 147 def decode_temperature(bytes) # Temperature is bytes [0..2], MSB first. ut = bytes[0] << 8 | bytes[1] # Calibration compensation from datasheet x1 = (ut - @calibration[:ac6]) * @calibration[:ac5] / 32768 x2 = (@calibration[:mc] * 2048) / (x1 + @calibration[:md]) b5 = x1 + x2 # 160 instead of 16 since datasheet calculates to 0.1 C units. # Float to force the final value into float, but keep b5 integer for pressure. temperature = (b5 + 8) / 160.0 # Return temperature and b5 for pressure calculation. [temperature, b5] end |
#get_calibration_data ⇒ Object
196 197 198 199 |
# File 'lib/denko/sensor/bmp180.rb', line 196 def get_calibration_data bytes = i2c_read_raw(22, register: 0xAA) process_calibration(bytes) if bytes end |
#pre_callback_filter(data) ⇒ Object
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/denko/sensor/bmp180.rb', line 112 def pre_callback_filter(data) # Temperature is 2 bytes. if data.length == 2 @raw_bytes[0] = data[0] @raw_bytes[1] = data[1] # Pressure is 3 bytes and triggers callbacks. elsif data.length == 3 @raw_bytes[2] = data[0] @raw_bytes[3] = data[1] @raw_bytes[4] = data[2] return decode_reading(@raw_bytes) end # Anything other than pressure avoids callbacks. return nil end |
#pressure_samples=(factor) ⇒ Object
70 71 72 73 |
# File 'lib/denko/sensor/bmp180.rb', line 70 def pressure_samples=(factor) raise ArgumentError, "invalid oversampling factor: #{factor}" unless OVERSAMPLE_FACTORS.keys.include? factor @oss = OVERSAMPLE_FACTORS[factor] end |
#process_calibration(bytes) ⇒ Object
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 |
# File 'lib/denko/sensor/bmp180.rb', line 201 def process_calibration(bytes) if bytes @calibration = { ac1: bytes[0..1].pack('C*').unpack('s>')[0], ac2: bytes[2..3].pack('C*').unpack('s>')[0], ac3: bytes[4..5].pack('C*').unpack('s>')[0], ac4: bytes[6..7].pack('C*').unpack('S>')[0], ac5: bytes[8..9].pack('C*').unpack('S>')[0], ac6: bytes[10..11].pack('C*').unpack('S>')[0], b1: bytes[12..13].pack('C*').unpack('s>')[0], b2: bytes[14..15].pack('C*').unpack('s>')[0], mb: bytes[16..17].pack('C*').unpack('s>')[0], mc: bytes[18..19].pack('C*').unpack('s>')[0], md: bytes[20..21].pack('C*').unpack('s>')[0], } @calibration_data_loaded = true end end |
#read(*args, **kwargs, &block) ⇒ Object
Workaround for :read callbacks getting automatically removed on first reading.
98 99 100 101 102 103 |
# File 'lib/denko/sensor/bmp180.rb', line 98 def read(*args, **kwargs, &block) get_calibration_data unless calibration_data_loaded read_using(self.method(:_read_temperature), *args, **kwargs) read_using(self.method(:_read_pressure), *args, **kwargs, &block) end |
#reading ⇒ Object
44 45 46 |
# File 'lib/denko/sensor/bmp180.rb', line 44 def reading @reading ||= { temperature: nil, pressure: nil } end |
#soft_reset ⇒ Object
Configuration Methods
51 52 53 |
# File 'lib/denko/sensor/bmp180.rb', line 51 def soft_reset i2c_write(SOFT_RESET) end |
#state ⇒ Object
40 41 42 |
# File 'lib/denko/sensor/bmp180.rb', line 40 def state @state ||= { temperature: nil, pressure: nil } end |
#update_measurement_time ⇒ Object
57 58 59 60 61 62 63 64 65 66 67 68 |
# File 'lib/denko/sensor/bmp180.rb', line 57 def update_measurement_time # Get oversample bits from current register setting. oversample_exponent = (@register & 0b11000000) >> 6 # Calculate time in milliseconds. extra_samples = (2 ** oversample_exponent) - 1 extra_time = extra_samples * 3 total_time = 4.5 + extra_time # Sleep 1ms extra for safety and convert it to seconds. @measurement_time = (total_time + 1) / 1000.0 end |
#update_state(reading) ⇒ Object
129 130 131 132 133 134 135 |
# File 'lib/denko/sensor/bmp180.rb', line 129 def update_state(reading) @state_mutex.lock @state[:temperature] = reading[:temperature] @state[:pressure] = reading[:pressure] @state_mutex.unlock @state end |
#write_settings ⇒ Object
75 76 77 78 |
# File 'lib/denko/sensor/bmp180.rb', line 75 def write_settings update_measurement_time i2c_write [0xF4, @register] end |