Mais sobre displays de LED com 74HC595 - Parte II

Na parte inicial deste artigo, vimos a parte de hardware de uma montagem com 12 displays de LED conectados ao Arduino via três CIs 74HC595.

Agora vamos discutir os fontes da aplicação:

#include "Arduino.h"
/*****************************************************************
 Controle de "n" displays de LED 3x8 tipo Para Light A-573H 
 http://automatobr.blogspot.com.br
******************************************************************/

// Este programa funcionará com qualquer número de dígitos
#define nDigits 12 // número de dígitos a serem usados
#define nCIs    3  // número de CIs 595 existentes no
                   // circuito, no mínimo 2.

// pinos para comunicação com o CI 74HC595
#define latchPin 8
#define clockPin 12
#define dataPin  11 

/* máscara de bits para os dígitos, conforme diagrama abaixo:
     A 
    --- 
  F|   |B
   | G | 
    ---
  E|   |C
   | D | 
    --- *d
*/
byte digits[] = 
//  dGFEDCBA - segmentos
  {B00111111, // 0
   B00000110, // 1
   B01011011, // 2
   B01001111, // 3
   B01100110, // 4
   B01101101, // 5
   B01111101, // 6
   B00000111, // 7
   B01111111, // 8
   B01101111, // 9
   B10000000, // dot
   B00000000}; // blank  

// valor apresentado no display
uint64_t displayValue = 0;

// rotina que envia um byte para o 595 de maneira serial, 
// um bit de cada vez

void shiftOut(byte dataOut) 
{
  boolean pinState; 
// prepara o envio
  digitalWrite(dataPin, LOW); 
  digitalWrite(clockPin, LOW);
  for (int i=0; i<=7; i++) 
  { 
    digitalWrite(clockPin, LOW); 
// se o bit "i" está ligado, envia para o pino de dados um byte com 
// só o primeiro bit ligado (HIGH), se não, envia 0 (LOW)
    if ( dataOut & (1 << i) ) 
      pinState = HIGH;
    else 
      pinState = LOW;
// envia o bit
    digitalWrite(dataPin, pinState);
// informa ao chip que terminou o envio
    digitalWrite(clockPin, HIGH); 
    digitalWrite(dataPin, LOW);
  }
  digitalWrite(clockPin, LOW); 
}

// "desenha" um determinado dígito (digit) no display 
// (display). O número 1 é o menos significativo
// (primeiro da direita) e assim por diante.
void displayDigit(int display, int digit)
{
// primeiro montamos o endereço do display, quer dizer, 
// vamos indicar qual display será
// habilitado e mostrará o dígito.
  int data1, data2;
  if(display <= 8)
  {
    data1 = B00000001 << (8-display);
    data2 = B00000000;
  }
  else
  {
    data1 = B00000000;
    data2 = B00000001 << (16-display);
  } 
  // prepara o envio
  digitalWrite(latchPin, LOW);
  // envia o dígito para o CI 3
  shiftOut(digits[digit]);
  // envia o endereço (máscara de bits) indicando 
  // o display a ser ativado
  shiftOut(data1);
  // se tiver mais de 1 CI de endereçamento, envia 
  // a outra parte do endereço
  if (nCIs > 2)
    shiftOut(data2);
  // termina o envio
  digitalWrite(latchPin, HIGH);
}

// exibe um número inteiro
void display(uint64_t number)
{
    for (int i = 1;i <= nDigits && number != 0;i++) 
    {
      // pega o i-ésimo dígito
      int digit = number % 10LL;
      // envia para exibição
      displayDigit(i,digit);
      // trunca o número, eliminando o último 
      // dígito exibido
      number /= 10LL;
    }
}

void setup()
{
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin,  OUTPUT);  
  // "inverte" a máscara de bits, porque os displays são 
  // anodo comum => o bit "1" desliga o LED.
  // Se os seus displays forem catodo comum, 
  // delete as próximas duas linhas.
  for(int i=0; i < sizeof(digits)/sizeof(digits[0]);i++)
    digits[i]=~digits[i];
}

