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