Publicidade:

quarta-feira, 14 de outubro de 2015

Arduino - LCD Progress Bar - Barra de Progresso

Eventualmente é necessário, em algumas aplicações, mostrar o progresso de determinado processamento, ou valores que variam dentro de um intervalo, como a leitura de potenciômetros ou coisas do gênero. Nesses casos é bem comum o uso de displays LCD.

Pra facilitar a inclusão de barras de progresso em displays LCD, criei uma classe chamada LCDProgressBar, que com poucas linhas é possível incluir uma ou mais barras de progresso, que podem, inclusive, serem mostradas ao mesmo tempo.

A ideia foi criar uma barra customizável, onde o programador indica a posição (linha e coluna) no display e o tamanho que a barra de progresso terá.

A Classe possui um método chamado setPerc(), o qual irá receber um valor que deverá estar entre 0 e 100. A barra será gerada de acordo com o valor passado como parâmetro, sendo que em 0 a barra não aparece e em 100 ela é completamente preenchida.


Vídeo da primeira versão:



vídeo da segunda versão:



código da primeira versão:

/*
Fabiano A. Arndt - 2015
www.youtube.com/user/fabianoallex
www.facebook.com/dicasarduino
fabianoallex@gmail.com
*/

#include <LiquidCrystal.h>

/*************************************************************************************************************
*******************************CLASSE LCD PROGRESS BAR********************************************************
**************************************************************************************************************/
byte c1[8] = {B10000,  B10000,  B10000,  B10000,  B10000,  B10000,  B10000,  B10000};
byte c2[8] = {B11000,  B11000,  B11000,  B11000,  B11000,  B11000,  B11000,  B11000};
byte c3[8] = {B11100,  B11100,  B11100,  B11100,  B11100,  B11100,  B11100,  B11100};
byte c4[8] = {B11110,  B11110,  B11110,  B11110,  B11110,  B11110,  B11110,  B11110};
byte c5[8] = {B11111,  B11111,  B11111,  B11111,  B11111,  B11111,  B11111,  B11111};

class LCDProgressBar {
  private:
    LiquidCrystal * _lcd;
    int _row;
    int _col;
    int _len;
    int _perc; /*0..100*/
  public:
    void createChars() {
      _lcd->createChar(0, c1);
      _lcd->createChar(1, c2);
      _lcd->createChar(2, c3);
      _lcd->createChar(3, c4);
      _lcd->createChar(4, c5);
    }
  
    LCDProgressBar(LiquidCrystal * lcd, int row, int col, int len) {
      _lcd = lcd;      _row = row;      _col = col;      _len = len;
    }
    
    void setPerc(int perc){
      _perc = perc;
      if (perc > 100) { _perc = 100; }
      if (perc < 000) { _perc = 000; }
      
      _lcd->setCursor(_col, _row);
      for (int i=0; i<(_len);i++) { _lcd->print(" "); }
      _lcd->setCursor(_col, _row);
      
      int bars  = 5 * _len * _perc / 100;
      int div   = bars / 5;  //divisao
      int resto = bars % 5;  //resto
      for (int i=0; i<div; i++)  { _lcd->write((byte)4);         }  //pinta todo o quadro
      if (resto > 0 )            { _lcd->write((byte)(resto-1)); }  //pinta o quadro com a quantidade de barras proporcional
    }
};
/*************************************************************************************************************
*******************************FIM CLASSE LCD PROGRESS BAR****************************************************
**************************************************************************************************************/


LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
LCDProgressBar lcdBar1(&lcd, 0, 8,  8); //inclui uma barra no lcd, primeira linha, coluna 8. tamanho 8
LCDProgressBar lcdBar2(&lcd, 1, 12, 4); //inclui outra barra no lcd, segunda linha, coluna 12. tamanho 4

void setup()   {
  Serial.begin(9600);
  lcdBar1.createChars();
  pinMode(44, OUTPUT);
  analogWrite(44, 255/6); //utilizado para aumentar o contraste
  lcd.begin(16, 2);
}

int i = 0;
int perc;

void loop() {
  lcd.setCursor(0, 0);
  int value = i % 100;
  perc = value/100.0 * 100;
  if (value < 010) {lcd.print("00");} else {
  if (value < 100) {lcd.print("0");}       }
  lcd.print(value);
  lcd.print("/");
  lcd.print(100);
  
  lcdBar1.setPerc(perc);  //atualização da primeira barra de progresso
  
  
  lcd.setCursor(0, 1);
  value = (i++) % 200;
  perc = value/200.0 * 100;
  if (value <= 010) {lcd.print("00");} else {
  if (value <  100) {lcd.print("0");}       }
  lcd.print(value);
  lcd.print("/");
  lcd.print(200);
  
  lcdBar2.setPerc(perc); //atualização da segunda barra de progresso
  
  delay(100);  
}




