Publicidade:

segunda-feira, 5 de outubro de 2015

Arduino - Max7219 e 74HC595 Juntos + Attiny85

Nesse Artigo vou explicar um pouco dos detalhes de como implementei o código para poder controlar o Max7219 junto com o 74HC595, os quais mostrei dois vídeos na página do facebook.



74hc595 e Max7219 juntos no mesmo barramento.



Agora rodando em um attiny85.74hc595 e Max7219 juntos no mesmo barramento.






Apesar de a ideia não ser entrar em detalhes do que são e como funcionam Registradores de Deslocamento, vou deixar aqui um trecho do que a wikipedia diz sobre eles:

Em eletrônica digital um registrador de deslocamento é um conjunto de registradores configurados em um arranjo linear de tal forma que a informação é deslocada pelo circuito conforme o mesmo é ativado.
Os registradores de deslocamento podem possuir uma combinação de entradas e saídas seriais e paralelas, incluindo as configurações entrada serial, saída paralela (SIPO) e entrada paralela, saída serial (PISO). Existem outra configurações possuindo ambas as entradas serial e paralela e outra com saídas serial paralela. Existem também registradores de deslocamento bi-direcionais, os quais permitem que se varie a direção do deslocamento da informação. As entradas e saídas seriais de um registrador podem ser conectadas juntas, de modo a formar um registrador de deslocamento circular. Poderiam também ser desenvolvidos registradores de deslocamento multi-dimensionais, os quais podem realizar processamentos mais complexos. Mais informações, aqui.

Dois exemplos de Registradores de Deslocamento são o Max7219 e o 74HC595, cada um com uma finalidade diferente. Enquanto o 595 é usado apenas para expandir saídas, o Max7219 tem o objetivo de servir como driver para display de 7 segmentos e matriz de Leds 8x8. Apesar de terem suas diferenças, a comunicação entre os dois é basicamente a mesma, com a pequena diferença de que o 595 possui 8 bits de Saída, enquanto que o Max7219 possui 16.

Também não vou entrar em maiores detalhes de como cada um funciona, mas pra quem quiser mais informações, seguem os links para os datasheets:

https://www.sparkfun.com/datasheets/Components/General/COM-09622-MAX7219-MAX7221.pdf
http://www.nxp.com/documents/data_sheet/74HC_HCT595.pdf

Aqui no blog mesmo, há várias postagens sobre o 74HC595: http://fabianoallex.blogspot.com.br/search?q=74HC595

A grande vantagem dos Registradores de Deslocamento é que eles podem ser ligados em cascata e sem um limite de quantidade. Ambos possuem 3 pinos de comunicação, clock e data, além do Load no max7219 e o seu equivalente Latch para o 74HC595.

Fisicamente não há grandes dificuldades na comunicação entre eles, uma estudada sobre como são as ligações de ambos dará pra entender (instintivamente) como liga-los juntos. Mas no caso específico que mostro aqui, há algumas regras. Foi necessário ligar primeiramente os Max7219, e por último os 595, nunca intercalando um com o outro.

Programação


A parte que deu mais trabalho foi a parte de programação, já que a ideia foi reutilizar as classes já existentes para controle de ambos, no caso do Max 7219 a biblioteca LedControl, e do 74HC595, utilizar uma classe que já disponibilizei aqui no blog ( veja ). Eu poderia criar uma classe do zero e recriar todas as funcionalidades nessa única classe, mas achei que seria retrabalho, então a ideia foi fazer algo que unisse a funcionalidade das duas.

As explicações dadas daqui pra baixo irão exigir um conhecimento básico de conceitos de Orientação a Objetos. Já fiz um vídeo falando algumas coisas sobre o assunto: http://fabianoallex.blogspot.com.br/2014/09/arduino-dicas-de-programacao-04.html

Ambas as classes agora precisam funcionar de maneira unificada. Quando os dados de qualquer uma das duas for atualizado, será necessário envia-los para todos os CIs que estão ligados em cascata e não apenas a que foi alterada. Pra isso foi necessário criar uma terceira classe que controlasse o envio dos dados para os registradores, a qual chamei de ShiftRegisterController.

