LCD bargraph help(solved)

I 'll start by explaining what I am trying to accomplish.
I have a Uno connected to an i2c 4x20 lcd display. It has 4 Freescale MPX series pressure sensors connected to analog inputs A0 to A3.
What I would like to do is have the four pressure sensors control 4 bars on the lcd.
I found a sketch in the exhibition section that will do exactly what I need. I managed to get it to display four bars numbered from 1 to 4.
What I need help with is attaching the four analog inputs to each individual bar. The original author has A0 controlling all four bars for demo purposes.
As you have heard many times I am a novice to coding so you will probably have to walk me through this step by step, which I would prefer so I can learn something.
Just for those that are wondering, I am building a unit to check the syncronization on motercyle carbs.

Here is the code

[code]

*/

// include the library code:
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>  // fmalpartida version
// download here: https://bitbucket.org/fmalpartida/new-liquidcrystal/downloads
// remove the standard Arduino liquidcrystal from ...programs/Arduino/libraries

#define lcdlength 20  // DEFINES YOUR display length in columns
#define lcdheigth 4   // DEFINES YOUR display heigth in rows

unsigned char b, b2;
double a, a2;
unsigned int segment, segment2;
double perc=100;
boolean logar;
byte bn;   // bn BAR NUMBER every bar have to be numbered from 1 to 40                     
unsigned int xpos, ypos, blen;
double pkval[41]; // to store the last peak value for each bar
int    pkcyc[41][2];    // set the num. of printbar recall TO DO [1] and DONE [2] for each bar before the peak decays, 
                        // if pkcyc[bn][1] == 0 no peaks wanted
                        // it's a workaround to avoid to waste time in delay functions (internal or external)
                        // that may interfere your application performances
                        
// Bar characters definitions (8 maximum allowed)
byte block[8][8]=  
{
  { 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10 },  // define characters for bar
  { 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18 },
  { 0x1C,0x1C,0x1C,0x1C,0x1C,0x1C,0x1C,0x1C },
  { 0x1E,0x1E,0x1E,0x1E,0x1E,0x1E,0x1E,0x1E },

  { 0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08 },  // define characters for peak
  { 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04 },
  { 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02 },
  { 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01 },
};

// #define del 100                         // REMOVE IT, delay for testing purposes only
 int potalim = 12;                       // REMOVE IT, to supply 5V al to testing potentiometer

// Set the pins on the I2C chip used for LCD connections:
//                    addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address
// A0 A1 A2 in I2C unsoldered means 0x27 address

//==============
void setup() {
  // set up the LCD's number of columns and rows:
  lcd.begin(20,4);         // initialize the lcd for 20 chars 4 lines and turn on backlight

  
           pinMode(potalim, OUTPUT);    // REMOVE IT, test purposes, defines pin 12 to power signal potentiometer

  for( int i=0 ; i<8 ; i++ )
    lcd.createChar( i,block[i] );
    

// lcd.backlight(); // LCD backlight on (default when init)      
// lcd.noBacklight();  // LCD backlight off      
}

void loop() 
{
          digitalWrite(potalim, HIGH);  // REMOVE IT, TEST purposes, activates 5V on pin 12 for the signal potentiometer
//          delay(del);                   // REMOVE IT, to slow down display without a real application running
  
// Assign value (in this case from Analog Input 0)
  unsigned int value = analogRead(0);
  perc = value/1023.0*100;      // perc is the value from 0 to 100 for the length of the bargraph of the meter

// Setting parameters for bars ( you can put directly values inside the function)
// xpos=0; 
// ypos=1; 
// blen= 20;
// remember that bar starts from lower point raising of blen positions
// LEFT UPPER ANGLE IS xpos = 0 AND ypos = 0
logar = false; 
// bn = 1;   // BAR NUMBER every bar have to be numbered from 1 to 40

for (int i=1;i<41;i++)  // setting 15 cycles for all bars... YOUR CHOICE !!
    { pkcyc[i][1]=  15;}

//==============================================================
//           EXAMPLE OF PRINTING ON DISPLAY 
//   (I use same input for all bars for demo purposes)

// printbar (bn, perc, xpos, ypos, blen, logar);

lcd.setCursor(0,0); lcd.print ("1");
printbar (1,perc,1,0,19, true);
lcd.setCursor(0,1); lcd.print ("2");
printbar (2,perc,1,1,19, true);
lcd.setCursor(0,2); lcd.print ("3");
printbar (3,perc,1,2,19, true);
lcd.setCursor(0,3); lcd.print ("4");
printbar (4,perc,1,3,19, true);

//          END OF EXAMPLE
//==============================================================
}