Código 01 da segunda versão :


/*
Fabiano A. Arndt - 2015
www.youtube.com/user/fabianoallex
www.facebook.com/dicasarduino
fabianoallex@gmail.com
*/
 
#include <LiquidCrystal.h>
 
/*************************************************************************************************************
*******************************CLASSE LCD PROGRESS BAR********************************************************
**************************************************************************************************************/
byte c1[8] = {B00000, B00000, B00000, B00000, B00000, B00000, B00000, B11111};
byte c2[8] = {B00000, B00000, B00000, B00000, B00000, B00000, B11111, B11111};
byte c3[8] = {B00000, B00000, B00000, B00000, B00000, B11111, B11111, B11111};
byte c4[8] = {B00000, B00000, B00000, B00000, B11111, B11111, B11111, B11111};
byte c5[8] = {B00000, B00000, B00000, B11111, B11111, B11111, B11111, B11111};
byte c6[8] = {B00000, B00000, B11111, B11111, B11111, B11111, B11111, B11111};
byte c7[8] = {B00000, B11111, B11111, B11111, B11111, B11111, B11111, B11111};
byte c8[8] = {B11111, B11111, B11111, B11111, B11111, B11111, B11111, B11111};
             
 
class LCDProgressBar {
  private:
    LiquidCrystal * _lcd;
    int _row;
    int _col;
    int _len;
    int _perc; /*0..100*/
  public:
    void createChars() {
      _lcd->createChar(0, c1);
      _lcd->createChar(1, c2);
      _lcd->createChar(2, c3);
      _lcd->createChar(3, c4);
      _lcd->createChar(4, c5);
      _lcd->createChar(5, c6);
      _lcd->createChar(6, c7);
      _lcd->createChar(7, c8);
    }
   
    LCDProgressBar(LiquidCrystal * lcd, int row, int col, int len) {
      _lcd = lcd;      _row = row;      _col = col;      _len = len;
    }
     
    void setPerc(int perc){
      _perc = perc;
      if (perc > 100) { _perc = 100; }
      if (perc < 000) { _perc = 000; }
       
      _lcd->setCursor(_col, _row);
      for (int i=0; i<(_len);i++) { _lcd->print(" "); }
      _lcd->setCursor(_col, _row);
       
      int bars  = (8+1) * _len * _perc / 100;
      int div   = bars / 8;  //divisao
      int resto = bars % 8;  //resto
      for (int i=0; i<div; i++)  { _lcd->write((byte)7);         }  //pinta todo o quadro
      if (resto > 0 )            { _lcd->write((byte)(resto-1)); }  //pinta o quadro com a quantidade de barras proporcional
    }
};
/*************************************************************************************************************
*******************************FIM CLASSE LCD PROGRESS BAR****************************************************
**************************************************************************************************************/
 
 
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
LCDProgressBar lcdBar1(&lcd, 0, 8,  8); //inclui uma barra no lcd, primeira linha, coluna 8. tamanho 8
LCDProgressBar lcdBar2(&lcd, 1, 12, 4); //inclui outra barra no lcd, segunda linha, coluna 12. tamanho 4
 
void setup()   {
  Serial.begin(9600);
  lcdBar1.createChars();
  pinMode(44, OUTPUT);
  analogWrite(44, 255/6); //utilizado para aumentar o contraste
  lcd.begin(16, 2);
}
 
int i = 0;
int perc;
 
void loop() {
  lcd.setCursor(0, 0);
  int value = i % 100;
  perc = value/100.0 * 100;
  if (value < 010) {lcd.print("00");} else {
  if (value < 100) {lcd.print("0");}       }
  lcd.print(value);
  lcd.print("/");
  lcd.print(100);
   
  lcdBar1.setPerc(perc);  //atualização da primeira barra de progresso
   
   
  lcd.setCursor(0, 1);
  value = (i++) % 200;
  perc = value/200.0 * 100;
  if (value <= 010) {lcd.print("00");} else {
  if (value <  100) {lcd.print("0");}       }
  lcd.print(value);
  lcd.print("/");
  lcd.print(200);
   
  lcdBar2.setPerc(perc); //atualização da segunda barra de progresso
   
  delay(100);  
}



Código 02 da segunda versão :


/*
Fabiano A. Arndt - 2015
www.youtube.com/user/fabianoallex
www.facebook.com/dicasarduino
fabianoallex@gmail.com
*/
 
#include <LiquidCrystal.h>
 
