Wiki

Clone wiki

Arduino LCD Bitmap / Home

LCDBitmap Library for Arduino


Index


Introduction

Arduino library that allows you to create a tiny 20x16 pixel bitmap (raster) display on a normally character-only Hitachi HD44780 based LCD display. Typical drawing functions like line, rectangle, invert, etc. Control is right down to the pixel level.

YouTube of LCDBitmap library for Arduino

Works with both the standard Liquid Crystal library as well as Francisco's New Liquid Crystal library. Works with LCD connection methods including: 4bit, shift register (2 or 3 wire), and I2C. In-depth example sketches are included with library download.

It works by creating a memory array for the 20x16 pixel bitmap that the functions work within. It then converts this bitmap to the 8 custom characters available with the HD44780 and displaying them as 2 rows of 4 characters at the location specified. As each character is 5x8 pixels and arranged in a 4x2 character array, the total addressable resolution is 20x16. As there's an 8 custom character limit with the HD44780, 20x16 is the maximum resolution that can be achieved (5*4=20 X 8*2=16).


Download & Install

v1.6 Released

Save the .zip file to your desktop, then use the Importing a .zip Library instructions to import the library into the Arduino IDE.

(2,694 downloads on Google Code before being closed)

If you wish to fork this library, please create a private repository as to not confuse others trying to download the latest official version.


Show Your Appreciation

Help future development by making a small donation.

Donate


Connection Examples

Connection via standard 4bitConnection via shift registerConnection to Teensy 2.0
Connection via standard 4bitConnection via shift registerConnection to Teensy 2.0

Syntax

LCDBitmap bitmap( &lcd, x, y ) - &lcd is from Liquid Crystal, (x,y) is character position of the bitmap, 0,0 = top/left, 12,0 = far righton a 16x2 LCD. The 20x16 pixel display that LCDBitmap creates is 4 characters wide by 2 characters high.

  • bitmap.begin() - Initialize the LCD bitmap
  • bitmap.clear() - Clear the bitmap display (automatically updates bitmap display) doesn't clear text
  • bitmap.inverse() - Invert the bitmap, automatically updates the bitmap display
  • bitmap.update() - Update bitmap display
  • bitmap.clear_text() - Clear just the text on the display (leaves bitmap alone)
  • bitmap.home() - Move cursor the home position (0,0). Does a lcd.setCursor(0,0), just added for convenience
  • bitmap.move( x, y ) - Move the LCD bitmap position to this character position
  • bitmap.pixel( x, y, color, update ) - Add pixel at (x,y), color is either ON or OFF, update is either UPDATE or NO_UPDATE
  • bitmap.line( x1, y1, x2, y2, color, update ) - Draw the line from (x1,y1) to (x2,y2), color & update as in pixel
  • bitmap.rect( x1, y1, x2, y2, color, update ) - Draw a rectangle from (x1,y1) to (x2,y2), color & update as in pixel
  • bitmap.rectFill( x1, y1, x2, y2, color, update ) - Draw a filled rectangle from (x1,y1) to (x2,y2), color & update as in pixel
  • bitmap.barGraph( bars, *graph, color, update ) - Draw bar graph, bars is # of bars (1,2,4,5,10,20), graph is array containing height values, color & update as in pixel

History

v1.6 - Released 7/05/2012: BITMAP_RANGE_CHK bug fix.

v1.5 - Released 6/28/2012: 4bit method now works without the New LiquidCrystal? library (was always supposed to work this way, oversight on my part). Update switch now optional on all functions, defaults to NO_UPDATE.

v1.4 - Released 5/25/2012: Fixed a few problems with the barGraph function. Further optimization with the range checking. Compatible with Arduino 0023 through 1.0+

v1.3 - Released 5/10/2012: Many performance tweaks and reduced compiled code size. Optimization were enough to deprecate the lineHor and lineVert commands. Both functions still work, there's just no longer any advantage in using them. Thanks to robtillaart for suggesting the Bresenham line algorithm. Modified range checking removing redundant checks. Added new function barGraph that easily creates a 1 to 20 bar graph.


Support Forum

LCD Bitmap support forum


Examples

Simple sketch using I2C LCD interface

Simple sketch using I2C LCD interface

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <LCDBitmap.h>

LiquidCrystal_I2C lcd(0x38);

// Assign LCD bitmap to "&lcd", set bitmap display location to character position (0,0).
LCDBitmap bitmap(&lcd, 0, 0);

void setup() {
  lcd.begin(16,2); // Do this first.
  bitmap.begin();  // Then initialize the LCD bitmap.
  lcd.setCursor(5, 0);
  lcd.print("LCDBitmap");
}

