Manual

do

Maker

.

com

Expansor de IO MCP23017 com ESP32

Expansor de IO MCP23017 com ESP32

Esse expansor de IO MCP23017 com ESP32 ou outro qualquer é incrível! Se você precisa de mais pinos em seu projeto, tudo o que você precisa é de uma MCU/CPU que ofereça interface I2C para utilizá-lo. Claro, provavelmente quererá também uma biblioteca, porque esse expansor de IO tem bastante interação, o que acaba dando um trabalhinho para gerenciá-lo "manualmente".

Se deseja um expansor de IO mais barato e mais simples, recomendo fortemente o PCF8574, do qual já fiz uso em diversos artigos importantes, mas para manipulá-lo adequadamente escrevi o artigo Dominando PCF8574 com Arduino. Não se preocupe com o título, o controle é o mesmo para qualquer MCU/CPU, bastando acesso ao barramento I2C.

Expansor de IO MCP23017 com ESP32

São 2 bytes de expansão - ou, 16 pinos. Possui interrupção separada para cada byte ou pode ser configurado para interromper em apenas 1 das interrupções. O expansor de IO MCP23017 possui pullup interno para cada pino utilizado como entrada, sendo totalmente configurável. Desse modo, não é necessário utilizar resistores externamente para esse propósito.

É possível expandir até 8 módulos MCP23017, bastando configurar seus endereços para que sejam diferentes. Com isso, garante-se 128 pinos de IO, utilizando apenas os  pinos VCC, GND, SDA e SCL.

Há também a possibilidade de utilizá-lo com o barramento SPI, obtendo então uma velocidade de 10MHz no barramento, caso seja necessário tal velocidade.

Os resistores internos de pullup são de 100k. Também podemos misturar e relacionar entradas e saídas.

Para usar o MCP23017 com ESP32 é transparente, graças à tolerância ao nível lógico!

Pinout

O pinout está "silkado" na parte de trás desse módulo, chamado de CJMCU-2317. De um lado temos todos os GPIO, a alimentação e as interrupções. Do outro lado, o endereço, pinos de conexão, VCC e GND novamente.

mcp23017-pinout-241x300.webp

Specs

O expansor de IO MCP23017 trabalha com tensões entre 1.8V e 5.5V, com baixíssimo consumo (1mA) e oferece 25mA por pino. Opera com no máximo 125mA de saída e 150 para GND. Então, mesmo que esteja usando-o como entrada para aterrar o LED, não passe dos 150mA para não produzir a cauda de um gênio.

Se desejar dar uma olhada no datasheet, eis o link.

Se está procurando controlar muitos LEDs, dê uma olhada em "shift registers". No site você encontra artigos com o buffer não inverso CD4050, shift register HC595 e mais algumas coisas.

Registradores

O expansor de IO MCP23017 possui diversos registradores, o que não anima muito em fazer interação diretamente com ele. Como já existem diversas bibliotecas disponíveis no repositório de bibliotecas do Arduino, é mais prático utilizá-las do que reinventar a roda. De outro modo, deleite-se com o datasheet supracitado.

Vou citar alguns dos registradores apenas para ter uma ideia do que estou falando. Por exemplo, o registrador IODIR logo abaixo é um registrador de 8 bits, onde cada bit pode ser configurado individualmente. Pense nos registradores como check box, onde você predefine o modo de trabalho do processador.

IODIR - registrador de direção

Para controle da direção de cada pino, o expansor de IO MCP23017 possui o registrador IODIR A e B, permitindo ajustar o pino para OUTPUT ou INPUT, com 0 e 1, respectivamente. A lógica é "a mesma" que a utilizada na maioria das microcontroladoras; escrevi sobre isso com PIC há alguns anos: "0" é como "O", de "Output".

GPPU - registrador de pullup

Colocando um bit em HIGH, ativa o pullup para um pino de IO correspondente - lembrando que isso só faz sentido quando o pino for configurado para INPUT.

OLAT - registrador de latch de saída

Para quem vem de PIC, não estranhará nada. Com ele, podemos ler a saída desejada de um pino, independente do estado real. Isso significa que se a tensão do pino for abaixo do limite lógico, a leitura do pino retornaria 0, quando na verdade deveria retornar 1, mas com OLAT ele retornará o estado verdadeiro.

IPOL - registrador de inversão do pino

Permite inversão seletiva de qualquer pino de entrada. O uso correto desse registrador oferece um conjunto de benefícios dos quais ainda não estou hábil a discorrer sobre eles, por isso vou evitar cometer equívocos nessa apresentação.

SQEOP - modo polling

Essa é uma maneira de contornar uma situação onde possam ocorrer muitas interrupções, que eventualmente poderiam interferir na tratativa, ou simplesmente porque a interrupção deveria ser reservada para uso em uma situação crítica específica, invés de uso geral.

Esse modo (também chamado de "byte mode") permite ler o mesmo conjunto de GPIOs usando clocks. Isso significa ler continuamente sem atualizar o próprio registrador de endereço.

Biblioteca

Uma das bibliotecas disponíveis para esse expansor de IO MCP23017 é a da Adafruit, a qual podemos instalar através do gerenciador de bibliotecas da IDE do Arduino ou do PlatformIO, em sua IDE preferida.