/*************************************************************************************************************
*******************************CLASSE LCD PROGRESS BAR********************************************************
**************************************************************************************************************/
byte c1[8] = {B00000, B00000, B00000, B00000, B00000, B00000, B00000, B11111};
byte c2[8] = {B00000, B00000, B00000, B00000, B00000, B00000, B11111, B11111};
byte c3[8] = {B00000, B00000, B00000, B00000, B00000, B11111, B11111, B11111};
byte c4[8] = {B00000, B00000, B00000, B00000, B11111, B11111, B11111, B11111};
byte c5[8] = {B00000, B00000, B00000, B11111, B11111, B11111, B11111, B11111};
byte c6[8] = {B00000, B00000, B11111, B11111, B11111, B11111, B11111, B11111};
byte c7[8] = {B00000, B11111, B11111, B11111, B11111, B11111, B11111, B11111};
byte c8[8] = {B11111, B11111, B11111, B11111, B11111, B11111, B11111, B11111};
             
 
class LCDProgressBar {
  private:
    LiquidCrystal * _lcd;
    int _row;
    int _col;
    int _len;
    int _perc; /*0..100*/
  public:
    void createChars() {
      _lcd->createChar(0, c1);
      _lcd->createChar(1, c2);
      _lcd->createChar(2, c3);
      _lcd->createChar(3, c4);
      _lcd->createChar(4, c5);
      _lcd->createChar(5, c6);
      _lcd->createChar(6, c7);
      _lcd->createChar(7, c8);
    }
   
    LCDProgressBar(LiquidCrystal * lcd, int row, int col, int len) {
      _lcd = lcd;      _row = row;      _col = col;      _len = len;
    }
     
    void setPerc(int perc){
      _perc = perc;
      if (perc > 100) { _perc = 100; }
      if (perc < 000) { _perc = 000; }
       
      _lcd->setCursor(_col, _row);
      for (int i=0; i<(_len);i++) { _lcd->print(" "); }
      _lcd->setCursor(_col, _row);
      
      int bars  = (8+1) * _len * _perc / 100.0;
      int div   = bars / 8.0;  //divisao
      int resto = bars % 8;  //resto
      Serial.println(div);
      for (int i=0; i<div; i++)  { _lcd->write((byte)7);         }  //pinta todo o quadro
      if (resto > 0 )            { _lcd->write((byte)(resto-1)); }  //pinta o quadro com a quantidade de barras proporcional
    }
};
/*************************************************************************************************************
*******************************FIM CLASSE LCD PROGRESS BAR****************************************************
**************************************************************************************************************/
 
 
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
LCDProgressBar lcdBar1(&lcd, 1, 0,  1); //inclui uma barra no lcd, segunda linha, coluna 0. tamanho 1
LCDProgressBar lcdBar2(&lcd, 1, 2, 1); //inclui outra barra no lcd, segunda linha, coluna 2. tamanho 1
LCDProgressBar lcdBar3(&lcd, 1, 4, 1); //inclui outra barra no lcd, segunda linha, coluna 4. tamanho 1
LCDProgressBar lcdBar4(&lcd, 1, 6, 1); //inclui outra barra no lcd, segunda linha, coluna 6. tamanho 1
LCDProgressBar lcdBar5(&lcd, 1, 8, 1); //inclui outra barra no lcd, segunda linha, coluna 8. tamanho 1
LCDProgressBar lcdBar6(&lcd, 1, 10, 1); //inclui outra barra no lcd, segunda linha, coluna 10. tamanho 1
LCDProgressBar lcdBar7(&lcd, 1, 12, 1); //inclui outra barra no lcd, segunda linha, coluna 12. tamanho 1
LCDProgressBar lcdBar8(&lcd, 1, 14, 1); //inclui outra barra no lcd, segunda linha, coluna 14. tamanho 1

 
void setup()   {
  Serial.begin(9600);
  lcdBar1.createChars();
  pinMode(44, OUTPUT);
  analogWrite(44, 255/6); //utilizado para aumentar o contraste
  lcd.begin(16, 2);
}
 
unsigned int i = 0;
int perc;
 
void loop() {
  lcd.setCursor(0, 0);
  lcd.print("1 2 3 4 5 6 7 8");
  lcd.setCursor(0, 1);
  
  int value = i % 100;
  perc = value/100.0 * 100;
  lcdBar1.setPerc(perc);  //atualização da primeira barra de progresso
  
  
  value = i % 10;
  perc = value/10.0 * 100;
  lcdBar2.setPerc(perc);  //atualização da segunda barra de progresso
  
  
  value = i % 50;
  perc = value/50.0 * 100;
  lcdBar3.setPerc(perc);  //atualização da terceira barra de progresso
  
  
  value = i % 300;
  perc = value/300.0 * 100;
  lcdBar4.setPerc(perc);  //atualização da quarta barra de progresso
   
  
  value = i % 240;
  perc = value/240.0 * 100;
  lcdBar5.setPerc(perc);  //atualização da quinta barra de progresso
  
  
  value = i % 140;
  perc = value/140.0 * 100;
  lcdBar6.setPerc(perc);  //atualização da sexta barra de progresso
  
  
  value = i % 30;
  perc = value/30.0 * 100;
  lcdBar7.setPerc(perc);  //atualização da setima barra de progresso
  
  
  value = (i++) % 180;
  perc = value/180.0 * 100;
  lcdBar8.setPerc(perc); //atualização da oitava barra de progresso
   
  delay(100);  
}