void loop() {
  // Draws some concentric rectangles to the bitmap, don't update bitmap display till the final command.
  bitmap.rectFill(0, 0, 19, 15, ON, NO_UPDATE);
  bitmap.rectFill(2, 2, 17, 13, OFF, NO_UPDATE);
  bitmap.rectFill(4, 4, 15, 11, ON, NO_UPDATE);    
  bitmap.rect(6, 6, 13, 9, OFF, UPDATE);

  while(1){}
}

barGraph sketch using standard 4bit LCD interface

barGraph sketch using standard 4bit LCD interface

#include <LiquidCrystal.h>
#include <LCDBitmap.h>

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
LCDBitmap bitmap(&lcd, 0, 0);  // Set the bitmap to the &lcd display at character position 0,0.

byte graph[20];
byte bars[] = { 1, 2, 4, 5, 10, 20 };

void setup() {
  lcd.begin(16,2); // Initialize the LCD display, do this before you initialize LCDBitmap.
  bitmap.begin();  // Then initialize the LCD bitmap.
  lcd.setCursor(5, 0);
  lcd.print("LCDBitmap");
}

void loop() {
  byte curr_bars = bars[(millis()/3000)%6];
  for (byte x=0; x<curr_bars; x++) {
    graph[x] = random(0, BITMAP_H+1);
  }
  bitmap.barGraph(curr_bars, graph, ON, UPDATE);  // Display the bar graph.
  delay(50);
}

Complex sketch using 4bit LCD interface

#include <LiquidCrystal.h>
#include <LCDBitmap.h>

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
LCDBitmap bitmap(&lcd, 12, 0);  // Assign the LCD bitmap to "&lcd" set in the previous line and set display location to (12,0)

unsigned long currentMillis;  // Timer variable
#define sample 4000  // Sets how long to run each sample

void setup() {
  lcd.begin(16,2);  // Initialize the LCD 
  bitmap.begin();  // Initalize the LCD bitmap
  bitmap.home();  // Move cursor the home position (0,0)
  lcd.print("LCDBitmap");  
  randomSeed(analogRead(A0));
}

