20 de fevereiro de 2012

Ampliar saídas do Arduino

Vamos ampliar o número de saídas do Arduino.


Nesse exemplo, controlei 30 Leds utilizando apenas 3 saídas do Arduino.


O segredo é utilizar os registradores de deslocamento 74HC595.
Utilizei 4 registradores. O primeiro é ligado diretamento no Arduino, os demais são conectados um ao outro. Para cada registrador ganhamos 8 saídas. No exemplo eu poderia conectar até 32 Leds. O número de registradores fica por sua conta. Pode-se ligar uma quantidade praticamente ilimitada!
Cada registrador custa em média menos de 1 Real.

No código que fiz, é necessário que você indique dentro da função shiftWrite() quantos registradores está usando:
void shiftWrite(int pin){
  int qtdRegistradores = 4; //QUANTIDADE DE REGISTRADORES (74HC595).

E para acionar os Leds, usei o loop:
int tempo = 200;
for (int i=1; i<=30; i++){
   shiftWrite(i);
   delay(tempo);
}
Onde i é o número do Led. Nesse caso, de 1 a 30.

Para um controle mais exato de cada saída, é necessário uma grande melhoria nessa lógica. A função pode ser modificada para ter um controle exatamente como o digitalWrite(), onde podemos controlar cada porta de forma individual.
Agora quando precisar de mais saídas, antes de pensar em gastar aquela grana toda comprando um Arduino Mega, lembre dos registradores de deslocamento!

Esse foi só um exemplo de como podemos ampliar as portas de saída do Arduino.

Segue o esquema elétrico do circuito do vídeo, e o código fonte.

Abraços e bons projetos!

Atualização:
http://www.efeitonerd.com.br/2012/09/ampliar-saidas-do-arduino-library.html



/*---------------------------------------------
 S H I F T O U T  M E G A
 Ampliar o número de saídas do Arduino com
 Registrador de Deslocamento 74HC595
 Fellipe Couto - 19/02/2012
 --------------------------------------------*/

/*¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨
 - Pino 8 do Arduino ligado ao pino 12 do CI.
 - Pino 11 do Arduino ligado ao pino 14 do CI.
 - Pino 12 do Arduino ligado ao pino 11 do CI.
 - Led 1 = Pino 15 do CI.
 - Led 2 = Pino 1 do CI.
 - Led 3 = Pino 2 do CI.
 - Led 4 = Pino 3 do CI.
 - Led 5 = Pino 4 do CI.
 - Led 6 = Pino 5 do CI.
 - Led 7 = Pino 6 do CI.
 - Led 8 = Pino 7 do CI.
 - Pinos 10 e 16 do CI ligados ao Vcc.
 - Pinos 8 e 13 do CI ligados ao GND.
 - Pino 9 do CI ligado ao pino 14 do próximo CI.
 ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨*/
int latchPin = 8;  //Pino conectado ao pino 12 do 74HC595 (Latch).
int dataPin = 11;  //Pino conectado ao pino 14 do 74HC595 (Data).
int clockPin = 12; //Pino conectado ao pino 11 do 74HC595 (Clock).

void setup(){
  //Define os pinos como saída
  pinMode(latchPin,OUTPUT);
  pinMode(dataPin,OUTPUT);
  pinMode(clockPin,OUTPUT);
}

void loop(){
  int tempo = 200;
  for (int i=1; i<=30; i++){
    shiftWrite(i);
    delay(tempo);
  }
  for (int i=30; i>0; i--){
    shiftWrite(i);
    delay(tempo);
  }

  tempo = 10;
  for (int j=0; j<3; j++){
    for (int i=1; i<=30; i++){
      shiftWrite(i);
      delay(tempo);
    }
    for (int i=30; i>0; i--){
      shiftWrite(i);
      delay(tempo);
    }
    tempo -= 2;
  }
}

void shiftWrite(int pin){
  int qtdRegistradores = 4; //QUANTIDADE DE REGISTRADORES (74HC595).

  int countShift = 1;
  int data = 256;
  for (int i=1; i<=pin; i++){
    if (data <= 1){
      data = 256;
      countShift++;
    }
    data /= 2;
  }

  digitalWrite(latchPin, LOW);
  for (int i=qtdRegistradores; i>0; i--){
    if (i == countShift){
      shiftOut(data);
    }
    else{
      shiftOut(0);
    }
  }
  digitalWrite(latchPin, HIGH);
}

void shiftOut(byte dataOut){
  //Desloca 8 bits, com o bit menos significativo (LSB) sendo deslocado primeiro, no extremo ascendente do clock.
  boolean pinState;
  digitalWrite(dataPin, LOW); //Deixa o registrador de deslocamento pronto para enviar dados.
  digitalWrite(clockPin, LOW);

  for (int i=0; i<8; i++){ //Para cada bit em dataOut, envie um bit.
    digitalWrite(clockPin, LOW); //Define clockPin como LOW antes de enviar o bit.

    //Se o valor de dataOut E(&) de uma mascara de bits forem verdadeiros, defina pinState como 1 (HIGH).
    if (dataOut & (1<<i)){
      pinState = HIGH;
    }
    else{
      pinState = LOW;
    }

    digitalWrite(dataPin, pinState); //Define dataPin como HIGH ou LOW, dependendo de pinState.
    digitalWrite(clockPin, HIGH); //Envia o bit no extremo ascendente do clock.
  }
  digitalWrite(clockPin, LOW); //Interrompe o deslocamento de dados.
}

33 comentários:

  1. Você é Foda...
    Muito BOM tio

    ResponderExcluir
  2. Fodice ao extremo. Nesse circuito é possível controlar individualmente o estado de cada saída? Quero dizer, dá para fazer a saída segurar o estado depois que a varredura passou por ela? Sds.

    ResponderExcluir
    Respostas
    1. Opa! Na lógica postada, não. Eu já havia começado a modifica-la, para funcionar exatamente como o DigitalWrite() padrão do Arduino, mas por falta de tempo não terminei ainda. A idéia estava sendo em guardar última saída em memória, para apenas atualizar os estados, mantendo os HIGH e LOW anteriores.
      Se alguém já tiver conseguido terminar algo do tipo, será ótimo enviar pra gente postar!
      Abraços!

      Excluir
    2. muito legal no passado montei muito sequencial para as discos mas usava cicuitos ttl e cmos tinha que montar com timers pra cada sequencia e cada efeito fazia tudo na mao rsrs vus 3914com 40 canais e 800 lampadas bolinhas era show a casa parava no arduino vou começar eheh me diga e o controle de velocidade como faz e para funcionar com som mande dicas fico grato dema.me@hotmail.com

      Excluir
  3. Tentei uma saída por Hardware, FF tipo D em cada saída, mas as vezes dá caca por atrasos de CI e o sistema se perde. Vamos trabalhar juntos nisso, me diga, é possível mandar 2 leds acenderem isoladamente ao mesmo tempo? Se postar aqui como fazemos isso, vou tentar construir uma matriz com o estado atual e outra com estado anterior de todas as portas e a cada varredura sobreescrever nova na antiga e guardar denovo, ou seja, trato as portas virtualmente e mando o resultado somente depois de virtualmente fazer minha varredura, mas pelo pouco que conheço do 74595 não rola isso, é um estado só por vez, eu acho... Mas seu projeto me ajudou bastante, eu já estava fazendo algo parecido com portas E e não filtrando saídas do Arduino (0 a 8 em BIN resultava no endereço de cada saída) mas além do seu modelo ser mais simples em qtd de componentes, uso a mesma quantidade de saidas arduino para um numero ilimitado de portas, muito melhor que meu esquema. Responde isso se dá pra gravar concomitante 2 ou mais portas, se der, acho que o que estou propondo pode funcionar. Puta projeto esse se funcionar!

    ResponderExcluir
    Respostas
    1. Desculpe a demora na resposta, e repondendo na pressa agora também... Mas...
      A função shiftWrite() foi feita para enviar uma sequencia binária, onde acendemos apenas um led por vez, sequindo a sequencia. Mas pode-se enviar, por exemplo um valor que acenda os leds 3, 8, e 20, na mesma varredura.
      O que eu estava fazendo era uma lógica onde eu guardava o valor enviado (com quais leds acenderiam) em uma variável, e na próxima varredura apenas alterava os necessários.
      Funcionou, mas estava com alguns problemas nos calculos binarios. Ainda não consegui tempo pra terminar isso.
      Mas a ideia é essa! Funcionar, funciona sim!
      Abraços!

      Excluir
  4. Consegui, com a ajuda do meu irmão que é mais experiente com programação, trabalhar 64 saídas de uma vez, mas a quantidade é ilimitada. Envio todos os estados ao mesmo tempo através de um array, basta atualizar o array para ter nova sequencia de acendimento. Tem pequenas falhas mas está ganhando corpo a idéia, agora estou trabalhando em envio desse array por serial mas estou falhando na conversão de dados e construção do array com os dados que recebo, quando conseguir estabilizar o sistema apresento a ideia pra vocês.

    Sds.

    ResponderExcluir
  5. http://www.efeitonerd.com.br/2012/09/ampliar-saidas-do-arduino-library.html

    ResponderExcluir
  6. olá, gostaria de saber como você faz para o código aparecer dentro dessa janelinha que fica parecida com a IDE do arduino, como faco isso no meu blog?

    ResponderExcluir
    Respostas
    1. Bom dia!
      Uso o SyntaxHighlighter (http://alexgorbatchev.com/SyntaxHighlighter/).
      É só adicionar o código dentro do html da página do seu blog.
      Abraços!

      Excluir
  7. Amigo estou construindo um cubo de led e preciso de 110 portas digitais para isso, vou usar o arduino, porem o msm não possui o numero de portas, a logica de construção é essa

    http://tecnomelque.blogspot.com.br/2011/06/arduino-cubo-led.html

    esse de 3x3x3 eu ja fiz e fuincionou com esse programa que o cara mostra, porem quero fazer um de 10x10x10, sera que consigo intercalar o seu programa multiplexador com o programa desse site para controlar o cubo ????


    Muito obrigado.
    Felipe Yuri.
    fy.teixeira@gmail.com

    ResponderExcluir
    Respostas
    1. Boa tarde, Felipe Yuri!
      Acredito que funcionaria sim. Nunca testei utilizando um cubo de LEDs, mas já utilizei 80 saídas (10 registradores) e funcionou bem. Abraços!!

      Excluir
  8. Felipe, pelo amor de DEUS !!!!!!!!!! me ajuda............. tenho um mega, e não consigo de forma nenhuma transferia esse codigo para funcionar com as saídas digitais dele. Me ajuda. aliancavideoproducoes@hotmail.com Por favor.

    ResponderExcluir
    Respostas
    1. Olá Alexandre! Boa noite!

      Qual erro exatamente está retornando?

      O arduino mega já possui 54 saídas, se não me engano, e nesse caso poderia utiliza-las sem os registradores 74HC595. Poderia adaptar o código do "Sequencial de LEDs" [ http://www.efeitonerd.com.br/2011/12/sequencial-de-leds.html ] para utilizar mais portas. Altere as variáveis no inicio do código, de quantidade de Leds e a variável vetor com os pinos utilizados. Acredito que já vá funcionar.

      Utilizando os registradores, conseguimos com apenas 3 portas do arduino, controlar muitos Leds, como no exemplo utilizei 30. Já testou utilizando a biblioteca que fiz? Usando o biblioteca fica bem mais limpo o código.
      O link do post é esse: http://www.efeitonerd.com.br/2012/09/ampliar-saidas-do-arduino-library.html

      Abraços!

      Excluir
  9. Bom dia!
    Estou com dificuldade de inicializar a sua biblioteca juntamente com a ethernet shield, parece que quando inicializo a sua lib, ele trava, saberia me dizer o que ocorre?
    Junior

    ResponderExcluir
  10. Boa Tarde...
    Sabe me dizer qual é a amperagem de cada porta de saída deste CI ?
    Até quantos led de alto brilho eu poderia colocar em serie em cada saida ?
    Por favor, quem souber, poderia me responder pelo email gutosoft@hotmail.com
    Grato
    Augusto.

    ResponderExcluir
  11. Olá Pessoal...
    Poderiam me dizer qual é a voltagem de entrada deste CI 74HC595, se eu posso aplicar 12V ?
    E qual é a voltagem e amperagem de saida nas portas ? Pois em cada porta eu preciso colcoar 5 leds em serie !!!!
    Grato e aguardo retorno...
    Augusto
    email: gutosoft@hotmail.com

    ResponderExcluir
    Respostas
    1. Bom dia!!
      A tensão de alimentação do CI é de 5v.
      Segue o datasheet para consulta: http://www.nxp.com/documents/data_sheet/74HC_HCT595.pdf
      Abraços!

      Excluir
  12. Excelente tutorial, parabens.

    Fica uma dica: Para o controle de leds usando esse esquema, pode-se usar um resistor de 330ohms na entrada Vcc do primeiro 74959, economizando espaço e resistores.

    ResponderExcluir
    Respostas
    1. Lembrando que tem que alimentar a porta Vcc do chip com 5V. Para usar 12V tem que usar um redutor LM7805.

      Excluir
    2. Obrigado pelo elogio, Fernando!
      E valeu as dicas!
      Abraços!

      Excluir
  13. Obrigado pelo tutorial, sabe me dizer qual é o melhor extensor?

    O 74HC595 OU PCF8574AP

    Abraço

    ResponderExcluir
    Respostas
    1. Boa tarde!
      Não sei dizer qual seria o melhor, pois nunca usei o PCF8574AP. Uma boa dica para eu pegar isso pra testar! Mas o 74HC595 funciona muito bem!
      Abraços!

      Excluir
  14. Oi Felipe,as suas invensões são muito boas!mas aqui não consigo encontrar esses registradosres para comprar,será que pode me indicar

    ResponderExcluir
    Respostas
    1. Boa tarde!! Obrigado pelo elogio!!!
      http://www.eletrodex.com.br/8-bit-shift-register-74hc595n.html Tem disponível nessa loja. É confiável!
      Abraços!

      Excluir
  15. Boa Tarde, a tempos estou tentando ampliar as portas do ARDUINO E NADA, ja usei os dois Expansores de portas, o 74HC595 e o PCF8574A. Gostaria de saber se esse seu esquema eu poderia adaptar e controlar outras coisas, motores, etc

    Obrigado

    ResponderExcluir
    Respostas
    1. Boa tarde, Eduardo!
      Sim, dá sim!
      Dê uma olhada nesse post: http://www.efeitonerd.com.br/2012/09/ampliar-saidas-do-arduino-library.html
      Com a biblioteca fica mais fácil ainda controlar os CIs 74HC595. E vc utiliza como se fosse as portas do Arduino mesmo.
      Abraços!

      Excluir
  16. Amigo, qual esquema eu utilizo para a utilização de apenas 1 multiplexador? Posso ignorar as ligações das saídas digitais 8 e 12 do arduino e utilizar apenas a 11? Como ficariam as saídas ST_CP e SH_CP do 74HC595? Dessa forma, eu só precisaria colocar os 5V no 16 e no 10 e o GND no 8 e 13? E a saída 9 ficaria aberta ?

    ResponderExcluir
    Respostas
    1. Bom dia!
      Todas as ligações entre o Arduino e o primeiro registrador deve ser mantidas. Apenas as ligações feitas diretamente entre um registrador e outro, que você pode eliminar. E no fonte, setar a variável qtdRegistradores na função shiftWrite.
      Apenas isso.
      Abraços!

      Excluir
  17. uma coisa q ainda nao achei "procurando a 2 dias no google" eh como controlar apenas uma saida do shift, tem de tudo, um milhao de leds, lcd, cubos de leds, mas usar isso como realmente um EXTENSOR de portas, onde podemos controlalas individualmente como no duino, mandando a porta 0 ou 1, nao achei ate agora, nao vou usar o 74hc595 pra brincar de leds, quero algo mais para controlar as coisas, para expandir mesmo as portas dos meus duinos, e nao achei, e nao entendi nada ate agora q possa me ajudar nisso!!!

    ResponderExcluir
    Respostas
    1. Bom dia, Thiago!
      Seria isso? http://www.efeitonerd.com.br/2012/09/ampliar-saidas-do-arduino-library.html
      Controle individual de cada saída do shift.

      Excluir
  18. Bom dia Tiago e galera!
    Estou desenvolvendo um projeto com vinte e cinco servos MG995 com engrenagens de metal, estou pensando em alimenta-los como uma Lipo 2s 7,4V de 2200mah.

    Estou como dificuldades para distribuir essa alimentação para cada oito servos. Que estrutura física de fiação devo utilizar? Nunca trabalhei com essas baterias esei que a saída dessa bateria é bem melindrosa.
    Se poderem me ajudar agradeço de montão. Sou de Recife jcammorim@gmail.com

    ResponderExcluir