Arduino Playground is read-only starting December 31st, 2018. For more info please look at this Forum Post

Saídas digitais múltiplas com o uso de um registrador de deslocamento 74HC595

Texto iniciado por Carlyn Maw e Tom Igoe, Nov 2006

Deslocamentos e o chip 595

Haverá vezes em que você sentirá falta de mais pinos na sua placa Arduino e precisará de uma expansão, com registradores de deslocamento. Este exemplo baseia-se no 74HC595. Sua folha de dados explica que se trata de "um registrador de deslocamento de 8 bits com entrada serial e saída serial ou paralela, com latches de saída; com três estados". Em outras palavras, pode-se usá-lo para controlar 8 saídas de uma vez e para tal usa-se apenas alguns poucos pinos de seu microcontrolador. Pode-se encadear vários registradores de deslocamento, de forma a expandir ainda mais o número de saídas possíveis. (Caso deseje, procure por outros chips com 595 ou 596 contidos no código do modelo, há vários deles. O STP16C596, por exemplo, pode acionar 16 LEDs e substitui os resistores de pull-up por fontes de corrente constante, integrados a eles).

Isto tudo funciona graças à chamada comunicação serial síncrona. Aplica-se uma sequência de pulsos, cada um a representar um bit, de forma que ao final teremos comunicado um byte inteiro de dados ao registrador. É pela aplicação de pulsos ao pino 2, que é o pino de clock, que você delineia os bits. Esse tipo de comunicação contrasta com a comunicação serial assíncrona usada pela função Serial.begin(), que baseia-se na negociação de uma velocidade de transmissão específica entre o emissor e o receptor. Uma vez transmitido todo o byte ao registrador, as mensagens HIGH e LOW atribuídas a cada bit são entregues a cada pino respectivo de saída. Esta é a parte chamada de saída paralela - todos os pinos apresentam o byte todo de uma só vez.

A parte chamada de saída serial é atribuída a um pino extra do registrador, que passa a informação ipsis litteris vinda do microcontrolador. Isso quer dizer que pode-se transmitir 16 bits (2 bytes) de uma tacada só, sendo que os primeiros 8 bits vão atravessar o registrador e atingirão um segundo registrador, por exemplo, onde serão disponibilizados. Isso será visto no segundo exemplo abaixo.

A parte do "três estados" refere-se ao fato de podermos configurar os pinos de saída como HIGH, LOW e alta impedância. Ao contrário dos estados HIGH e LOW, o de alta impedância não pode ser concedido aos pinos individualmente, mas apenas a todos os pinos juntos. Isso é uma situação bastante especial - imagine um vetor de LEDs controlados por mais de um microcontrolador, dependendo de modos de configuração no seu projeto. Nenhum exemplo abaixo utiliza-se dessa característica do registrador de deslocamento e você provavelmente não precisará de um chip que apresente saídas de três estados.

Aqui está uma tabela que explica a pinagem (adaptada da folha de dados da Phillips)

Pinos 1-7, 15 Q0-Q7 Pinos de saída
Pino 8 GND Terra
Pino 9 Q7' Saída serial
Pino 10 MR Master Reclear, ativo em LOW
Pino 11 SH_CP Pino de clock do registrador de deslocamento
Pino 12 ST_CP Storage Register Clock Pin (pino de latch)
Pino 13 OE Output Enable, ativo em LOW
Pino 14 DS Entrada de dados seriais
Pino 16 VCC Pino de alimentação positiva

Exemplo 1: um registrador de deslocamento

O primeiro passo é estender o Arduino com o uso de um registrador de deslocamento.

O circuito

1) Ligar

Faça as seguintes conexões:

  • GND (pino 8) ao terra
  • VCC (pino 16) aos 5 V
  • OE (pino 13) ao terra
  • MR (pino 10) aos 5 V

Essa montagem torna ativos todos os pinos de saída e sempre endereçáveis. Um porém dessa configuração é que acaba-se com as luzes ligadas de forma arbitrária toda vez que o circuito for acionado pela primeira vez e antes que o programa comece a rodar. Pode-se resolver isso com o controle dos pinos OE e MR, mas aí teríamos que usar pinos adicionais da placa Arduino.

2) Conectar ao Arduino

  • DS (pino 14) ao pino digital 11 do Arduino (fio azul)
  • SH_CP (pino 11) ao pino digital 12 do Arduino (amarelo)
  • ST_CP (pino 12) ao pino digital 8 do Arduino (verde)