A finalidade dessa classe é gerenciar o envio dos dados para os CIs. Porém ainda há um outro detalhe, foi necessário criar uma outra classe que fosse a classe-base para LedControl e para a classe Expansor74HC595, de modo que as duas herdem as mesmas funcionalidades básicas.


class ShiftRegisterController; //prototipo

class ShiftRegister{
  protected:
    ShiftRegisterController * _controller;
  public:
    virtual void shiftOutRegister() ;
};

class ShiftRegisterController {
  private:
    int             _pin_latch;  // ou load no max7219
    ShiftRegister * _exp_595;
    ShiftRegister * _exp_lc;
  public:
    ShiftRegisterController(int pin_latch)      { 
      _pin_latch = pin_latch; 
      pinMode(_pin_latch,OUTPUT);
      digitalWrite(_pin_latch, HIGH);
    }  
    
    void setLedControl(ShiftRegister * lc)      { _exp_lc  = lc;          }
    void setExp74HC595(ShiftRegister * exp_595) { _exp_595 = exp_595;     }
    
    void shiftOutRegisters() {
      if (_exp_595 && _exp_lc){
        digitalWrite(_pin_latch, LOW); 
        _exp_595->shiftOutRegister();
        _exp_lc ->shiftOutRegister();
        digitalWrite(_pin_latch, HIGH);
      }
    } 
};


Além da inclusão dessas novas classes, foram feitas alterações nas definições das classes já existentes, indicando que as mesmas, agora serão herdadas de ShiftRegister:

class Expansor74HC595 : public ShiftRegister {...};
class LedControl : public ShiftRegister {...};

Podemos ver que há um atributo chamado _pin_latch na classe ShiftRegisterController, que anteriormente ficava nas classes LedControl e Expansor74HC595, pois é através desse pino que todos os CIs são "notificados" que as alterações estão prontas e devem ser aplicadas as suas respectivas saídas, logo, as duas classes citadas não controlam mais quando os dados são finalizados, ficando essa função para a classe  ShiftRegisterController.

Observação: Pra não ter que fazer essas alterações diretamente na biblioteca LedControl, eu copiei todo o conteúdo da classe dentro da própria sketch e fiz as alterações necessárias, como pode ser visto no código completo mais abaixo. Em outro artigo eu já mostrei como fazer isso, incluindo algumas melhorias na classe LedControl, a quais explico nesse artigo: http://fabianoallex.blogspot.com.br/2015/09/arduino-alteracoes-na-biblioteca.html

O código abaixo mostra como devem ser declarados os objetos, que são 3.

int const PIN_DATA = 10;
int const PIN_CLK = 9;
int const PIN_LATCH = 8;
int const QUANTIDADE_MAX7219 = 2;
int const QUANTIDADE_74HC595 = 1;

ShiftRegisterController exp_src = ShiftRegisterController(PIN_LATCH);
LedControl      exp_lc  = LedControl     (PIN_DATA,PIN_CLK,QUANTIDADE_MAX7219, &exp_src);
Expansor74HC595 exp_595 = Expansor74HC595(PIN_DATA,PIN_CLK,QUANTIDADE_74HC595 , &exp_src);

Primeiramente foi necessário criar o objeto controlador e posteriormente criar os outros dois Objetos, um LedControl e outro Expansor74HC595. Veja que o primeiro objeto recebeu como parâmetro o PIN_LATCH, enquanto que as demais classes não recebem mais esse parâmetro, recebendo apenas o pino de clock e o pino de data, porém recebem como parâmetro o endereço do objeto controlador.

Código-Fonte - Arduino Uno:

