Monday, 24 February 2014

LCD Interfacing - Creating Custom Characters

So you have been using an LCD for sometime and now have the need to create a custom character / symbol... How do you do it?
(Please check this before proceeding -   LCD Interfacing - Working with the Simple Labs' LCD Shield)

Before getting onto it, lets understand how an LCD displays characters. If you notice, each character on a LCD display typically is inside a small 5 Rows x 8 Columns array of dots. Depending upon the character to be displayed, the required dots are turned On / Off. Most LCD's come pre-configured to display standard characters. Each character has a definition matrix, which defines which dots are to be On and which dots are to be Off.

Here's an image that will help you understand better. Here's a Custom Smiley and its corresponding Binary definition

Here's how we will define a BYTE variable to hold the definition for the above Character. If you look at it the first row above is stored in the 0th index of the array mySmiley.

byte mySmiley[8] = {
0b00000, 
0b01010, 
0b01010, 
0b01010, 
0b00000, 
0b10001, 
0b01110,
0b00000
};

if Binary is not your game, you can use the below image, to find the decimal equivalent. (both images are using different characters - so use your common sense ;) )


So we can rewrite the definition in decimal as follows
byte mySmiley[8] = { 0, 10,10,10,0,17,14,0};

Here's a simple program to display the Smiley on your LCD

Here's the Program
/*  Induino R3 User Guide - Program 20.0 - LCD Interfacing - Creating Custom Characters on a 16x2 LCD using the Induino R3 */

/* This program uses the Simple Labs LCD Shield, 16x2 LCD from Simple Labs and the Induino R3 Board. Change the pin numbers according your own hardware */

#include <LiquidCrystal.h> //Include the LCD Header

// initialize the lcd
LiquidCrystal lcd(8, 9,10, 11, 12,13);

byte mySmiley[8] = {0,10,10,10,0,17,14,0}; // Define the Smiley Character


void setup()
{
  // add the mySmiley Character to the 0th Location of the LCD's CGRAM 
  // 0-7 are possible values here
  lcd.createChar(0, mySmiley);
  
  // set up number of columns and rows
  lcd.begin(16, 2); 
  
  // Write out Smiley Character.
 // Type casting is required as we are directly mentioning a value
  lcd.write((uint8_t)0); 
}

void loop()
{

}


Now lets play around by creating a set of 8 Characters, each representing a line at a different height (see the output to get a clear understanding)

byte line_0[8] = { 0,0,0,0,0,0,0,31};
byte line_1[8] = { 0,0,0,0,0,0,31,0};
byte line_2[8] = { 0,0,0,0,0,31,0,0};
byte line_3[8] = { 0,0,0,0,31,0,0,0};
byte line_4[8] = { 0,0,0,31,0,0,0,0};
byte line_5[8] = { 0,0,31,0,0,0,0,0};
byte line_6[8] = { 0,31,0,0,0,0,0,0};
byte line_7[8] = { 31,0,0,0,0,0,0,0};

Now the above definition can be optimized by making it an array, so we can redefine it as 

byte line[8][8]={
{ 0,0,0,0,0,0,0,31},
{ 0,0,0,0,0,0,31,0},
{ 0,0,0,0,0,31,0,0},
{ 0,0,0,0,31,0,0,0},
{ 0,0,0,31,0,0,0,0},
{ 0,0,31,0,0,0,0,0},
{ 0,31,0,0,0,0,0,0},
31,0,0,0,0,0,0,0}
};

Here's the Program
/*  Induino R3 User Guide - Program 20.1 - LCD Interfacing - Creating Custom Characters on a 16x2 LCD using the Induino R3 */

/* This program uses the Simple Labs LCD Shield, 16x2 LCD from Simple Labs and the Induino R3 Board. Change the pin numbers according your own hardware */

#include <LiquidCrystal.h> //Include the LCD Header

// initialize the lcd
LiquidCrystal lcd(8, 9,10, 11, 12,13);