Atualizado 25/05/2016

Em um artigo sobre Rotary Encoder fiz alguns exemplos utilizando as barras de progresso e fiz algumas modificações em uma das barras mostradas aqui.

Veja o artigo aqui: http://fabianoallex.blogspot.com.br/2016/05/arduino-rotary-encoder.html

Vídeo:



Atualizado 27/05/2016

Implementei outra versão das barras de progresso, ela segue o padrão utilizado para mostrar o volume de um som ou a intensidade de um sinal sem fio.

Há duas possibilidades de uso, com altura=1 ou altura=2, que indicará se a barra ocupará uma ou duas linhas do display.

Vídeo:


Código-fonte:


/*
Fabiano A. Arndt - 2016
www.youtube.com/user/fabianoallex
www.facebook.com/dicasarduino
fabianoallex@gmail.com
*/
  
#include <LiquidCrystal.h>
 
/*************************************************************************************************************
************************************CLASSE ROTARY ENCODER*****************************************************
*************************************************************************************************************/
#define ROTARY_NO_BUTTON     255
   
struct RotaryEncoderLimits{
  int min;
  int max;
};
   
class RotaryEncoder {
  private:
    byte _pin_clk;
    byte _pin_dt;
    byte _pin_sw;
    volatile byte _num_results;
    volatile int _result;
    volatile int * _results;
    byte _index_result;
    RotaryEncoderLimits * _limits;
       
    boolean _a;
    boolean _b;
  public:
    RotaryEncoder(byte pin_clk, byte pin_dt, byte pin_sw = ROTARY_NO_BUTTON, byte num_results=1, RotaryEncoderLimits * limits=0){   //parametro do botao opcional
      _pin_clk = pin_clk;
      _pin_dt = pin_dt;
      _pin_sw = pin_sw;
      pinMode(_pin_clk, INPUT);
      pinMode(_pin_dt, INPUT);
      if (_pin_sw != ROTARY_NO_BUTTON){ 
        pinMode(_pin_sw, INPUT); 
        digitalWrite(_pin_sw, HIGH);
      }
      if (num_results == 0) { num_results = 1; }
      _num_results = num_results;
      _results = new int[_num_results];
      for (int i; i<_num_results; i++){ _results[i] = (limits) ? limits[i].min : 0; }
      _index_result = 0;
      _limits = limits;
      _a = false;
      _b = false;
    }
    byte getIndex() { return _index_result; }
    void next()     { _index_result++; if (_index_result >= _num_results) { _index_result = 0; } } 
    void update_a() {
      _result = 0;
      delay (1);
      if( digitalRead(_pin_clk) != _a ) { 
        _a = !_a;
        if ( _a && !_b ) { _result = -1; }
      }
      if (_results[_index_result]+_result >= _limits[_index_result].min && 
          _results[_index_result]+_result <= _limits[_index_result].max ) {
        _results[_index_result] += _result;
      }
    }
    void update_b() {
      _result = 0;
      delay (1);
      if( digitalRead(_pin_dt) != _b ) {  
        _b = !_b;
        if ( _b && !_a ) { _result = +1; }
      }
      if (_results[_index_result]+_result >= _limits[_index_result].min && 
          _results[_index_result]+_result <= _limits[_index_result].max ) {
        _results[_index_result] += _result;
      }
    }
    int read(){ return _result; }                                        //retorn -1, 0 ou 1.
    int getValue(int index=-1) {                                         //retorna o valor da variável corrente ou a passada como parametro
      if (index < 0 ){ return _results[_index_result]; }
      return _results[index];
    }
    void setValue(int value){ _results[_index_result] = value; }         //caso a variável inicializa em determinado valor diferente de zero, utilizar esse método.
    int buttonRead(){ return (_pin_sw == ROTARY_NO_BUTTON) ? LOW : digitalRead(_pin_sw); }
};
/*************************************************************************************************************
************************************FIM CLASSE ROTARY ENCODER*************************************************
*************************************************************************************************************/
  
