Bom dia, Habrovsk!
Breve introdução
Outro dia, tornei-me o feliz proprietário de um dos menores jogadores de placa única trabalhando no LEDE, e a primeira coisa que eu queria fazer (depois de piscar o LED) foi uma estação meteorológica doméstica, que pode ser acessada de qualquer lugar. O primeiro passo foi coletar dados de temperatura, umidade e pressão. Para isso, foram selecionados os sensores
DHT11 e
LPS3311AP adquiridos anteriormente (foto sob o corte).
Fotos para os interessados Após uma breve pesquisa, verificou-se que, se a primeira família está bem documentada e tem muitas bibliotecas para trabalhar, o barômetro que eu escolhi não é tão popular, exceto pela biblioteca auto-escrita (embora de alta qualidade) para a loja do Arduino onde o sensor foi comprado (não para publicidade, apenas uma homenagem), nada foi encontrado.
Que escolha resta?
- Colete a camada no microcontrolador ATmega328, faça flash, preencha o código final e leia a partir dele. Muito emocionante, mas parece tentar montar uma bicicleta para uso posterior como muleta.
- Leia "manualmente" com o I2C, confiando na folha de dados oficial . Tentei, é possível, mas não queria produzir scripts bash e não parecia metodologicamente correto.
- Escreva uma biblioteca para trabalhar com o sensor da maneira que desejar.
Se você está interessado em como veio e no que veio, então seja bem-vindo ao gato.
A primeira pergunta que me deparei é a escolha do idioma. Pelo que funciona neste quadro único sem dançar com um pandeiro - C ++ e Python. Como no futuro quero colocar esse projeto no coração de uma casa inteligente para mim, a escolha recaiu sobre o último.
Devido ao efeito de patinho, não levantei a próxima pergunta (qual versão) e imediatamente coloquei o python3 leve e a biblioteca para trabalhar com o barramento I2C.
Depois, houve horas de fumar, primeiro uma
folha de dados , depois um
guia de software do fabricante. Eles tornaram possível preparar rapidamente o sensor para operação (embora o guia do software tenha sido mais completo, incluindo recomendações para verificar a conclusão da medição e "redefinir" o sensor para obter uma coleta mais precisa.
A primeira dificuldade que encontrei é a leitura de dados. Como os dados do termômetro são transmitidos em dois bytes e a pressão em três, é necessário obter vários bytes e combiná-los em um número grande. Mas o python converterá hex para int por padrão, e a concatenação simples não funciona. A conversão de int em hexadecimal retorna uma sequência perfeitamente concatenada, mas não convertida novamente em um número. Saída? Seria possível conectar o suporte para c-types, mas eu não queria mexer, além de entupir a memória com uma biblioteca adicional, por isso foi decidido escrever uma função em 7 (na verdade 8, se contarmos o dicionário) linhas para traduzir a sequência de pseudo-bytes para um número.
Hex contendo string para ints_t_h = { '0' : 0, '1' : 1, '2' : 2, '3' : 3, '4' : 4, '5' : 5, '6' : 6, '7' : 7, '8' : 8, '9' : 9, 'a' : 10, 'b' : 11, 'c' : 12, 'd' : 13, 'e' : 14, 'f' : 15 } def __string_to_int(self, hex_string): l = len(hex_string) - 1 res = 0 for h in hex_string: res += s_t_h[h] * (16 ** l) l -= 1 return res
Acredito que a pergunta “por que ler no dicionário?” Pode ser feita aqui. a resposta é simples - não me ocorreu tomar decisões óbvias sobre a conversão de tipos; se os especialistas tiverem uma resposta para essa pergunta, terei o prazer de fazer alterações.
A segunda dificuldade que me intrigou é a interpretação dos dados. Ambos os documentos acima fornecem fórmulas muito simples para conversão:
Pout(mbar)=(PRESS_OUT_H & PRESS_OUT_L & PRESS_OUT_XL)[dec] / 4096
para pressão;
T(degC) = 42.5 + (Temp_OUTH & TEMP_OUT_L)[dec] / 480
para temperatura.
O que agrada, eles oferecem imediatamente um sistema métrico.
No entanto, a primeira abordagem teimosamente me deu o resultado 0x2F8000, o que significa 760 milibares ou cerca de 585 mmHg. Art. Para uma altura de 130 metros acima do nível do mar, isso claramente não é suficiente. Verificar novamente o código, reler as informações sobre a medição da pressão, reiniciar o sensor e jogar com precisão não deu nada. Mas o estudo repetido da diretriz ajudou - 760 mbar estável é interpretado como um sinal de que o sensor está com defeito. Os leitores que examinaram cuidadosamente a foto anexada no início do artigo podem garantir que o sensor, além disso, esteja em princípio ausente no chip :) Felizmente, eu rapidamente comprei duas delas ao mesmo tempo.
Foto de um chip de trabalho e operação adequada
O pequeno quadrado preto no centro é a placa de medição HCLGA-16L, o "coração" do sensor.

Após essa descoberta, ficou óbvio que uma verificação de saúde deveria ser feita. Então a função nasceu:
working_check BROKEN_MARKER = 0x2f8000/4096 def __working_check(self, address): c1 = self.__read_pressure(address) c2 = self.__read_pressure(address) c3 = self.__read_pressure(address) if c1 == c2 == c3 == BROKEN_MARKER: return True else: return False
Para evitar um caso raro, mas ainda potencialmente provável, de falsos positivos, as leituras são feitas três vezes e somente depois é emitido um veredicto de inoperabilidade. É possível usar excessivamente uma constante nesse código, mas um bom tom deve ser observado sempre que possível.
Imediatamente me ocorreu que não seria ruim durante a inicialização verificar se o endereço no barramento está correto e a função
__deviceAdressCheck foi adicionada, que verifica o registro
WHO_AM_I e
espera receber o número estimado 0xBB.
Parece que não há mais pontos interessantes sobre isso. O
código completo está disponível no github e está disponível para uso e modificação.