27 de out. de 2012

Expansão de I/O - 74HC595

Pessoal, continuando com os posts relacionados aos CI’s de expansão de I/O, apresento a vocês o CI 74HC595, tal como o CI 74LS164, consiste em um conversor serial paralelo de 8 bits (Shift Register) porém com características que ao meu ver o tornam muito mais interessante que o 74164.

74595

Uma das características que o tornam tão especial é o fato de possuir dois registradores para manuseio dos dados, sendo:

  • Shift Register
    Armazena as informações transferidas serialmente como registrador temporário, a cada pulso de clock no pino SRCLK este registrador é carregado bit a bit conforme o nível lógico disponível no pino SER (Entrada Serial).
  • Storage Register
    Este registrador é carregado com as informações disponíveis no registrador  Shift Register quando o pino RCLK é pulsado com um nível lógico alto (Latch), ou seja, podemos manusear o envio dos bits um a um e ao término habilitamos o latch. Isto nos trás uma vantagem enorme na simplificação do hardware, pois no caso do uso do 74164 teríamos que providenciar um mecanismo eletrônico que durante a atualização dos dados apagasse o display para evitar que a serialização fosse percebida.

Além desses dois registradores, o 74595 possui um pino que habilita a operação do mesmo (OE), sendo que quando garantimos um nível alto neste pino temos todas as saídas configuradas como tri-state, ou seja, não drena e nem fornece corrente alguma ao circuito, portando fica configurada como alta impedância.

Outra característica importante é que este CI é capaz de trabalhar com cargas de +- 6ma sendo suficiente para por exemplo, alimentarmos pequenos leds para uso em painéis de IHMs diretamente pelos I/Os do CI.

Lógica de operação:

Diagrama temporal

Aqui podemos observar o funcionamento deste CI passo a passo!


Exemplo de uso

Para exemplificar o uso deste componente, vamos criar uma aplicação junto a PK2Lab, que consiste num contador de 0 à 99 com o uso de dois displays de sete segmentos conectados aos shift registers 74595 em cascata (Daisy Chain), assim podemos criar posteriormente projetos maiores como por exemplo um relógio com horas, minutos e segundos… tendo apenas como limite a sua imaginação!

Esquema:

Esquema

Podemos observar que além dos pinos de alimentação, são utilizados apenas 3 pinos de I/O para controlar os dois displays, e mesmo aumentando a quantidade de CIs, continuamos utilizando apenas 3 pinos, esta é a grande vantagem de se utilizar a comunicação serial para transferência de dados.

DSC01053

Poderíamos ainda ter utilizado os pinos de Reset e Operational Enable para controlar mais algumas funcionalidades, porém no exemplo não foram implementadas ficando estas a cargo do leitor caso queira implementar.


Software

A parte de software deste exemplo já foi explorado anteriormente nos outros posts, apenas temos o acréscimo de um pino de latch que fará com que os dados previamente setados no Shift Register sejam transferidos para os pinos do CI acionando os segmentos dos displays.

Uma prática interessante que podemos adotar ao construir software é o cuidado utilizado ao criar nomes de variáveis dentro de funções, por exemplo, podemos criar uma função chamada Display() e utiliza-lá em muitos projetos com grande facilidade, basta apenas que as variáveis internas desta função utilizem características próprias da função de origem, neste exemplo podemos observar que foi criada a função SN74HC595() e todas as variáveis internas desta função começam com SN74HC595_ seguido do nome da variável propriamente dito, a primeira vista temos a impressão de que o programa fica carregado, porém, facilita muito o inter-relacionamento das variáveis como um todo.

Outro ponto interessante é a chamada recorrente de funções, na linha abaixo podemos ver que chamamos a função display() duas vezes dentro da função SN74HC595().

SN74HC595(Display(Unidade), Display(Dezena));

Com esta única linha de comando montamos os dois bytes referentes aos dígitos de dezena e unidade e enviamos serialmente essas informações.

/******************************************************************************

                      JL Audio Manutenção Eletrônica

Data: 10/2012
Autor: Jean Carlos
Projeto: Registrador de deslocamento SN74HC595
Microprocessador: PIC18F4520
Clock do processador: 8MHz
Estação de desenvolvimento: PK2Lab V 1.1
Compilador: MikroC PRO V 4.60.0.0
Versão atual: 1.0
Descrição:

          Demonstração do uso de shift register para expansão de I/O


*******************************************************************************/
// Inicializações do programa