/*
Criado em 04/10/2015
 Por: 
   Fabiano A. Arndt 
   http://www.youtube.com/fabianoallex
   http://fabianoallex.blogspot.com.br
   fabianoallex@gmail.com
*/
/*
 *    LedControl.h / LedControl.cpp - A library for controling Leds with a MAX7219/MAX7221
 *    Copyright (c) 2007 Eberhard Fahle
 * 
 *    Permission is hereby granted, free of charge, to any person
 *    obtaining a copy of this software and associated documentation
 *    files (the "Software"), to deal in the Software without
 *    restriction, including without limitation the rights to use,
 *    copy, modify, merge, publish, distribute, sublicense, and/or sell
 *    copies of the Software, and to permit persons to whom the
 *    Software is furnished to do so, subject to the following
 *    conditions:
 * 
 *    This permission notice shall be included in all copies or 
 *    substantial portions of the Software.
 * 
 *    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 *    OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 *    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 *    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 *    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 *    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 *    OTHER DEALINGS IN THE SOFTWARE.
 */
/*************************************************************************************************************
*******************************CLASSES ShiftRegister E ShiftRegisterController********************************
**************************************************************************************************************/

class ShiftRegisterController; //prototipo

class ShiftRegister{
  protected:
    ShiftRegisterController * _controller;
  public:
    virtual void shiftOutRegister() ;
};

class ShiftRegisterController {
  private:
    int             _pin_latch;
    ShiftRegister * _exp_595;
    ShiftRegister * _exp_lc;
  public:
    ShiftRegisterController(int pin_latch)      { 
      _pin_latch = pin_latch; 
      pinMode(_pin_latch,OUTPUT);
      digitalWrite(_pin_latch, HIGH);
    }  
    
    void setLedControl(ShiftRegister * lc)      { _exp_lc  = lc;          }
    void setExp74HC595(ShiftRegister * exp_595) { _exp_595 = exp_595;     }
    
    void shiftOutRegisters() {
      if (_exp_595 && _exp_lc){
        digitalWrite(_pin_latch, LOW); 
        _exp_595->shiftOutRegister();
        _exp_lc ->shiftOutRegister();
        digitalWrite(_pin_latch, HIGH);
      }
    } 
};

/*************************************************************************************************************
***************************FIM CLASSES ShiftRegister E ShiftRegisterController********************************
**************************************************************************************************************/

/*************************************************************************************************************
*******************************EXPANSOR 74HC595***************************************************************
**************************************************************************************************************/
class Expansor74HC595 : public ShiftRegister {
  private:
    int  _pin_clock;
    int  _pin_data;
    int  _num_cis;
    byte* _pins;
    int  _auto_send;
  public:
    Expansor74HC595(int pin_data, int pin_clock, int num_cis,  ShiftRegisterController * controller){
      _pin_clock  = pin_clock;
      _pin_data   = pin_data;
      _num_cis    = num_cis;
      _auto_send  = true;
      _pins       = new byte[_num_cis];
      _controller = controller;
      
      _controller->setExp74HC595(this);
 
      pinMode(_pin_clock,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 shiftOutRegister(){  for(int i=_num_cis-1; i>=0; i--) {  shiftOut(_pin_data, _pin_clock, MSBFIRST, readByte(i) );  }  };
    
    void send(){
      _controller->shiftOutRegisters();
      _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(); }
    };
};

/*************************************************************************************************************
*******************************FIM 74HC595********************************************************************
**************************************************************************************************************/



/*************************************************************************************************************
*******************************LEDCONTROL ALTERADA************************************************************
**************************************************************************************************************/
 
//the opcodes for the MAX7221 and MAX7219
#define OP_DECODEMODE  9
#define OP_INTENSITY   10
#define OP_SCANLIMIT   11
#define OP_SHUTDOWN    12
#define OP_DISPLAYTEST 15
 
class LedControl : public ShiftRegister {
  private :
    byte spidata[16];
    byte * status;
    int SPI_MOSI;
    int SPI_CLK;
    int maxDevices;
    int _auto_send;
     
    void spiTransfer(int addr, volatile byte opcode, volatile byte data) {
      int offset   = addr*2;
      int maxbytes = maxDevices*2;
      for(int i=0;i<maxbytes;i++)  { spidata[i]=(byte)0; }
      spidata[offset+1] = opcode;
      spidata[offset]   = data;
      
      _controller->shiftOutRegisters();
      
    }
  public:
    void shiftOutRegister(){ for(int i=maxDevices*2;i>0;i--) { shiftOut(SPI_MOSI,SPI_CLK,MSBFIRST,spidata[i-1]); } };
  