/*************************************************************************************************************
*******************************CLASSE LCD PROGRESS BAR********************************************************
**************************************************************************************************************/
byte c0[8] = {B00000,  B00000,  B00000,  B00000,  B00000,  B00000,  B00000,  B10000 };
byte c1[8] = {B00000,  B00000,  B00000,  B00000,  B00000,  B00000,  B11000,  B11000 };
byte c2[8] = {B00000,  B00000,  B00000,  B00000,  B00011,  B00011,  B11011,  B11011 };
byte c3[8] = {B00000,  B00000,  B11000,  B11000,  B11000,  B11000,  B11000,  B11000 };
byte c4[8] = {B00011,  B00011,  B11011,  B11011,  B11011,  B11011,  B11011,  B11011 };
byte c5[8] = {B11000,  B11000,  B11000,  B11000,  B11000,  B11000,  B11000,  B11000 };
byte c6[8] = {B11011,  B11011,  B11011,  B11011,  B11011,  B11011,  B11011,  B11011 };
  
class LCDProgressBar {
  private:
    LiquidCrystal * _lcd;  //ponteiro para um objeto lcd
    int _row;
    int _col;
    int _perc; /*0..100*/
    int _heigh;
  public:
    void createChars() { _lcd->createChar(0, c0);  _lcd->createChar(1, c1);  _lcd->createChar(2, c2); _lcd->createChar(3, c3);  _lcd->createChar(4, c4);  _lcd->createChar(5, c5);  _lcd->createChar(6, c6);  }
    LCDProgressBar(LiquidCrystal * lcd, int row, int col, int heigh=1) { 
      _lcd = lcd; 
      _row = row; 
      _col = col; 
      _heigh = (heigh >= 2 && _row > 0) ? 2 : 1;   //heigh assume apenas os valores 2 e 1. e só assume valor = 2 quando estiver posicionado a partir da segunda linha
    }
    void setPerc(int perc) {
      int division = (_heigh == 2) ? 33 / 2 : 33;
      _perc = perc;
      if (perc > 100) { _perc = 100; }
      if (perc < 000) { _perc = 000; } 
      if (_heigh == 2){
        _lcd->setCursor(_col+2, _row-1);
        _lcd->print("  ");
        _lcd->setCursor(_col+2, _row-1);
      }
      _lcd->setCursor(_col, _row);
      _lcd->print((_heigh == 2) ? "    " : "  ");
      _lcd->setCursor(_col, _row);
      if (_perc == 0) {  _lcd->write((byte)0); } else {
        if (_perc > 0 && _perc <= division) { 
          _lcd->write((byte)1); 
        } else { 
          _lcd->write((byte)2); 
          if (_perc > division*2 && _perc < 100/_heigh) { _lcd->write((byte)3); } 
          if (_perc >= 100/_heigh)                      { _lcd->write((byte)4);
          }
        }
      }
      if (_heigh == 2 && _perc > 50){
        if (_perc > 50 && _perc <= (50+division)) { 
          _lcd->write((byte)5); 
        } else { 
          _lcd->write((byte)6); 
          if (_perc > (50+division*2) && _perc < 100) { _lcd->write((byte)5); } 
          if (_perc == 100       )                    { _lcd->write((byte)6); }
        }
        _lcd->setCursor(_col+2, _row-1);
        _lcd->print("  ");
        _lcd->setCursor(_col+2, _row-1);
        if (_perc > 50 && _perc <= (50+division)) { 
          _lcd->write((byte)1); 
        } else { 
          _lcd->write((byte)2); 
          if (_perc > (50+division*2) && _perc < 100 ) { _lcd->write((byte)3); } 
          if (_perc >= 100)                            { _lcd->write((byte)4); }
        }
      }
    }
};
/*************************************************************************************************************
*******************************FIM CLASSE LCD PROGRESS BAR****************************************************
**************************************************************************************************************/

/*************************************************************************************************************
*******************************DECLARACAO DOS OBJETOS*********************************************************
**************************************************************************************************************/
LiquidCrystal lcd(12, 11, 10, 9, 8, 7);
LCDProgressBar lcdBar1(&lcd, 0, 9, 1); //inclui uma barra no lcd, primeira linha, coluna 9. altura 1
LCDProgressBar lcdBar2(&lcd, 1, 11, 2); //inclui outra barra no lcd, segunda linha, coluna 11. altura 2
 
RotaryEncoderLimits lim[] = { {0,30}, {0,20} };  //limites máximos e mínimos que as variaveis podem atingir
RotaryEncoder       re(A0, A1, 4, 2, lim);  //pino clk, pino dt, pino sw, variaveis, limites
/*************************************************************************************************************
*******************************FIM DECLARACAO DOS OBJETOS*****************************************************
**************************************************************************************************************/
 
/*************************************************************************************************************
*******************************TRATAMENTO DAS INTERRUPÇÕES****************************************************
**************************************************************************************************************/
//interrupções dos pinos A0 e A1 via Pin Change Interrupt
ISR(PCINT1_vect) {
  volatile static byte lastVal_a0 = LOW;
  volatile static byte lastVal_a1 = LOW;
  byte val_a0 = digitalRead(A0);
  byte val_a1 = digitalRead(A1);
  if (lastVal_a0 != val_a0){ re.update_a(); lastVal_a0 = val_a0; }
  if (lastVal_a1 != val_a1){ re.update_b(); lastVal_a1 = val_a1; }
}

