Publicidade:

sexta-feira, 5 de junho de 2015

Arduino - 74HC595 e 74HC165 Juntos

Quando se fala em expansão de portas do Arduino, uma das possibilidades é fazer isso através desses dois CIs, o 74HC595 e o 74HC165. Pra quem ainda não os conhece, são dois CIs que com apenas três pinos do Arduino permitem expandir saídas (595) e entradas (165). Tanto um quanto o outro, permitem que sejam conectados vários CIs em cascata, o que dá a possibilidade de infinitas portas.

Datasheets aqui:

http://www.nxp.com/products/logic/shift_registers/74HC595N.html
http://www.nxp.com/products/logic/shift_registers/74HC165N.html

Pra quem quiser ver um exemplo de como expandir apenas saídas, utilizando apenas 74HC595, criei um classe que permite o uso de maneira bem facilitada, que pode ser visto nesse link aqui.

Nesse post de hoje, vou demonstrar como criar uma Classe no Arduino, que permita nos mesmos 3 pinos ligar 595 e 165 juntos, e serem acessados compartilhando os mesmos 3 pinos, Latch, Clock e Data (sim, o pino Data é o mesmo para entradas e saídas :D ).

Como meu foco é mais disponibilizar o código que facilite a programação, não vou entrar muito nos detalhes da implementação, mas vou deixar aqui o link para o site no qual me baseei para chegar nessa solução:

http://homepages.which.net/~paul.hills/Software/ShiftRegister/ShiftRegisterBody.html

A imagem abaixo foi retirado do site acima, e demonstra como fazer a ligação entre os CIs.


Obs: output enable (que é ligado ao pino 13 do 595) não precisa ser ligado ao Arduino. Os Pinos 13 dos 595s devem ser ligado diretamente ao Ground. Outro detalhes é que o pino identificado como Strobe no esquema acima, no arduino é identificado como Latch.

As principais regras ao ligar são:

 - Primeiro devem ser ligados os 595 e após o último 595, ligar os 165.
 - Não ligar os CIs intercalados.
 - Não há limites para quantidades de cada um, podendo ser apenas um ou outro. Mas para ser usado apenas um dos CIs, recomendo utilizar a classe só para 595, que mostrei acima. Em breve criarei uma classe ser usado apenas por 165.
 - Todas as entradas dos CIs 165 devem obrigatoriamente ser ligadas a resistores PULL DOWN ou PULL UP. Caso alguma entrada fique "em aberto" a entrada ficará flutuando, inclusive interferindo nas demais entradas do CI.

Para testar o circuito acima, montei o mesmo em uma protoboard, mas não liguei todas as saídas e entradas, pois deixaria o circuito muito poluído e com muitas conexões, então preferi focar nas ligações de conexões dos próprios componentes.



Mas para testar as saídas liguei apenas um led na protoboard, onde testo uma saída por vez, como poderá ser visto no vídeo que postarei em breve. Nos Caso das entradas, liguei algumas diretamente ao vcc e outras diretamente ao ground.

Identificação dos pinos

No exemplo acima, foi utilizado 4 cis, dois 595 e dois 165.

Cada um dos pinos é identificado por um número, começando de 0 (zero) e indo até a quantidade de CIs multiplicado por 8 menos 1. No nosso exemplo temos 32 pinos adicionais, sendo os pinos de 0 a 15 os pinos de saídas e os pinos de 16 a 31 os pinos de entradas.

Se for ligado um botão no último pino do ultimo CI 165, faremos a leitura da seguinte maneira:

  int valor = exp->read(31);

Já para leitura de todas as entradas de uma única vez de um determinado CI 165, faremos o seguinte:

  byte valor = exp->readByte(3);  //leitura de todos os bits do quarto CI 

Da mesma maneira que é possível fazer a leitura de um bit por vez ou vários de uma vez, é possível ainda fazer a escrita da mesma forma, utilizando os métodos write() e writeByte().   exemplo:

exp->writeByte(1, B00011001); ou 
exp->writeByte(1, B10011000, LSBFIRST); 

exp->read(9, HIGH); ou
exp->read(9, LOW); 

Tanto os métodos write, writeByte, read e readByte, manipulam apenas os dados que estão em cache na classe. Para que as leituras e escritas tenham efeito é necessário chamar o método update(). Ele é quem envia e recebe os dados para os CIs.

o método update() deve ser chamado antes de serem feitas as leituras das entradas, e após serem feitas as escritas nas saídas.

Vídeo:



Código-Fonte:

/*
Criado em 04/06/2015
 Por: 
   Fabiano A. Arndt 
   http://www.youtube.com/fabianoallex
   http://fabianoallex.blogspot.com.br
   fabianoallex@gmail.com
*/

/********************************************************************************************
*******************CLASSE Expansor74HC595_74HC165     INICIO*********************************
*********************************************************************************************/