Com ela, acessamos facilmente cada bit de forma separada, se desejado. Nas funções de controle pode indicar a direção do pino, fazer leituras e escritas chamando os métodos com os mesmos nomes dos métodos utilizados na IDE do Arduino.

mcp.pinMode(0, OUTPUT);

mcp.digitalWrite(0,HIGH);

mcp.digitalRead(0);

Leia o datasheet

Todos os endereços de registradores estão especificados no datasheet. Se quiser criar uma biblioteca, o datasheet é o primeiro passo.

Não vou discorrer sobre todos os registradores, porque além de ser um assunto extenso, fica chato pra caramba. O problema é que utilizar uma biblioteca poderá limitar as possibilidades, sendo muito mais agradável (pelo menos para mim) ler o registrador e manipular os bits.

Tenhamos em mente a lista de registradores e seus respectivos endereços:

IOCON.BANK = 0

Access to:

00h IODIRA

01h IODIRB

02h IPOLA

03h IPOLB

04h GPINTENA

05h GPINTENB

06h DEFVALA

07h DEFVALB

08h INTCONA

09h INTCONB

0Ah IOCON

0Bh IOCON

0Ch GPPUA

0Dh GPPUB

0Eh INTFA

0Fh INTFB

10h INTCAPA

11h INTCAPB

12h GPIOA

13h GPIOB

14h OLATA

15h OLATB

Agora vamos observar uma operação básica, utilizando a biblioteca escrita pela Adafruit. Provavelmente qualquer biblioteca deve funcionar ao utilizar o MCP23017 com ESP32 , ESP8266, Arduino ou qualquer outro. A vantagem em utilizar essa biblioteca é que todos os registradores estão dispostos nela, o que facilita a utilização de forma mais aberta do que apenas chamar funções para um propósito específico, o que acaba nos deixando "engessados".

Exemplo básico

Por padrão, os pinos de IO são configurados como OUTPUT. Redefinindo o valor de IODIRA e IODIRB, podemos passar todos de uma vez para INPUT. Também podemos ler os 2 Bytes de uma vez, através da função readGPIOAB. Nesse caso, será necessário conhecer bitwise para identificar os bits que estão "em pé". Além disso, ele possui internamente resistores de pullup, bastando definir também seu estado inicial:

#include <Arduino.h>
#include <Adafruit_MCP23017.h>

//configura direção de A e B para INPUT
#define MCP23017_IODIRA 255
#define MCP23017_IODIRB 255

//resistores de pull up em ambas as portas
#define MCP23017_GPPUA 255
#define MCP23017_GPPUB 255

Adafruit_MCP23017 mcp;

void setup() {
    mcp.begin();
    Serial.begin(9600);
    vTaskDelay(pdMS_TO_TICKS(3000));
    
    Serial.println(mcp.readGPIOAB());

}

void loop() {
  vTaskDelay(pdMS_TO_TICKS(1000));
  Serial.println(mcp.readGPIOAB());
}

Mesmo com os resistores de pullup, achei bastante sensível a resposta ao estado do pino, mas com esse exemplo você já poderá ver a mudança de estados colocando o pino em VCC (use um resistor, please) ou apenas gerando alguma energia com a mão mesmo.

Se quisermos ler apenas uma porta (1 Byte), podemos selecioná-la através da função readGPIO, passando o parâmetro 0 para A1para B. Do mesmo modo, será necessário conhecer bitwise. O artigo sugerido no início do artigo lhe habilitará a fazê-lo, caso ainda não tenha essa experiência.

Serial.println(mcp.readGPIO(0));

Para utilizá-lo adequadamente, é bom dar uma lida no datasheet, disponível através desse link.

Polaridade de entrada

Isso serve bem para confundir a cabeça de quem está iniciando com esses tipos de expansores de IO. Se for o seu caso, talvez não seja o momento de dar atenção a isso, mas o MCP23017 possui um registrador que inverte a lógica da polaridade. Isto é, quando estiver em 1, ele pode retornar 0.

Essa configuração pode ser feita por pino, apenas ajustando o respectivo bit da porta em questão.

Montes de outros recursos

Podemos definir interrupção por pino, definir que ambos os Bytes reportem em um mesmo pino de interrupção e mais um monte de coisas. Serei obrigado a escrever conforme os casos que for utilizando, senão esse artigo ficará gigantesco e chato.

Resumidamente, esse expansor de I/O pode ser considerado melhor que o PCF8574 devido à flexibilidade. Por outro lado, sua complexidade é bem maior. Além disso, tem a questão de preço, sendo que o PCF8574 é mais barato, mas aí vai da necessidade, porque o MCP23017 possui 3 bits de endereçamento I2C, o que permite expandir tantos I/O quanto um projeto possa ter.

Para melhor proveito, sugiro a utilização do Visual Studio Code, que possui versões gratuitas para Linux e Windows, suporte a PlatformIO e montes de recursos que a IDE do Arduino talvez nunca tenha.

Vamos ver se consigo utilizá-lo de forma prática já no próximo artigo!

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

Também estamos no Instagram.

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.