byte mySmiley[8] = {0,10,10,10,0,17,14,0}; // Define the Smiley Character


void setup()
{
  // add the custom characters to the LCD's CGRAM 
  lcd.createChar(0, mySmiley);
  
  // set up number of columns and rows
  lcd.begin(16, 2); 
  
  // Write out the custom Characters
  // Type casting is required as we are directly mentioning a value
  lcd.write((uint8_t)0); 
}

void loop()
{

}

Now Lets to try to modify the above program to create a set of characters that can produce a BAR Graph with 8 different levels.

First we redefine the Character Array

byte line[8][8]={
{ 0,0,0,0,0,0,0,31}, // Level 1
{ 0,0,0,0,0,0,31,31}// Level 2
{ 0,0,0,0,0,31,31,31}// Level 3
{ 0,0,0,0,31,31,31,31}// Level 4
{ 0,0,0,31,31,31,31,31}// Level 5
{ 0,0,31,31,31,31,31,31}// Level 6
{ 0,31,31,31,31,31,31,31}// Level 7
31,31,31,31,31,31,31,31// Level 8
};

Here's the Program
/*  Induino R3 User Guide - Program 20.2 - LCD Interfacing - Creating Custom Characters on a 16x2 LCD using the Induino R3 */

/* This program creates a series of Bar Graph Characters- an experimentation with custom characters */

#include <LiquidCrystal.h> //Include the LCD Header

// initialize the lcd
LiquidCrystal lcd(8, 9,10, 11, 12,13);

// Define the Characters for creating a Bar Graph with Various Levels
byte line[8][8]={
{ 0,0,0,0,0,0,0,31}, // Level 1
{ 0,0,0,0,0,0,31,31}, // Level 2
{ 0,0,0,0,0,31,31,31}, // Level 3
{ 0,0,0,0,31,31,31,31}, // Level 4
{ 0,0,0,31,31,31,31,31}, // Level 5
{ 0,0,31,31,31,31,31,31}, // Level 6
{ 0,31,31,31,31,31,31,31}, // Level 7
{ 31,31,31,31,31,31,31,31} // Level 8
};

void setup()
{
  // add the custom characters to the LCD's CGRAM 
  for(int i =0; i <8; i++)
  {
    lcd.createChar(i, line[i]);
  }
  // set up number of columns and rows
  lcd.begin(16, 2); 
}

void loop()
{
  // Show the Bar Graph Characters as increasing
  for(int i =0; i <8; i++)
  {
   // Print the Bar Graph Character on the First Line
   lcd.setCursor(i,0);   
   lcd.write(i);
   
   // Print the Corresponding value on the Second Line
   lcd.setCursor(i,1);   
   lcd.print(i);
   delay(1000); 
  }
  delay(1000); 
  // Clear the display
  lcd.clear();
}

Now lets use the bar graph characters to indicate sensor value. We shall use the value of the LDR on the Induino R3 board and try to represent it using the Bar Graph.

Here's the Program
/*  Induino R3 User Guide - Program 20.3 - LCD Interfacing Custom Characters- Displaying the LDR Value as a Single Bar Graph Character Induino R3 */

/* This program creates a series of Bar Graph Characters- an experimentation with custom characters */

#include <LiquidCrystal.h> //Include the LCD Header

// initialize the lcd
LiquidCrystal lcd(8, 9,10, 11, 12,13);

// Define the Characters for creating a Bar Graph with Various Levels
byte line[8][8]={
{ 0,0,0,0,0,0,0,31}, // Level 1
{ 0,0,0,0,0,0,31,31}, // Level 2
{ 0,0,0,0,0,31,31,31}, // Level 3
{ 0,0,0,0,31,31,31,31}, // Level 4
{ 0,0,0,31,31,31,31,31}, // Level 5
{ 0,0,31,31,31,31,31,31}, // Level 6
{ 0,31,31,31,31,31,31,31}, // Level 7
{ 31,31,31,31,31,31,31,31} // Level 8
};