void setup_interrupts(){
  //-----PCI - Pin Change Interrupt ----
  pinMode(A0,INPUT);   // set Pin as Input (default)
  digitalWrite(A0,HIGH);  // enable pullup resistor
  pinMode(A1,INPUT);   // set Pin as Input (default)
  digitalWrite(A1,HIGH);  // enable pullup resistor
  cli();
  PCICR |= 0b00000010; // habilita a porta C - Pin Change Interrupts
  PCMSK1 |= 0b00000011; // habilita interrupção da porta c nos pinos: PCINT8 (A0) e PCINT9(A1)
  sei();
}

/*************************************************************************************************************
*******************************FIM TRATAMENTO DAS INTERRUPÇÕES****************************************************
**************************************************************************************************************/

void indicador_rotary(){
  char c = ((re.getIndex() == 0)) ? '>' : ' ';
  lcd.setCursor(7, 0); 
  lcd.print(c);
  c = ((re.getIndex() == 1)) ? '>' : ' ';
  lcd.setCursor(7, 1); 
  lcd.print(c);
}
  
void setup() { 
  setup_interrupts();
  
  lcdBar1.createChars();
  lcd.begin(16, 2);
  indicador_rotary();
}
  
void loop() {
  static int value1 = -1;
  static int value2 = -1;
   
  if (value1 != re.getValue(0)) {
    lcd.setCursor(0, 0);
    value1 = re.getValue(0);
    int perc = value1/30.0 * 100;
    if (value1 <  10) {lcd.print("00");} else {
    if (value1 < 100) {lcd.print("0");}       }
    lcd.print(value1);
    lcd.print("/");
    lcd.print(30);
 
    lcdBar1.setPerc(perc);  //atualização da primeira barra de progresso
  }
    
  if (value2 != re.getValue(1)) {
    lcd.setCursor(0, 1);
    value2 = re.getValue(1);
    int perc = value2/20.0 * 100;
    if (value2 <  10) {lcd.print("00");} else {
    if (value2 < 100) {lcd.print("0");}       }
    lcd.print(value2);
    lcd.print("/");
    lcd.print(20);
     
    lcdBar2.setPerc(perc); //atualização da segunda barra de progresso
  }
    
  //controla o click do botao do enconder
  static byte b = HIGH; //pra ler apenas uma vez o botao ao pressionar
  if( re.buttonRead() == LOW && b != re.buttonRead() ) {
    re.next();           //passa para a próxima variável (index)
    indicador_rotary();
    delay(200);          //debounce meia boca
  }
  b = re.buttonRead();
    
  delay(100);
}

e nessa outra versão, uma barra que permite informar valores que variam de um número negativo até um número positivo:

vídeo



código-fonte:
/*
Fabiano A. Arndt - 2016
www.youtube.com/user/fabianoallex
www.facebook.com/dicasarduino
fabianoallex@gmail.com
*/
  
#include <LiquidCrystal.h>
 
/*************************************************************************************************************
************************************CLASSE ROTARY ENCODER*****************************************************
*************************************************************************************************************/
#define ROTARY_NO_BUTTON     255
   
struct RotaryEncoderLimits{
  int min;
  int max;
};
   
class RotaryEncoder {
  private:
    byte _pin_clk;
    byte _pin_dt;
    byte _pin_sw;
    volatile byte _num_results;
    volatile int _result;
    volatile int * _results;
    byte _index_result;
    RotaryEncoderLimits * _limits;
       
