Table of Contents
Barômetro BMP180 com Raspberry
BMP180 com Raspberry? Poderia ser apenas mais um artigo após uma longa temporada de sofrimento solitário em busca de um sorriso regado à lágrimas, mas dessa vez tenho o prazer, a honra, o orgulho e o puxa-saquismo de anunciar o primeiro post com ajuda direta do meu chefe, Denis Orsi. Não foi ajuda do tipo “formatar o texto”; foi bem do tipo “formatar a fórmula”, sem hipérboles e não-figurativo. Explico no decorrer desse artigo.
Já há algum tempo eu chocava alguns desses barômetros por serem fantásticos; uma miniatura dessa com capacidade de medir a pressão atmosférica e altitude, além de medir com muita precisão a temperatura. Nesse artigo disponho do código Python utilizado no ato do desenvolvimento. “No ato do desenvolvimento” é um sinônimo explícito de “rascunho”, primo da discrepância e passivo de incoerências.
Se alguém (ainda que uma pessoa só) pedir para organizar em uma classe, eu escrevo e disponibilizo com prazer, mas por ora é apenas isso.
Leia sempre o datasheet
Como diria o Steeve (amigo do Osmar – a primeira fatia do pão de forma):
“Existem dois tipos de pessoas; as que lêem o datasheet e as que não gostam de patinhas de sirí”.
Eu quase sempre lia o datasheet em busca de alguma informação extra, mas desde que comecei a trabalhar com o Denis, a primeira coisa que faço é ler o datasheet. Não adianta pegar material pronto como por exemplo, uma biblioteca; inseri-la, chamar seu método e não saber como um dispositivo funciona. E isso não é o pior; tem tutoriais que induzem à perdição! Vi um tutorial de um dispositivo com nível lógico de 3.3V e o cara dizendo pra chutar o pau em 5V que não tinha problema. Aí olho o datasheet e ‘pow’! O ponto de morte estava marcado como 4.5V no pino lógico. Por isso a recomendação: leia-o-datasheet!
Para o BMP180 não haveria outra opção, claro. E veja o porquê:
De forma alguma você faria esse dispositivo funcionar a contento sem ler o datasheet – exceto estivesse esperando por esse artigo, claro.
Se você achou que agora ficou fácil lendo essa fórmula, experimente implementar antes de usar o desse artigo. É o C A O S implementar isso, sério.
Se desejar verificar, os coeficientes de calibração estão na página 13 do datasheet.
A lógica (explicada de maneira porca e superficial)
Basicamente, é necessário fazer uma leitura inicial para calibrar o dispositivo. Essa leitura inicial é armazenada em diversas variáveis e devem ser utilizadas a seu tempo, depois algumas delas são modificadas, mas elas devem ser lidas na ordem que indica a fórmula para não dar muita variação no resultado final.
Existem 3 níveis de precisão para a leitura e cálculo da pressão atmosférica (em hPa) e utilizamos “hard-coded” o nível 3, que é o mais preciso.
Os delays inseridos no código não são enfeites; estão nas posições onde os tempos de delay são necessários e um pouquinho acima do tempo suficiente para o dispositivo “jogar o cabelo pro lado certo”.
Características do dispositivo
Normalmente inicio com essas informações – nunca cito todas, apenas as necessárias para uma apresentação. Claro que hoje não será diferente, exceto pelo fato da disposição da informação.
O BMP180 é um sensor digital de pressão criado pela Bosch, com níveis de medição entre 300 e 1100Pa (9000 metros à -500 metros relativo ao nível do mar). É um LGA com dimensões de 4mmX4mm (sem contar a board, obviamente), consome 5uA e trabalha entre as tensões de 1.62V à 3.6V. Ele mede temperatura, pressão e altitude, possui interface I²C e os usos ficam por conta da sua imaginação.
A temperatura tem precisão de 16bits e a pressão tem precisão de 16 à 19bits. É isso.
Já habilitou seu I²C hoje?
Pois é, não basta conectar o dispositivo ao Raspberry. Para habilitar o I²C, siga esse tutorial que escrevi como introdutório aos artigos relacionados à I²C, é fundamental que seja feito. Após isso, volte a esse ponto e dê sequência.
Não vou falar de wiring porque é uma vergonha. Leia esse artigo. Todos os dispositivos I²C são conectados assim; SDA, SCL, VCC e GND. Ponto.
Código rascunho com os prints de debug
O código está no estado mais crú (eu tiraria o acento e o ‘R’) que se pode imaginar. Está 100% funcional, mas está zoneado. Se for pra criticar, me mande 100 reais primeiro. Se for elogiar, antecipo meu muito obrigado – e creio que falo pelo Denis também nesse aspecto.
#!/usr/bin/env python from smbus import SMBus import time ADDR = 0x77 bus = SMBus(1) def invertWord(val): return ((val&0xff)<<8)+(val>>8) def toSigned(val): return val if val<0x8000 else val-0x10000 #Leitura inicial de todos os valores pertinentes def calibrate(addr): global addresses addresses = {"AC1":toSigned(invertWord(bus.read_word_data(addr, 0xAA))), "AC2":toSigned(invertWord(bus.read_word_data(addr,0xAC))), "AC3":toSigned(invertWord(bus.read_word_data(addr, 0xAE))), "AC4":toSigned(invertWord(bus.read_word_data(addr, 0xB0))), "AC5":toSigned(invertWord(bus.read_word_data(addr, 0xB2))), "AC6":toSigned(invertWord(bus.read_word_data(addr, 0xB4))), "B1":toSigned(invertWord(bus.read_word_data(addr, 0xB6))), "B2": toSigned(invertWord(bus.read_word_data(addr, 0xB8))), "MB":toSigned(invertWord(bus.read_word_data(addr, 0xBA))), "MC":toSigned(invertWord(bus.read_word_data(addr, 0xBC))), "MD":toSigned(invertWord(bus.read_word_data(addr, 0XBE)))} def getTemp(addr): #leitura discompensada da temperatura #escreve 0x2E para 0xF4 aguarda 4.5ms bus.write_byte_data(addr,0xF4,0x2E) time.sleep(0.010) #le 0xF6 (MSB) e 0xF7 (LSB) MSB = bus.read_byte_data(addr,0xF6) LSB = bus.read_byte_data(addr,0xF7) UT = (MSB << 8) + LSB #calcular temperatursa X1 = float(UT - addresses["AC6"])*addresses["AC5"]/2**15 X2 = addresses["MC"]*2**11/(X1+addresses["MD"]) B5 = X1 + X2 T = round((B5+8)/160,1) return T def getTempAndPressure(addr): # leitura discompensada da temperatura # escreve 0x2E para 0xF4 aguarda 4.5ms bus.write_byte_data(addr, 0xF4, 0x2E) time.sleep(0.010) # le 0xF6 (MSB) e 0xF7 (LSB) MSB = bus.read_byte_data(addr, 0xF6) LSB = bus.read_byte_data(addr, 0xF7) UT = (MSB << 8) + LSB #pressao bus.write_byte_data(addr,0xF4,0xF4) time.sleep(0.03) MSB = bus.read_byte_data(addr, 0xF6) LSB = bus.read_byte_data(addr, 0xF7) XLSB = bus.read_byte_data(addr, 0xF8) UP = ((MSB << 16) + (LSB <<8) + XLSB) >> (8-3) print "UP =", UP # calcular temperatura X1 = float(UT - addresses["AC6"]) * addresses["AC5"] / 2 ** 15 X2 = addresses["MC"] * 2 ** 11 / (X1 + addresses["MD"]) B5 = X1 + X2 T = round((B5 + 8) / 160,1) #calcular pressao B6 = B5-4000 X1 = (addresses["B2"]*(B6**2/2**12))/2**11 X2 = addresses["AC2"]*B6/2**11 X3 = X1+X2 B3 = ((addresses["AC1"]*4+X3)*2**3)/4 print "B5 =",B5 print "B6 =",B6 print "B2 =",addresses["B2"] print "X1 =",X1 print "AC2 =",addresses["AC2"] print "X2 =",X2 print "AC1 =",addresses["AC1"] print "B3 =",B3 X1 = addresses["AC3"]*B6/2**13 X2 = (addresses["B1"] * (B6**2/2**12))/2**18 X3 = (X1+X2)/4 B4 = addresses["AC4"]*(X3+32768)/2**15 print "AC3 =",addresses["AC3"] print "X1 =",X1 print "B1 =",addresses["B1"] print "X2 =",X2 print "X3 =",X3 print "AC4 =",addresses["AC4"] print "B4 =",B4 B7 = (UP-B3)*(50000 >> 3) P = B7/B4*2 print "B7 =",B7 print "P =",P X1 = (int(P)>>8)**2 print "X1 (primeiro) = ",X1 X1 = float(X1*3038)/2**16 X2 = (-7357*P)/2**16 #pressao em hPa (resolucao 0.01) P = round((P+(X1+X2+3791)/16)/100,2) print "x1 = ",X1 print "X2 = ",X2 print P
Basta salvar esse código em um arquivo. Se quiser experimentá-lo com bpython, siga esses passos:
import seuArquivoComEsseCodigoSemExtensao as teste teste.calibrate(0x77) teste.getTemp(0x77) teste.getTempAndPressure(0x77)
Fácil ou não? É, utilizar agora ficou fácil, mas dessa vez o trabalho foi feito a quatro mãos, e podem esperar por mais!
Aproveite para ler esse artigo sobre dicas, dúvidas e erros comuns com Raspberry.
Siga-nos no Do bit Ao Byte no Facebook.
Inscreva-se no nosso canal Do bit Ao Byte Brasil no YouTube.
Próximo post a caminho!
4 thoughts on “Barômetro BMP180 com Raspberry”