    LedControl(int dataPin, int clkPin, int numDevices,  ShiftRegisterController * controller) {
      _auto_send  = true;
      SPI_MOSI    = dataPin;
      SPI_CLK     = clkPin;
      maxDevices  = numDevices;
      
      _controller = controller;
      _controller->setLedControl(this);
       
      pinMode(SPI_MOSI, OUTPUT);
      pinMode(SPI_CLK,  OUTPUT);
       
      status      = new byte[maxDevices * 8]; //instancia o array de acordo com a quantia de displays usados
      for(int i=0;i<maxDevices * 8 ;i++) { status[i]=0x00; }
      
    }
    
    void begin(){
      for(int i=0;i<maxDevices;i++) {
        spiTransfer(i, OP_DISPLAYTEST,0);
        setScanLimit(i, 7);               //scanlimit is set to max on startup
        spiTransfer(i, OP_DECODEMODE,0);  //decode is done in source
        clearDisplay(i);
        shutdown(i,true);                 //we go into shutdown-mode on startup
      }
    }
     
    void startWrite() {  _auto_send = false;  };
     
    void send() {
      for (int j=0; j<maxDevices; j++) {
        int offset = j*8;
        for(int i=0;i<8;i++) { spiTransfer(j, i+1, status[offset+i]); }
      }
      _auto_send = true;
    }
     
    int getDeviceCount(){ return maxDevices; }
     
    void shutdown(int addr, bool b){
      if(addr<0 || addr>=maxDevices) return;
      spiTransfer(addr, OP_SHUTDOWN, b ? 0 : 1);
    }
     
    void setScanLimit(int addr, int limit){
      if(addr<0 || addr>=maxDevices) return;
      if(limit>=0 && limit<8) spiTransfer(addr, OP_SCANLIMIT,limit);
    }
     
    void setIntensity(int addr, int intensity) {
      if(addr<0 || addr>=maxDevices)   {  return;                                    }
      if(intensity>=0 && intensity<16) {  spiTransfer(addr, OP_INTENSITY, intensity); }
    }
     
    void clearDisplay(int addr){
      if(addr<0 || addr>=maxDevices) return;
       
      int offset = addr*8;
      for(int i=0;i<8;i++) {
        status[offset+i] = 0;
        if (_auto_send) { spiTransfer(addr, i+1, status[offset+i]); }
      }
    }
     
    void setLed(int addr, int row, int column, boolean state) {
      if(addr<0 || addr>=maxDevices)             { return; }
      if(row<0 || row>7 || column<0 || column>7) { return; }
       
      int offset = addr*8;
      byte val = B10000000 >> column;
       
      if(state) { status[offset+row] = status[offset+row] | val; }
      else {
        val=~val;
        status[offset+row] = status[offset+row]&val;
      }
       
      if (_auto_send) { spiTransfer(addr, row+1, status[offset+row]); }
    }
     
    void setRow(int addr, int row, byte value) {
      if(addr<0 || addr>=maxDevices) return;
      if(row<0 || row>7) return;
      int offset = addr*8;
      status[offset+row] = value;
      if (_auto_send) {
        spiTransfer(addr, row+1, status[offset+row]);
      }
    }
     