//  METER BARS PRINTING FUNCTION
// passing percentage, x and y position, positions bar length, linear/audio logaritmic bar
// barnum is used to manage times of decayn of each peak separately (see definitions)

void printbar (byte bn, double perc, int xpos, int ypos, int blen, boolean logar) 
{
  if ((logar == true) && (perc > 0))   // logaritmic bar
    {
    perc = ( log10(perc ) )*50;    // 10 * log10 (value) linear to logaritmic for AUDIO conversion       
    if ( perc < 0 ) { perc = 0; }  // avoid negative values 
    }

  a=blen/99.5*perc;      // calculate length of bar
  b = 0;

  if ( pkcyc[bn][1] > 0 )              // if PEAK is activated
  {
    if ( (a > (pkval[bn]-0.01)) || (pkcyc[bn][2] > pkcyc[bn][1]) )   // new peak (w little histeresys) or expiration of peak
    {
      pkval[bn] = a;    
      pkcyc[bn][2] = 0;    // reset cycles
    }

    pkcyc[bn][2]++;
        
   }

  // drawing filled rectangles  
  if (a>=1) {  
    
    for (int i=1;i<a;i++) {
      lcd.setCursor(xpos-1+i,ypos);
      lcd.write(255);  
      b=i;
      }
 
     a=a-b;
  }
  segment= a*5;

// drawing final part of the bar
if (b < blen)
{
  lcd.setCursor(xpos+b,ypos);
  
  switch (segment) {
  case 0:
    lcd.print(" ");
    break;
  case 1:
    lcd.write((byte)0);
    break;
  case 2:
    lcd.write(1);
    break;
  case 3:
    lcd.write(2);
    break;
  case 4:
    lcd.write(3);
    break;
   }  
  }
  
// cleaning rest of line
  for (int i =0;i<(blen-b-1);i++) 
  {
    lcd.setCursor(xpos+ b+ 1+ i, ypos);
    lcd.print(" ");
  }

  b2= (int) pkval[bn];
  a2= pkval[bn]-b2;
  segment2= a2*5; 
  
  if ( (pkcyc[bn][1] > 0) && (    // DRAWING PEAK 
            ((b + segment) == 0)                            // if bar empty
         || (b2 > b)                                        // or different box position
         || ( (b2 == b) && segment == 0 && segment2 >0 )    // special case, too long to explain :-)
        ))
  {
  lcd.setCursor(xpos + b2, ypos);
 
  switch (segment2) {
  case 0:
   if ( (b2 > 0) || (b2 > b+1))
     { 
     lcd.setCursor(xpos + b2-1, ypos); 
     lcd.write(7);
     };  
    break;
  case 1:
    lcd.write(byte(0));
    break;
  case 2:
    lcd.write(4);
    break;
  case 3:
    lcd.write(5);
    break;
  case 4:
    lcd.write(6);
    break;
    }
}
}

[/code]

try this variation, should work with 4 pot meters, look especially to the rewritten loop()

  • stripped comments a bit.
// include the library code:
#include <Wire.h>
#include <LiquidCrystal_I2C.h>  // fmalpartida version

// download here: https://bitbucket.org/fmalpartida/new-liquidcrystal/downloads
// remove the standard Arduino liquidcrystal from ...programs/Arduino/libraries

#define lcdlength 20  // DEFINES YOUR display length in columns
#define lcdheigth 4   // DEFINES YOUR display heigth in rows

unsigned char b, b2;
double a, a2;
unsigned int segment, segment2;
double perc = 100;
boolean logar;
byte bn;                 // bn BAR NUMBER every bar have to be numbered from 1 to 40
unsigned int xpos, ypos, blen;
double pkval[41];        // to store the last peak value for each bar
int    pkcyc[41][2];     // set the num. of printbar recall TO DO [1] and DONE [2] for each bar before the peak decays,

// if pkcyc[bn][1] == 0 no peaks wanted
// it's a workaround to avoid to waste time in delay functions (internal or external)
// that may interfere your application performances

