25 de outubro de 2021

Do bit Ao Byte

Embarcados, Linux e programação

Multiplexador CD74HC4067 com Arduino

leitura digital | CD74HC4067 com Arduino

Nesse artigo discorro sobre esse versátil e dinâmico multiplexador CD74HC4067 com Arduino que atende a múltiplos propósitos, mas para um projeto iminente terá uma função relativamente simples. De qualquer modo, antes de escrever sobre o projeto, é melhor fazer essa introdução sobre esse componente de baixíssimo custo e altamente eficaz.

Aplicações do Multiplexador CD74HC4067

Se olharmos para essa placa, veremos escrito sobre ela as palavras “16-channel analog multiplexer”, mas ela é mais do que isso, e sua função dependerá do seu objetivo. A leitura dele é simples também, mas pro código ficar bem curto, vamos usar explicitamente bitwise, tanto para ler como para configurar os pinos.

Esse CI pode ser usado como entrada ou saída, e com 4 pinos digitais configuramos os 16 bits para HIGH ou LOW – ou para determinar seu estado, indicando o pino de leitura.

Disporei no artigo um exemplo claro de uso, portanto não é necessário se preocupar com a questão dos bits, caso não esteja habituado. De qualquer modo, recomendo a leitura da manipulação de bits com PCF8574.

Devo escrever outro artigo mostrando a manipulação do CH74HC4067 com Arduino para escrita, mas nesse artigo veremos a leitura binária (apenas interessando o estado), que será a aplicação dessa placa em um artigo bastante interessante.

Wiring do CD74HC4067 com Arduino

CD74HC4067 com Arduino

O Arduino utilizado nesse projeto que disporei em alguns dias é o Arduino Pro Micro. Tem que ser ele no projeto por duas razões; tamanho e a MCU, que é um Atmega32u. Tem que ser Atmega32u para o projeto e, nesse caso, poderia ser um Arduino Leonardo, mas o tamanho inviabiliza. Porém, para usar o CD74HC4067 com Arduino, basta que seja um Arduino; Uno, Nano, Pro Mini, Pro Micro, Leonardo, Mega etc. Então, seja lá qual for o Arduino que pretende utilizar, não se preocupe, funcionará – desde que a configuração dos pinos correspondam. Mas explico adiante.

A placa contém os seguintes pinos:

  • 16 pinos de saída/entrada.
  • VCC e GND.
  • 1 pino Enable (não utilizado aqui).
  • 4 pinos de controle, que usam GPIO do Arduino (S0, S1, S2, S3).
  • 1 pino de saída para leitura através de uma única porta (SIG).
  • Trabalha entre 2V e 6V, portanto pode ser utilizado com microcontroladores com nível lógico de 3V3.

O datasheet pode ser visto nesse link. Acabei encontrando também um link direto para o datasheet aqui.

Os pinos de entrada (à esquerda) vão de 0 a 15. VCC e GND, podendo ser fonte externa, mas lembre-se de colocar o GND comum com a MCU que escolher.

Os valores dos pinos são lidos em SIG. Definimos qual pino ler através dos 4 bits de entrada, que totaliza 15 valores possíveis:

  • S0 = 1 (GPIO8)
  • S1 = 2 (GPIO9)
  • S2 = 4 (GPIO10)
  • S3 = 8 (GPIO11)

Se colocamos o GPIO 8 em HIGH, teremos o valor 1 no pino S0. Então quando lermos o pino SIG, o resultado virá do pino 1 do MUX.

Se colocarmos o GPIO 11 em HIGH e o GPIO 10 em HIGH, a soma será 8+4=12, portanto ao lermos o pino SIG estaremos lendo o pino 12 do MUX.

A corrente de saída é de no máximo 25mA, não ultrapasse. A corrente máxima para GND é de 50mA.

O tempo de leitura varia conforme a tensão aplicada, mas consideremos a média de 500ns (é ‘nano’ mesmo).

O Wiring ficou assim:

ArduinoCD74HC4067
8C0
9C1
10C2
11C3

Código do CD74HC4067 com Arduino