    void setColumn(int addr, int col, byte value) {
      if(addr<0 || addr>=maxDevices) return;
      if(col<0 || col>7)             return;
       
      byte val;
      for(int row=0; row<8; row++) {
        val=value >> (7-row);
        val=val & 0x01;
        setLed(addr,row,col,val);
      }
    }
};
/*************************************************************************************************************
*******************************FIM LEDCONTROL ALTERADA********************************************************
**************************************************************************************************************/
 

/*
 pin 10 is connected to the DataIn 
 pin 9 is connected to the CLK 
 pin 8 is connected to LOAD 
 */
 
int const PIN_DATA = 10;
int const PIN_CLK = 9;
int const PIN_LATCH = 8;
int const QUANTIDADE_MAX7219 = 2;
int const QUANTIDADE_74HC595 = 1;
 
ShiftRegisterController exp_src = ShiftRegisterController(PIN_LATCH);
LedControl      exp_lc  = LedControl     (PIN_DATA,PIN_CLK,QUANTIDADE_MAX7219, &exp_src);
Expansor74HC595 exp_595 = Expansor74HC595(PIN_DATA,PIN_CLK,QUANTIDADE_74HC595 , &exp_src);
const int LINHAS  = 8;
const int COLUNAS = 16;
 
int cont=0;
 
 
void update_displays() {
  exp_lc.startWrite();
   
  for (int lin=0; lin<8; lin++) {
    for (int col=0; col<16; col++) {
      for (int i=0; i<2; i++) {
        int l = lin;
        int c = col - (i*8); 
         
        if (l>=0 && l<=7 && c>=0 && c<=7) {
          exp_lc.setLed(i, l, c, (l+c+cont)%2 );
        }
      }
    }
  }
   
  cont++;
  exp_lc.send();
}
  
void setup() {
  //Serial.begin(9600);
  
  exp_lc.begin();
  exp_lc.shutdown(0,false);
  exp_lc.setIntensity(0,8);
  exp_lc.clearDisplay(0);  
  exp_lc.shutdown(1,false);
  exp_lc.setIntensity(1,8);
  exp_lc.clearDisplay(1);  
}
 
void loop() {
  
  for (byte b=0; b<=255; b++) {    //i=0-> B00000000   i=255-> B11111111
    exp_595.startWrite();
    exp_595.writeByte(0, b, LSBFIRST);
    exp_595.send();
  
    update_displays();
    
    delay(500);
  }
}


Código-fonte Attiny85:

/*
Criado em 04/10/2015
 Por: 
   Fabiano A. Arndt 
   http://www.youtube.com/fabianoallex
   http://fabianoallex.blogspot.com.br
   fabianoallex@gmail.com
*/ 
/*
 *    LedControl.h / LedControl.cpp - A library for controling Leds with a MAX7219/MAX7221
 *    Copyright (c) 2007 Eberhard Fahle
 * 
 *    Permission is hereby granted, free of charge, to any person
 *    obtaining a copy of this software and associated documentation
 *    files (the "Software"), to deal in the Software without
 *    restriction, including without limitation the rights to use,
 *    copy, modify, merge, publish, distribute, sublicense, and/or sell
 *    copies of the Software, and to permit persons to whom the
 *    Software is furnished to do so, subject to the following
 *    conditions:
 * 
 *    This permission notice shall be included in all copies or 
 *    substantial portions of the Software.
 * 
 *    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 *    OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 *    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 *    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 *    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 *    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 *    OTHER DEALINGS IN THE SOFTWARE.
 */
/*************************************************************************************************************
*******************************CLASSES ShiftRegister E ShiftRegisterController********************************
**************************************************************************************************************/
class ShiftRegisterController; //prototipo

class ShiftRegister{
  protected:
    ShiftRegisterController * _controller;
  public:
    virtual void shiftOutRegister() ;
};

class ShiftRegisterController {
  private:
    int             _pin_latch;
    ShiftRegister * _exp_595;
    ShiftRegister * _exp_lc;
  public:
    ShiftRegisterController(int pin_latch)      { 
      _pin_latch = pin_latch; 
      pinMode(_pin_latch,OUTPUT);
      digitalWrite(_pin_latch, HIGH);
    }  
    
    void setLedControl(ShiftRegister * lc)      { _exp_lc  = lc;          }
    void setExp74HC595(ShiftRegister * exp_595) { _exp_595 = exp_595;     }
    