// Bar characters definitions (8 maximum allowed)
byte block[8][8] =
{
  { 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 }, // define characters for bar
  { 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18 },
  { 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C },
  { 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E },

  { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 }, // define characters for peak
  { 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 },
  { 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 },
  { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
};

LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);


void setup()
{
  lcd.begin(20, 4);
  for ( int i = 0 ; i < 8 ; i++ ) lcd.createChar( i, block[i] );
}

void loop()
{
  // MAKE 4 MEASUREMENTS
  float perc[4];
  for (int i = 0; i < 4; i++)
  {
    perc[i] = analogRead(0) / 1023.0 * 100;
  }
  // Setting parameters for bars ( you can put directly values inside the function)
  // xpos=0;
  // ypos=1;
  // blen= 20;
  // remember that bar starts from lower point raising of blen positions
  // LEFT UPPER ANGLE IS xpos = 0 AND ypos = 0
  logar = false;

  for (int i = 1; i < 41; i++) // setting 15 cycles for all bars... YOUR CHOICE !!
  {
    pkcyc[i][1] =  15;
  }

  // DISPLAY MEASUREMENTS
  for (int bar = 0; bar < 4; bar++)
  {
    lcd.setCursor(0, bar); lcd.print (bar + 1);
    printbar (1, perc[bar], 1, bar, 19, true);
  }
}

//  METER BARS PRINTING FUNCTION
// passing percentage, x and y position, positions bar length, linear/audio logaritmic bar
// barnum is used to manage times of decayn of each peak separately (see definitions)
void printbar (byte bn, double perc, int xpos, int ypos, int blen, boolean logar)
{
  if ((logar == true) && (perc > 0))   // logaritmic bar
  {
    perc = ( log10(perc ) ) * 50;      // 10 * log10 (value) linear to logaritmic for AUDIO conversion
    if ( perc < 0 ) perc = 0;          // avoid negative values
  }

  a = blen / 99.5 * perc;              // calculate length of bar
  b = 0;

  if ( pkcyc[bn][1] > 0 )              // if PEAK is activated
  {
    if ( (a > (pkval[bn] - 0.01)) || (pkcyc[bn][2] > pkcyc[bn][1]) ) // new peak (w little histeresys) or expiration of peak
    {
      pkval[bn] = a;
      pkcyc[bn][2] = 0;                // reset cycles
    }
    pkcyc[bn][2]++;
  }

  // drawing filled rectangles
  if (a >= 1)
  {
    for (int i = 1; i < a; i++)
    {
      lcd.setCursor(xpos - 1 + i, ypos);
      lcd.write(255);
      b = i;
    }
    a = a - b;
  }
  segment = a * 5;

  // drawing final part of the bar
  if (b < blen)
  {
    lcd.setCursor(xpos + b, ypos);

    switch (segment) {
      case 0:
        lcd.print(" ");
        break;
      case 1:
        lcd.write((byte)0);
        break;
      case 2:
        lcd.write(1);
        break;
      case 3:
        lcd.write(2);
        break;
      case 4:
        lcd.write(3);
        break;
    }
  }

  // cleaning rest of line
  for (int i = 0; i < (blen - b - 1); i++)
  {
    lcd.setCursor(xpos + b + 1 + i, ypos);
    lcd.print(" ");
  }

  b2 = (int) pkval[bn];
  a2 = pkval[bn] - b2;
  segment2 = a2 * 5;

  // DRAWING PEAK
  if ( (pkcyc[bn][1] > 0) && (
         ((b + segment) == 0)                               // if bar empty
         || (b2 > b)                                        // or different box position
         || ( (b2 == b) && segment == 0 && segment2 > 0 )   // special case, too long to explain :-)
       ))
  {
    lcd.setCursor(xpos + b2, ypos);

    switch (segment2) {
      case 0:
        if ( (b2 > 0) || (b2 > b + 1))
        {
          lcd.setCursor(xpos + b2 - 1, ypos);
          lcd.write(7);
        };
        break;
      case 1:
        lcd.write(byte(0));
        break;
      case 2:
        lcd.write(4);
        break;
      case 3:
        lcd.write(5);
        break;
      case 4:
        lcd.write(6);
        break;
    }
  }
}

in main loop this line is setting what the bar will display

 unsigned int value = analogRead(0);
  perc = value/1023.0*100;

the original program used perc as the percentage to display

later in the code the program says print perc