void loop()
{
  displayValue=188459823945LL;
  while(displayValue < 9999999999999LL)
  {
    display(displayValue);
    displayValue++;
  }
}

O fonte está todo comentado acima.

As constantes nDigits e nCIs servem para vc adaptar o programa ao seu circuito, informando quantos CIs 595 vc tem e o número de dígitos que vc usou. Para usar mais ou menos CIs (e dígitos, consequentemente) vc deve adaptar o circuito que publiquei, não é difícil. Se forem, por exemplo, seis displays, vc pode usar 2 CIs, um para controlar os segmentos e outro para multiplexar (selecionar) os displays. Nesse caso a diferença é que vc não terá o CI 1 e consequentemente nenhuma de suas conexões e o pino de dados do CI 2 (pino 14) será conectado ao Arduino (pino 11). Mas nada impede que vc controle menos displays com algum CI sobrando, ou seja, os números são "quase" independentes ou seja: para controlar 10 displays vc é obrigado a ter no mínimo 3 CIs, já para controlar 4 displays apenas 2 são necessários, mas se vc tiver ligado 3 o programa funcionará.

Uma curiosidade desse sketch é que eu usei o tipo de dado uint64_t, que é um inteiro 64 bits suportado pelo Arduino. Usando-se esse tipo de dados podemos manipular um decimal até 20 dígitos.

É isso. Vou fazer ainda mais um post com outras brincadeiras com esse mesmo circuito.

Obrigado pela força do Euclides e do César, nosso "associado remoto".