    void shiftOutRegisters() {
      if (_exp_595 && _exp_lc){
        digitalWrite(_pin_latch, LOW); 
        _exp_595->shiftOutRegister();
        _exp_lc ->shiftOutRegister();
        digitalWrite(_pin_latch, HIGH);
      }
    } 
};


/*************************************************************************************************************
***************************FIM CLASSES ShiftRegister E ShiftRegisterController********************************
**************************************************************************************************************/


/*************************************************************************************************************
*******************************EXPANSOR 74HC595***************************************************************
**************************************************************************************************************/
class Expansor74HC595 : public ShiftRegister {
  private:
    int  _pin_clock;
    int  _pin_data;
    int  _num_cis;
    byte* _pins;
    int  _auto_send;
  public:
    Expansor74HC595(int pin_data, int pin_clock, int num_cis,  ShiftRegisterController * controller){
      _pin_clock  = pin_clock;
      _pin_data   = pin_data;
      _num_cis    = num_cis;
      _auto_send  = true;
      _pins       = new byte[_num_cis];
      _controller = controller;
      
      _controller->setExp74HC595(this);
 
      pinMode(_pin_clock,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 shiftOutRegister(){  for(int i=_num_cis-1; i>=0; i--) {  shiftOut(_pin_data, _pin_clock, MSBFIRST, readByte(i) );  }  };
    
    void send(){
      _controller->shiftOutRegisters();
      _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(); }
    };
};

/*************************************************************************************************************
*******************************FIM 74HC595********************************************************************
**************************************************************************************************************/



/*************************************************************************************************************
*******************************LEDCONTROL ALTERADA************************************************************
**************************************************************************************************************/
 
//the opcodes for the MAX7221 and MAX7219
#define OP_DECODEMODE  9
#define OP_INTENSITY   10
#define OP_SCANLIMIT   11
#define OP_SHUTDOWN    12
#define OP_DISPLAYTEST 15
 
class LedControl : public ShiftRegister {
  private :
    byte spidata[16];
    byte * status;
    int SPI_MOSI;
    int SPI_CLK;
    int maxDevices;
    int _auto_send;
     
    void spiTransfer(int addr, volatile byte opcode, volatile byte data) {
      int offset   = addr*2;
      int maxbytes = maxDevices*2;
      for(int i=0;i<maxbytes;i++)  { spidata[i]=(byte)0; }
      spidata[offset+1] = opcode;
      spidata[offset]   = data;
      
      _controller->shiftOutRegisters();
      
    }
  public:
    void shiftOutRegister(){ for(int i=maxDevices*2;i>0;i--) { shiftOut(SPI_MOSI,SPI_CLK,MSBFIRST,spidata[i-1]); } };
  
    LedControl(int dataPin, int clkPin, int numDevices,  ShiftRegisterController * controller) {
      _auto_send  = true;
      SPI_MOSI    = dataPin;
      SPI_CLK     = clkPin;
      maxDevices  = numDevices;
      
      _controller = controller;
      _controller->setLedControl(this);
       
      pinMode(SPI_MOSI, OUTPUT);
      pinMode(SPI_CLK,  OUTPUT);
       
      status      = new byte[maxDevices * 8]; //instancia o array de acordo com a quantia de displays usados
      for(int i=0;i<maxDevices * 8 ;i++) { status[i]=0x00; }
      
    }
    
    void begin(){
      for(int i=0;i<maxDevices;i++) {
        spiTransfer(i, OP_DISPLAYTEST,0);
        setScanLimit(i, 7);               //scanlimit is set to max on startup
        spiTransfer(i, OP_DECODEMODE,0);  //decode is done in source
        clearDisplay(i);
        shutdown(i,true);                 //we go into shutdown-mode on startup
      }
    }
     
    void startWrite() {  _auto_send = false;  };
     
    void send() {
      for (int j=0; j<maxDevices; j++) {
        int offset = j*8;
        for(int i=0;i<8;i++) { spiTransfer(j, i+1, status[offset+i]); }
      }
      _auto_send = true;
    }
     
    int getDeviceCount(){ return maxDevices; }
     
    void shutdown(int addr, bool b){
      if(addr<0 || addr>=maxDevices) return;
      spiTransfer(addr, OP_SHUTDOWN, b ? 0 : 1);
    }
     