    boolean _a;
    boolean _b;
  public:
    RotaryEncoder(byte pin_clk, byte pin_dt, byte pin_sw = ROTARY_NO_BUTTON, byte num_results=1, RotaryEncoderLimits * limits=0){   //parametro do botao opcional
      _pin_clk = pin_clk;
      _pin_dt = pin_dt;
      _pin_sw = pin_sw;
      pinMode(_pin_clk, INPUT);
      pinMode(_pin_dt, INPUT);
      if (_pin_sw != ROTARY_NO_BUTTON){ 
        pinMode(_pin_sw, INPUT); 
        digitalWrite(_pin_sw, HIGH);
      }
      if (num_results == 0) { num_results = 1; }
      _num_results = num_results;
      _results = new int[_num_results];
      for (int i; i<_num_results; i++){ _results[i] = (limits) ? limits[i].min : 0; }
      _index_result = 0;
      _limits = limits;
      _a = false;
      _b = false;
    }
    byte getIndex() { return _index_result; }
    void next()     { _index_result++; if (_index_result >= _num_results) { _index_result = 0; } } 
    void update_a() {
      _result = 0;
      delay (1);
      if( digitalRead(_pin_clk) != _a ) { 
        _a = !_a;
        if ( _a && !_b ) { _result = -1; }
      }
      if (_results[_index_result]+_result >= _limits[_index_result].min && 
          _results[_index_result]+_result <= _limits[_index_result].max ) {
        _results[_index_result] += _result;
      }
    }
    void update_b() {
      _result = 0;
      delay (1);
      if( digitalRead(_pin_dt) != _b ) {  
        _b = !_b;
        if ( _b && !_a ) { _result = +1; }
      }
      if (_results[_index_result]+_result >= _limits[_index_result].min && 
          _results[_index_result]+_result <= _limits[_index_result].max ) {
        _results[_index_result] += _result;
      }
    }
    int read(){ return _result; }                                        //retorn -1, 0 ou 1.
    int getValue(int index=-1) {                                         //retorna o valor da variável corrente ou a passada como parametro
      if (index < 0 ){ return _results[_index_result]; }
      return _results[index];
    }
    void setValue(int value, int index=-1){ _results[ (index==-1) ? _index_result : index] = value; }         //caso a variável inicializa em determinado valor diferente de zero, utilizar esse método.
    int buttonRead(){ return (_pin_sw == ROTARY_NO_BUTTON) ? LOW : digitalRead(_pin_sw); }
};
/*************************************************************************************************************
************************************FIM CLASSE ROTARY ENCODER*************************************************
*************************************************************************************************************/
  
/*************************************************************************************************************
*******************************CLASSE LCD PROGRESS BAR********************************************************
**************************************************************************************************************/
/*
  0        1        2        3        4
** **    ** **    ** **    ** **    ** **
           *      **          **    ** **
           *      **          **    ** **
           *      **          **    ** **
           *      **          **    ** **
           *      **          **    ** **
           *      **          **    ** **
** **    ** **    ** **    ** **    ** **

*/
byte c0[8] = {B11011,  B00000,  B00000,  B00000,  B00000,  B00000,  B00000,  B11011 };
byte c1[8] = {B11011,  B00000,  B00000,  B00100,  B00100,  B00000,  B00000,  B11011 };
byte c2[8] = {B11011,  B11000,  B11000,  B11000,  B11000,  B11000,  B11000,  B11011 };
byte c3[8] = {B11011,  B00011,  B00011,  B00011,  B00011,  B00011,  B00011,  B11011 };
byte c4[8] = {B11011,  B11011,  B11011,  B11011,  B11011,  B11011,  B11011,  B11011 };

  
class LCDProgressBar {
  private:
    LiquidCrystal * _lcd;  //ponteiro para um objeto lcd
    int _row;
    int _col;
    int _perc; /*0..100*/
    int _len;
  public:
    void createChars() { 
      _lcd->createChar(0, c0);  
      _lcd->createChar(1, c1);  
      _lcd->createChar(2, c2); 
      _lcd->createChar(3, c3);  
      _lcd->createChar(4, c4);
    }
    LCDProgressBar(LiquidCrystal * lcd, int row, int col, int len) { 
      _lcd = lcd; 
      _row = row; 
      _col = col; 
      _len = len; 
    }
    void setPerc(int perc) {
      _perc = perc;
      if (_perc >  100) { _perc =  100; }
      if (_perc < -100) { _perc = -100; } 
      
      _lcd->setCursor(_col, _row);
      for (int i=0; i<(_len*2-1);i++) { _lcd->write((byte)0); }   //preenche com caracteres vazio
      _lcd->setCursor(_col + (_len-1), _row);
      _lcd->write((byte)1);                                 //preenche com caracter zero (nenhum valor)
      
      if (_perc > 0){
        _lcd->setCursor(_col + (_len-1), _row); 
        int bars  = (2*(_len-1)+1) * _perc / 100;  
        if (bars >= 1) { _lcd->write((byte)3); }
        int div   = (bars-1) / 2;  //divisao
        int resto = (bars-1) % 2;  //resto
        for (int i=0; i<div; i++) { _lcd->write((byte)4);         }  //pinta todo o quadro
        if (resto > 0)            { _lcd->write((byte)2); }
      } else if (_perc < 0) {
        _lcd->setCursor(_col + (_len-1), _row); 
        int bars  = (2*(_len-1)+1) * (-_perc) / 100;  
        if (bars >= 1) { _lcd->write((byte)2); }
        int div   = (bars-1) / 2;  //divisao
        int resto = (bars-1) % 2;  //resto
        int i = 0;
        for (i=0; i<div; i++) {
          _lcd->setCursor(_col + _len/2-i, _row); 
          _lcd->write((byte)4); 
        }
        if (resto > 0) { 
          _lcd->setCursor(_col + _len/2-i, _row); 
          _lcd->write((byte)3); 
        }
      }
    }
};
/*************************************************************************************************************
*******************************FIM CLASSE LCD PROGRESS BAR****************************************************
**************************************************************************************************************/

