Manual

do

Maker

.

com

Barômetro BMP180 com Raspberry

Barômetro BMP180 com Raspberry

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ê:

formula.webp

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 datasheetBST-BMP180-DS000-09.pdf.

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.

Inscreva-se no nosso canal Manual do Maker Brasil no YouTube.

Próximo post a caminho!

Nome do Autor

Djames Suhanko

Autor do blog "Do bit Ao Byte / Manual do Maker".

Viciado em embarcados desde 2006.
LinuxUser 158.760, desde 1997.