MicroPython – protocolo I2C em ESP8266 e ESP3

Os sensores usam protocolos mestre-escravo para interface com microcontroladores e microcomputadores. Entre muitos protocolos escravo-mestre diferentes, os protocolos I2C e SPI são os protocolos de comunicação serial comuns amplamente encontrados em dispositivos embarcados. Ambos os protocolos permitem que o microcontrolador/microcomputador assuma o papel de mestre e permita a interface de vários sensores e blocos embarcados em um barramento comum. Este tutorial discutirá a implementação do protocolo I2C no MicroPython e explorará como os sensores fazem interface com ESP8266 e ESP32 usando o barramento I2C. Saiba mais sobre o protocolo I2C antes de continuar este tutorial.

Módulo de máquina
O módulo de máquina do MicroPython é responsável por gerenciar recursos básicos de hardware das portas suportadas. O módulo inclui classes para controlar entrada/saída digital, controlar sinais de saída de dispositivos externos, modulação por largura de pulso, conversão de analógico para digital, controlar periféricos ADC, UART, SPI, I2C, I2S, temporizador, RTC, temporizador Watchdog e gerenciamento de cartão SD . Possui classe I2C para gerenciamento do barramento I2C das portas suportadas.

Classe I2C
I2C é um protocolo de dois fios. Ele usa duas linhas – uma linha de dados (SDA) e uma linha de clock (SCL). MicroPython implementa hardware I2C e software I2C. O hardware I2C utiliza o periférico I2C subjacente e o barramento de portas suportadas para comunicação serial de acordo com o protocolo I2C. Como os periféricos de hardware I2C estão vinculados a pinos específicos em uma porta, a implementação do hardware I2C poderia ser feita apenas nesses pinos específicos.

O hardware I2C é implementado na classe I2C do módulo de máquina. A classe I2C é importada em um script MicroPython usando a instrução a seguir.
da importação de máquina I2C

Após importar a classe I2C, é necessário instanciar um objeto I2C. Uma função construtora faz isso. A função construtora tem o seguinte protótipo.
classe máquina.I2C(id, *, scl, sda, freq=400000)

A função construtora pode receber quatro argumentos – id, scl, sda e freq. O id é o identificador do periférico I2C específico. Se uma porta tiver vários periféricos I2C, é importante passar o ID I2C. O id pode ser um número inteiro, string ou tupla. Isso depende da porta específica. O scl e o sda são os pinos usados ​​para o relógio I2C e os dados I2C, respectivamente. Se os pinos SCL e SDA puderem ser alterados em uma porta, esses argumentos poderão ser passados ​​para atribuir pinos aos periféricos I2C disponíveis. Se scl e sda ​​não forem passados ​​como argumentos, os pinos padrão serão atribuídos para I2C SCL e SDA respectivamente. Os pinos SDA e SCL podem ser fixados em muitas portas e não podem ser alterados. A freq define a frequência máxima para o clock I2C. A seguir estão alguns exemplos válidos do construtor I2C.

i2c = I2C(0)
i2c = I2C(1, scl=Pino(5), sda=Pino(4), freq=400000)
i2c = I2C(scl=Pino(5), sda=Pino(4), freq=100000)

A classe I2C inclui os seguintes métodos para configurar e gerenciar a comunicação de dados.

I2C.init : Este método é usado para inicializar o barramento I2C. Aplica-se a um objeto I2C, que já está instanciado com um id I2c. O método init pode receber sda, scl e freq como argumentos.

I2C.deinit : Este método desliga o barramento I2C. Está disponível apenas na porta WiPy.

I2C.scan : este método verifica todos os endereços I2C entre 0x08 e 0x77 e retorna uma lista de endereços que respondem. Este método é útil para listar dispositivos I2C conectados. Os dispositivos são reconhecidos pelos seus endereços I2C.

I2C.readfrom(addr, nbytes, stop=True): Este método lê nbytes do endereço I2C endereço. Uma condição de parada será gerada após a conclusão da operação de leitura se a parada for verdadeira. Uma chamada a este método retorna um objeto do tipo byte, que deve ser armazenado em uma variável.

I2C.readfrom_into(addr, buf, stop=True): Este método lê o buffer I2C a partir do endereço I2C endereço. O método não retorna nada, mas todos os bytes disponíveis no barramento I2C para leitura são salvos. A condição de parada é criada após a leitura no buffer se a parada for verdadeira.

I2C.writeto(addr, buf, stop=True): Este método grava bytes do buffer no endereço I2c endereço. Ele retorna o número de confirmações recebidas. Se nenhuma confirmação for recebida após o envio de um byte, os bytes restantes não serão enviados. Se parar for verdadeiro, a condição de parada é gerada após o envio dos bytes.

