Publicidade:

quinta-feira, 23 de julho de 2015

Arduino - Voltímetro com display de 7 Segmentos + 74hc595

No post anterior (aqui) mostrei como fazer um voltímetro com o Arduino utilizando displays de 7 segmentos. Para isso foi necessário utilizar 12 pinos do Arduino.

Visando reduzir a quantidade de pinos utilizados, alterei o circuito para trabalhar com o 74HC595, que é um expansor de portas bem útil (veja aqui outros exemplos desse CI).

O primeiro 74HC595 foi utilizado para acionar cada um dos 8 segmentos do display, enquanto que o segundo foi utilizado pra controlar qual dos displays será exibido a cada vez. Como no exemplo foi utilizado apenas 4 displays, sobraram 4 pinos do segundo 595, sendo possível expandir esse exemplo para até oito displays.

Para saber como fazer as ligações entre os dois expansores e o Arduino, veja o esquema abaixo.



Ligações entre Arduino / 74HC595

Arduino - pino 08 ---> 74HC595 - DS - DATA PIN        (Ligar apenas no primeiro 595)
Arduino - pino 09 ---> 74HC595 - STCP- LATCH PIN  (Ligar em todos os 595)
Arduino - pino 10 ---> 74HC595 - SHCP- CLOCK PIN (Ligar em todos os 595)

Ligações entre os 74HC595 e os Displays

PRIMEIRO 74HC595 - Q0 --> DP (segmento de ponto decimal)
PRIMEIRO 74HC595 - Q1 --> g
PRIMEIRO 74HC595 - Q2 --> f
PRIMEIRO 74HC595 - Q3 --> e
PRIMEIRO 74HC595 - Q4 --> d
PRIMEIRO 74HC595 - Q5 --> c
PRIMEIRO 74HC595 - Q6 --> b
PRIMEIRO 74HC595 - Q7 --> a

SEGUNDO 74HC595 - Q0 --> primeiro display
SEGUNDO 74HC595 - Q1 --> segundo display
SEGUNDO 74HC595 - Q2 --> terceiro display
SEGUNDO 74HC595 - Q3 --> quarto display
SEGUNDO 74HC595 - Q4..Q7 --> não utilizados (mas poderiam ser utilizados para gerenciar mais displays)

Verifique como ligar os demais pinos no esquema abaixo, ou verifique nesse site aqui.






Código-fonte:

/************************************************************************************************************
**********************************expansor 74hc595***********************************************************
************************************************************************************************************/

class Expansor74HC595 {
  private:
    int  _pin_clock;
    int  _pin_latch;
    int  _pin_data;
    int  _num_cis;
    byte* _pins;
    int  _auto_send;
  public:
    Expansor74HC595(int pin_clock, int pin_latch, int pin_data, int num_cis){
      _pin_clock        = pin_clock;
      _pin_latch        = pin_latch;
      _pin_data         = pin_data;
      _num_cis          = num_cis;
      _auto_send        = true;
      _pins             = new byte[_num_cis];
 
      pinMode(_pin_clock,OUTPUT);
      pinMode(_pin_latch,OUTPUT);
      pinMode(_pin_data, OUTPUT);
      clear();
    };
   
    void startWrite() {  _auto_send = false;  };
     
    void clear() { 
      for (int i=0; i<_num_cis; i++) {  _pins[i] = 0b00000000;  }
      send();  
    };
   
    int read(int pin)  { 
      if (pin >= _num_cis * 8) {return LOW;} 
      int pos = pin / 8;
      pin = pin % 8;
      return (_pins[pos] & (1 << pin)) != 0;
    };
   
    byte readByte(int num_ci) { return _pins[num_ci]; };
    
    void send(){
      digitalWrite(_pin_latch, LOW); 
      for(int i=_num_cis-1; i>=0; i--) {  shiftOut(_pin_data, _pin_clock, MSBFIRST, readByte(i) );  }
      digitalWrite(_pin_latch, HIGH);
      _auto_send = true;
       
    };
     
    void writeByte(int num_ci, byte b, int first = MSBFIRST) {  
      if (first == MSBFIRST){
        byte reversed;
        for(int i=0;i<8;i++){
          reversed |= ((b>>i) & 0b1)<<(7-i);
        }
        b = reversed;
      }
       
      _pins[num_ci] = b; 
      if (_auto_send) { send(); } 
    };
     
    void write(int pin, int value) {
      if (pin >= _num_cis * 8) { return; }
       
      int pos = pin / 8;
      pin     = pin % 8;
 
      if (value){
        _pins[pos] |= (1 << pin);  //set a bit HIGH
      } else {
        _pins[pos] &= ~(1 << pin); //set a bit LOW
      }
 
      if (_auto_send) { send(); }
    };
};
  
 
const int PIN_CLOCK = 10;   //SHCP
const int PIN_LATCH = 9;    //STCP
const int PIN_DATA  = 8;    //DS
 
Expansor74HC595 *exp1;

/************************************************************************************************************
**********************************fim expansor 74hc595*******************************************************
************************************************************************************************************/
  