Comentários

  1. Respostas
    1. Esse sketch não tem delay, quer dizer, ele funciona na velocidade máxima do Arduino.
      Vc pode por um delay, por exemplo, na função loop, dentro do while. Nesse caso o que vai atrasar é a troca de todos os números, ou seja, não será afetada a velocidade de cada dígito.
      Se vc quiser "atrasar" a exibição de cada dígito vc pode por o delay dentro do for da função displayDigit.

      Excluir
    2. Vc mora em Piracicaba? Eu vou bastante aí, a sede da minha empresa é em Pira. Vc sabe se tem algum grupo aí que se reúna para praticar robótica, Arduino etc?

      Excluir
    3. Olá Mauro,
      Moro aqui sim, porém vc acredita que até agora não encontrei nenhum grupo aqui!!!

      Esta semana estarei dando um mini-curso de arduino para meus alunos na Anhanguera, sou iniciante também neste assunto e os alunos só ouviram falar até agora sobre arduino, a maioria nem viu ao vivo, sabe apenas que existe por conta da internet.

      Excluir
    4. Eu tb já dei aula na Anhanguera Jacareí e usava muito o Arduino nas minhas aulas. Promovi inclusive uma guerra de robôs, evento que acontece até hoje por lá (tem um post aqui no blog sobre isso).

      Veja se consegue juntar uma turma a[i, praticar em grupo é muito mais divertido.

      Excluir
  2. Olá Mauro,

    Vlw pela dica, agora deu para entender um pouco melhor o que está acontecendo.
    Vamos ver então se vc consegue me ajudar.
    Primeiro: De acordo com o esquema montado pela parte I, as patas livres do CI 1 e 2 não fornecem nenhuma ddp, ou seja, o sistema não funciona.
    Segundo: Retirei o jumper de conexão do pino 9 do CI3 conectado no pino 14 do CI2, pois isto estava fechando o sistema, uma vez que o CI3 nesta situação reenvia os dados para o CI2 e conflita com os dados enviados pelo CI1.
    Terceiro: revendo um pouco mais o esquema, notei que, ao retirar o jumper da segunda questão, apenas os pinos 15, 1 e 2 do CI2 produziram ddp, porém os dígitos não apareceram de forma correta.

    Para facilitar a visualização, inseri um delay(1000) na função e produzi um video para lhe mostrar o único modo que o sistema utilizou.

    Neste link estão o Sketch, as imagens esquemáticas e o projeto fritzing do esquema apresentado na parte I e II.
    https://drive.google.com/a/derpiracicaba.com.br/?tab=mo#folders/0B2wsb4nZqhDWVG1Ydi1Hd3I4OGs


    PS.: Estou utilizando um display de 3 díg. com anodo comum.

    ResponderExcluir
    Respostas
    1. Márcio,

      Vou testar o seu problema amanhã à noite, que é quando terei tempo.
      Dou notícias.

      [],

      Mauro

      Excluir
  3. Olá Mauro, primeiramente queria lhe parabenizar pelo excelente tutorial, gostei muito da sua maneira de explicar o circuito e o funcionamento do CI.
    Bom, vamos lá...
    Dei uma estudada na sua programação e no seu circuito e percebi que os 12 dígitos que são exibidos nos displays são derivados da variável "displayValue". se a variável receber o valor 1, será exibido no display os seguintes dígitos "000000000001".
    Minha dúvida é a seguinte, teria como eu controlar cada display com uma variável diferente ??
    Exemplo:
    Temos 12 dígitos, eu gostaria que cada variável exibisse 2 dígitos.
    Nesse caso eu teria os 12 dígitos controlados por 6 variáveis.
    Não sei se estou sendo claro com minha dúvida, mas desde já agradeço a atenção

    Lucas

    ResponderExcluir
    Respostas
    1. Lucas,

      O jeito mais fácil de fazer isso é mesclar os valores num valor só. colocando em displayValue. Um exemplo, supondo que vc quer mostrar 10,20,30,40,50 e 60 no display, da esquerda prá direita:

      displayValue=60LL+50LL*100LL+40LL*10000LL+30LL*1000000LL+
      20LL*100000000LL+10LL*10000000000LL;

      O display deve mostrar 102030405060.

      Assim vc não precisa nem mexer no meu código do display.

      Não testei, não tenho mais a montagem, mas estou quaaaase certo que funciona. Se vc testar e funcionar, por favor avise cá.

      Excluir
    2. Olá Mauro, fiz as alterações conforme você me propôs, porém quando fui testar e montar na protoboard ocorre um erro parecido com o comentário que o Márcio deixou no seu blog.
      Eu estou utilizando um display com 2 dígitos, porém modifiquei as ligações dos segmentos do meu display pois são diferentes dos seus.
      Só que não forma os números de forma correta, e alguns segmentos ficam com o brilho diferente de outros (Tive uma leve sensação de um pequeno curto, porém refiz todas as ligações e o problema continua igual).
      Não consigo achar o problema, será que você poderia me dar uma mão =/ ?!?!?!

      Desde já agradeço de mais sua atenção.

      Atenciosamente,

      Lucas.

      Excluir
    3. Lucas/Márcio,

      O capacitor serve para evitar o flick que acontece quando a gente liga muitos LEDs ao mesmo tempo através do 595. Ele funciona como filtro de alta, eliminando qualquer pulso que ocorra no circuito.

      Quanto ao brilho diferente em cada LED, eu não sei te dizer porque isso ocorreria, afinal estão todos alimentados com a mesma tensão. Vc pode tentar ligar uma fonte externa (de no máximo 5V!) e testar. Observe que o ideal era haver um resistor de uns 220 ohms para cada segmento dos displays. Vc pode também experimentar colocar um resistor no terminal comum (anodo ou catodo, a depender do seu display) também de 220 ou 330 ohms e ver o que acontece, mas essa forma de ligar costuma produzir o efeito de ir atenuando o brilho à medida que mais segmentos vão sendo acesos. Às vezes é perceptível, às vezes não.

      Quanto a não formar números de forma correta leva a pensar que vc não ligou corretamente o display.

      Sugiro que vc faça programas mais simples e teste a ligação.

      Excluir
  4. Oi Lucas,

    Por questão de falta de tempo acabei não voltando na remontagem do projeto, contudo, procurando outras coisas no mercado livre, encontrei um link (http://produto.mercadolivre.com.br/MLB-535777347-74hc595-shift-register-para-matriz-rgb-_JM) em que a pessoa colocou um capacitor na porta de leitura do arduino com o terra, pode ser que o problema seja a questão de montagem mesmo pois nesta situação o capacitor acaba funcionando como filtro, correto?

    Abs.

    ResponderExcluir
  5. Olá Mauro/Márcio

    Fiz alguns testes e cheguei em algumas conclusões, vamos lá.
    Montei as ligações dos segmentos no CI de acordo com a tabela que você montou mas seguindo o datasheet do meu display, consegui formar os numero porém a ligação dos segmentos no CI ficaram da seguinte forma:

    Seg A ----- CI 3 porta 7
    Seg B ----- CI 3 porta 6
    Seg C ----- CI 3 porta 5
    Seg D ----- CI 3 porta 4
    Seg E ----- CI 3 porta 3
    Seg F ----- CI 3 porta 2
    Seg G ----- CI 3 porta 1

    Em sua tabela a ligação é assim:

    Seg A ----- CI 3 porta 15
    Seg B ----- CI 3 porta 1
    Seg C ----- CI 3 porta 2
    Seg D ----- CI 3 porta 3
    Seg E ----- CI 3 porta 4
    Seg F ----- CI 3 porta 5
    Seg G ----- CI 3 porta 6

    Outra observação que fiz foi que, quando eu coloco um delay de 10milisegundos em baixo da linha 103, os números aparecem nítidos sem que outros segmentos que não estão habilitados apareçam, porém se eu retiro o delay alguns segmentos acendem sem serem habilitados com um brilho menor.

    Outra observação que tive é que não está ocorrendo a multiplexação dos displays, qualquer uma das portas dos CIs 1 e 2 que eu ligue em um dos terminais comuns dos displays faz com que os dois displays acendam mostrando apenas o primeiro dígito da variável displayValue.

    Tenho a impressão que estou perto de corrigir esses erros, porém ainda não consegui acha-los, se vocês tiverem alguma noção de onde possa estar o erro agradeço a ajuda

    Um grande abraço,

    Lucas.

    ResponderExcluir
    Respostas
    1. Lucas,

      Pode-se se ligar os pinos das duas formas, porque na realidade precisamos de 7 portas para comandar os segmentos, certo? Qualquer das oito portas disponíveis servem para ligar os segmentos.

      Acontece que o meu programa está preparado para funcionar segundo a forma que eu indiquei de ligação, ou seja, é bem estranho que o meu programa funcione na sua ligação. O meu programa nem aciona a porta 7...

      Excluir
  6. Respostas
    1. anuela, que bom que vc gostou!

      Apareça de vez em quando prá ver as novidades.

      Abracadabraço,

      Mauro

      Excluir
  7. Olá Mauro,

    Resolvi voltar aqui no seu script, já desenvolvi vários com o deslocador 595, porém este seu ainda não consegui decifrar.

    Resolvi remontar com o projeto (enfim tive um breve tempinho pra isso - rsrsrs)
    realizando as diversas discussões que teve aqui porém não consegui chegar em um consenso.

    Acredito que possivelmente o problema esteja na sequencia de deslocamento ou na montagem da sequencia de leds (a,b,c...), mas já fiz diversas alterações e o que está original no site (inclusive a retirada da linha para catodo comum - meu tipo) é o que está funcionando melhor.

    Tem como dar uma olhadinha.

    As evidências estão no link do dropbox (https://www.dropbox.com/sh/gxxhu8vydce4b1q/AADBquvo3_Qr3sJ5HijvI7vVa?dl=0) .

    Abs.

    ResponderExcluir

Postar um comentário

Postagens mais visitadas deste blog

Controle PID de Potência em Corrente Alternada - Arduino e TRIAC - Parte III

Controle PID de Potência em Corrente Alternada - Arduino e TRIAC - Parte I

Dividindo um programa (sketch) do Arduino em mais de um arquivo