A partir daqui, chamaremo-nos, respectivamente, de dataPin, clockPin e latchPin. Repare no capacitor de 0,1 uF no latchPin, se ocorrerem irregularidades ao pulsar o latchPin, utilize o capacitor para filtrar o ruído.

3) Adicionar 8 LEDs

Neste caso, conecte o catodo (terminal curto) de cada LED a um terra comum e o ânodo (terminal longo), à saída respectiva do registrador de deslocamento. Chama-se o registrador de deslocamento de fonte de corrente quando se alimenta os LEDs da maneira explicada. Alguns registradores de deslocamento não podem fazê-lo, mas sim drenar corrente; nesse caso, basta inverter os terminais dos LEDs. Verifique se a folha de dados de seu componente eletrônico diz que ele pertence à série 595. Não se esqueça dos resistores de 220 ohms em série, para proteger os LEDs contra sobrecarga.

Diagrama esquemático do circuito

O código

Aqui estão três códigos-exemplos. O primeiro é apenas um código de "olá mundo", que exibe o valor de um byte de 0 a 255. O segundo programa acende um LED por vez, e o terceiro circula através de um vetor.

Tabela-verdade do registrador 74HC595 | Diagrama de tempo

Os códigos baseiam-se em duas porções de informação presentes na folha de dados: o diagrama de tempo e a tabela-verdade. A tabela-verdade nos diz que, basicamente, tudo o que é de importante ocorre na borda de subida do clock. Quando o clockPin vai de LOW para HIGH, o registrador de deslocamento lê o estado do dataPin. Conforme os dados são deslocados através do chip, eles são salvos em uma memória interna. Quando o latchPin vai de LOW para HIGH, os dados saem dessa memória interna e vão realmente para os pinos de saída, acendendo os LEDs.

Exemplo 1.1 Olá mundo
Exemplo 1.2 Um por um
Exemplo 1.3 Vetor

Exemplo 2

Neste exemplo, adiciona-se mais um registrador de deslocamento e, assim, dobra-se a quantidade de pinos de saída sem alterar a quantidade de pinos usados no Arduino.

O circuito

1) Adicionar um segundo registrador de deslocamento

A partir do exemplo anterior, instale um segundo registrador de deslocamento na protoboard e puxe os fios de alimentação e terra.

'''2) Conectar os dois registradores Duas conexões simplesmente estendem os mesmos sinais de clock e de latch, vindos do Arduino, ao segundo registrador de deslocamento (fios amarelo e verde). O novo fio azul vai do pino saída serial (pino 9) do primeiro registrador à entrada serial de dados (pino 14) do segundo registrador.

3) Incluir um segundo conjunto de LEDs Neste caso, adicionei LEDs verdes para que, quando se fizer a leitura do código, fique claro qual byte foi para qual conjunto de LEDs.

Diagrama esquemático do circuito

O código

De novo, temos três exemplos. Se você for curioso, pode testar os programas do exemplo anterior com a nova montagem do circuito, para ver o que acontece.

Exemplo 2.1 Contador binário duplo Há apenas um linha extra de código em relação ao Exemplo 1.1. Ele envia um segundo byte. Isto força o primeiro registrador, o que conecta-se diretamente ao Arduino, a deixar passar o primeiro byte, levando-o ao segundo registrador, acendendo os LEDs verdes. O segundo byte acende nos LEDs vermelhos.

Exemplo 2.2 2 bytes, um por um Se compararmos este código com o código similar do Examplo 1, veremos que um pouco mais deve ser mudado aqui. A função blinkAll() mudou para blinkAll_2Bytes(), para refletir o fato de que agora há 16 LEDs a serem controlados. Além disso, na versão 1 os pulsos do latchPin foram colocados dentro das subfunções lightShiftPinA() e lightShiftPinB(). Aqui, elas precisam ser recolocadas no loop(), para que cada subfunção rode duas vezes em uma tacada só, uma vez para os LEDs verdes e outra para os vermelhos.

Exemplo 2.3 Dois vetores Tal como em 2.2, o Exemplo 2.3 também aproveita-se da nova função blinkAll_2bytes(). A grande diferença com relação ao Exemplo 1.3 é que, em vez de termos uma única variável "data" e um único vetor "dataArray", agora há também dataRED, dataGREEN, dataArrayRED, dataArrayGREEN. Isto significa que a linha data = dataArray[j]; torna-se

    dataRED = dataArrayRED[j];
    dataGREEN = dataArrayGREEN[j]; 

e shiftOut(dataPin, clockPin, data); torna-se

    shiftOut(dataPin, clockPin, dataGREEN);
    shiftOut(dataPin, clockPin, dataRED);