Não vou repetir aqui tudo o que já falei em posts anteriores sobre I2C, o único ponto a destacar é que o endereço é 0x77 (acrescentando a indicação de leitura ou escrita obtemos 0xEF e 0xEE) e o clock pode ser de até 3,4MHz.
O sensor em si opera com tensão até 3.6V, mas o módulo possui um regulador para poder alimentar com 5V. Além dos tradicionais VCC, SDA, SCL e GND, o módulo tem os sinais XCLR e EOC. XCLR resseta o sensor quando em nível baixo; este sinal pode ser deixado desconectado. O pino EOC indica foi concluída uma conversão, também não vamos usá-lo.
O sensor mede tanto temperatura como pressão. Existem quatro opções de resolução, uma resolução maior requer mais leituras e leva mais tempo. Os valores lidos precisam ser corrigidos usando uma calibração que é gravada (na fábrica) no próprio sensor. A partir da pressão corrigida é possível calcular a altitude. Para dar uma ideia de precisão, a pressão obtida no modo "ultra high resolution" permite calcular (segundo o fabricante) a altitude com um erro de 25cm. Os registradores e fórmulas envolvidos podem ser vistos no datasheet. A Adafruit disponibiliza uma biblioteca para o Arduino no github.
No meu teste usei o Raspberry Pi. Os meus posts anteriores falam sobre como preparar o Rasp Pi para uso do I2C. O programa abaixo é uma adaptação da biblioteca da Adafruit para o Arduino, que eu fiz como exercício de programação Python (ou seja, não esperem alta qualidade no código). A Adafruit tinha uma biblioteca para o Rasp Pi, que foi suplantada por uma biblioteca para Rasp Pi e Beaglebone Black.
# Exemplo de uso do sensor barometrico BMP085 no Raspberry Pi # Baseado no codigo da Adafruit para Arduino # # autor: Daniel Quadros import smbus from time import sleep # Seleciona o i2c conforme a versao do Raspberry Pi revision = ([l[12:-1] for l in open('/proc/cpuinfo','r').readlines() if l[:8]=="Revision"]+['0000'])[0] bus = smbus.SMBus(1 if int(revision, 16) >= 4 else 0) # Constantes para uso do BMP085 BMP085_ULTRALOWPOWER = 0 BMP085_STANDARD = 1 BMP085_HIGHRES = 2 BMP085_ULTRAHIGHRES = 3 BMP085_CAL_AC1 = 0xAA # R Calibration data (16 bits) BMP085_CAL_AC2 = 0xAC # R Calibration data (16 bits) BMP085_CAL_AC3 = 0xAE # R Calibration data (16 bits) BMP085_CAL_AC4 = 0xB0 # R Calibration data (16 bits) BMP085_CAL_AC5 = 0xB2 # R Calibration data (16 bits) BMP085_CAL_AC6 = 0xB4 # R Calibration data (16 bits) BMP085_CAL_B1 = 0xB6 # R Calibration data (16 bits) BMP085_CAL_B2 = 0xB8 # R Calibration data (16 bits) BMP085_CAL_MB = 0xBA # R Calibration data (16 bits) BMP085_CAL_MC = 0xBC # R Calibration data (16 bits) BMP085_CAL_MD = 0xBE # R Calibration data (16 bits) BMP085_CONTROL = 0xF4 BMP085_TEMPDATA = 0xF6 BMP085_PRESSUREDATA = 0xF6 BMP085_READTEMPCMD = 0x2E BMP085_READPRESSURECMD = 0x34 class BMP085: # Endereco I2C address = None # Modo de operacao oversampling = None # Calibracao ac1 = None ac2 = None ac3 = None ac4 = None ac5 = None ac6 = None b1 = None b2 = None mb = None mc = None md = None # construtor def __init__(self, modo = BMP085_ULTRAHIGHRES, address = 0x77): self.address = address self.oversampling = modo # Le a calibracao self.ac1 = self.readS16(BMP085_CAL_AC1) self.ac2 = self.readS16(BMP085_CAL_AC2) self.ac3 = self.readS16(BMP085_CAL_AC3) self.ac4 = self.readU16(BMP085_CAL_AC4) self.ac5 = self.readU16(BMP085_CAL_AC5) self.ac6 = self.readU16(BMP085_CAL_AC6) self.b1 = self.readS16(BMP085_CAL_B1) self.b2 = self.readS16(BMP085_CAL_B2) self.mb = self.readS16(BMP085_CAL_MB) self.mc = self.readS16(BMP085_CAL_MC) self.md = self.readS16(BMP085_CAL_MD) # leitura da altitude def leAltitude(self, sealevelPressure = 101325.0): pressure = self.lePressao() return 44330.0 * (1.0 - pow(pressure/sealevelPressure, 0.1903)) # leitura da pressao barometrica # formulas extraidas do datasheet def lePressao(self): UT = self.readRawTemperature() UP = self.readRawPressure() B5 = self.computeB5(UT) B6 = B5 - 4000 X1 = (self.b2 * ((B6 * B6) >> 12)) >> 11 X2 = (self.ac2 * B6) >> 11 X3 = X1 + X2 B3 = (((self.ac1*4 + X3) << self.oversampling) + 2) / 4 X1 = (self.ac3 * B6) >> 13 X2 = (self.b1 * ((B6 * B6) >> 12)) >> 16 X3 = ((X1 + X2) + 2) >> 2 B4 = (self.ac4 * (X3 + 32768)) >> 15 B7 = (UP - B3) * (50000 >> self.oversampling) if B7 < 0x80000000: p = (B7 * 2) / B4 else: p = (B7 / B4) * 2 X1 = (p >> 8) * (p >> 8) X1 = (X1 * 3038) >> 16 X2 = (-7357 * p) >> 16 p = p + ((X1 + X2 + 3791) >> 4) return p # leitura da pressao barometrica "bruta" def readRawPressure(self): bus.write_byte_data(self.address, BMP085_CONTROL, BMP085_READPRESSURECMD + (self.oversampling << 6)) if self.oversampling == BMP085_ULTRALOWPOWER: sleep(0.005) elif self.oversampling == BMP085_STANDARD: sleep(0.008) elif self.oversampling == BMP085_HIGHRES: sleep(0.014) else: sleep(0.026) raw = self.readU16(BMP085_PRESSUREDATA) raw = raw << 8 raw = raw | self.read8(BMP085_PRESSUREDATA+2) raw = raw >> (8 - self.oversampling) return raw # leitura da temperatura def leTemperatura(self): UT = self.readRawTemperature() B5 = self.computeB5(UT) return ((B5+8) >> 4) / 10.0 # leitura da temperatura "bruta" def readRawTemperature(self): bus.write_byte_data(self.address, BMP085_CONTROL, BMP085_READTEMPCMD) sleep(0.005) return self.readU16(BMP085_TEMPDATA) # calcula B5 (temperatura corrigida) # formulas extraidas do datasheet def computeB5 (self, UT): X1 = ((UT - self.ac6) * self.ac5) >> 15 X2 = (self.mc << 11) / (X1 + self.md) return X1 + X2 # leitura de valor de 16 bits (sem sinal) def readU16(self, reg): bytes = bus.read_i2c_block_data(self.address, reg, 2) ret = (bytes[0] << 8) | bytes[1] #print "Read (%d) = %d %d = %d" % (reg, bytes[0], bytes[1], ret) return ret # leitura de valor de 16 bits (com sinal) def readS16(self, reg): bytes = bus.read_i2c_block_data(self.address, reg, 2) ret = (bytes[0] << 8) | bytes[1] if bytes[0] > 127: ret = ret - 65536 #print "Read (%d) = %d %d = %d" % (reg, bytes[0], bytes[1], ret) return ret # leitura de valor de 8 bits def read8(self, reg): return bus.read_byte_data(self.address, reg) if __name__ == "__main__": # Teste simples se executado diretamente sensor = BMP085() temp = sensor.leTemperatura() print "Temperatura = %.1f C" % temp pressao = sensor.lePressao() print "Pressao = %d hPa" % pressao alt = sensor.leAltitude() print "Altitude = %.3f m" % alt
Abaixo o resultado do i2cdetect e um exemplo de saída do programa
Nenhum comentário:
Postar um comentário