I2C.writevto(endereço, vetor, parada = Verdadeiro): Este método envia bytes armazenados em um vetor para o endereço I2C endereço. Um vetor é uma lista ou tupla de objetos com um protocolo de buffer. Usando este método, vários objetos podem ser enviados para um determinado endereço I2c com uma única chamada. O método retorna o número de confirmações recebidas. O método envia o endereço uma vez e, em seguida, os objetos de byte são enviados sequencialmente. Os bytes e objetos restantes não serão enviados se a confirmação não for recebida após o envio de um byte. Se parar for verdadeiro, a condição de parada é gerada após o envio do vetor.

I2C.start : Este método gera uma condição de inicialização no barramento I2C. O SDA é puxado para BAIXO na condição de partida enquanto o SCL é puxado para ALTO.

I2C.stop : Este método gera uma condição de parada no barramento I2C. O SDA é puxado para ALTO na condição de parada enquanto o SCL é puxado para BAIXO.

I2C.readinto(buf, nack=True): Este método é usado para ler bytes do barramento e armazená-los no buffer. O número de bytes lidos é igual ao tamanho do buffer. Depois que todos os bytes forem recebidos, a confirmação será enviada; caso contrário, nenhuma confirmação será enviada, desde que nack está definido como verdadeiro.

I2C.write(buf): Este método é usado para gravar bytes do buffer no barramento I2C. O método retorna o número de confirmações recebidas. É igual ao número de bytes gravados no barramento com sucesso. Após o envio de cada byte, a confirmação é recebida. Se nenhuma confirmação for recebida, os bytes restantes não serão gravados.

I2C.readfrom_mem(addr, memaddr, nbytes, *, addrsize=8): Este método é usado para ler bytes do endereço I2C endereço começando pelo endereço de memória memadr. O tamanho do endereço especifica o tamanho do endereço de memória em bits. O número de bytes lidos é igual a nbytes. O método retorna um objeto byte.

I2C.readfrom_mem_into(addr, memaddr, buf, *, addrsize=8): Este método é usado para ler bytes no buffer bufante do endereço I2C endereço começando pelo endereço de memória memadr. O tamanho do endereço especifica o tamanho do endereço de memória em bits. O número de bytes lidos é igual ao tamanho do buffer.

I2C.writeto_mem(addr, memaddr, buf, *, addrsize=8): Este método é usado para escrever um buffer bufante para o endereço I2C endereço começando pelo endereço de memória memadr. O método não retorna nada. O tamanho do endereço especifica o tamanho do endereço de memória em bits.

Software I2C em MicroPython
O software I2C é implementado em MicroPython usando a classe SoftI2C. A classe SoftI2C é importada em um script MicroPython usando a instrução a seguir.
da importação de máquina SoftI2C

Após importar a classe SoftI2C, é necessário instanciar um objeto I2C. Uma função construtora faz isso. A função construtora tem o seguinte protótipo.
máquina de classe.SoftI2C (scl, sda, freq = 400000)

Todos os métodos disponíveis na classe I2C, os mesmos também estão disponíveis na classe SoftI2C como está. O software I2C é implementado usando bit banging. Ele pode ser gerado em qualquer GPIO com capacidade de saída. É importante notar que o software I2C não é tão eficiente comparado ao hardware I2C. É possível comunicar-se com vários dispositivos I2C no mesmo barramento I2C, desde que cada dispositivo conectado ao barramento possua um endereço I2C diferente. Portanto, mesmo que apenas um periférico I2C de hardware esteja disponível em uma porta, ele deverá ser utilizado para comunicação I2C. O software I2C deve ser apenas um último recurso.

I2C em ESP8266
Existe um único driver I2C no ESP8266. Este driver é implementado em software e está disponível em todos os GPIO. Como a implementação de software do ESP8266 I2C é interna, a classe I2C (escrita para hardware I2C) do MicroPython é usada para gerenciar a comunicação I2C no ESP8266. Os pinos I2C padrão no ESP8266 são GPIO4 (SDA) e GPIO5 (SCL).

A seguir está um exemplo válido de uso da classe I2C para comunicação de dados no ESP8266.
da importação da máquina Pin, I2C
i2c = I2C(scl=Pino(5), sda=Pino(4), freq=100000)
i2c.readfrom(0x3a, 4)
i2c.writeto(0x3a, '0xFF')

Hardware I2C em ESP32
Existem dois periféricos I2C de hardware no ESP32. Esses periféricos são identificados pelos ids – 0 e 1. Os pinos SDA e SCL padrão para I2C0 são GPIO19 e GPIO18, respectivamente. Os pinos SDA e SCL padrão para I2C1 são GPIO26 e GPIO25, respectivamente. No entanto, qualquer GPIO com capacidade de saída pode ser usado como linhas SDA e SCL no ESP32. A seguir está um exemplo válido de uso de hardware I2C no ESP32.