class Expansor74HC595_74HC165 {
  private:
    int  _pin_clock;
    int  _pin_latch;
    int  _pin_data;
    byte* _pins_out;
    byte* _pins_in;
    int _num_cis_out;
    int _num_cis_in;
  public:
    Expansor74HC595_74HC165(int pin_clock, int pin_latch, int pin_data, int num_cis_out, int num_cis_in){
      _pin_clock = pin_clock;
      _pin_latch = pin_latch;
      _pin_data  = pin_data;
      
      _num_cis_out = num_cis_out;
      _num_cis_in  = num_cis_in;
      
      _pins_out    = new byte[num_cis_out];
      _pins_in     = new byte[num_cis_in];
      
      pinMode(_pin_clock,OUTPUT);
      pinMode(_pin_latch,OUTPUT);
      
      clear();
    }
   
    void clear(){
      for (int i=0; i<_num_cis_out; i++){
        _pins_out[i] = B00000000;
      }
      update();
    }
   
    void update(){
      digitalWrite(_pin_clock, LOW); 
      digitalWrite(_pin_latch, LOW); 
      digitalWrite(_pin_latch, HIGH);
      
      for(int i=max(_num_cis_in, _num_cis_out) * 8 - 1; i>=0;  i-- ) {   //max -->o for vai até o que tiver mais, ou entradas, ou saidas
        int pos = i / 8;
        int pin = 7-(i % 8);  
        
        if (i < _num_cis_in * 8){
          pinMode(_pin_data, INPUT);
          
          if ( digitalRead(_pin_data) ){
            _pins_in[pos] |= (1 << pin);  //set a bit HIGH
          } else { 
            _pins_in[pos] &= ~(1 << pin); //set a bit LOW
          }
        }
        
        if (i < _num_cis_out * 8){
          pinMode(_pin_data, OUTPUT);
          digitalWrite(_pin_data,   (_pins_out[pos] & (1 << pin)) != 0   );
        }        
        digitalWrite(_pin_clock, HIGH); 
        digitalWrite(_pin_clock, LOW); 
      }      
      digitalWrite(_pin_latch, LOW); 
      digitalWrite(_pin_latch, HIGH);
      pinMode(_pin_data, INPUT);
    }
    
    int read(int  pin){
      int pos = pin / 8;
      pin     = 7-(pin % 8);  
      
      if (pos > _num_cis_out) {
        pos = pos - _num_cis_out;
        return (  (_pins_in[pos] & (1 << pin)) != 0   );
      } else {
        return (  (_pins_out[pos] & (1 << pin)) != 0   );
      }
    }
    
    byte readByte(int num_ci) { 
      if (num_ci >= _num_cis_out) {
        num_ci = num_ci - _num_cis_out;
        return _pins_in[num_ci];
      } else {
        return _pins_out[num_ci];
      }
    }
    
    void write(int pin, int value){
      if (pin >= _num_cis_out*8) { return; }
      
      int pos = pin / 8;  //pos -> indica qual ci será atualizado.
      pin     = 7-(pin % 8);
 
      if (pos > _num_cis_out) {
        return; //se estiver tentando escrever um pino de entrada, apenas retorna, sem fazer nada.
      } else {
        if (value){
          _pins_out[pos] |= (1 << pin);  //set a bit HIGH
        } else {
          _pins_out[pos] &= ~(1 << pin); //set a bit LOW
        }
      }
    }
    
    void writeByte(int num_ci, byte b, int first = MSBFIRST) {  
      if (num_ci > _num_cis_out) {
        return; //se estiver tentando escrever um pino de entrada, apenas retorna, sem fazer nada.
      }
      
      if (first == LSBFIRST) {
        byte r=0;
        for(int i=0;i<8;i++) {
          r |= ((b>>i) & 0b1)<<(7-i);
        }
        b = r;
      }
       
      _pins_out[num_ci] = b; 
    } ;
};

/********************************************************************************************
*******************CLASSE Expansor74HC595_74HC165     FIM ***********************************
*********************************************************************************************/


const int PIN_CLOCK = 4; 
const int PIN_LATCH = 7; 
const int PIN_DATA  = 12; 

 
Expansor74HC595_74HC165 * exp1;
  
void setup() {
  exp1   = new Expansor74HC595_74HC165(PIN_CLOCK, PIN_LATCH, PIN_DATA, 2, 2);
  
  Serial.begin(9600);
}
  
void loop() {
  exp1->writeByte(0, B00000000);
  exp1->writeByte(0, B11001101, LSBFIRST);
  
  exp1->write(8, HIGH);
  exp1->write(9, HIGH);
  
  exp1->write(10, HIGH);
  exp1->write(11, HIGH);
  
  exp1->write(14, HIGH);
  exp1->write(15, !exp1->read(15));  //blink
  
  
    
  exp1->update();  //AS ESCRITAS DEVEM SER FEITAS ANTES DO UPDATE. E AS LEITURAS APOS O UPDATE
   
  Serial.println(exp1->readByte(0), BIN);  //LE O PRIMEIRO CI (595)
  Serial.println(exp1->readByte(1), BIN);  //LE O SEGUNDO CI (595)
  Serial.println(exp1->readByte(2), BIN);  //LE O TERCEIRO CI (165)
  Serial.println(exp1->readByte(3), BIN);  //LE O QUARTO CI (165)
  Serial.println("");
  
  delay(1000);
}

Um comentário:

  1. Boa Tarde,

    Os resistores são R1 10k e R2 47k?
    Na foto do esquema montado parece que vc usou outros valores..

    ResponderExcluir