Dá pra fazer de diversas maneiras, como por exemplo fazendo a configuração dos pinos com pinMode() e digitalWrite(), mas isso dá mais trabalho. Do mesmo modo, podemos definir um array dos valores binários, mas também não é o mais prático. Lembra do Desafio maker 01? Vamos fazer algo parecido.

PORTB

O registrador PORTB tem os pinos 8, 9, 10 e 11 em PB4, PB5, PB6 e PB7, respectivamente. Os outros pinos desse registrador são referentes ao SPI, mas podem ser utilizados como desejado. De qualquer modo, vamos manipular apenas os MSB e deixar os pinos PB0 ao PB3 como estiverem. Para referência (Atmega32u):

CD74HC4067 com Arduino

Preservar MSB com máscara de bits

Para preservar os bits mais significativos, fazemos assim:

(portb&15)

Com essa máscara, pegamos os valores apenas dos 4 bits menos significativos. Ex:

CD74HC4067 com Arduino

E para pegar os bits mais significativos:

(portb&~0xF)

Repare que tanto faz a base numérica utilizada, desde que o valor seja o mesmo, mas se considerarmos a preguiça, 0xF tem uma letra a mais pra digitar em relação ao decimal 15.

Se não está habituado com bitwise, não deixe que isso ferva sua cabeça, desfrute a leitura para juntar conceitos e depois aproveite o código disposto.

Se jogarmos um bit novamente na mesma posição, ele não será somado, apenas atribuído, então não precisamos nos preocupar em validar antes de atribuir. Como vamos ligar ou desligar os bits, duas operações serão necessárias:

Soma

Para somar, pegamos o valor da porta e adicionamos um pipe:

(PORTB|1<<0)

Subtração

Para subtrair trocamos o operador apenas:

(PORTB&~1<<0)

Exemplo:

CD74HC4067 com Arduino

Como testar bitwise?

Seria um porre ter que escrever o código, compilar, gravar o firmware, testar na serial para validar. Para facilitar, eu utilizo o bpython no Linux. O bpython é uma ferramenta poderosa de desenvolvimento in flow, ótima para validação de testes. Essa imagem acima é um teste para exemplo do artigo, feito nesse editor.

Tendo definido o modo de operação, agora precisamos ler do multiplexador.

 Como ler os valores do CD74HC4067?

Precisamos primeiramente configurar os pinos de GPIO como OUTPUT, mas apenas os 4 bits que vamos utilizar, os demais devem se manter. Para configurar os pinos selecionados como OUTPUT, usamos o registrador DDRB e para configurar os pinos como HIGH ou LOW, utilizamos o registrador PORTB. A função setup() ficará assim:

void setup() {
    DDRB = 0xF<<4;
    PORTB = 0;    //(PORTB&~0xF);
    Serial.begin(9600);
}

Na função loop() fazemos apenas isso (para prova de conceito):

void loop() {
  getValues();
  delay(2000);
}

E a função getValues() fica com o seguinte conteúdo:

uint8_t getValues(){
    
    for (uint8_t i=0;i<16;i++){
        //escolhe o pino a ler (PORTB: 0000xxxx)
        PORTB |= (i<<4);    //aqui desloca 4 bits para a esquerda
        delay(1); //1ms é um tempo altíssimo
        //le o canal
        pb_values = analogRead(READ_MUX_PIN);    //lê SIG no analógico A0

        //trata o valor como quiser
        Serial.print("C");
        Serial.print(i);
        Serial.print(":");
        handler(pb_values);
        
        //retorna o valor anterior ao pino
        PORTB &= ~(i<<4);
        delay(1);
    }
}

Como estou usando jumper para testar, tirei um print apenas do pino 15. Com a lógica desse código, basta colocar o pino em GND (por exemplo, um botão) e o resultado deve ser 0 na leitura:

CD74HC4067 com Arduino

Os resultados dos demais pinos são flutuantes e a leitura analógica tem 10 bits.

Onde comprar o CD74HC4067?

Esse multiplexador extremamente barato você encontra na Eletrônica Mangili, que tem outros itens interessantes em sua lista, mas o link direto para o multiplexador é esse.

No próximo artigo relacionado vamos ver a aplicação desse componente ao projeto, não perca!

 

Revisão: Ricardo Amaral de Andrade