da importação da máquina Pin, I2C
i2c = I2C(0)
i2c.readfrom(0x3a, 4)
i2c.writeto(0x3a, '0xFF')

O exemplo a seguir mostra o uso de pinos diferentes do padrão para hardware I2C.
da importação da máquina Pin, I2C

i2c = I2C(0, scl=Pino(5), sda=Pino(4), freq=400000)
i2c.readfrom(0x3a, 4)
i2c.writeto(0x3a, '0xFF')

Software I2C em ESP32
O software I2C pode ser usado em qualquer GPIO no ESP32 com capacidade de saída. Saiba mais sobre a disponibilidade do GPIO no ESP8266 e ESP32. A seguir está um exemplo válido de uso do software I2C no ESP32.
do Pin de importação da máquina, SoftI2C

i2c = SoftI2C(scl=Pino(5), sda=Pino(4), freq=100000)
i2c.readfrom(0x3a, 4)
i2c.writeto(0x3a, '12')
buf = bytearray(3)
i2c.writeto(0x3a, buf)

Interface ADXL345 com ESP8266 usando barramento I2C
Agora que você está familiarizado com a implementação do protocolo I2C no MicroPython, vamos colocar a mão na massa. Os sensores geralmente usam os protocolos I2C e SPI para fazer interface com controladores e microcomputadores incorporados. Vamos fazer a interface de um sensor acelerômetro ADXL345 com ESP8266 usando a implementação MicroPython do protocolo I2C.

Componentes necessários

  1. ESP8266/ESP32 x1
  2. Sensor acelerômetro ADXL345 x1
  3. Tábua de ensaio x1
  4. Conectando fios/fios de jumper
  5. Cabo micro USB x1

Conexões de circuito

O sensor acelerômetro ADXL345 pode ter interface com ESP8266 ou ESP32 usando protocolos I2C ou SPI. As placas breakout típicas do sensor acelerômetro ADXL345 possuem pinagem para ambas as interfaces ou apenas para o barramento I2C. Uma placa breakout expondo apenas o barramento I2C para interface com ADXL345 é mostrada na imagem abaixo.

Conecte os pinos VCC e Terra do sensor ADXL com saída 3V e GND do ESP8266, respectivamente. Conecte os pinos SCL, SDA e CS da placa breakout ADXL345 com os pinos D0 (GPIO16), D1 (GPIO5) e D2 (GPIO4) do ESP8266. Observe que os pinos I2C padrão na placa ESP8266 são D1 (SCL) e D2 (SDA). No entanto, podemos usar qualquer GPIO com capacidade de saída no ESP8266 para linhas SDA e SCL. Escolhemos D0 para SCL e D1 para SDA.

Observe que você deve ter carregado o firmware MicroPython para ESP8266 e estar pronto para o uPyCraft IDE antes de continuar este projeto.

Script MicroPython

Sobre o acelerômetro ADXL345

ADXL345 é um sensor acelerômetro MEMS de 3 eixos. É um sensor inercial digital e usa um design de acelerômetro capacitivo. Possui uma faixa selecionável pelo usuário de até +/- 16g, uma resolução máxima de saída de 13 bits, uma sensibilidade de 3,9 mg/LSB e uma taxa de dados de saída máxima de 3200 Hz. O sensor possui interfaces I2C e SPI para se comunicar com controladores/computadores. ADXL345 mede a aceleração estática devido à gravidade, bem como a aceleração dinâmica resultante de movimento ou choque. Ele pode ser usado para detectar a aceleração linear em 3 eixos e detectar a inclinação e queda livre de um objeto. Ele pode detectar a presença ou falta de movimento relativo comparando os valores de aceleração com limites definidos pelo usuário.

O ADXL345 possui registros integrados que podem ser lidos e gravados para definir as configurações do sensor e ler os valores de aceleração. ADXL345 oferece quatro faixas de medição: +/-2g, +/-4g, +/-8g e +/-16g. A faixa de medição padrão é +/-2g, que pode detectar aceleração de até 19,6 m/s2 em qualquer direção ao longo de cada eixo. As resoluções máximas são 10 bits para +/-2g, 11 bits para +/-4g, 12 bits para +/-8g e 13 bits para a faixa de +/-16g. A resolução padrão é de 10 bits, o que para a faixa de +/-2g (padrão) permite uma sensibilidade de 3,9mg/LSB. A taxa de dados padrão é 100 Hz. Todas essas configurações podem ser alteradas ou definidas gravando dados nos registros integrados do ADXL345. Um controlador/computador pode ler a aceleração lendo valores dos registros 0x32 a 0x37.

