Quem já tentou tratar uma interrupção dentro de uma classe sabe que não é muito simples fazer isso. Nesse vídeo mostro como redefinir a função attachInterrupt para anexar objetos ao invés de funções.
MyInterrupt.h
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
Part of the Wiring project - http://wiring.uniandes.edu.co
Copyright (c) 2004-05 Hernando Barragan
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
Modified 24 November 2006 by David A. Mellis
Modified 1 August 2010 by Mark Sproul
*/
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <stdio.h>
#include "wiring_private.h"
class Interrupt; //declaracao previa
void attachInterrupt(uint8_t interruptNum, Interrupt * interruptObject, int mode); //declaracao previa
class Interrupt {
public:
void attach(uint8_t interruptNum, int mode) { attachInterrupt(interruptNum, this, mode); };
void volatile virtual execInterrupt(uint8_t interruptNum);
};
Interrupt * interruptObjects[EXTERNAL_NUM_INTERRUPTS];
//static volatile voidFuncPtr intFunc[EXTERNAL_NUM_INTERRUPTS];
// volatile static voidFuncPtr twiIntFunc;
void attachInterrupt(uint8_t interruptNum, Interrupt * interruptObject, int mode) {
if(interruptNum < EXTERNAL_NUM_INTERRUPTS) {
interruptObjects[interruptNum] = interruptObject;
// Configure the interrupt mode (trigger on low input, any change, rising
// edge, or falling edge). The mode constants were chosen to correspond
// to the configuration bits in the hardware register, so we simply shift
// the mode into place.
// Enable the interrupt.
switch (interruptNum) {
#if defined(__AVR_ATmega32U4__)
// I hate doing this, but the register assignment differs between the 1280/2560
// and the 32U4. Since avrlib defines registers PCMSK1 and PCMSK2 that aren't
// even present on the 32U4 this is the only way to distinguish between them.
case 0:
EICRA = (EICRA & ~((1<<ISC00) | (1<<ISC01))) | (mode << ISC00);
EIMSK |= (1<<INT0);
break;
case 1:
EICRA = (EICRA & ~((1<<ISC10) | (1<<ISC11))) | (mode << ISC10);
EIMSK |= (1<<INT1);
break;
case 2:
EICRA = (EICRA & ~((1<<ISC20) | (1<<ISC21))) | (mode << ISC20);
EIMSK |= (1<<INT2);
break;
case 3:
EICRA = (EICRA & ~((1<<ISC30) | (1<<ISC31))) | (mode << ISC30);
EIMSK |= (1<<INT3);
break;
case 4:
EICRB = (EICRB & ~((1<<ISC60) | (1<<ISC61))) | (mode << ISC60);
EIMSK |= (1<<INT6);
break;
#elif defined(EICRA) && defined(EICRB) && defined(EIMSK)
case 2:
EICRA = (EICRA & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00);
EIMSK |= (1 << INT0);
break;
case 3:
EICRA = (EICRA & ~((1 << ISC10) | (1 << ISC11))) | (mode << ISC10);
EIMSK |= (1 << INT1);
break;
case 4:
EICRA = (EICRA & ~((1 << ISC20) | (1 << ISC21))) | (mode << ISC20);
EIMSK |= (1 << INT2);
break;
case 5:
EICRA = (EICRA & ~((1 << ISC30) | (1 << ISC31))) | (mode << ISC30);
EIMSK |= (1 << INT3);
break;
case 0:
EICRB = (EICRB & ~((1 << ISC40) | (1 << ISC41))) | (mode << ISC40);
EIMSK |= (1 << INT4);
break;
case 1:
EICRB = (EICRB & ~((1 << ISC50) | (1 << ISC51))) | (mode << ISC50);
EIMSK |= (1 << INT5);
break;
case 6:
EICRB = (EICRB & ~((1 << ISC60) | (1 << ISC61))) | (mode << ISC60);
EIMSK |= (1 << INT6);
break;
case 7:
EICRB = (EICRB & ~((1 << ISC70) | (1 << ISC71))) | (mode << ISC70);
EIMSK |= (1 << INT7);
break;
#else
case 0:
#if defined(EICRA) && defined(ISC00) && defined(EIMSK)
EICRA = (EICRA & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00);
EIMSK |= (1 << INT0);
#elif defined(MCUCR) && defined(ISC00) && defined(GICR)
MCUCR = (MCUCR & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00);
GICR |= (1 << INT0);
#elif defined(MCUCR) && defined(ISC00) && defined(GIMSK)
MCUCR = (MCUCR & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00);
GIMSK |= (1 << INT0);
#else
#error attachInterrupt not finished for this CPU (case 0)
#endif
break;
case 1:
#if defined(EICRA) && defined(ISC10) && defined(ISC11) && defined(EIMSK)
EICRA = (EICRA & ~((1 << ISC10) | (1 << ISC11))) | (mode << ISC10);
EIMSK |= (1 << INT1);
#elif defined(MCUCR) && defined(ISC10) && defined(ISC11) && defined(GICR)
MCUCR = (MCUCR & ~((1 << ISC10) | (1 << ISC11))) | (mode << ISC10);
GICR |= (1 << INT1);
#elif defined(MCUCR) && defined(ISC10) && defined(GIMSK) && defined(GIMSK)
MCUCR = (MCUCR & ~((1 << ISC10) | (1 << ISC11))) | (mode << ISC10);
GIMSK |= (1 << INT1);
#else
#warning attachInterrupt may need some more work for this cpu (case 1)
#endif
break;
case 2:
#if defined(EICRA) && defined(ISC20) && defined(ISC21) && defined(EIMSK)
EICRA = (EICRA & ~((1 << ISC20) | (1 << ISC21))) | (mode << ISC20);
EIMSK |= (1 << INT2);
#elif defined(MCUCR) && defined(ISC20) && defined(ISC21) && defined(GICR)
MCUCR = (MCUCR & ~((1 << ISC20) | (1 << ISC21))) | (mode << ISC20);
GICR |= (1 << INT2);
#elif defined(MCUCR) && defined(ISC20) && defined(GIMSK) && defined(GIMSK)
MCUCR = (MCUCR & ~((1 << ISC20) | (1 << ISC21))) | (mode << ISC20);
GIMSK |= (1 << INT2);
#endif
break;
#endif
}
}
}
void detachInterrupt(uint8_t interruptNum) {
if(interruptNum < EXTERNAL_NUM_INTERRUPTS) {
// Disable the interrupt. (We can't assume that interruptNum is equal
// to the number of the EIMSK bit to clear, as this isn't true on the
// ATmega8. There, INT0 is 6 and INT1 is 7.)
switch (interruptNum) {
#if defined(__AVR_ATmega32U4__)
case 0:
EIMSK &= ~(1<<INT0);
break;
case 1:
EIMSK &= ~(1<<INT1);
break;
case 2:
EIMSK &= ~(1<<INT2);
break;
case 3:
EIMSK &= ~(1<<INT3);
break;
case 4:
EIMSK &= ~(1<<INT6);
break;
#elif defined(EICRA) && defined(EICRB) && defined(EIMSK)
case 2:
EIMSK &= ~(1 << INT0);
break;
case 3:
EIMSK &= ~(1 << INT1);
break;
case 4:
EIMSK &= ~(1 << INT2);
break;
case 5:
EIMSK &= ~(1 << INT3);
break;
case 0:
EIMSK &= ~(1 << INT4);
break;
case 1:
EIMSK &= ~(1 << INT5);
break;
case 6:
EIMSK &= ~(1 << INT6);
break;
case 7:
EIMSK &= ~(1 << INT7);
break;
#else
case 0:
#if defined(EIMSK) && defined(INT0)
EIMSK &= ~(1 << INT0);
#elif defined(GICR) && defined(ISC00)
GICR &= ~(1 << INT0); // atmega32
#elif defined(GIMSK) && defined(INT0)
GIMSK &= ~(1 << INT0);
#else
#error detachInterrupt not finished for this cpu
#endif
break;
case 1:
#if defined(EIMSK) && defined(INT1)
EIMSK &= ~(1 << INT1);
#elif defined(GICR) && defined(INT1)
GICR &= ~(1 << INT1); // atmega32
#elif defined(GIMSK) && defined(INT1)
GIMSK &= ~(1 << INT1);
#else
#warning detachInterrupt may need some more work for this cpu (case 1)
#endif
break;
#endif
}
interruptObjects[interruptNum] = 0;
}
}
/*
void attachInterruptTwi(void (*userFunc)(void) ) {
twiIntFunc = userFunc;
}
*/
#if defined(__AVR_ATmega32U4__)
ISR(INT0_vect) {
if(interruptObjects[EXTERNAL_INT_0])
interruptObjects[EXTERNAL_INT_0]->execInterrupt(EXTERNAL_INT_0);
}
ISR(INT1_vect) {
if(interruptObjects[EXTERNAL_INT_1])
interruptObjects[EXTERNAL_INT_1]->execInterrupt(EXTERNAL_INT_1);
}
ISR(INT2_vect) {
if(interruptObjects[EXTERNAL_INT_2])
interruptObjects[EXTERNAL_INT_2]->execInterrupt(EXTERNAL_INT_2);
}
ISR(INT3_vect) {
if(interruptObjects[EXTERNAL_INT_3])
interruptObjects[EXTERNAL_INT_3]->execInterrupt(EXTERNAL_INT_3);
}
ISR(INT6_vect) {
if(interruptObjects[EXTERNAL_INT_4])
interruptObjects[EXTERNAL_INT_4]->execInterrupt(EXTERNAL_INT_4);
}
#elif defined(EICRA) && defined(EICRB)
ISR(INT0_vect) {
if(interruptObjects[EXTERNAL_INT_2])
interruptObjects[EXTERNAL_INT_2]->execInterrupt(EXTERNAL_INT_2);
}
ISR(INT1_vect) {
if(interruptObjects[EXTERNAL_INT_3])
interruptObjects[EXTERNAL_INT_3]->execInterrupt(EXTERNAL_INT_3);
}
ISR(INT2_vect) {
if(interruptObjects[EXTERNAL_INT_4])
interruptObjects[EXTERNAL_INT_4]->execInterrupt(EXTERNAL_INT_4);
}
ISR(INT3_vect) {
if(interruptObjects[EXTERNAL_INT_5])
interruptObjects[EXTERNAL_INT_5]->execInterrupt(EXTERNAL_INT_5);
}
ISR(INT4_vect) {
if(interruptObjects[EXTERNAL_INT_0])
interruptObjects[EXTERNAL_INT_0]->execInterrupt(EXTERNAL_INT_0);
}
ISR(INT5_vect) {
if(interruptObjects[EXTERNAL_INT_1])
interruptObjects[EXTERNAL_INT_1]->execInterrupt(EXTERNAL_INT_1);
}
ISR(INT6_vect) {
if(interruptObjects[EXTERNAL_INT_6])
interruptObjects[EXTERNAL_INT_6]->execInterrupt(EXTERNAL_INT_6);
}
ISR(INT7_vect) {
if(interruptObjects[EXTERNAL_INT_7])
interruptObjects[EXTERNAL_INT_7]->execInterrupt(EXTERNAL_INT_7);
}
#else
ISR(INT0_vect) {
if(interruptObjects[EXTERNAL_INT_0])
interruptObjects[EXTERNAL_INT_0]->execInterrupt(EXTERNAL_INT_0);
}
ISR(INT1_vect) {
if(interruptObjects[EXTERNAL_INT_1])
interruptObjects[EXTERNAL_INT_1]->execInterrupt(EXTERNAL_INT_1);
}
#if defined(EICRA) && defined(ISC20)
ISR(INT2_vect) {
if(interruptObjects[EXTERNAL_INT_2])
interruptObjects[EXTERNAL_INT_2]->execInterrupt(EXTERNAL_INT_2);
}
#endif
#endif
/*
ISR(TWI_vect) {
if(twiIntFunc)
twiIntFunc();
}
*/
Sketch
#include "MyInterrupt.h"
class Abc : public Interrupt{
private:
public:
Abc(){
attach(0, CHANGE);
attach(1, CHANGE);
}
void volatile execInterrupt(uint8_t interruptNum){
Serial.print("Abc: ");
Serial.print(interruptNum);
Serial.print(" - millis: ");
Serial.println(millis());
}
};
Abc * abc;
void setup() {
Serial.begin(9600);
abc = new Abc();
}
void loop() {
// put your main code here, to run repeatedly:
}
Esse post demonstra vários exemplo de como gerar números grandes em displays LCD. Mais abaixo tem um exemplo de como utilizar mais de 8 caracteres customizáveis e ao final mostro um exemplo de um relógio em display LCD com números grandes.
São vários exemplos diferentes.
Vídeo 01:
Vídeo 02:
Código-fonte 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 BIG NUMBERS*********************************************************
**************************************************************************************************************/
struct LCDNumber {
byte top;
byte bottom;
};
class LCDBigNumbers {
private:
LiquidCrystal * _lcd;
int _row;
int _col;
long _value; /*0..100*/
void _clear(){
int cont = 1;
long x = 9;
while (_value > x){
cont++;
x = x * 10 + 9;
}
for (int i=0; i<cont; i++) {
_lcd->setCursor(_col+i, _row);
_lcd->print( " " );
_lcd->setCursor(_col+i, _row+1);
_lcd->print( " " );
}
}
public:
static byte c0[8];
static byte c1[8];
static byte c2[8];
static byte c3[8];
static byte c4[8];
static byte c5[8];
static byte c6[8];
static byte c7[8];
static LCDNumber _lcd_numbers[];
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);
_lcd->createChar(7, c7);
}
LCDBigNumbers(LiquidCrystal * lcd, int row, int col) {
_lcd = lcd; _row = row; _col = col;
}
void setRow(int row){
_clear();
_row = row;
setValue(_value);
}
void setCol(int col){
_clear();
_col = col;
setValue(_value);
}
void setValue(long value){
_clear();
_value = value;
int cont = 1;
long x = 9;
while (abs(_value) > x){
cont++;
x = x * 10 + 9;
}
for (int i=0; i<cont; i++) {
int n = value / pow(10, cont-1-i);
value = value - pow(10, cont-1-i) * n;
_lcd->setCursor(_col+i, _row);
_lcd->write( _lcd_numbers[n].top );
_lcd->setCursor(_col+i, _row+1);
_lcd->write( _lcd_numbers[n].bottom );
}
}
};
byte LCDBigNumbers::c0[8] = {B11111, B10001, B10001, B10001, B10001, B10001, B10001, B10001};
byte LCDBigNumbers::c1[8] = {B10001, B10001, B10001, B10001, B10001, B10001, B10001, B11111};
byte LCDBigNumbers::c2[8] = {B00001, B00001, B00001, B00001, B00001, B00001, B00001, B00001};
byte LCDBigNumbers::c3[8] = {B11111, B00001, B00001, B00001, B00001, B00001, B00001, B11111};
byte LCDBigNumbers::c4[8] = {B11111, B10000, B10000, B10000, B10000, B10000, B10000, B11111};
byte LCDBigNumbers::c5[8] = {B11111, B00001, B00001, B00001, B00001, B00001, B00001, B00001};
byte LCDBigNumbers::c6[8] = {B11111, B10001, B10001, B10001, B10001, B10001, B10001, B11111};
byte LCDBigNumbers::c7[8] = {B00001, B00001, B00001, B00001, B00001, B00001, B00001, B11111};
LCDNumber LCDBigNumbers::_lcd_numbers[] = {
{0, 1}, //0
{2, 2}, //1
{5, 4}, //2
{3, 7}, //3
{1, 2}, //4
{4, 7}, //5
{4, 1}, //6
{5, 2}, //7
{6, 1}, //8
{6, 7} // 9
};
/*************************************************************************************************************
*******************************FIM CLASSE LCD BIG NUMBERS*****************************************************
**************************************************************************************************************/
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
LCDBigNumbers lcdNum(&lcd, 0,0); //inclui uma barra no lcd, primeira linha, coluna 8. tamanho 8
void setup() {
Serial.begin(9600);
lcdNum.createChars();
pinMode(44, OUTPUT);
analogWrite(44, 255/6); //utilizado para aumentar o contraste
lcd.begin(16, 2);
}
long i = 0;
int col = 0;
void loop() {
lcdNum.setValue(i++ * 11);
if (i>=10000) i = 0;
if (i%10 == 0){
lcdNum.setCol(col++);
if (col >= 10){
col = 0;
}
}
delay(500);
}
O Código abaixo é uma versão alterada pra mostrar números e letras, a qual não está no vídeo. Ainda precisa de umas melhorias, mas de qualquer maneira, deixo aqui pra quem quiser testar:
Nesse outro exemplo, é mostrado como juntar mais de um formato em uma mesma sketch. Por padrão o LCD aceita apenas 8 caracteres customizáveis, mas é possível criar mais de oito, desde que se tenha apenas 8 sendo usado por vez. Ao terminar de usar os primeiros 8, pode-se definir os outros 8 caracteres customizáveis.
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.