Multidisplay, a Open Source inCar Display, Logger

A bit OT, I know, but...

I wrote some code to display a "progress bar" with pixel resolution rather than character resolution. It uses 5 custom chars.

Here's an example sketch that includes the function and different display styles.

How did you implement your "bars" ?

/*
 * Simple "graphical" bar on 5x8 lcd display.
 *
 * Author: Marcello Romani mromani@ottotecnica.com
 *
 * Hardware requirements:
 * - Arduino 2009 board
 * - Nuelectrocnics display shield:
 *   http://www.nuelectronics.com/estore/index.php?main_page=product_info&cPath=1&products_id=2
 * - A standard LCD shield can be used as well, provided you correct the LiquidCrystal pin assignments
 *
 * Usage:
 * - Connect two potentiometers to analog inputs 1 and 2.
 * - select the display style by uncommenting the desired display funcion in loop()
 * 
 */

#include <LiquidCrystal.h>

// pin assignments are for nuelectronics' lcd+keypad shield;
// adjust for other lcd shields
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

// lcd size
const int LCD_NUM_COLS = 16;
const int LCD_NUM_ROWS = 2;

// analog channels to read and display
// change to taste
#define ANALOG_CHANNEL_1  1
#define ANALOG_CHANNEL_2  2


const int ANALOG_POLL_TIME = 100;    // unit: ms
const int NUM_VALUES = LCD_NUM_ROWS;
const int MAX_VALUE = 1023;
const int MIN_VALUE = 0;
int value[NUM_VALUES];
const int channels[NUM_VALUES] = { ANALOG_CHANNEL_1, ANALOG_CHANNEL_2 };

// custom characters for progress bar generation
byte graph0[8] = {
  B00000,
  B00000,
  B00000,
  B00000,
  B00000,
  B00000,
  B00000,
  B00000,
};

byte graph1[8] = {
  B10000,
  B10000,
  B10000,
  B10000,
  B10000,
  B10000,
  B10000,
  B10000,
};

byte graph2[8] = {
  B11000,
  B11000,
  B11000,
  B11000,
  B11000,
  B11000,
  B11000,
  B11000,
};

byte graph3[8] = {
  B11100,
  B11100,
  B11100,
  B11100,
  B11100,
  B11100,
  B11100,
  B11100,
};

byte graph4[8] = {
  B11110,
  B11110,
  B11110,
  B11110,
  B11110,
  B11110,
  B11110,
  B11110,
};

byte graph5[8] = {
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
};


void createCustomChars() {
  lcd.createChar(0, graph0);
  lcd.createChar(1, graph1);
  lcd.createChar(2, graph2);
  lcd.createChar(3, graph3);
  lcd.createChar(4, graph4);
  lcd.createChar(5, graph5);
}


//
// draw a horizontal bar on the display
// using custom chars 0..4
//
// row = number of row to draw to (0 or 1)
// maxChars = maximum bar lenght, in number of display characters
// value = raw value to display
// minValue, maxValue = minimum and maximum value for the value parameter
//
void drawBar(LiquidCrystal* lcdObj, int col, int row, int maxChars, int value, int minValue, int maxValue) {
  // character width in number of pixels
  static const int pixelsPerChar = 5;
  
  // maximum bar width in pixels
  int maxPixels;
  
  // calculated actual bar width
  int numPixels;
  
  // number of full chars to draw
  int q;
  
  // number of pixels in the last char
  int r;
  
  // counter
  int i;
  
  maxPixels = maxChars * pixelsPerChar;
  numPixels = map(value, minValue, maxValue, 0, maxPixels);
  
  q = numPixels / pixelsPerChar;
  r = numPixels % pixelsPerChar;

/*
  // debug over serial line
  Serial.println("----");
  Serial.println(value);
  Serial.println(maxPixels);
  Serial.println(numPixels);
  Serial.println(q);
  Serial.println(r);
*/

  lcdObj->setCursor(col, row);
  
  // always redraw the full bar to erase the previous one
  for (i = 0; i < maxChars; i++) {
    if (i < q) {
      lcdObj->write(5);    // full char
    }
    else if (i == q) {
      lcdObj->write(r);    // last char
    }
    else {
      lcdObj->write(0);    // erase any previous chars
    }
  }
}


// read the analog channels
void updateValues() {
  int i;
  
  for (i = 0; i < NUM_VALUES; i++) {
    value[i] = analogRead(channels[i]);
  }
}


// two orizontal bars
void updateDisplay0() {
  int i;
  
  for (i = 0; i < NUM_VALUES; i++) {
    drawBar(&lcd, 0, i, LCD_NUM_COLS, value[i], MIN_VALUE, MAX_VALUE);
  }
}


// two horizontal bars with raw analog values on the right
void updateDisplay1() {
  static char buf[10];
  int i;
  
  for (i = 0; i < NUM_VALUES; i++) {
    drawBar(&lcd, 0, i, LCD_NUM_COLS - 4, value[i], MIN_VALUE, MAX_VALUE);
    sprintf(buf, "%4d", value[i]);
    lcd.setCursor(LCD_NUM_COLS - 4, i);
    lcd.print(buf);
  }
}


// two horizontal bars with raw analog values on the left
void updateDisplay2() {
  static char buf[10];
  int i;
  
  for (i = 0; i < NUM_VALUES; i++) {
    drawBar(&lcd, 4, i, LCD_NUM_COLS - 4, value[i], MIN_VALUE, MAX_VALUE);
    sprintf(buf, "%4d", value[i]);
    lcd.setCursor(0, i);
    lcd.print(buf);
  }
}


// two horitonal bars with raw analog values beneath them
void updateDisplay3() {
  static char buf[10];
  int i;
  
  for (i = 0; i < NUM_VALUES; i++) {
    drawBar(&lcd, i*(LCD_NUM_COLS/2), 0, LCD_NUM_COLS/2, value[i], MIN_VALUE, MAX_VALUE);
    sprintf(buf, "%8d", value[i]);    // NOTE: field width must be equal to LCD_NUM_COLS/2
    lcd.setCursor(i*(LCD_NUM_COLS/2), 1);
    lcd.print(buf);
  }
}


void setup() {
  // this is required only for debug
  //Serial.begin(115200);
  
  // initialize lcd library
  lcd.begin(LCD_NUM_COLS, LCD_NUM_ROWS);
  
  // create required custom chars
  createCustomChars();
}


void loop() {
    // read the analog values
    updateValues();
    
    // uncomment only one of these:
    //updateDisplay0();
    //updateDisplay1();
    //updateDisplay2();
    updateDisplay3();
    
    // don't write too fast to the lcd...
    delay(ANALOG_POLL_TIME);
}