lcd.setCursor(0,0); lcd.print ("1");
printbar (1,perc,1,0,19, true);
lcd.setCursor(0,1); lcd.print ("2");
printbar (2,perc,1,1,19, true);
lcd.setCursor(0,2); lcd.print ("3");
printbar (3,perc,1,2,19, true);
lcd.setCursor(0,3); lcd.print ("4");
printbar (4,perc,1,3,19, true);

notice that the code is printing perc to all 4 lines of the display

so you can change the code to control each one (read 4 different analog pins)

unsigned int value = analogRead(0);
  perc0 = value / 1023.0 * 100;
  unsigned int value = analogRead(1);
  perc1 = value / 1023.0 * 100;
  unsigned int value = analogRead(2);
  perc2 = value / 1023.0 * 100;
  unsigned int value = analogRead(3);
  perc3 = value / 1023.0 * 100;

then display the results

 lcd.setCursor(0, 0); lcd.print ("1");
  printbar (1, perc0, 1, 0, 19, true);
  lcd.setCursor(0, 1); lcd.print ("2");
  printbar (2, perc1, 1, 1, 19, true);
  lcd.setCursor(0, 2); lcd.print ("3");
  printbar (3, perc2, 1, 2, 19, true);
  lcd.setCursor(0, 3); lcd.print ("4");
  printbar (4, perc3, 1, 3, 19, true);

once you understand that you can change the code to use "for" to remove some of the repeating code
which is what rob has done for you

I really appreciate both of your help, but so far no go. Maybe it is something I am doing wrong or don't understand because as I said before I am pretty new to programming.

Rob
I loaded your sketch, but all four bars are still being controlled by A0. I noticed that in your sketch there is no analogue read for the other three pins.

Gpop

I didn't know if you wanted me to make the changes to the original sketch or to Rob's. I changed the analogue read part of the original sketch and it would not compile with the following error message.

exit status 1
redeclaration of 'unsigned int value'

It did this as soon as I started adding the additional analogue read lines.
When I am modifying sketches I always go line by line and verify, so I can spot my mistakes.
I am sure that with your assistance we can get this through my antique brain.

Thanks again
Dennis

try changing robs posted code

  float perc[4];
  for (int i = 0; i < 4; i++)
  {
    perc[i] = analogRead(0) / 1023.0 * 100;
  }

to

float perc[4];
for (int i = 0; i < 4; i++)
{
perc = analogRead(i) / 1023.0 * 100;

  • }*

Gpop

Before we go any farther. What is the last character in your user name. I can't make out exactly what it is and I hate to keep getting it wrong.
I copied and pasted the code you posted into Rob's sketch and got the following error.

exit status 1
incompatible types in assignment of 'double' to 'float [4]'

Did this compile for you?

detown:
Gpop

Before we go any farther. What is the last character in your user name. I can't make out exactly what it is and I hate to keep getting it wrong.

It's the digit 1 (one).
The trick is to copy the text and then paste it into a word processor or something. Then you can change the font to make it easier to read.

robs code with the change made so it should now read a0-A1-A2-A3

// include the library code:
#include <Wire.h>
#include <LiquidCrystal_I2C.h>  // fmalpartida version

// download here: https://bitbucket.org/fmalpartida/new-liquidcrystal/downloads
// remove the standard Arduino liquidcrystal from ...programs/Arduino/libraries

#define lcdlength 20  // DEFINES YOUR display length in columns
#define lcdheigth 4   // DEFINES YOUR display heigth in rows

unsigned char b, b2;
double a, a2;
unsigned int segment, segment2;
double perc = 100;
boolean logar;
byte bn;                 // bn BAR NUMBER every bar have to be numbered from 1 to 40
unsigned int xpos, ypos, blen;
double pkval[41];        // to store the last peak value for each bar
int    pkcyc[41][2];     // set the num. of printbar recall TO DO [1] and DONE [2] for each bar before the peak decays,

// if pkcyc[bn][1] == 0 no peaks wanted
// it's a workaround to avoid to waste time in delay functions (internal or external)
// that may interfere your application performances

// Bar characters definitions (8 maximum allowed)
byte block[8][8] =
{
  { 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 }, // define characters for bar
  { 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18 },
  { 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C },
  { 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E },

  { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 }, // define characters for peak
  { 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 },
  { 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 },
  { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
};

LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);


void setup()
{
  lcd.begin(20, 4);
  for ( int i = 0 ; i < 8 ; i++ ) lcd.createChar( i, block[i] );
}

