Manual
do
Maker
.
com
Escrevi diversos artigos sobre o PCF8574 (como o "Dominando PCF8574 com Arduino"), que é um expansor de IO de 8 bits (ou se preferir, "um byte"). Hoje vamos ver o expansor de IO PCF8575, da mesma família, porém com 16 bits (ou, bem; 2 bytes).
Os jumpers de garrinha da imagem de destaque são da Mekanus. Já recomendei em outro artigo e, devido à dificuldade de encontrar, recomendarei sempre que possível. O analisador lógico que usei nesse artigo tem um vídeo próprio, com uma boa apresentação.
Se não conhece ainda, um expansor de IO aumenta o número de pinos disponíveis em uma MCU para, por exemplo, acionar relés, controlar display matricial etc. Esses displays de matriz 16x2 comumente já vem com um PCF8574 nele; se for I2C, pode ter certeza.
Podemos usar um expansor de IO não apenas como saída, mas também como entrada. Porém não é prático controlar um expansor de IO sem utilizar bitwise (por isso recomendo mais uma vez o tradicional artigo "Dominando PCF8574 com Arduino"). Se estiver utilizando o PCF8574 mas não estiver com disposição para aprender a manipular bits nesse momento, instale a biblioteca EasyPCF8574 , disponível no repositório do Arduino (e cuja biblioteca eu criei). Para esse expansor de 16 bits ainda estarei escrevendo a biblioteca, com oferecimento da Indústria Pontalti, que fabrica bojo de sutiã para grandes marcas. Bem, o que tem a ver sutiã? - Calma. É que estou fazendo uma automação meio sigilosa, mas algumas coisas genéricas poderão ser ofertadas aos makers, como a biblioteca para PCF8575 que devo escrever em uns 2 ou 3 dias após a publicação desse artigo.
O expansor de IO PCF8575 possui (os já citados) 16 bits. Não é necessário controle de sinal e ele é chamado de quasi-bidirectional. Hábil com alta corrente, pode ser usado para alimentar LEDs.
Ao iniciá-lo, seu estado mantém todos os IOs em HIGH. Não precisamos nos preocupar com a sinalização usando a biblioteca Wire, nativa da API do Arduino (bastando fazer seu include, como exemplificado mais adiante).
Essa placa tem um pino de interrupção também, que pode ser conectado à MCU e tratado no código como interrupção, para qualquer mudança de estado - isso significa que escrita pelo seu programa também gerará interrupção, portanto a ISR deverá tratar o evento antes de agir.
16 bits são 2 bytes. O primeiro byte refere à porta 0, que vai de P07 à P00. O segundo byte refere à porta 1, de P17 à P10. Não se preocupe com essas informações, porque o artigo exemplifica o uso e o vídeo demonstra o conceito. Apenas leia para ter o conhecimento e tudo ficará claro mais adiante.
Podemos usar até 8 expansores de IO PCF8575 interconectados, totalizando 16 bytes, totalizando 128 bits ! É IO demais!
Podemos simplesmente usar um scan e descobrir o endereço do dispositivo, mas se quisermos interconectar módulos, é bom já saber previamente quais são os endereços possíveis. Abaixo, a tabela de endereços, retirada do datasheet da Texas Instruments:
Essa tabela é o limite do limite. Não devemos usar como referência de normalidade. Por exemplo, VCC pode ir de -0.5 à 6.5, mas claro, vamos usar 3v3 ou 5v, considerando que se houver uma variação, não afetará o funcionamento do dispositivo.
Ele oferece até 50mA de corrente de saída. Podemos conectar 2 LEDs sim, desde que não ultrapasse 40mA, mas também não vejo benefício em usar um expansor de IO para acender LEDs, já que podemos usar multiplexadores, que é mais adequado para esse propósito.
A recomendação de operação é entre 2.5v e 5.5v, além de não mais de 25mA. Para constar, ele trabalha no barramento I2C na velocidade de 400kHz e tem tempo de resposta de 4us.
Antes de seguirmos com bitwise, tenha em mente que o expansor de IO PCF8575 é I2C, portanto usa 2 IOs da MCU, além de GND e VCC. Com um PCF8575 você terá 16 IOs. Tirando os 2 que usou da MCU para fazer a interface, o aumento de IOs de fato é de 14 pinos. "Mas", podemos serializar dispositivos I2C, bastando mudar seu endereço. Para fazê-lo, bastar fechar um ou mais jumper na parte de trás da placa. Lindo ou não?
Para fazer a comunicação, usamos a biblioteca Wire. No expansor de IO PCF8575 os bytes são escritos de forma sequencial. Isso é, se enviarmos 2 bytes, ele escreverá para a primeira porta, então para a segunda. Se escrevermos 3 bytes, ele escreverá na primeira porta, segunda porta e então sobrescreverá o valor da primeira porta. Essa informação é "fundamental" para debug, porque podemos estar escrevendo um valor que ultrapasse os 2 bytes e então o comportamento será inesperado. Se ocorrer algo do tipo, depure escrevendo os bytes, então leia-os em seguida para saber que bits foram manipulados. Use uma máscara e compare o valor passado e o valor escrito.
Uma mensagem de envio poderia seguir um desses formatos:
#include <Wire.h>
void setup(){
//sempre deve ser inicializado
Wire.begin();
//Uma escrita em binário:
Wire.beginTransmission(0x20); //O endereço do PCF. Depois explico como pegar
Wire.write(0b10000000); //Escrita em binário
//ou..
Wire.write(0xF0);
//ou..
Wire.write(128);
}
Aparentemente é mais fácil usar o binário, porém 16 bits teriam uma representação demasiadamente longa e de difícil leitura. Assim sendo, o mais fácil seria "empurrar" o bit para a posição desejada, lembrando que isso ocorre da direita para a esquerda a partir da posição 0:
Wire.write(1<<7);
Ou seja, não precisamos saber o valor, apenas onde queremos colocar o bit em HIGH.
Supondo que erguemos o bit 7 (outra vez, lembrando que começa em 0) e agora queremos levantar o bit 1. Não basta fazer isso:
Wire.write(1);
A razão é que o PCF8575 (ou o predecessor, PCF8574) escreve bytes. Para preservar o valor anterior e levantar o bit 0, também não precisamos ter uma variável para guardar isso. Basta fazer assim:
buf = buf|(1<<0)
"Mas isso não é uma variável?" - Claro que sim, no exemplo. Mas podemos ler o valor, modificar e reescrever diretamente. Mostro no vídeo.
Se desejar colocar um bit em LOW, pode parecer que é só trocar o "1" por "0", mas seria um engano. Para baixar agora o bit 7, fazemos:
buf = buf&~(1<<7)
Não é complicado e, sempre que esquecer, basta fazer um teste rápido (ou consultar esse artigo - coisa que obviamente eu prefiro).
Se quisermos fazer um blink, não temos compromisso com o estado do pino em nenhum momento, apenas queremos que o valor de inverta dentro de um período. Para isso, usamos outro operador. Por exemplo, em loop() nós poderíamos fazer assim para fazer blink no bit 0:
void loop(){
buf = buf^(1<<7);
Wire.beginTransmission(0x20);
Wire.write(buf);
Wire.endTransmission();
}
A maneira mais simples de testar se um bit está em HIGH ou LOW é assim:
buf&(1<<7)
Com essas operações, podemos facilmente interagir com o expansor de IO PCF8575 ou seu antecessor.
Para ter uma referência rápida, podemos consultar a tabela a seguir:
OPERADOR | OPERAÇÃO | RETORNO | AÇÃO |
AND | 7&(1<<0) | 1 | Testa o valor do bit na posição 0. (00000111) |
OR | 6 | (1<<0) | 7 |
AND NOT | 7&~(1<<0) | 6 | Baixa o bit na posição 0. (00000110) |
XOR | 7^(1<<0) | 6 | Inverte o valor do bit na posição 0 (se 1, vira zero e vice-versa). |
É quase igual o PCF8574, mas tem mais bits. Lá pro começo do artigo vimos como escrever um valor no expansor de IO, agora vamos ver como é feita a leitura.
Wire.requestFrom(pcf_addr, num_of_bytes);
Fácil ou não? Simplesmente usamos a função requestFrom, passando o endereço do PCF (nos exemplos aqui, 0x20) e o número de bytes a ser lido. No caso do expansor de IO PCF8575, podemos ler 2 bytes, que correspondem a 16 bits.
O código para escrita com diversos detalhes pode ser visto no artigo "ESP32 com PCF8575" (publicado 2 artigos após esse).
A placa vem com o endereço padrão 0x20, mas fica a dica para quando precisar encontrar o endereço de outro dispositivo.
Já escrevi sobre esse scanner I2C, há algum tempo já tem um sketch nos exemplos da IDE do Arduino e hoje vou recomendar esse link do Arduino.cc. Mas se você tiver um dispositivo qualquer com MicroPython, pode seguir o exemplo do artigo "Factory Defaults". Se não for uma RPi Pico, mudará o pinout, mas o código será o mesmo.
Como preciso escrever uma biblioteca para esse dispositivo, vou começar os testes com MicroPython na Raspberry Pi Pico mesmo, que acaba sendo uma ótima ferramenta para teste e planejamento.
Primeiro, vamos a uma leitura. Conforme a descrição, o dispositivo inicia com todos os pinos em HIGH. Vejamos:
Ok, lidos os 2 bytes do endereço 0x20. Tudo em HIGH. Qual é o LSB?
No datasheet vemos que o primeiro byte está à esquerda e o segundo byte à direita. Os bits sempre são lidos da direita para a esquerda, por isso temos o bit P00 na oitava posição e o bit 17 na nona.
No artigo "Dominando PCF8574" eu mostro a interação com o modelo de 1 byte, sem biblioteca. Para Arduino (ou qualquer MCU em que estiver usando C++) fiz uma biblioteca que está disponível no repositório oficial; a EasyPCF8574.
Sendo meu primeiro contato com o PCF8575, antes de escrever uma biblioteca, precisaria testar a leitura e verificar os bits correspondentes. Para isso, usei a RPi Pico como analisador de protocolos e sinais. Se não leu o artigo, aproveite para fazer seu analisador lógico com a RP Pico porque sai muito mais em conta que comprar um analisador de grife.
A leitura é aquela mais acima. Para escrever, sempre precisamos preservar o valor anterior, se for necessário manter o estado dos pinos. Por essa razão iniciei o artigo discorrendo sobre bitwise.
Basicamente, apontamos o endereço e passamos uma lista de bytes - No caso, 2 bytes. Coloquei o analisador lógico no bit 0 e no 15, então fiz uma captura usando o PulseView ("tem" que seguir o artigo supracitado para fazer seu analisador lógico funcionar no PulseView). Iniciei a escrita baixando todos os pinos:
i2c.writeto(0x20,bytes([0,0]))
Então iniciei a captura de 5 mil amostras na frequência padrão do programa e seguidamente, levantei os bits 0 e 15:
i2c.writeto(0x20,bytes([1,128]))
A leitura com mudança de nível lógico (canal 12 e 16):
Tendo constatado a ordem dos bits, agora é só desenvolver a biblioteca. Logo trarei novidades, acompanhe aqui! Ah, mas também farei vídeo, por isso peço sua gentileza, inscrevendo-se em nosso canal DobitaobyteBrasil no Youtube e clicando no sininho para receber notificações!
Inscreva-se no nosso canal Manual do Maker no YouTube.
Também estamos no Instagram.
Autor do blog "Do bit Ao Byte / Manual do Maker".
Viciado em embarcados desde 2006.
LinuxUser 158.760, desde 1997.