// Configuração do LCD da placa PK2Lab V.1.1

sbit LCD_RS at RB2_bit;
sbit LCD_EN at RB3_bit;
sbit LCD_D4 at RB4_bit;
sbit LCD_D5 at RB5_bit;
sbit LCD_D6 at RB6_bit;
sbit LCD_D7 at RB7_bit;

sbit LCD_RS_Direction at TRISB2_bit;
sbit LCD_EN_Direction at TRISB3_bit;
sbit LCD_D4_Direction at TRISB4_bit;
sbit LCD_D5_Direction at TRISB5_bit;
sbit LCD_D6_Direction at TRISB6_bit;
sbit LCD_D7_Direction at TRISB7_bit;

//******************************************************************************
// Variáveis Globais

short Contador = 0;       // Variável para contagem de 0 a 99.
short Dezena   = 0, Unidade = 0;

#define Latch      PORTC.B0
#define Clock      PORTC.B1
#define Ser_Out  PORTC.B2

//******************************************************************************
// Rotinas Auxiliares
//******************************************************************************
// Driver de display de 7 segmentos, número a ser impresso é passado como
// argumento da função.

unsigned char Display(unsigned char no)
{
    unsigned char Pattern;
    unsigned char SEGMENT[] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,
                                                0x7D,0x07,0x7F,0x6F};

    Pattern = SEGMENT[no];             // Segmento a retornar
    return (Pattern);
}

void SN74HC595(char SN74HC595_Display1, char SN74HC595_Display2)
{
short SN74HC595_Aux;                 // Variável local de controle do laço for
for(SN74HC595_Aux = 0; SN74HC595_Aux < 8; SN74HC595_Aux ++)
    {
     if( SN74HC595_Display1 & 0b10000000)  Ser_Out = 1;// Máscara o sétimo bit
     else Ser_Out = 0;                      // e verifica se é zero ou um.
     SN74HC595_Display1 = SN74HC595_Display1 << 1; // Rotaciona o próximo bit
     Clock = 1;                                // Pulsa o clock para envio do bit
     Delay_us(1);
     Clock = 0;
    }
Ser_Out = 0;                               // Mantém a linha de dados em nivel baixo
 
  for(SN74HC595_Aux = 0; SN74HC595_Aux < 8; SN74HC595_Aux ++)
    {
     if( SN74HC595_Display2 & 0b10000000)  Ser_Out = 1;// Máscara o sétimo bit
     else Ser_Out = 0;                   // e verifica se é zero ou um.
     SN74HC595_Display2 = SN74HC595_Display2 << 1; // Rotaciona o próximo bit
     Clock = 1;                             // Pulsa o clock para envio do bit
     Delay_us(1);
     Clock = 0;
    }
Ser_Out = 0;                             // Mantém a linha de dados em nivel baixo
 
Latch = 1;
Delay_us(1);
Latch = 0;
}

 

//******************************************************************************
//Rotina Principal

void main()
{
TRISA    = 0b00000000;
PORTA  = 0b00000000;
TRISB    = 0b00000000;
PORTB  = 0b00000000;
TRISC    = 0b00000000;
PORTC  = 0b00000000;
TRISD    = 0b00000000;
PORTD  = 0b00000000;
TRISE    = 0b00000000;
PORTE  = 0b00000000;
ADCON1 = 0X0F;            // Entradas digitais.
OSCCON.B5 = 1;            // Ajusta oscilador interno para 8MHz
OSCCON.B4 = 1;            // Ajusta oscilador interno para 8MHz

Lcd_Init();
Lcd_Cmd(_Lcd_Cursor_Off);
Lcd_Cmd(_LCD_CLEAR);
Lcd_Out(1,1,"***  PK2Lab  ***");
Lcd_Out(2,1,"Shift  SN74HC595");
Sound_Init(&PORTE,0);
Sound_Play(1000,200);
Delay_ms(100);
Sound_Play(1000,200);

while(1)
{
Dezena  = Contador / 10;
Unidade = Contador % 10;
SN74HC595(Display(Unidade), Display(Dezena));
Delay_ms(200);
Contador ++;
if(Contador == 100)
   {
   Contador = 0;
   Sound_Play(1000,200);
   Delay_ms(100);
   Sound_Play(1000,200);
   Delay_ms(100);
   Sound_Play(1000,200);
   while(1){};          // Trava o programa até ser pressionado o reset
   }
  
}//while(1)
}//main