void loop() {
  // bitmap.pixel
  lcd.setCursor(0, 1);
  lcd.print(".pixel   ");
  currentMillis = millis();
  while(millis()-currentMillis<sample) {
    for (byte i=0; i<8; i++) {
      bitmap.pixel(random(0, BITMAP_W), random(0, BITMAP_H), random(0, 2), NO_UPDATE);  // Add one random pixel but don't update bitmap display
    }
    bitmap.update();  // 8 pixels positioned, now update bitmap display
  }

  // bitmap.line sample #1
  lcd.setCursor(0, 1);
  lcd.print(".line #1 ");
  bitmap.clear();  // Clear the bitmap display (automatically updates bitmap display) doesn't clear text
  currentMillis = millis();
  int startdelay=120;
  while(millis()-currentMillis<sample*2) {
    for (byte x=0; x<BITMAP_W; x=x+2) {
      bitmap.line(x, 0, BITMAP_W-x-1, BITMAP_H-1, ON, UPDATE);  // Draw the line from (x, 0) to (BITMAP_W-x-1, BITMAP_H-1) and update bitmap display
      delay(startdelay);
      bitmap.clear();  // Clear the display
    }
    for (byte y=0; y<BITMAP_H; y=y+2) {
      bitmap.line(0, BITMAP_H-y-1, BITMAP_W-1, y, ON, UPDATE);
      delay(startdelay);
      bitmap.clear();  // Clear the display
    }
    startdelay=startdelay*2/3;
  }

  // bitmap.line sample #2
  lcd.setCursor(0, 1);
  lcd.print(".line #2 ");
  currentMillis = millis();
  while(millis()-currentMillis<sample) {
    for (byte x=0; x<BITMAP_W; x++) {
      bitmap.line(x, 0, x, BITMAP_H-1, ON, UPDATE);  // Draw the line from (x, 0) to (x, BITMAP_H-1) and update bitmap display
    }
    for (byte y=0; y<BITMAP_H; y++) {
      bitmap.line(0, y, BITMAP_W-1, y, OFF, UPDATE);
    }
  }
  bitmap.clear();  // Clear the display

  // bitmap.rect
  lcd.setCursor(0, 1);
  lcd.print(".rect    ");
  currentMillis = millis();
  while(millis()-currentMillis<sample) {
    bitmap.rect(random(0, BITMAP_W), random(0, BITMAP_H), random(0, BITMAP_W), random(0, BITMAP_H), ON, UPDATE);  // Draw a rectangle from (x1,y1) to (x2,y2) and update bitmap display
    delay(150);
    bitmap.clear();  // Clear the display
  }

  // bitmap.rectFill
  lcd.setCursor(0, 1);
  lcd.print(".rectFill");
  currentMillis = millis();
  while(millis()-currentMillis<sample*1.5) {
    bitmap.rectFill(random(0, BITMAP_W), random(0, BITMAP_H), random(0, BITMAP_W), random(0, BITMAP_H), ON, NO_UPDATE);  // Draw a filled rectangle from (x1,y1) to (x2,y2) and update bitmap display
    bitmap.rectFill(random(0, BITMAP_W), random(0, BITMAP_H), random(0, BITMAP_W), random(0, BITMAP_H), OFF, NO_UPDATE);  // Draw a filled rectangle from (x1,y1) to (x2,y2) and update bitmap display
    bitmap.update();  // Filled rectangles drawn, now update bitmap display
    delay(10);
  }
  bitmap.clear();  // Clear the display

  // bitmap.barGraph
  lcd.setCursor(0, 1);
  lcd.print(".barGraph ");
  byte bars=10;
  byte graph[bars];  // 10 Bar graph values
  currentMillis = millis();
  while(millis()-currentMillis<sample*2) {
    for (byte x=0; x<bars; x++) {
      graph[x] = random(0, BITMAP_H);  // Fill array with random height values
    }
    bitmap.barGraph(bars, graph, ON, UPDATE);  // Display the bar graph
    delay(10);
    if (bars==10 && millis()-currentMillis>=sample) bars=4;
  }
  bitmap.clear();  // Clear the display

  // This creates a big "X" using the LCDBitmap to show the inverse and move functions
  for (byte x=0; x<=4; x++) {
    bitmap.line(x, BITMAP_H-1, x+BITMAP_H-1, 0, ON, NO_UPDATE);  // Draw a line, but don't update the bitmap display
    bitmap.line(x, 0, x+BITMAP_H-1, BITMAP_H-1, ON, NO_UPDATE);  // Draw a line, but don't update the bitmap display
  }
  bitmap.update();  // Now that everything is written to the bitmap, show the changes

  // bitmap.inverse
  lcd.setCursor(0, 1);
  lcd.print(".inverse ");
  delay(1000);
  int x_status = 1;
  currentMillis = millis();
  while(millis()-currentMillis<sample/2) {
    for (byte a=0; a<6; a++) {
      bitmap.inverse();  // Invert the bitmap, automatically updates the bitmap display
      x_status *= -1;
      delay(75);
    }
  }
  if (x_status==-1) bitmap.inverse();

  // bitmap.move
  bitmap.clear_text();  // Clear just the text on the display (leaves bitmap alone)
  lcd.setCursor(0, 1);
  lcd.print(".move");
  for (byte x=11; x>4; x--) {
    bitmap.move(x,0);  // Move the LCD bitmap position to the left one position
    delay(150);
  }
  for (byte x=6; x<13; x++) {
    bitmap.move(x,0);  // Move the LCD bitmap position to the right one position
    delay(150);
  }
  bitmap.home();  // Move cursor the home position (0,0)
  lcd.print("LCDBitmap");  
  delay(500);
  
  // bitmap.clear
  lcd.setCursor(0, 1);
  lcd.print(".clear   ");
  delay(1000);
  bitmap.clear();  // Clear the bitmap display only (automatically updates bitmap display) doesn't clear text
  delay(2000);
}

My Other Arduino Libraries

NewPing Works with many ultrasonic sensors, can communicate using only one pin, very low lag, fast (up to 30 pings per second), timer interrupt method for event-driven sketches, light code, and much more.

LCDBitmap Arduino library that allows you to create a tiny 20x16 pixel bitmap (raster) display on a normally character-only Hitachi HD44780 based LCD display. Typical drawing functions like line, rectangle, invert, etc. Control is right down to the pixel level.

toneAC Replacement to the standard tone library with the advantage of nearly twice the volume, higher quality, can produce higher frequencies, 1.5k smaller compiled code, and less stress on the speaker.

toneAC2 Replacement to the standard tone library with the advantage of nearly twice the volume, 800 bytes smaller compiled code size, and less stress on the speaker.

NewTone About 1,200 bytes smaller code size than the standard tone library, faster execution time, exclusive use of port registers for fastest and smallest code, higher quality sound output than tone library.

TimerFreeTone Replacement to the standard tone library but without using timers. Also over 1.5k smaller compiled code, exclusive use of port registers, and compatible with ATmega, ATtiny, and ARM-based microcontrollers.

Updated