Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import pyftdi as F
- from pyftdi import i2c
- from ctypes import c_short
- from time import sleep
- import atexit
- ### Some utility functions
- # These both assume the second byte is the higher bits.
- # Concat two adacent bytes to a signed short
- def getShort(data, index):
- return c_short((data[index+1] << 8) + data[index]).value
- # Concat two adacent bytes to an unsigned short
- def getUShort(data, index):
- return (data[index+1] << 8) + data[index]
- ### Important register addresses
- # See the datasheet.
- # i2c adress.
- BME_ADDR = 0x76
- # Register that contains raw measurement values (ro).
- REG_DATA = 0xF7
- # Controls for oversampling and power options (rw).
- REG_CONTROL = 0xF4
- # Controls sampling rate, filter coefficients and interface (rw, but
- # writes may be ignored unless the device is in sleep mode).
- # I will be leaving this as the default settings, it's just here for reference.
- REG_CONFIG = 0xF5
- # Calibration data registers (ro)
- REG_CAL1 = 0x88
- REG_CAL2 = 0xA1 # Not used (is for the BME280)
- # Reset register, writing the value 0xB6 will trigger a soft reset.
- REG_RESET = 0xE0
- ### Calculate the values for configuration.
- # I will use forced mode, where it takes one measurement and then goes
- # to sleep. You can also put it in free-run mode, where it constantly
- # takes measurements, but forced mode is more appropriate here.
- #
- # You need to write the control register every time
- # you want a new measurement in this mode.
- OVERSAMPLE_TEMP = 2 # 2x oversampling (0b010)
- OVERSAMPLE_PRES = 2 # 2x oversampling (0b010)
- MODE = 1 # Forced mode, take one measurement then sleep (0b1)
- control = OVERSAMPLE_TEMP << 5 | OVERSAMPLE_PRES << 2 | MODE
- # 0b01000000 0b00001000 0b00000001
- # --------------------------------------------------------
- # = 0b01001001
- ### Set up i2c.
- # Same deal as the SPI example
- ctrl = i2c.I2cController()
- ctrl.configure('ftdi://ftdi:232h/1')
- atexit.register(ctrl.terminate)
- # Port here automatically prepends the i2c slave address to all transactions.
- port = ctrl.get_port(BME_ADDR)
- ### Now let's start talking to the chip!
- # Force a reset to start fresh. Device will start in sleep mode (not taking
- # measurements.
- port.write_to(REG_RESET, [0xB6])
- # Read the chip id, you can use this to distinguish between different chips
- # in the line. All the chips have the same interface, but some have more
- # sensors. E.g. the BMP280 is pressure and temperature, BME280 is the same thing
- # but also humidity. Reading pressure and temperature is exactly the same
- # between the two.
- # If you adapt this code for the BME280, you need to change the i2c address
- # and add code to also read the humidity.
- chip_id = port.read_from(0xD0, 1) # Should be 0x58 == 88 for production BMP280.
- # Set oversampling and activate forced mode.
- port.write_to(REG_CONTROL, [control])
- ### Read values and do the conversion
- # The following procedure just comes from the datasheet, we're just reading
- # out register values and converting them.
- # Read calibration. This is fixed and only needs to be done once.
- cal1 = port.read_from(REG_CAL1, 24)
- cal2 = port.read_from(REG_CAL2, 1) # Not used, will be zero
- # Convert the raw bytes to the calibration coefficients. Ditto, only
- # needs to be done once.
- dig_T1 = getUShort(cal1, 0)
- dig_T2 = getShort(cal1, 2)
- dig_T3 = getShort(cal1, 4)
- dig_P1 = getUShort(cal1, 6)
- dig_P2 = getShort(cal1, 8)
- dig_P3 = getShort(cal1, 10)
- dig_P4 = getShort(cal1, 12)
- dig_P5 = getShort(cal1, 14)
- dig_P6 = getShort(cal1, 16)
- dig_P7 = getShort(cal1, 18)
- dig_P8 = getShort(cal1, 20)
- dig_P9 = getShort(cal1, 22)
- # Sleep long enough for a measurement to complete. You can calculate
- # the minimum wait time using a formula in the datasheet or you can also
- # look at the status register if you want. Here I'm just sleeping for
- # a relatively long time.
- # The actual sampling time depends on oversampling settings.
- sleep(0.100)
- # Read the raw measurement data from the device. These are in the form
- # of raw ADC readings, which must be converted using the device-specific
- # calibration and the procedure in the datasheet.
- data = port.read_from(REG_DATA, 8)
- # Cat together the bytes to get the raw integer pressure and temp readings.
- pres_raw = (data[0] << 12) | (data[1] << 4) | (data[2] >> 4)
- temp_raw = (data[3] << 12) | (data[4] << 4) | (data[5] >> 4)
- # Formulas... first calculate the temperature.
- var1 = ((((temp_raw >> 3) - (dig_T1 << 1))) * (dig_T2)) >> 11
- var2 = (((((temp_raw >> 4) - (dig_T1)) * ((temp_raw >> 4) - (dig_T1))) >> 12) * (dig_T3)) >> 14
- t_fine = var1 + var2
- temperature = float(((t_fine * 5) + 128) >> 8);
- # Now calculate some values that are used to compensate the pressure reading
- # for temperature.
- var1 = t_fine / 2.0 - 64000.0
- var2 = var1 * var1 * dig_P6 / 32768.0
- var2 = var2 + var1 * dig_P5 * 2.0
- var2 = var2 / 4.0 + dig_P4 * 65536.0
- var1 = (dig_P3 * var1 * var1 / 524288.0 + dig_P2 * var1) / 524288.0
- var1 = (1.0 + var1 / 32768.0) * dig_P1
- # Use the above values to compensate the base pressure reading for
- # temperature.
- if var1 == 0:
- pressure = 0 # An error occurred with the reading so skip this.
- else:
- pressure = 1048576.0 - pres_raw
- pressure = ((pressure - var2 / 4096.0) * 6250.0) / var1
- var1 = dig_P9 * pressure * pressure / 2147483648.0
- var2 = pressure * dig_P8 / 32768.0
- pressure = pressure + (var1 + var2 + dig_P7) / 16.0
- # Print out the readings.
- print("id: 0x{:x}".format(chip_id[0]))
- print("temp: {0:.2f}C".format(temperature / 100.0))
- print("pressure: {0:.2f}hPa".format(pressure / 100.0))
Add Comment
Please, Sign In to add comment