/************************************************************************************************************
**********************************display de 7 segmentos*****************************************************
************************************************************************************************************/
const int  d7seg_595_index        = 0;   //em qual dos 595´s será usado pra armazenar os segmentos a, b, c, d, e, f, g e dp
const int  d7seg_595_pin_enable[] = {8,9,10,11};               //pinos do 595 para habilitar os displays
const byte d7seg_digits[]         = {B11111100, B01100000, B11011010, B11110010, B01100110, 
                                     B10110110, B10111110, B11100000, B11111110, B11110110};  //Babcdefg.  0--9

void d7seg_write(int digit, int pos, boolean point=false) {
  exp1->startWrite();
  exp1->write(d7seg_595_pin_enable[pos], HIGH);
  exp1->writeByte(d7seg_595_index, point ? d7seg_digits[digit] | (1 << 0) : d7seg_digits[digit], LSBFIRST);  // | (1 << 0) --> alterar o bit que representa o dp (ponto) do display. envia para o 595
  exp1->send();
  
  delay(1);   
  
  exp1->write(d7seg_595_pin_enable[pos], LOW);
}

void d7seg_write_number(float f, int decimals=0) {
  f = (f+0.000001) * pow(10, decimals);
  for(int i=0; i<sizeof(d7seg_595_pin_enable)/sizeof(int); i++) {  
    d7seg_write( (unsigned int)(f/pow(10, i)) % 10, i,  (i!=0)&&(decimals==i) );  
  }
}
/************************************************************************************************************
**********************************fim display de 7 segmentos*************************************************
************************************************************************************************************/

/************************************************************************************************************
**********************************voltimetro*****************************************************************
************************************************************************************************************/
const unsigned long r1   = 1000000;  //resistor de 1M
const unsigned long r2   = 100000;   //resistor de 100K
const unsigned int  aRef = 5;        //referencia de 5v
float               tensao = 0;      //tensao lida
unsigned long       millis_ref = 0;
const unsigned long time_refresh = 500; //faz nova leitura a cada 500 ms

float get_tensao(int pin){
  return (analogRead(pin) * aRef) / 1023.0 * ( (r1+r2)/r2 );
}
/************************************************************************************************************
**********************************fim voltimetro*************************************************************
************************************************************************************************************/

/************************************************************************************************************
**********************************setup/loop*****************************************************************
************************************************************************************************************/
void setup(){
  exp1   = new Expansor74HC595(PIN_CLOCK, PIN_LATCH, PIN_DATA, 2);
}  

void loop() {
  if ( (millis()-millis_ref) > time_refresh ) { //intervalo de tempo pra atualizar a leitura. 
    tensao = get_tensao(A0); //calculo da tensão lida
    millis_ref = millis();
  }
  float f = tensao;
  d7seg_write_number(f, f>=1000 ? 0 : (f>=100 ? 1 : (f>=10 ? 2 : 3) ) );  //de acordo com o numero, mostra 0, 1, 2 ou 3 casas decimais
}

/************************************************************************************************************
**********************************fim setup/loop*************************************************************
************************************************************************************************************/

Veja também: montagem dos 74hc595


8 comentários:

  1. Olá Fabiano!!!
    Primeiramente parabéns pelo post. Cara estou tendo dificuldade para enterpretar seu esquema elétrico. Você poderia me dar uma ajuda, principalmente nas ligações dos transistores, não entendi a ligação para o ci 74hc595. Eu já tenho conhecimento com eletronica, mas ainda não conheço integrado 74hc595. Se puder me mandar por email o esquema eletrico ta ai. e-mail: awnr.bios@gmail.com. Desde já agradeço.

    ResponderExcluir
  2. Gostaria de saber qual o limite de tensão. Vou fazer uma fonte 30Vcc ajustável, quero montar um voltimetro para indicar o valor de saída da mesma.

    ResponderExcluir
  3. Este comentário foi removido pelo autor.

    ResponderExcluir
  4. Fabiano, como você faz para castear os 74HC595 se o pino 14 (Data) do próximo CI vai ligado ao pino 9 do primeiro, sendo que esse pino Data precisa ser ligado ao Arduino ? O segundo módulo então nunca poderá ser o primeiro, certo ?

    ResponderExcluir
    Respostas
    1. somente o primeiro 595 que tem o pino 14 ligado ao arduino. os demais 595 têm sempre ligado o pino 14 ao pino 9 do 595 anterior... com isso pode-se ligar tantos cis quanto forem necessários.

      Excluir
    2. Pois é... mas se vc. quiser ligar um "segundo", como se fosse o "primeiro", não vai poder, ou seja, sempre terá um dos módulos que será considerado o "primeiro". Pensei em no lugar de 4 vias, fazer um barramento com 5 vias e um JUMPER para ligar o pino 14 ou ao pino 9 do próximo ou ao Arduino. Assim, ele poderá ser o primeiro ou segundo, ou terceiro... O que acha ?

      Excluir
    3. acho que funcionaria sim... mas eu só não consegui enxergar uma aplicação prática pra poder alterar qual dos CIs seria o primeiro.

      Excluir
    4. Imagina vários displays com dígitos grandes... cada um ligado ao seu próprio 74HC595....

      Excluir