void setup()
{
  // add the custom characters to the LCD's CGRAM 
  for(int i =0; i <8; i++)
  {
    lcd.createChar(i, line[i]);
  }
  // set up number of columns and rows
  lcd.begin(16, 2); 
}

void loop()
{
 // Read the LDR Value and store it in a variable
 int val = analogRead(3);
 // Map the analog value from the sensor to a scale of 0 to 7 (8 Levels)
 val = map(val, 0, 1023, 0, 7);
 
 // Print the numerical value to the LCD
 lcd.setCursor(0,1);
 lcd.print(val);
 
 //set the cursor
 lcd.setCursor(0,0);
 
  // Write the Bar Graph Level Value corresponding to the Value of the LDR

 lcd.write(val);
 
 delay(100);  
 lcd.clear(); 
}

Now Having a static Bar is not much fun, lets convert this into a realtime BAR graph. A Running Bar Graph based on the last 16 values of the sensor. 16 Values as we can display only 16 characters per line.

/*  Induino R3 User Guide - Program 20.4 - LCD Interfacing Custom Characters- Displaying the LDR Value as a Running Bar Graph using the Induino R3 */

/* This program creates a series of Bar Graph Characters- an experimentation with custom characters */

#include <LiquidCrystal.h> //Include the LCD Header

// initialize the lcd
LiquidCrystal lcd(8, 9,10, 11, 12,13);

// Define the Characters for creating a Bar Graph with Various Levels
byte line[8][8]={
{ 0,0,0,0,0,0,0,31}, // Level 1
{ 0,0,0,0,0,0,31,31}, // Level 2
{ 0,0,0,0,0,31,31,31}, // Level 3
{ 0,0,0,0,31,31,31,31}, // Level 4
{ 0,0,0,31,31,31,31,31}, // Level 5
{ 0,0,31,31,31,31,31,31}, // Level 6
{ 0,31,31,31,31,31,31,31}, // Level 7
{ 31,31,31,31,31,31,31,31} // Level 8
};

// a variable array to store the last 16 values of the sensor
int hist_val[16];

// to count the first 16 values
int cnt = 0;

void setup()
{
  // add the custom characters to the LCD's CGRAM 
  for(int i =0; i <8; i++)
  {
    lcd.createChar(i, line[i]);
  }
  // set up number of columns and rows
  lcd.begin(16, 2); 
}

void loop()
{
 // Read the LDR Value and store it in a variable
 int val = analogRead(3);
 // Map the analog value from the sensor to a scale of 0 to 7 (8 Levels)
 val = map(val, 0, 1023, 0, 7);
 
 lcd.setCursor(0,0);
 lcd.print(val);
 
 // Check if cnt is less than 16, if it is less than 16, we need to increment it
// we also need to store the values of the sensor for the first 16 counts
 if(cnt<16)
 {
   hist_val[cnt] = val;
   // Increment cnt  
   cnt++;
 }
 else
 // if count is greater than 16, we need to push out the oldest of the values and add the latest value to the set of 16 values.
 // the oldest value will be stored in the 0th array index and the latest value in the 15th array index
 // in addition, we also need to move up all other historic values by one position
 {
   // do the moving up of the historic values
   for(int j=0; j<15;j++) 
     hist_val[j] = hist_val[j+1];
     
   // store the latest value in the last position
   hist_val[15] = val; 
 }
 // Displaying the Values as a Running Bar Graph
 for(int i=0; i<cnt; i++)
 {
    lcd.setCursor(i,0);
                  lcd.write(hist_val[i]);
                 /* lcd.setCursor(i,1);
                  lcd.print(hist_val[i]); */
                  delay(10);
 }

}

Thats It For This Part! Enjoy... and feel free to drop us an email with questions you might have -> info@simplelabs.co.in

Visit www.simplelabs.co.in for more interesting products

2 comments:

  1. nice but how to print present time and date in lcd ?

    ReplyDelete
  2. Check this
    http://www.induino.com/2013/07/i2c-communication-what-where-how.html

    ReplyDelete