/*************************************************************************************************************
*******************************DECLARACAO DOS OBJETOS*********************************************************
**************************************************************************************************************/
LiquidCrystal lcd(12, 11, 10, 9, 8, 7);
LCDProgressBar lcdBar1(&lcd, 0, 9, 3); //inclui uma barra no lcd, primeira linha, coluna 9. tamanho 3 (3*2-1 --> 5)
LCDProgressBar lcdBar2(&lcd, 1, 9, 4); //inclui outra barra no lcd, segunda linha, coluna 11. tamanho 4 (4*2-1 --> 7)
 
RotaryEncoderLimits lim[] = { {-30,30}, {-20,20} };  //limites máximos e mínimos que as variaveis podem atingir
RotaryEncoder       re(A0, A1, 4, 2, lim);  //pino clk, pino dt, pino sw, variaveis, limites
/*************************************************************************************************************
*******************************FIM DECLARACAO DOS OBJETOS*****************************************************
**************************************************************************************************************/
 
/*************************************************************************************************************
*******************************TRATAMENTO DAS INTERRUPÇÕES****************************************************
**************************************************************************************************************/
//interrupções dos pinos A0 e A1 via Pin Change Interrupt
ISR(PCINT1_vect) {
  volatile static byte lastVal_a0 = LOW;
  volatile static byte lastVal_a1 = LOW;
  byte val_a0 = digitalRead(A0);
  byte val_a1 = digitalRead(A1);
  if (lastVal_a0 != val_a0){ re.update_a(); lastVal_a0 = val_a0; }
  if (lastVal_a1 != val_a1){ re.update_b(); lastVal_a1 = val_a1; }
}

void setup_interrupts(){
  //-----PCI - Pin Change Interrupt ----
  pinMode(A0,INPUT);   // set Pin as Input (default)
  digitalWrite(A0,HIGH);  // enable pullup resistor
  pinMode(A1,INPUT);   // set Pin as Input (default)
  digitalWrite(A1,HIGH);  // enable pullup resistor
  cli();
  PCICR |= 0b00000010; // habilita a porta C - Pin Change Interrupts
  PCMSK1 |= 0b00000011; // habilita interrupção da porta c nos pinos: PCINT8 (A0) e PCINT9(A1)
  sei();
}

/*************************************************************************************************************
*******************************FIM TRATAMENTO DAS INTERRUPÇÕES****************************************************
**************************************************************************************************************/

void indicador_rotary(){
  char c = ((re.getIndex() == 0)) ? '>' : ' ';
  lcd.setCursor(7, 0); 
  lcd.print(c);
  c = ((re.getIndex() == 1)) ? '>' : ' ';
  lcd.setCursor(7, 1); 
  lcd.print(c);
}
  
void setup() { 
  setup_interrupts();
  
  lcdBar1.createChars();
  lcd.begin(16, 2);
  
  re.setValue(0, 0);
  re.setValue(0, 1);
  
  indicador_rotary();
}
  
void loop() {
  static int value1 = -1;
  static int value2 = -1;
   
  if (value1 != re.getValue(0)) {
    lcd.setCursor(0, 0);
    value1 = re.getValue(0);
    int perc = value1/30.0 * 100;
    lcd.print("       ");
    lcd.setCursor(0, 0);
    lcd.print(value1);
    lcd.print("/");
    lcd.print(30);
 
    lcdBar1.setPerc(perc);  //atualização da primeira barra de progresso
  }
    
  if (value2 != re.getValue(1)) {
    lcd.setCursor(0, 1);
    value2 = re.getValue(1);
    int perc = value2/20.0 * 100;
    lcd.print("       ");
    lcd.setCursor(0, 1);
    lcd.print(value2);
    lcd.print("/");
    lcd.print(20);
     
    lcdBar2.setPerc(perc); //atualização da segunda barra de progresso
  }
    
  //controla o click do botao do enconder
  static byte b = HIGH; //pra ler apenas uma vez o botao ao pressionar
  if( re.buttonRead() == LOW && b != re.buttonRead() ) {
    re.next();           //passa para a próxima variável (index)
    indicador_rotary();
    delay(200);          //debounce meia boca
  }
  b = re.buttonRead();
    
  delay(100);
}

2 comentários:

  1. Hola, podrias subir el mismo código pero para usar un display I2C, muchas gracias!

    ResponderExcluir
  2. amigo como faz uma barra de progresso para timer???vc tem o codigo???

    ResponderExcluir