Download do código

Abaixo podemos observar os sinais de controle que foram capturados no analisador lógico, o primeiro sinal é referente ao pino de DADOS, o segundo é o clock e por fim temos o pino de habilitação de transferência(Latch) que é onde efetivamente carregamos os novos valores nos displays.

Analisando as informações podemos ver o número “00” no display, onde os dois pulsos baixos iniciais correspondem aos segmentos “g”  e “.” (ponto decimal) apagados e os outros segmentos acesos.

Analisador

Protótipo montado

Montagem

 

Vídeo do projeto

Bom pessoal, é isso, grande abraço a todos e ótimos projetos!!!

14 comentários:

  1. Ótimo post Jean! Sempre encontro informações valiosas neste blog...hehe. Parabéns!

    ResponderExcluir
  2. Muito Bom Sr. Jean, sou um dos adquirentes desta Placa e aconselho para quem quer desenvolver/aprender a manusear PIC devido a sua qualidade de construção e tbm a sua versatilidade.
    Grato !!

    ResponderExcluir
  3. parabéns Jean, acredito que irei aprender muito neste site, e com certeza ajudarei alguém e não esquecerei de comentar onde aprendi e o nome do prof., obrigado pela iniciativa, saúde e sucesso.....

    ResponderExcluir
  4. Boa tarde eu ja montei um circuito com 4 74HC595, com os led's funciona perfeita mente.
    só que tenho um problema. eu preciso acionar oito Reles de 5V.
    mas a corrente que ele manda para cada nova porta é muito fraca para os reles. tem como aumentar essa corrente que ele manda? ou usar alguma peça para poder aumentar essa corrente para 5v cada saida do 74HC595.?.... agradesso des de já....

    ResponderExcluir
  5. Olá Gustavo, o que você precisa na verdade é um driver de corrente, pois o CI não possui corrente suficiente para acionar um rele direto pelo seu pino, esse driver de corrente pode ser construido utilizando-se um transistor BC548 e um resistor de 1K em série na sua base, estes valores podem ser utilizados para reles com bobina alimentada em 5VCC, não pode esquecer de colocar um diodo em paralelo com o rele(roda livre), segue um exemplo...

    http://www.eletronica.com/acionando-rele-partir-de-saida-logica-arduino/

    ResponderExcluir
  6. Jean Carlos, cara só tenho a agradecer, quebrei muito a cabeça montando a programação de forma errada enviando os bytes da forma mais difícil mas aqui posso
    dizer que tive uma aula completa de como controlar o 74HC595 muito agradecido
    vou aprender muito com você, valeu

    ResponderExcluir
  7. Como acrescentar mais um digito no display para contar até 999

    ResponderExcluir
  8. Olá Valdir, para incluir mais um digito você pode expandir mais um 74HC595, porém, acredito ser mais interessante o uso de multiplexação de displays, aqui no blog você encontra este exemplo! Grande abraço!

    ResponderExcluir
  9. Olá Valdir, para incluir mais um digito você pode expandir mais um 74HC595, porém, acredito ser mais interessante o uso de multiplexação de displays, aqui no blog você encontra este exemplo! Grande abraço!

    ResponderExcluir
  10. ola jean vc pode me ajudar fazer um codigo com 3 display 7segmento,pra fazer um velocimetro pro meu jogo ets2

    ResponderExcluir
  11. vc tem whatsap pra gente conversar manda no meu e-mail obrigado

    ResponderExcluir
  12. Bom dia Jean, como faço para deixar todas as saídas em nível alto sem necessidade de microcontrolador? 74hc595

    ResponderExcluir
  13. Bom dia Jean, como faço para deixar todas as saídas em nível alto sem necessidade de microcontrolador? 74hc595

    ResponderExcluir