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);
}
Hola, podrias subir el mismo código pero para usar un display I2C, muchas gracias!
ResponderExcluiramigo como faz uma barra de progresso para timer???vc tem o codigo???
ResponderExcluir