Publicidade:

sexta-feira, 25 de setembro de 2015

Arduino - Alterações na biblioteca LedControl

Algumas alterações feitas na biblioteca LedControl.

Quando usamos repetidamente o método setLed da biblioteca LedControl, percebemos um atraso na atualização dos displays (como pode ser visto no vídeo abaixo). Isso acontece, pois a cada chamada de setLed, é feito o envio do status de todos os leds do display, inclusive, os que não tiveram alterações, o que compromete muito a eficiência do código.

Para melhorar a performance da biblioteca foi incluída uma nova funcionalidade, a qual permite atualizar os status dos leds sem enviar os dados para os registradores de deslocamento (Max7219), ou seja, as alterações são mantidas na memória, e depois do processamento terminado, os dados são, então, enviados todos de uma única vez aos registradores. Essa funcionalidade se chama "Auto Send". 

Por default a biblioteca funciona da mesma forma que é originalmente, com o auto send igual a true, ou seja, cada chamada a clear(), setLed(), setRow() ou setColumn() continua enviando os dados aos registradores. Mas caso o programador queira fazer um conjunto de alterações nos leds e só enviar as informações para os registradores após todas as alterações estarem prontas, deve-se então, usar o método startWrite().

Depois de chamado startWrite(), os dados serão alterados mas apenas na memória e só serão enviados aos registradores através de um outro método que foi criado. O método send().

No código-fonte a baixo, vemos o uso desses dois métodos, na função update_display. Como pode ser visto, antes de iniciar o processamento dos dados, é feita uma chamada a startWrite(), e ao final uma chamada a send().


void update_displays() {
  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) {
          lc.setLed(i, l, c, (l+c+cont)%2 );
        }
      }
    }
  }
  
  cont++;
  lc.send();
}





Observações: No código abaixo, foram removidas as funcionalidades voltadas ao uso de displays de 7 segmentos, pois não serão utilizados nos meu projetos futuros, mas nada impede que sejam inclusos novamente.

Código-fonte:

/*************************************************************************************************************
*******************************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 {
  private :
    byte spidata[16];
    byte * status;
    int SPI_MOSI;
    int SPI_CLK;
    int SPI_CS;
    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;
      
      digitalWrite(SPI_CS,LOW);
      for(int i=maxbytes;i>0;i--) { shiftOut(SPI_MOSI,SPI_CLK,MSBFIRST,spidata[i-1]); }
      digitalWrite(SPI_CS,HIGH);
    }
      
  public:
    LedControl(int dataPin, int clkPin, int csPin, int numDevices) {
      _auto_send  = true;
      SPI_MOSI    = dataPin;
      SPI_CLK     = clkPin;
      SPI_CS      = csPin;
      maxDevices  = numDevices;
      
      pinMode(SPI_MOSI, OUTPUT);
      pinMode(SPI_CLK,  OUTPUT);
      pinMode(SPI_CS,   OUTPUT);
      digitalWrite(SPI_CS, HIGH);
      
      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; }
      
      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 4 is connected to the DataIn 
 pin 6 is connected to the CLK 
 pin 5 is connected to LOAD 
 */
LedControl lc=LedControl(4,6,5,2);

const int LINHAS  = 8;
const int COLUNAS = 16;

int cont=0;


void update_displays() {
  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) {
          lc.setLed(i, l, c, (l+c+cont)%2 );
        }
      }
    }
  }
  
  cont++;
  lc.send();
}


void setup() {
  lc.shutdown(0,false);
  lc.setIntensity(0,8);
  lc.clearDisplay(0);  
  lc.shutdown(1,false);
  lc.setIntensity(1,8);
  lc.clearDisplay(1);  
  

  
  Serial.begin(9600);
}

void loop() {
  update_displays();
  
  for(int i=0;i<LINHAS;i++){ 
    for(int j=0;j<COLUNAS;j++){ 
      Serial.print( (i+j)%2 );
      Serial.print(" ");
    } 
    Serial.println(" ");
  }
  Serial.println(" ");
  delay(2000);
  
}

Nenhum comentário:

Postar um comentário