Postagem em destaque

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

Este post é o primeiro de uma série de seis que escrevi tratando de controle de potência e PID (controle proporcional, integral e derivativo...

sexta-feira, 2 de agosto de 2013

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".