void loop()
{
  // MAKE 4 MEASUREMENTS
  float perc[4];
  for (int i = 0; i < 4; i++)
  {
    perc[i] = analogRead(i) / 1023.0 * 100;
  }
  // Setting parameters for bars ( you can put directly values inside the function)
  // xpos=0;
  // ypos=1;
  // blen= 20;
  // remember that bar starts from lower point raising of blen positions
  // LEFT UPPER ANGLE IS xpos = 0 AND ypos = 0
  logar = false;

  for (int i = 1; i < 41; i++) // setting 15 cycles for all bars... YOUR CHOICE !!
  {
    pkcyc[i][1] =  15;
  }

  // DISPLAY MEASUREMENTS
  for (int bar = 0; bar < 4; bar++)
  {
    lcd.setCursor(0, bar); lcd.print (bar + 1);
    printbar (1, perc[bar], 1, bar, 19, true);
  }
}

//  METER BARS PRINTING FUNCTION
// passing percentage, x and y position, positions bar length, linear/audio logaritmic bar
// barnum is used to manage times of decayn of each peak separately (see definitions)
void printbar (byte bn, double perc, int xpos, int ypos, int blen, boolean logar)
{
  if ((logar == true) && (perc > 0))   // logaritmic bar
  {
    perc = ( log10(perc ) ) * 50;      // 10 * log10 (value) linear to logaritmic for AUDIO conversion
    if ( perc < 0 ) perc = 0;          // avoid negative values
  }

  a = blen / 99.5 * perc;              // calculate length of bar
  b = 0;

  if ( pkcyc[bn][1] > 0 )              // if PEAK is activated
  {
    if ( (a > (pkval[bn] - 0.01)) || (pkcyc[bn][2] > pkcyc[bn][1]) ) // new peak (w little histeresys) or expiration of peak
    {
      pkval[bn] = a;
      pkcyc[bn][2] = 0;                // reset cycles
    }
    pkcyc[bn][2]++;
  }

  // drawing filled rectangles
  if (a >= 1)
  {
    for (int i = 1; i < a; i++)
    {
      lcd.setCursor(xpos - 1 + i, ypos);
      lcd.write(255);
      b = i;
    }
    a = a - b;
  }
  segment = a * 5;

  // drawing final part of the bar
  if (b < blen)
  {
    lcd.setCursor(xpos + b, ypos);

    switch (segment) {
      case 0:
        lcd.print(" ");
        break;
      case 1:
        lcd.write((byte)0);
        break;
      case 2:
        lcd.write(1);
        break;
      case 3:
        lcd.write(2);
        break;
      case 4:
        lcd.write(3);
        break;
    }
  }

  // cleaning rest of line
  for (int i = 0; i < (blen - b - 1); i++)
  {
    lcd.setCursor(xpos + b + 1 + i, ypos);
    lcd.print(" ");
  }

  b2 = (int) pkval[bn];
  a2 = pkval[bn] - b2;
  segment2 = a2 * 5;

  // DRAWING PEAK
  if ( (pkcyc[bn][1] > 0) && (
         ((b + segment) == 0)                               // if bar empty
         || (b2 > b)                                        // or different box position
         || ( (b2 == b) && segment == 0 && segment2 > 0 )   // special case, too long to explain :-)
       ))
  {
    lcd.setCursor(xpos + b2, ypos);

    switch (segment2) {
      case 0:
        if ( (b2 > 0) || (b2 > b + 1))
        {
          lcd.setCursor(xpos + b2 - 1, ypos);
          lcd.write(7);
        };
        break;
      case 1:
        lcd.write(byte(0));
        break;
      case 2:
        lcd.write(4);
        break;
      case 3:
        lcd.write(5);
        break;
      case 4:
        lcd.write(6);
        break;
    }
  }
}

I think that did it. The problem I had with all of the bars moving when I was changing the voltage on one input was my own stupidity.
I do not have the pressure sensors yet, so I was using a pot to vary the voltage on one of the inputs. Like a dumb ass I was leaving the other 3 pins not connected to anything so they were floating.
As soon as I grounded the open pins it started moving the bar for the input I had the pot on.I will do some more testing tomorrow, because it is getting pretty late here.
Again, thanks for all the help and after studying the code will probably bug you with explaining some of the code that got this working.

Again, thanks a lot
Dennis