Nas minhas brincadeiras com I2C no Raspberry eu tenho usado principalmente Python e a biblioteca smbus. SMbus não é a mesma coisa que I2C, mas até agora tinha dado para ignorar isto. O que pega aqui não são as diferenças elétricas (afinal, o hardware do Raspberry é I2C), mas a forma como o SMBus modela os dispositivos ligados.
Se olharmos as funções da biblioteca, vamos ver que quase todas tem um parâmetro cmd. Considerando apenas as funções de leitura, a biblioteca assume que deve ser feita uma escrita de um comando (ou número de registrador) e logo em seguida a leitura da resposta. A única leitura disponível sem informar um comando é a leitura de um byte.
No HDC1080 uma escrita de 0 ou 1 (que corresponde a selecionar o registrador de temperatura ou umidade) dispara uma amostragem dos sensores. Depois disso é preciso aguardar a amostragem completar e aí ler os bytes do resultado (2 ou 4, dependendo da configuração). Portanto não tem como fazer isto com as funções disponíveis na biblioteca.
O jeito é baixar o nível. Após da uma estudada em uma implementação alternativa da biblioteca e a documentação do kernel, sem achar uma saída, encontrei um biblioteca específica para o HDC1000, que me mostrou o segredo. Uma vez definido (via ioctl) o endereço do escravo, as funções read() e write() do objeto obtido por io.open fazem a leitura e escrita "bruta" do I2C. Descoberto isto, não foi muito difícil fazer um programa de teste:
import struct, array, time, io, fcntl
# Classe para simplificar o acesso ao I2C
class i2c_device:
# construtor
def __init__(self, addr):
# salva o endereco
self.addr = addr
# seleciona o i2c conforme a versao do Raspberry Pi
self.revision = ([l[12:-1] for l in open('/proc/cpuinfo','r').readlines() if l[:8]=="Revision"]+['0000'])[0]
self.busNumber = 1 if int(self.revision, 16) >= 4 else 0
# inicia o acesso ao i2c
self.fd = None
self.open(self.busNumber)
# escreve de valor de 16 bits (sem sinal) em um registrador
def writeReg(self, reg, val):
data = [ reg, val >> 8, val & 0xFF ]
buf = bytearray(data)
self.fd.write(buf)
# leitura de valor de 16 bits (sem sinal) de um registrador
def readReg(self, reg):
data = [ reg ]
buf = bytearray(data)
self.fd.write(buf)
time.sleep(0.0625)
data = self.fd.read(2)
buf = array.array('B', data)
ret = (buf[0] << 8) | buf[1]
return ret
# dispara leitura de temperatura ou umidade
def access(self, reg):
data = [ reg ]
buf = bytearray(data)
self.fd.write(buf)
# pega o resultado de uma leitura
def readResult(self):
data = self.fd.read(2)
buf = array.array('B', data)
ret = (buf[0] << 8) | buf[1]
return ret
def open(self, bus):
self.fd = io.open("/dev/i2c-{}".format(bus), "r+b", buffering=0)
I2C_SLAVE = 0x0703
fcntl.ioctl(self.fd, I2C_SLAVE, self.addr)
def close(self):
if self.fd:
self.fd.close()
self.fd = None
# Classe para acesso ao HDC1080
class HDC1080(object):
# construtor
def __init__(self, addr=0x40):
# Constantes
self.REG_TEMP = 0
self.REG_UMID = 1
self.REG_CONF = 2
self.CONFIG = 0 # ler separado temp/umid, resolucao alta
# Guarda o endereco
self.addr = addr
# Iniciacao para uso com with
def __enter__(self):
self.init()
return self
# limpeza para uso com with
def __exit__(self, exc_type, exc_val, exc_tb):
self.device.close()
# iniciacao
def init(self):
# Inicia device
self.device = i2c_device(self.addr)
# espera acabar reset
while((self.device.readReg(self.REG_CONF) & 0x8000) != 0):
time.sleep(0.1)
# ler separado temperatura e umidade
self.device.writeReg(self.REG_CONF, self.CONFIG)
# le a temperatura
def readTemp(self):
# dispara a leitura
self.device.access(self.REG_TEMP)
# aguarda
time.sleep(0.05)
# le o resultado
val = self.device.readResult()
val = ((val * 1650) >> 16) - 400
return val / 10.0
# le a umidade
def readUmid(self):
# dispara a leitura
self.device.access(self.REG_UMID)
# aguarda
time.sleep(0.05)
# le o resultado
val = self.device.readResult()
return (val * 100) >> 16
# Teste simples
if __name__ == "__main__":
try:
with HDC1080() as sensor:
while(True):
print sensor.readTemp(), sensor.readUmid()
time.sleep(10)
except KeyboardInterrupt:
exit(1)

Nenhum comentário:
Postar um comentário