    void setScanLimit(int addr, int limit){
      if(addr<0 || addr>=maxDevices) return;
      if(limit>=0 && limit<8) spiTransfer(addr, OP_SCANLIMIT,limit);
    }
     
    void setIntensity(int addr, int intensity) {
      if(addr<0 || addr>=maxDevices)   {  return;                                    }
      if(intensity>=0 && intensity<16) {  spiTransfer(addr, OP_INTENSITY, intensity); }
    }
     
    void clearDisplay(int addr){
      if(addr<0 || addr>=maxDevices) return;
       
      int offset = addr*8;
      for(int i=0;i<8;i++) {
        status[offset+i] = 0;
        if (_auto_send) { spiTransfer(addr, i+1, status[offset+i]); }
      }
    }
     
    void setLed(int addr, int row, int column, boolean state) {
      if(addr<0 || addr>=maxDevices)             { return; }
      if(row<0 || row>7 || column<0 || column>7) { return; }
       
      int offset = addr*8;
      byte val = B10000000 >> column;
       
      if(state) { status[offset+row] = status[offset+row] | val; }
      else {
        val=~val;
        status[offset+row] = status[offset+row]&val;
      }
       
      if (_auto_send) { spiTransfer(addr, row+1, status[offset+row]); }
    }
     
    void setRow(int addr, int row, byte value) {
      if(addr<0 || addr>=maxDevices) return;
      if(row<0 || row>7) return;
      int offset = addr*8;
      status[offset+row] = value;
      if (_auto_send) {
        spiTransfer(addr, row+1, status[offset+row]);
      }
    }
     
    void setColumn(int addr, int col, byte value) {
      if(addr<0 || addr>=maxDevices) return;
      if(col<0 || col>7)             return;
       
      byte val;
      for(int row=0; row<8; row++) {
        val=value >> (7-row);
        val=val & 0x01;
        setLed(addr,row,col,val);
      }
    }
};
/*************************************************************************************************************
*******************************FIM LEDCONTROL ALTERADA********************************************************
**************************************************************************************************************/
  
 
/*
 pin 2 is connected to the DataIn 
 pin 1 is connected to the CLK 
 pin 0 is connected to LOAD 
 */
 

int const PIN_DATA = 2;
int const PIN_CLK = 1;
int const PIN_LATCH = 0;
int const QUANTIDADE_MAX7219 = 2;
int const QUANTIDADE_74HC595 = 1;
 
ShiftRegisterController exp_src = ShiftRegisterController(PIN_LATCH);
LedControl      exp_lc  = LedControl     (PIN_DATA,PIN_CLK,QUANTIDADE_MAX7219, &exp_src);
Expansor74HC595 exp_595 = Expansor74HC595(PIN_DATA,PIN_CLK,QUANTIDADE_74HC595, &exp_src);

 
const int LINHAS  = 8;
const int COLUNAS = 16;
 
int cont=0;
 
 
void update_displays() {
  exp_lc.startWrite();
   
  for (int lin=0; lin<8; lin++) {
    for (int col=0; col<16; col++) {
      for (int i=0; i<2; i++) {
        int l = lin;
        int c = col - (i*8); 
         
        if (l>=0 && l<=7 && c>=0 && c<=7) {
          exp_lc.setLed(i, l, c, (l+c+cont)%2 );
        }
      }
    }
  }
   
  cont++;
  exp_lc.send();
}
 
 
void setup() {
  //Serial.begin(9600);
  exp_lc.begin();
  exp_lc.shutdown(0,false);
  exp_lc.setIntensity(0,8);
  exp_lc.clearDisplay(0);  
  exp_lc.shutdown(1,false);
  exp_lc.setIntensity(1,8);
  exp_lc.clearDisplay(1);  
}
 
void loop() {
  for (byte b=0; b<=255; b++) {                    //i=0-> B00000000   i=255-> B11111111
    exp_595.startWrite();
    exp_595.writeByte(0, b, LSBFIRST);
    exp_595.send();
 
    update_displays();
    
    delay(500);
  }  
}





Nenhum comentário:

Postar um comentário