Como funciona
ADXL345 se comunica com o microcontrolador via I2C ou SPI. A placa breakout ADXL345 expõe apenas linhas I2C para comunicação de dados com o sensor. ADXL345 possui um pino de endereço ALT que pode ser conectado para definir o endereço I2C deste sensor digital. Se o pino ALT ADDRESS for puxado para cima em um módulo, o endereço I2C de 7 bits para o dispositivo será 0x1D, seguido pelo bit R/W. Isso se traduz em 0x3A para gravação e 0x3B para leitura. Se o pino ALT ADDRESS estiver conectado ao terra, o endereço I2C de 7 bits para o dispositivo será 0x53 (seguido pelo bit R/W). Isso se traduz em 0xA6 para gravação e 0xA7 para leitura. O pino ALT ADDRESS já está puxado para cima ou para baixo em um módulo. O endereço I2C do sensor ADXL345 usado neste tutorial é 0x53. Isso é confirmado pela varredura do barramento I2C usando o método i2c.scan da classe MicroPython I2C.

Os registros internos do ADXL345 precisam ser lidos e gravados para definir configurações (como definir faixa de medição, taxa de transferência de dados, sensibilidade e resolução) e ler valores de aceleração. Uma tabela desses registros é fornecida abaixo.

Para comunicação com ADXL345, primeiramente, seus parâmetros de configuração são definidos escrevendo nos registradores – DATA_FORMAT (0x31), BW_RATE (0x2C), POWER_CTL (0x2D), INT_ENABLE (0x2E), OFSX (0x1E), OFSY (0x1F), e OSFZ (0x20). Depois de escrever nos registradores de configuração através dos protocolos I2C, a aceleração ao longo do eixo x é obtida lendo os registradores 0x32 e 0x33 no barramento I2C. A aceleração ao longo do eixo y é obtida lendo os registros 0x34 e 0x35 no barramento I2C. A aceleração ao longo do eixo z é obtida lendo os registros 0x36 e 0x37 no barramento I2C.

Os valores de aceleração de leitura são de 16 bits. Os valores obtidos dos pares de registradores são convertidos em um único valor de 16 bits e complemento de 2 para obter os valores brutos finais de aceleração. Estes valores são multiplicados por um fator de 3,9, correspondente a uma resolução de +/-4g, para obter valores de aceleração em mg.

O código
O código MicroPython começa com a importação das classes Pin e I2C do módulo da máquina. O módulo time é importado para fornecer atraso e o módulo ustruct é importado para formatar valores de aceleração para 16 bits.

Segue-se a definição de constantes que representam os registos de configuração do ADXL345. Os pinos SCL, SDA e CS para o barramento I2C são definidos e o pino CS é definido como uma saída digital. Um objeto I2C é instanciado, definindo D0 (GPIO16) e D1 (GPIO5) como SCL e SDA, respectivamente, e definindo a frequência I2C máxima para 10.000 Hz. O barramento I2C é verificado chamando o método i2c.scan , e a lista retornada é armazenada em uma lista 'slv'. Com a ajuda de um loop for, os valores na lista 'slv' são comparados com o endereço I2c conhecido do ADXL345. Uma mensagem mostrando “ADXL345 foi encontrado” será impressa no console se o endereço for encontrado. O endereço correspondente é armazenado em uma variável 'slvAddr'.

Uma função 'writeByte ' é definida para gravar bytes no ADXL345 através do barramento I2C. Uma função 'readByte ' é definida para ler bytes do ADXL345 através do barramento I2C. A função writeByte é usada para gravar dados nos registradores de configuração – DATA_FORMAT, BW_RATE, INT_ENABLE, OFSX, OFSY, OFSZ e POWER_CTL.

Em um loop while infinito, os valores dos registros 0x32 e 0x33 são lidos chamando a função readByte definida pelo usuário. Os valores são formatados para um único número de 16 bits usando o método ustruct.unpack . Isso fornece o valor bruto da aceleração ao longo do eixo x. O valor bruto é multiplicado por 3,9 para obter a aceleração em mg.

Da mesma forma, os valores dos registros 0x34 e 0x35 são obtidos para derivar a aceleração ao longo do eixo y. Os valores dos registros 0x36 e 0x37 são obtidos para derivar a aceleração ao longo do eixo z. O loop continua indefinidamente até que a execução do script seja encerrada no uPyCraft ou Thonny IDE.

Resultado

Conteúdo Relacionado

Voltar para o blog

Deixe um comentário

Os comentários precisam ser aprovados antes da publicação.